Skip to main content
Version: 3.x

完整项目

1. 设置 npm 镜像仓库

依赖 node10.x 及以上版本,我们默认您已经安装 node 环境,如果您本地没有安装 node 环境,请安装

  1. 外部用户

    • 外部用户需要登录 npm 仓库,请联系客服索取 npm 账户信息,需要登录后才可以安装脚手架

      npm login -registry=https://artifact.iquantex.com/repository/npm-local/ -scope=@gza
      - Username: 【npm user】
      - Password: 【npm password】
      - Email: 【your email】
    • 如果您是首次使用 npm ,我们建议您设置 npm 国内镜像,否则可能会导致安装依赖很慢甚至失败

      npm config set registry=https://registry.npm.taobao.org
  2. 内部用户

    • 内部用户(宽拓员工)使用公司内部的 npm 源,无需执行以上登录操作

      npm config set registry=http://10.116.18.70:8081/content/groups/npm-quantex-group

2. 全局安装 @gza/create-godzilla-app

不推荐用 yarn 安装,目前框架暂没有去验证 yarn 模式下是否可用

npm i -g @gza/create-godzilla-app@latest #

3. 使用gza命令创建项目

  1. 创建项目

    • 方法一:可直接使用 gza init [project name] 初始化 UI 应用

      gza init godzilla-portal # 初始化UI应用,`godzilla-portal` is your project name
      cd godzilla-portal
  • 方法二:先创建应用目录,再使用 gza init 初始化

    mkdir godzilla-portal  #新建目录,`godzilla-portal` is your project name
    cd godzilla-portal
    gza init

    方法一和方法二都需要执行完2.配置项目的【配置 layout】的内容之后,再执行下面的命令,启动项目。

      npm start

    打开浏览器 http://127.0.0.1:8888 输入用户名密码(任意)即可进入系统

    PNG

  • 注意:在 MacOS 环境,如果出现如下错误,则参考此链接 https://github.com/schnerd/d3-scale-cluster/issues/7 修复

    PNG

    用 Create Godzilla APP 创建的 UI 项目,最开始只有 pages 目录

    // 目录结构
    app
    -- pages
    -- globals.d.ts
    config
    -- config.ts
    package.json
    ... 其它配置文件

    随着项目的复杂度增加,会需要更多的目录,目前框架约定支持如下其它目录

    // 目录结构
    app
    -- pages
    -- commonents // 公共业务组件
    -- layouts // 界面外观配置
    -- utils // 公共 utils
    -- styles // 公共样式
    -- images // images 目录
    config
    -- config.ts
    package.json
    ... 其它配置文件
  1. 配置项目
  • 配置 layout

    新增配置文件 app/layouts/index.ts,需要注意的是路径和文件名不可以自定义。 开发环境时,提供两种获取数据的方式,有两种设计方案,分别是: 方案一,一般是服务端没有提供接口,也没有提供接口文档的情况下,直接使用 Promise.resolve() 返回定义的数据; 方案二,当使用 API 调用请求方法时,可分为两种场景:一种已经提供了接口文档,但没有提供接口;另一种是已经提供接口或者是两者都提供了 具体案例如下:

    • 方案一 使用方案一时不会依赖 mock 服务,开发人员使用 Promise.resolve() 返回按照约定的自定义的数据,以完成一些简单的功能。
    import defaultLayouts from '@/containers/defaultLayouts';
    import { cloneDeep } from 'lodash';
    import { Util } from '@gza/quantex-utils';

    // 这里需要先深拷贝一份配置
    const layouts = cloneDeep(defaultLayouts);

    /*
    * 假设需要登录 GZA UI 系统,可以使用以下数据格式,所有字段不可更改:
    * {
    * code: "用户编码",
    * name: "用户名",
    * token : token
    * }
    */

    layouts.login.login = async (params) => {
    params.loginPassword = Util.sha256Encode(params.loginPassword);
    return Promise.resolve({
    code: 200,
    data: {
    code: 'test',
    name: 'test',
    token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6I...6MTU4NzQzNTc2NX0.I5McYxR4y0luSTWeaFGDmV',
    },
    msg: '操作成功!',
    });
    };

    // 此处只做覆盖,不做任何逻辑
    layouts.login.logout = async () => {
    return Promise.resolve();
    };

    // 此处只做覆盖,不做任何逻辑
    layouts.login.getMicroApp = () => {
    return Promise.resolve({ code: 200, data: { list: [] } });
    };

    /*
    * GZA UI 系统菜单数据,可以使用以下格式,所有字段不可更改:
    * 若是一级菜单需要按照以下格式,且父子菜单ID需要一致:
    * {
    * id: 子菜单ID,
    * pId: 父菜单ID,
    * icon: 菜单图标, (一级菜单需要)
    * appId: APP ID,
    * name: 菜单名称
    * }
    * 若不是是一级菜单需要按照以下格式:
    * {
    * id: 子菜单ID,
    * pId: 父菜单ID,
    * appId: APP ID,
    * name: 菜单名称
    * url: 菜单地址, (子菜单需要,appId/路径,路径是相对于 app/pages 的路径)
    * }
    */

    layouts.main.getUserMenu = () => {
    return Promise.resolve({
    code: 200,
    data: {
    list: [
    {
    id: 10,
    pId: 10,
    icon: 'chanpinguanli',
    appId: 'portal',
    name: '应用管理',
    },
    {
    id: 11,
    pId: 10,
    appId: 'portal',
    name: '应用管理',
    url: 'portal/system/Application',
    },
    {
    id: 12,
    pId: 10,
    appId: 'portal',
    name: '菜单管理',
    url: 'portal/system/Menu',
    },
    ],
    },
    msg: '操作成功!',
    });
    };

    export default layouts;
    • 方案二 使用 Util 工具库封装的 API 功能实现接口请求功能,使用方案二的场景有两种,分别是: 场景一,假设只提供了接口文档,未提供接口,开发人员可以依赖 mock 服务,实现接口功能,在本地按照约定创建数据。 场景二,假设已经提供接口或者是两者都提供,此时不需要依赖 mock 服务,直接从后端获取数据。

      有两点需要注意: 一是两种场景的使用方式是一样的,因此以下只以一种场景做演示; 二是 mock 服务的优先级比后台优先级高,在使用重名接口的调用时 mock 优先访问,所以当使用场景二的时候,需要将 app/pages/_mock.(js|ts) 文件删除

      假设开发人员的使用场景是场景一,那在开发之前需要在 app/pages 目录先建立 _mock.(ts|js) 文件,并添加接口数据,若是场景二,可直接跳过这一步。按照约定数据格式如下:

          // app/pages/_mock.js
      module.exports = {
      'POST /auth/api/users/login': {
      code: 200,
      data: {
      code: 'a',
      roleCodes: 'admin',
      loginTime: 1587435765100,
      loginName: 'a',
      name: 'a',
      roleNames: '超级管理员',
      exp: 1587522165,
      token: 'eyJhbGciOiLo...uSTWeaFGDmVLEh8mIramo7HlWPwiWtgI',
      },
      msg: '操作成功!',
      },
      'PUT /auth/api/users/logout': {
      code: 200,
      data: {},
      msg: '退出成功!',
      },
      'GET /auth/api/users/:code/menus': {
      code: 200,
      data: {
      list: [
      {
      id: 10,
      pId: 10,
      icon: 'chanpinguanli',
      appId: 'portal',
      name: '菜单名称',
      },
      {
      id: 11,
      pId: 10,
      appId: 'portal',
      name: '应用管理',
      url: 'portal/system/Application',
      },
      {
      id: 12,
      pId: 10,
      appId: 'portal',
      name: '菜单管理',
      url: 'portal/system/Menu',
      },
      ],
      },
      msg: '操作成功!',
      },
      };

      菜单规则:

      1. 设置一级菜单时,id 和 pId 需设置一致,且数值唯一。
      2. 设置 icon 时,是一级菜单需提供 icon 值,反之不设值。
      3. 设置 url 时,不是一级菜单需提供 url 值(格式 appID/路径,路径是相对于 app/pages 目录,如: portal/system/ServiceProxy ),反之不设值。
      4. 设置 appId 时,值必须和 app/config/config.ts 文件的属性 APP_ID 的值一致,且不可以设置为关键字 portal。

      两种场景的代码格式是一样的,因此这里不做区分。

        import defaultLayouts from '@/containers/defaultLayouts';
      import { cloneDeep } from 'lodash';
      import { Util, API } from '@gza/quantex-utils';
      import appWindow from '@/common/appWindow';

      // 这里需要先深拷贝一份配置
      const layouts = cloneDeep(defaultLayouts);

      // 两种场景直接使用 Util 工具库的 API 类生成一个实例,根据接口的请求类型调用对应请求方法即可获取到数据
      // 比如 /auth/api/users/login 是一个 post 方法,直接使用 new API('auth').post('/api/users/login',params) 即可实现功能
      // 场景一时,API 会获取本地的 mock 数据。场景二时,API获取后端数据。 但要注意,使用场景二的时候一定要删除 app/pages 下的 _mock.(ts|js) 文件
      layouts.login.login = async (params) => {
      params.loginPassword = Util.sha256Encode(params.loginPassword);
      return new API('auth').post('/api/users/login', params);
      };

      layouts.login.logout = async () => {
      return new API('auth').put('/api/users/logout');
      };

      // 此处只做覆盖,不做任何逻辑
      layouts.login.getMicroApp = () => {
      return Promise.resolve({ code: 200, data: { list: [] } });
      };

      layouts.main.getUserMenu = () => {
      const userInfo = appWindow.userLocalStore.getItem('userInfo');
      return new API('auth').get('/api/users/{code}/menus', {
      code: userInfo.code,
      });
      };
    • 框架默认的config.ts文件配置

        module.exports = {
      /** webpack配置修改 */
      webpackConfig: {
      // config 是项目的 webpack 配置,可修改
      // 如果你对 webpack 不了解,我们不建议修改
      chainWebpack: undefined,
      /** webpack 别名 */
      resolveAlias: {},
      /** 打包文件复制 */
      copyWebpack: [],
      },
      /** API配置 */
      apiConfig: {
      // 启动 mock 调试
      isDebug: true,
      // 代理服务,即访问接口域名会被替换成 proxyServer,isDebug 为 true 时有效(默认 /)
      // http://godzilla-midway.sz.iquantex.com/auth/api/v1/users/login?_t=1596162460875
      // 代理后 => /auth/api/v1/users/login?_t=1596162460875
      proxyServer: '/',
      // 基本路径,接口访问域名
      base: '',
      // 域,一般用于项目中有多个接口访问域名时
      domain: {},
      // url路径前缀
      urlPrefix: '',
      },
      /** YAPI配置,只在开发环境时有效 */
      yapiConfig: {
      // 启动使用
      enable: false,
      // yapi网站路径,如:https://yapi.iquantex.com
      host: '',
      // 需要 mock 的项目 token
      token: '',
      // 启动自动更新接口功能
      autoUpdate: false,
      // 间隔时间,默认五分钟
      interval: 5 * 60 * 1000,
      },
      /** webpack环境配置 */
      definePlugin: {
      // 正式环境是否只允许 SSO 登录(默认 true)
      ENABLE_SSO: true,
      // 是否支持系统自带的websocket(默认false)
      ENABLE_WEBSOCKET: false,
      // 应用ID
      APP_ID: JSON.stringify('portal'),
      // 应用名称
      PROJECT_NAME: JSON.stringify('Godzilla Portal'),
      },
      /** 系统配置 */
      systemConfig: {
      // dev server 端口(默认8888)
      devServerPort: 8888,
      // 主题开发dev server端口(默认9999)
      devThemeServerPort: 9999,
      // 脚手架开发(默认false,即普通开发)
      isScaffoldApp: false,
      // 是否是门户入口(默认false)
      isPortal: false,
      // npm scope
      npmScope: '',
      // Godzilla框架License
      godzillaLicenseKey: '',
      // Ag-Grid组件License,详见:https://www.ag-grid.com/license-pricing.php
      agGridLicenseKey: '',
      },
      /** 插件配置 */
      pluginConfig: [],
      /** 主题配置 */
      themeConfig: {
      defaultTheme: '',
      mainTheme: '',
      themes: [],
      },
      /** electron配置 */
      electronConfig: {
      // 启用Electron客户端(默认false)
      enableElectron: false,
      webSecurity:'',
      autoUpdate:'',
      },
      };

    • 自定义配置 app/config/config.ts

        // 注意!!修改该配置文件不会热更新,需要重新执行npm start
      const npmScope = '@gza'; // 私有npm依赖的scope
      const isDev = process.env.NODE_ENV === 'development';
      const config:IConfig = {
      webpackConfig: {
      resolveAlias: {
      'quantex-utils': `${npmScope}/quantex-utils`,
      'quantex-design': `${npmScope}/quantex-design`,
      'quantex-scripts': `${npmScope}/quantex-scripts`,
      },
      chainWebpack: webpackConfig => {}, // webpack配置修改
      },
      systemConfig: {
      isPortal: true, // 是否是Portal应用(主应用)
      devServerPort: 8888, // dev server 端口
      enableElectron: false, // 是否使用Electron客户端
      devThemeServerPort: 9999, // 主题开发dev server端口
      isScaffoldApp: false, // 是否是脚手架
      copyWebpack: [], // 详细使用参考: https://www.npmjs.com/package/copy-webpack-plugin
      godzillaLicenseKey:'', // godzilla license
      agGridLicenseKey:'', // ag grid license
      },
      apiConfig: {
      isDebug: isDev,
      proxyServer: '/',
      base: isDev ? 'http://127.0.0.1:8889' : '', // 基本路径,接口访问域名
      domain: {
      '/auth''http://127.0.0.1:8080/auth' // 例如这里配置/auth接口转发到http://127.0.0.1:8080/auth服务
      },
      },
      definePlugin: {
      ENABLE_SSO: false, // 正式环境是否只允许SSO登录
      APP_ID: JSON.stringify('pro'), // 应用ID
      ENABLE_WEBSOCKET: false, // 是否支持websocket
      PROJECT_NAME: JSON.stringify('Godzilla Scaffold') // 应用名称
      },
      themeConfig: {
      defaultTheme: 'themeDark',
      mainTheme: 'themeDark',
      themes: [
      {
      name: '深色',
      id: 'themeDark',
      },
      {
      name: '浅色',
      id: 'themeWhite',
      },
      ],
      },
      pluginConfig: [ // 插件配置
      [
      'metrics', // 埋点插件
      {
      enable: true,
      domain: 'http://10.16.18.166:32143',
      url: '/api/v1/metrics',
      method: 'POST',
      env: 'DEV', // ST、UAT、PRD等
      reportInterval: 10 * 1000, // 一分钟上报一次
      package: '@gza/quantex-plugin-metrics',
      },
      ],
      [
      'theme-dark', // 主题插件
      {
      enable: true,
      package: '@gza/quantex-plugin-theme-dark',
      },
      ]
      ],
      };
  1. 打包和部署

    打包

    在项目根目录下执行命令即可打包您的 UI 应用

    npm run dist

    打包成功之后,会在根目录生成 dist 文件夹,里面就是构建打包好的文件,通常是 .js、.css、index.html 等静态文件,然后就可以将这些静态资源文件拷贝到 CDN、nginx 等静态资源服务器部署应用。

    方案一
    部署参考

    请确保 config/config.ts 中 apiConfig.base 在正式环境(NODE_ENV=production)下为空

    {
    // ... 其它配置项
    "apiConfig": {
    "base": isDev ? "http://127.0.0.1:8889" : "" // 请注意这里,如果不是本地开发模式,则需要设置为空
    }
    }

    nginx.conf 配置参考,需要处理 history router 问题

    http {
    # ... 其它配置项
    server {
    # ... 其它配置项

    location / {
    root /usr/share/nginx/html; # 这里是nginx存放静态资源的目录,请根据自己环境配置
    index index.html index.htm;
    try_files $uri $uri/ @router;
    }
    location @router {
    # 处理history router 参考:https://blog.csdn.net/qq_35267557/article/details/81182097
    rewrite ^.*$ /index.html last;
    }
    #特殊处理部分svg资源问题
    location ~ \/app\/.*\.svg$ {
    rewrite ^\/app\/.*\/(.*)\.svg$ /assets/css/font/$1.svg last;
    }
    }
    }

    方案二

    Nginx(或者其它类似服务) 作为总网关,是客户端的唯一流量入口,所有的资源都在 Nginx 服务进行处理,如果是静态资源,则会转发到 CDN,如果是 Restful 接口,则会转发到 web 服务。

    优点:
    1. 部署简单、传统,稳定性高
    2. 跟现有网关集成程度高,无需改造。

    缺点:

    1. 遵循 api 接口规范,所有的 api 都必须带上一个统一的前缀(例如:/api-gateway),这样在 Nginx 才好识别
    2. 不支持动态新增子应用,每次新增子应用,需要修改 Nginx 配置并重启服务
    3. 灵活度不是特别高,不过一般不需要那么高的灵活度
    配置参考

    请确保 config/config.ts 中 apiConfig.base 在正式环境(NODE_ENV=production)时设置一个统一前缀

    {
    // ... 其它配置项
    "apiConfig": {
    "base": isDev ? "http://127.0.0.1:8889" : "/api-gateway" // 请注意这里,如果不是本地开发模式,需要设置一个api前缀,用于在nginx中识别并转发,这样业务代码就不需要单独增加前缀了
    }
    }

    nginx.conf 配置参考,除了需要处理 history router 问题,还要处理其它子系统的资源转发

    http {
    # ... 其它配置项
    server {
    # ... 其它配置项

    location / {
    root /usr/share/nginx/html; # 这里是nginx存放静态资源的目录,请根据自己环境配置
    index index.html index.htm;
    try_files $uri $uri/ @router;
    }
    location @router {
    # 处理history router 参考:https://blog.csdn.net/qq_35267557/article/details/81182097
    rewrite ^.*$ /index.html last;
    }
    #特殊处理部分svg资源问题
    location ~ \/app\/.*\.svg$ {
    rewrite ^\/app\/.*\/(.*)\.svg$ /assets/css/font/$1.svg last;
    }
    # 这里的`portal`就是应用ID,下同
    location /portal/ {
    rewrite ^(/portal)(.*$) $2 last;
    }

    # 子系统静态资源转发,这里只是示例,需根据实际情况修改
    location ^~ /godzillaPro/ {
    # 注意路径后面的`/`不能去掉
    proxy_pass http://godzilla-pro.sz.iquantex.com/;
    }

    #websocket 如果有websocket需求,则需要自己配置
    location /api-gateway/msgcenter/ {
    proxy_pass http://192.168.1.95:8889/msgcenter/;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # websock 代理设置
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    # websock 超时设置
    proxy_connect_timeout 7d;
    proxy_send_timeout 7d;
    proxy_read_timeout 7d;
    }
    }
    }