Kaynağa Gözat

chore: update umi to 4

lanjianrong 2 yıl önce
ebeveyn
işleme
5466043310
42 değiştirilmiş dosya ile 5941 ekleme ve 12510 silme
  1. 8 5
      .eslintrc.js
  2. 2 1
      .gitignore
  3. 6 10
      .prettierrc.js
  4. 4 3
      .stylelintrc.js
  5. 0 57
      README.md
  6. 0 21
      config/config.dev.ts
  7. 66 43
      config/config.ts
  8. 0 175
      mock/listTableList.ts
  9. 0 107
      mock/notices.ts
  10. 0 5
      mock/route.ts
  11. 0 200
      mock/user.ts
  12. 25 76
      package.json
  13. 15 0
      plugin.ts
  14. 5584 11381
      pnpm-lock.yaml
  15. 67 129
      src/app.tsx
  16. 1 1
      src/components/Footer/index.tsx
  17. 1 1
      src/components/NoticeIcon/index.tsx
  18. 6 10
      src/components/RightContent/AvatarDropdown.tsx
  19. 1 1
      src/components/RightContent/index.tsx
  20. 9 0
      src/global.less
  21. 1 2
      src/global.tsx
  22. 2 4
      src/hooks/core/useWebSocketFn.ts
  23. 1 1
      src/models/user.ts
  24. 1 1
      src/pages/404.tsx
  25. 4 11
      src/pages/Business/Attendance/index.tsx
  26. 1 1
      src/pages/Business/CommonSetting/index.tsx
  27. 3 10
      src/pages/Business/Contact/index.tsx
  28. 6 19
      src/pages/Business/Invoice/index.tsx
  29. 3 10
      src/pages/Business/Notification/index.tsx
  30. 8 16
      src/pages/Role/Customer/index.tsx
  31. 8 16
      src/pages/Role/Hr/index.tsx
  32. 12 28
      src/pages/Role/Product/index.tsx
  33. 15 39
      src/pages/Role/Statistic/index.tsx
  34. 4 12
      src/pages/Role/System/components/ConnectModal/index.tsx
  35. 10 21
      src/pages/Role/System/components/RoleMenu/index.tsx
  36. 8 14
      src/pages/Role/System/index.tsx
  37. 8 16
      src/pages/Role/Workbench/index.tsx
  38. 25 23
      src/pages/user/Login/index.tsx
  39. 2 15
      src/services/user/api.ts
  40. 1 1
      src/services/user/system.ts
  41. 5 1
      src/utils/consts.ts
  42. 18 23
      windi.config.ts

+ 8 - 5
.eslintrc.js

@@ -1,15 +1,12 @@
 module.exports = {
-  extends: [require.resolve('@umijs/fabric/dist/eslint')],
+  extends: require.resolve('@umijs/max/eslint'),
   globals: {
-    ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
-    page: true,
     REACT_APP_ENV: true
   },
   rules: {
     semi: ['error', 'never'],
     'no-multiple-empty-lines': [1, { max: 2 }],
     'no-use-before-define': 'off',
-    '@typescript-eslint/no-use-before-define': ['error'],
     'comma-dangle': [2, 'never'],
     'react/prop-types': 0,
     'spaced-comment': 'error',
@@ -30,6 +27,12 @@ module.exports = {
       {
         allowShortCircuit: true
       }
-    ]
+    ],
+    '@typescript-eslint/no-unused-expressions': 0
+  },
+  settings: {
+    react: {
+      version: 'detect'
+    }
   }
 }

+ 2 - 1
.gitignore

@@ -9,7 +9,7 @@ _roadhog-api-doc
 # production
 /dist
 /.vscode
-
+dist*
 # misc
 .DS_Store
 npm-debug.log*
@@ -19,6 +19,7 @@ yarn-error.log
 .idea
 yarn.lock
 package-lock.json
+/pnpm-lock.yaml
 *bak
 .vscode
 

+ 6 - 10
.prettierrc.js

@@ -1,7 +1,4 @@
-const fabric = require('@umijs/fabric');
-
 module.exports = {
-  ...fabric.prettier,
   semi: false,
   // quoteProps: 'consistent',
   htmlWhitespaceSensitivity: 'ignore',
@@ -9,8 +6,7 @@ module.exports = {
   trailingComma: 'none',
   bracketSpacing: true,
   arrowParens: 'avoid',
-
-  printWidth: 100,
+  printWidth: 110,
   tabWidth: 2,
   singleQuote: true,
   quoteProps: 'as-needed',
@@ -26,8 +22,8 @@ module.exports = {
     {
       files: '*.md',
       options: {
-        tabWidth: 2,
-      },
-    },
-  ],
-};
+        tabWidth: 2
+      }
+    }
+  ]
+}

+ 4 - 3
.stylelintrc.js

@@ -1,5 +1,5 @@
 module.exports = {
-  extends: [require.resolve('@umijs/fabric/dist/stylelint')],
+  extends: require.resolve('@umijs/max/stylelint'),
   rules: {
     indentation: 2,
     'block-no-empty': null,
@@ -8,9 +8,10 @@ module.exports = {
     'max-empty-lines': 2,
     'rule-empty-line-before': null,
     'unit-no-unknown': null,
-    'unit-whitelist': ['px', 'em', 'rem', 's', '%', 'vw', 'vh', 'deg'],
     'selector-max-compound-selectors': 5,
+    'color-hex-length': 'long',
     'at-rule-no-unknown': null,
-    'selector-pseudo-class-no-unknown': [true, { ignorePseudoClasses: ['global'] }]
+    'selector-pseudo-class-no-unknown': [true, { ignorePseudoClasses: ['global'] }],
+    'no-descending-specificity': null
   }
 }

+ 0 - 57
README.md

@@ -1,57 +0,0 @@
-# Ant Design Pro
-
-This project is initialized with [Ant Design Pro](https://pro.ant.design). Follow is the quick guide for how to use.
-
-## Environment Prepare
-
-Install `node_modules`:
-
-```bash
-npm install
-```
-
-or
-
-```bash
-yarn
-```
-
-## Provided Scripts
-
-Ant Design Pro provides some useful script to help you quick start and build with web project, code style check and test.
-
-Scripts provided in `package.json`. It's safe to modify or add additional script:
-
-### Start project
-
-```bash
-npm start
-```
-
-### Build project
-
-```bash
-npm run build
-```
-
-### Check code style
-
-```bash
-npm run lint
-```
-
-You can also use script to auto fix some lint error:
-
-```bash
-npm run lint:fix
-```
-
-### Test code
-
-```bash
-npm test
-```
-
-## More
-
-You can view full document on our [official website](https://pro.ant.design). And welcome any feedback in our [github](https://github.com/ant-design/ant-design-pro).

+ 0 - 21
config/config.dev.ts

@@ -1,21 +0,0 @@
-// https://umijs.org/config/
-import { defineConfig } from 'umi'
-
-export default defineConfig({
-  plugins: [
-    // https://github.com/zthxxx/react-dev-inspector
-    'react-dev-inspector/plugins/umi/react-inspector'
-  ],
-  // https://github.com/zthxxx/react-dev-inspector#inspector-loader-props
-  inspectorConfig: {
-    exclude: [],
-    babelPlugins: [
-      '@babel/plugin-proposal-optional-chaining',
-      '@babel/plugin-proposal-nullish-coalescing-operator'
-    ],
-    babelOptions: {}
-  },
-  webpack5: {
-    // lazyCompilation: {},
-  }
-})

+ 66 - 43
config/config.ts

@@ -1,66 +1,89 @@
 // https://umijs.org/config/
-import { defineConfig } from 'umi'
+
+const prodGzipList = ['js', 'css', 'html']
+
+import { defineConfig } from '@umijs/max'
 import defaultSettings from './defaultSettings'
 import proxy from './proxy'
 import routes from './routes'
-import WindiCSSPlugin from 'windicss-webpack-plugin'
 const { REACT_APP_ENV } = process.env
-
 export default defineConfig({
+  plugins: [require.resolve('@umijs/plugins/dist/unocss')],
+  npmClient: 'pnpm',
   hash: true,
-  antd: {},
-  dva: {
-    hmr: true
+  antd: { import: true },
+  model: {},
+  moment2dayjs: {},
+  request: {},
+  initialState: {},
+  access: {},
+  dva: {},
+  mfsu: {},
+  srcTranspiler: 'esbuild',
+  fastRefresh: true,
+  unocss: {
+    watch: ['src/pages/**/*.{jsx,tsx,less}', 'src/components/**/*.{jsx,tsx,less}'] // 添加其他包含 unocss 的 classname 的文件目录
   },
-  layout: {
-    // https://umijs.org/zh-CN/plugins/plugin-layout
-    locale: true,
-    siderWidth: 208,
-    ...defaultSettings
-  },
-  // https://umijs.org/zh-CN/plugins/plugin-locale
+  // Fast Refresh 热更新
+  theme: { 'primary-color': '#886ab5' },
+  layout: {},
   locale: {
-    // default zh-CN
     default: 'zh-CN',
-    antd: true,
-    // default true, when it is true, will use `navigator.language` overwrite default
-    baseNavigator: true
-  },
-  dynamicImport: {
-    loading: '@ant-design/pro-layout/es/PageLoading'
+    antd: false,
+    baseNavigator: false
   },
-  targets: {
-    ie: 11
-  },
-  // request: { dataField: 'data' },
-  // umi routes: https://umijs.org/docs/routing
+  define: { REACT_APP_ENV: REACT_APP_ENV || false },
+  targets: { ie: 11 },
   routes,
-  // Theme for antd: https://ant.design/docs/react/customize-theme-cn
-  theme: {
-    'primary-color': defaultSettings.primaryColor
-  },
-  // esbuild is father build tools
-  // https://umijs.org/plugins/plugin-esbuild
-  esbuild: {},
   title: false,
-  ignoreMomentLocale: true,
   proxy: proxy[REACT_APP_ENV || 'dev'],
-  manifest: {
-    basePath: '/'
-  },
-  // Fast Refresh 热更新
-  fastRefresh: {},
-  chainWebpack(config) {
-    config.plugin('windicss').use(WindiCSSPlugin)
-  },
+  manifest: { basePath: '/' },
   extraBabelPlugins: [
+    ['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }, 'antd'],
     [
       'import',
       {
         libraryName: '@icon-park/react',
         libraryDirectory: 'es/icons',
         camel2DashComponentName: false
-      }
+      },
+      '@icon-park/react'
     ]
-  ]
+  ],
+  externals: {
+    react: 'React',
+    'react-dom': 'ReactDOM'
+  },
+  chainWebpack(config, { env }) {
+    if (env === 'production') {
+      // config.merge({
+      //   optimization: {
+      //     minimize: true,
+      //     splitChunks: {
+      //       chunks: 'all',
+      //       minSize: 30000,
+      //       minChunks: 2,
+      //       automaticNameDelimiter: '.',
+      //       cacheGroups: {
+      //         vendor: {
+      //           name: 'vendors',
+      //           test: ({ resource }) => /[\\/]node_modules[\\/]/.test(resource),
+      //           chunks: 'all',
+      //           priority: 20
+      //         }
+      //       }
+      //     }
+      //   }
+      // })
+      config.plugin('compression-webpack-plugin').use(
+        new CompressionPlugin({
+          // filename: 文件名称,这里我们不设置,让它保持和未压缩的文件同一个名称
+          algorithm: 'gzip', // 指定生成gzip格式
+          test: new RegExp('\\.(' + prodGzipList.join('|') + ')$'), // 匹配哪些格式文件需要压缩
+          threshold: 10000, //对超过10k的数据进行压缩
+          minRatio: 0.6 // 压缩比例,值为0 ~ 1
+        })
+      )
+    }
+  }
 })

+ 0 - 175
mock/listTableList.ts

@@ -1,175 +0,0 @@
-// eslint-disable-next-line import/no-extraneous-dependencies
-import { Request, Response } from 'express';
-import moment from 'moment';
-import { parse } from 'url';
-
-// mock tableListDataSource
-const genList = (current: number, pageSize: number) => {
-  const tableListDataSource: API.RuleListItem[] = [];
-
-  for (let i = 0; i < pageSize; i += 1) {
-    const index = (current - 1) * 10 + i;
-    tableListDataSource.push({
-      key: index,
-      disabled: i % 6 === 0,
-      href: 'https://ant.design',
-      avatar: [
-        'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
-        'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
-      ][i % 2],
-      name: `TradeCode ${index}`,
-      owner: '曲丽丽',
-      desc: '这是一段描述',
-      callNo: Math.floor(Math.random() * 1000),
-      status: Math.floor(Math.random() * 10) % 4,
-      updatedAt: moment().format('YYYY-MM-DD'),
-      createdAt: moment().format('YYYY-MM-DD'),
-      progress: Math.ceil(Math.random() * 100),
-    });
-  }
-  tableListDataSource.reverse();
-  return tableListDataSource;
-};
-
-let tableListDataSource = genList(1, 100);
-
-function getRule(req: Request, res: Response, u: string) {
-  let realUrl = u;
-  if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
-    realUrl = req.url;
-  }
-  const { current = 1, pageSize = 10 } = req.query;
-  const params = (parse(realUrl, true).query as unknown) as API.PageParams &
-    API.RuleListItem & {
-      sorter: any;
-      filter: any;
-    };
-
-  let dataSource = [...tableListDataSource].slice(
-    ((current as number) - 1) * (pageSize as number),
-    (current as number) * (pageSize as number),
-  );
-  const sorter = JSON.parse(params.sorter || ('{}' as any));
-  if (sorter) {
-    dataSource = dataSource.sort((prev, next) => {
-      let sortNumber = 0;
-      Object.keys(sorter).forEach((key) => {
-        if (sorter[key] === 'descend') {
-          if (prev[key] - next[key] > 0) {
-            sortNumber += -1;
-          } else {
-            sortNumber += 1;
-          }
-          return;
-        }
-        if (prev[key] - next[key] > 0) {
-          sortNumber += 1;
-        } else {
-          sortNumber += -1;
-        }
-      });
-      return sortNumber;
-    });
-  }
-  if (params.filter) {
-    const filter = JSON.parse(params.filter as any) as {
-      [key: string]: string[];
-    };
-    if (Object.keys(filter).length > 0) {
-      dataSource = dataSource.filter((item) => {
-        return Object.keys(filter).some((key) => {
-          if (!filter[key]) {
-            return true;
-          }
-          if (filter[key].includes(`${item[key]}`)) {
-            return true;
-          }
-          return false;
-        });
-      });
-    }
-  }
-
-  if (params.name) {
-    dataSource = dataSource.filter((data) => data?.name?.includes(params.name || ''));
-  }
-  const result = {
-    data: dataSource,
-    total: tableListDataSource.length,
-    success: true,
-    pageSize,
-    current: parseInt(`${params.current}`, 10) || 1,
-  };
-
-  return res.json(result);
-}
-
-function postRule(req: Request, res: Response, u: string, b: Request) {
-  let realUrl = u;
-  if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
-    realUrl = req.url;
-  }
-
-  const body = (b && b.body) || req.body;
-  const { method, name, desc, key } = body;
-
-  switch (method) {
-    /* eslint no-case-declarations:0 */
-    case 'delete':
-      tableListDataSource = tableListDataSource.filter((item) => key.indexOf(item.key) === -1);
-      break;
-    case 'post':
-      (() => {
-        const i = Math.ceil(Math.random() * 10000);
-        const newRule: API.RuleListItem = {
-          key: tableListDataSource.length,
-          href: 'https://ant.design',
-          avatar: [
-            'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
-            'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
-          ][i % 2],
-          name,
-          owner: '曲丽丽',
-          desc,
-          callNo: Math.floor(Math.random() * 1000),
-          status: Math.floor(Math.random() * 10) % 2,
-          updatedAt: moment().format('YYYY-MM-DD'),
-          createdAt: moment().format('YYYY-MM-DD'),
-          progress: Math.ceil(Math.random() * 100),
-        };
-        tableListDataSource.unshift(newRule);
-        return res.json(newRule);
-      })();
-      return;
-
-    case 'update':
-      (() => {
-        let newRule = {};
-        tableListDataSource = tableListDataSource.map((item) => {
-          if (item.key === key) {
-            newRule = { ...item, desc, name };
-            return { ...item, desc, name };
-          }
-          return item;
-        });
-        return res.json(newRule);
-      })();
-      return;
-    default:
-      break;
-  }
-
-  const result = {
-    list: tableListDataSource,
-    pagination: {
-      total: tableListDataSource.length,
-    },
-  };
-
-  res.json(result);
-}
-
-export default {
-  'GET /api/rule': getRule,
-  'POST /api/rule': postRule,
-};

+ 0 - 107
mock/notices.ts

@@ -1,107 +0,0 @@
-import { Request, Response } from 'express';
-
-const getNotices = (req: Request, res: Response) => {
-  res.json({
-    data: [
-      {
-        id: '000000001',
-        avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
-        title: '你收到了 14 份新周报',
-        datetime: '2017-08-09',
-        type: 'notification',
-      },
-      {
-        id: '000000002',
-        avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
-        title: '你推荐的 曲妮妮 已通过第三轮面试',
-        datetime: '2017-08-08',
-        type: 'notification',
-      },
-      {
-        id: '000000003',
-        avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
-        title: '这种模板可以区分多种通知类型',
-        datetime: '2017-08-07',
-        read: true,
-        type: 'notification',
-      },
-      {
-        id: '000000004',
-        avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
-        title: '左侧图标用于区分不同的类型',
-        datetime: '2017-08-07',
-        type: 'notification',
-      },
-      {
-        id: '000000005',
-        avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
-        title: '内容不要超过两行字,超出时自动截断',
-        datetime: '2017-08-07',
-        type: 'notification',
-      },
-      {
-        id: '000000006',
-        avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
-        title: '曲丽丽 评论了你',
-        description: '描述信息描述信息描述信息',
-        datetime: '2017-08-07',
-        type: 'message',
-        clickClose: true,
-      },
-      {
-        id: '000000007',
-        avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
-        title: '朱偏右 回复了你',
-        description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
-        datetime: '2017-08-07',
-        type: 'message',
-        clickClose: true,
-      },
-      {
-        id: '000000008',
-        avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
-        title: '标题',
-        description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
-        datetime: '2017-08-07',
-        type: 'message',
-        clickClose: true,
-      },
-      {
-        id: '000000009',
-        title: '任务名称',
-        description: '任务需要在 2017-01-12 20:00 前启动',
-        extra: '未开始',
-        status: 'todo',
-        type: 'event',
-      },
-      {
-        id: '000000010',
-        title: '第三方紧急代码变更',
-        description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
-        extra: '马上到期',
-        status: 'urgent',
-        type: 'event',
-      },
-      {
-        id: '000000011',
-        title: '信息安全考试',
-        description: '指派竹尔于 2017-01-09 前完成更新并发布',
-        extra: '已耗时 8 天',
-        status: 'doing',
-        type: 'event',
-      },
-      {
-        id: '000000012',
-        title: 'ABCD 版本发布',
-        description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
-        extra: '进行中',
-        status: 'processing',
-        type: 'event',
-      },
-    ],
-  });
-};
-
-export default {
-  'GET /api/notices': getNotices,
-};

+ 0 - 5
mock/route.ts

@@ -1,5 +0,0 @@
-export default {
-  '/api/auth_routes': {
-    '/form/advanced-form': { authority: ['admin', 'user'] },
-  },
-};

+ 0 - 200
mock/user.ts

@@ -1,200 +0,0 @@
-import { Request, Response } from 'express';
-
-const waitTime = (time: number = 100) => {
-  return new Promise((resolve) => {
-    setTimeout(() => {
-      resolve(true);
-    }, time);
-  });
-};
-
-async function getFakeCaptcha(req: Request, res: Response) {
-  await waitTime(2000);
-  return res.json('captcha-xxx');
-}
-
-const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env;
-
-/**
- * 当前用户的权限,如果为空代表没登录
- * current user access, if is '', user need login
- * 如果是 pro 的预览,默认是有权限的
- */
-let access = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' ? 'admin' : '';
-
-const getAccess = () => {
-  return access;
-};
-
-// 代码中会兼容本地 service mock 以及部署站点的静态数据
-export default {
-  // 支持值为 Object 和 Array
-  'GET /api/currentUser': (req: Request, res: Response) => {
-    if (!getAccess()) {
-      res.status(401).send({
-        data: {
-          isLogin: false,
-        },
-        errorCode: '401',
-        errorMessage: '请先登录!',
-        success: true,
-      });
-      return;
-    }
-    res.send({
-      name: 'Serati Ma',
-      avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
-      userid: '00000001',
-      email: 'antdesign@alipay.com',
-      signature: '海纳百川,有容乃大',
-      title: '交互专家',
-      group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED',
-      tags: [
-        {
-          key: '0',
-          label: '很有想法的',
-        },
-        {
-          key: '1',
-          label: '专注设计',
-        },
-        {
-          key: '2',
-          label: '辣~',
-        },
-        {
-          key: '3',
-          label: '大长腿',
-        },
-        {
-          key: '4',
-          label: '川妹子',
-        },
-        {
-          key: '5',
-          label: '海纳百川',
-        },
-      ],
-      notifyCount: 12,
-      unreadCount: 11,
-      country: 'China',
-      access: getAccess(),
-      geographic: {
-        province: {
-          label: '浙江省',
-          key: '330000',
-        },
-        city: {
-          label: '杭州市',
-          key: '330100',
-        },
-      },
-      address: '西湖区工专路 77 号',
-      phone: '0752-268888888',
-    });
-  },
-  // GET POST 可省略
-  'GET /api/users': [
-    {
-      key: '1',
-      name: 'John Brown',
-      age: 32,
-      address: 'New York No. 1 Lake Park',
-    },
-    {
-      key: '2',
-      name: 'Jim Green',
-      age: 42,
-      address: 'London No. 1 Lake Park',
-    },
-    {
-      key: '3',
-      name: 'Joe Black',
-      age: 32,
-      address: 'Sidney No. 1 Lake Park',
-    },
-  ],
-  'POST /api/login/account': async (req: Request, res: Response) => {
-    const { password, username, type } = req.body;
-    await waitTime(2000);
-    if (password === 'ant.design' && username === 'admin') {
-      res.send({
-        status: 'ok',
-        type,
-        currentAuthority: 'admin',
-      });
-      access = 'admin';
-      return;
-    }
-    if (password === 'ant.design' && username === 'user') {
-      res.send({
-        status: 'ok',
-        type,
-        currentAuthority: 'user',
-      });
-      access = 'user';
-      return;
-    }
-    if (type === 'mobile') {
-      res.send({
-        status: 'ok',
-        type,
-        currentAuthority: 'admin',
-      });
-      access = 'admin';
-      return;
-    }
-
-    res.send({
-      status: 'error',
-      type,
-      currentAuthority: 'guest',
-    });
-    access = 'guest';
-  },
-  'POST /api/login/outLogin': (req: Request, res: Response) => {
-    access = '';
-    res.send({ data: {}, success: true });
-  },
-  'POST /api/register': (req: Request, res: Response) => {
-    res.send({ status: 'ok', currentAuthority: 'user', success: true });
-  },
-  'GET /api/500': (req: Request, res: Response) => {
-    res.status(500).send({
-      timestamp: 1513932555104,
-      status: 500,
-      error: 'error',
-      message: 'error',
-      path: '/base/category/list',
-    });
-  },
-  'GET /api/404': (req: Request, res: Response) => {
-    res.status(404).send({
-      timestamp: 1513932643431,
-      status: 404,
-      error: 'Not Found',
-      message: 'No message available',
-      path: '/base/category/list/2121212',
-    });
-  },
-  'GET /api/403': (req: Request, res: Response) => {
-    res.status(403).send({
-      timestamp: 1513932555104,
-      status: 403,
-      error: 'Unauthorized',
-      message: 'Unauthorized',
-      path: '/base/category/list',
-    });
-  },
-  'GET /api/401': (req: Request, res: Response) => {
-    res.status(401).send({
-      timestamp: 1513932555104,
-      status: 401,
-      error: 'Unauthorized',
-      message: 'Unauthorized',
-      path: '/base/category/list',
-    });
-  },
-
-  'GET  /api/login/captcha': getFakeCaptcha,
-};

+ 25 - 76
package.json

@@ -4,42 +4,21 @@
   "private": true,
   "description": "An out-of-box UI solution for enterprise applications",
   "scripts": {
-    "analyze": "cross-env ANALYZE=1 umi build",
-    "build": "umi build",
+    "analyze": "cross-env ANALYZE=1 max build",
+    "build": "cross-env REACT_APP_ENV=prod max build",
     "deploy:qa": "auto-deploy build -t qa",
     "deploy:prod": "auto-deploy build -t prod",
-    "deploy": "npm run site && npm run gh-pages",
     "dev": "npm run start:dev",
-    "gh-pages": "gh-pages -d dist",
-    "i18n-remove": "pro i18n-remove --locale=zh-CN --write",
-    "postinstall": "umi g tmp",
-    "lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier",
-    "lint-staged": "lint-staged",
-    "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
-    "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
-    "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
-    "lint:prettier": "prettier --check \"src/**/*\" --end-of-line auto",
-    "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
-    "openapi": "umi openapi",
+    "postinstall": "max setup",
     "precommit": "lint-staged",
-    "prettier": "prettier -c --write \"src/**/*\"",
-    "start": "cross-env UMI_ENV=dev umi dev",
-    "start:dev": "cross-env PORT=8081 REACT_APP_ENV=dev MOCK=none UMI_ENV=dev umi dev",
-    "start:no-mock": "cross-env MOCK=none UMI_ENV=dev umi dev",
-    "start:no-ui": "cross-env UMI_UI=none UMI_ENV=dev umi dev",
-    "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev umi dev",
-    "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev umi dev",
-    "pretest": "node ./tests/beforeTest",
-    "test": "umi test",
-    "test:all": "node ./tests/run-tests.js",
-    "test:component": "umi test ./src/components",
-    "tsc": "tsc --noEmit"
+    "start": "max dev",
+    "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none max dev",
+    "start:org": "cross-env REACT_APP_ENV=org MOCK=none max dev",
+    "prepare": "husky install"
   },
   "lint-staged": {
-    "**/*.less": "stylelint --syntax less",
-    "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js",
-    "**/*.{js,jsx,tsx,ts,less,md,json}": [
-      "prettier --write"
+    "**/*.{js,jsx,tsx,ts,less}": [
+      "max lint"
     ]
   },
   "browserslist": [
@@ -50,73 +29,43 @@
   "dependencies": {
     "@ant-design/icons": "^4.7.0",
     "@ant-design/pro-descriptions": "^1.10.60",
-    "@ant-design/pro-form": "1.43.2",
-    "@ant-design/pro-layout": "^6.34.8",
-    "@ant-design/pro-table": "^2.70.0",
+    "@ant-design/pro-form": "1.66.0",
+    "@ant-design/pro-layout": "6.38.8",
+    "@ant-design/pro-table": "2.76.3",
     "@icon-park/react": "^1.3.5",
-    "@umijs/plugin-openapi": "^1.3.2",
-    "@umijs/route-utils": "^1.0.37",
     "ahooks": "2.10.9",
     "antd": "^4.19.5",
     "array-move": "^4.0.0",
     "classnames": "^2.3.1",
     "lodash": "^4.17.21",
     "markdown-it": "^12.3.2",
-    "moment": "^2.29.2",
     "omit.js": "^2.0.2",
     "rc-queue-anim": "^1.8.5",
-    "react": "^17.0.2",
-    "react-dom": "^17.0.2",
+    "react": "18.1.0",
+    "react-dom": "18.1.0",
     "react-helmet-async": "^1.2.3",
     "react-markdown-editor-lite": "^1.3.2",
     "react-sortable-hoc": "^2.0.0",
-    "umi": "3.5.3"
+    "@umijs/max": "4.0.7",
+    "@umijs/plugins": "4.0.7"
   },
   "devDependencies": {
-    "@ant-design/pro-cli": "^2.1.5",
-    "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7",
-    "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
-    "@babel/plugin-proposal-optional-chaining": "^7.16.7",
-    "@types/classnames": "^2.3.1",
-    "@types/express": "^4.17.13",
-    "@types/history": "^4.7.11",
-    "@types/jest": "^26.0.24",
     "@types/lodash": "^4.14.181",
-    "@types/react": "^17.0.43",
-    "@types/react-dom": "^17.0.14",
-    "@types/react-helmet": "^6.1.5",
-    "@umijs/fabric": "2.10.2",
-    "@umijs/plugin-blocks": "^2.2.2",
-    "@umijs/plugin-esbuild": "^1.4.1",
-    "@umijs/preset-ant-design-pro": "^1.3.3",
-    "@umijs/preset-dumi": "^1.1.40",
-    "@umijs/preset-react": "1.8.22",
-    "@umijs/yorkie": "^2.0.5",
+    "@types/react": "^18.0.0",
+    "@types/react-dom": "^18.0.0",
     "babel-plugin-import": "^1.13.3",
-    "carlo": "^0.9.46",
     "cross-env": "^7.0.3",
-    "cross-port-killer": "^1.4.0",
-    "detect-installer": "^1.0.2",
-    "enzyme": "^3.11.0",
-    "eslint": "^7.32.0",
-    "eslint-plugin-javascript": "^1.3.4",
-    "eslint-plugin-jsx": "^0.1.0",
-    "eslint-plugin-typescript": "^0.14.0",
-    "express": "^4.17.3",
-    "gh-pages": "^3.2.3",
-    "jsdom-global": "^3.0.2",
     "lint-staged": "^10.5.4",
-    "mockjs": "^1.1.0",
-    "prettier": "^2.6.2",
-    "puppeteer-core": "^8.0.0",
-    "react-dev-inspector": "^1.7.1",
-    "stylelint": "^13.13.1",
+    "husky": "^8.0.0",
+    "eslint": "^8.17.0",
+    "prettier": "^2.6.1",
+    "stylelint": "^14.9.0",
     "typescript": "^4.6.3",
-    "windicss": "3.1.7",
-    "windicss-webpack-plugin": "1.4.6"
+    "@unocss/cli": "^0.44.2",
+    "unocss": "^0.44.2"
   },
   "engines": {
-    "node": ">=10.0.0"
+    "node": ">=14.0.0"
   },
   "packageManager": "pnpm@6.31.0"
 }

+ 15 - 0
plugin.ts

@@ -0,0 +1,15 @@
+import { IApi } from '@umijs/max'
+
+export default (api: IApi) => {
+  api.addHTMLHeadScripts(() => {
+    return process.env.NODE_ENV === 'development'
+      ? [
+          'https://d2.smartcost.com.cn/cach/cld/react18.1.0/react.development.js',
+          'https://d2.smartcost.com.cn/cach/cld/react18.1.0/react-dom.development.js'
+        ]
+      : [
+          'https://d2.smartcost.com.cn/cach/cld/react18.1.0/react.production.min.js',
+          'https://d2.smartcost.com.cn/cach/cld/react18.1.0/react-dom.production.min.js'
+        ]
+  })
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 5584 - 11381
pnpm-lock.yaml


+ 67 - 129
src/app.tsx

@@ -1,22 +1,13 @@
 import type { Settings as LayoutSettings } from '@ant-design/pro-layout'
-import { PageLoading } from '@ant-design/pro-layout'
 import { notification } from 'antd'
-import type { RequestConfig, RunTimeLayoutConfig } from 'umi'
-import { getIntl, getLocale, history } from 'umi'
+import type { RequestConfig, RunTimeLayoutConfig } from '@umijs/max'
+import { getIntl, getLocale, history } from '@umijs/max'
 import RightContent from '@/components/RightContent'
-import Footer from '@/components/Footer'
-import type { RequestOptionsInit, ResponseError } from 'umi-request'
 import { currentUser as queryCurrentUser } from './services/user/api'
 import consts from './utils/consts'
-
-const isDev = process.env.NODE_ENV === 'development'
+import defaultSettings from '../config/defaultSettings'
 const loginPath = '/user/login'
 
-/** 获取用户信息比较慢的时候会展示一个 loading */
-export const initialStateConfig = {
-  loading: <PageLoading />
-}
-
 /**
  * @see  https://umijs.org/zh-CN/plugins/plugin-initial-state
  * */
@@ -53,118 +44,81 @@ export async function getInitialState(): Promise<{
   }
 }
 
-const authHeaderInterceptor = (url: string, options: RequestOptionsInit) => {
-  const token = window.localStorage.getItem('TOKEN_ID')
+const authHeaderInterceptor = options => {
+  const token = JSON.parse(window.localStorage.getItem('TOKEN_ID'))
   // 如果是登录页面,不执行
-  if (!token && history.location.pathname !== loginPath) {
-    return history.push(loginPath)
-  }
-  const authHeader = { Authorization: `Bearer ${JSON.parse(token)}` }
-  return {
-    url: `${url}`,
-    options: { ...options, interceptors: true, headers: authHeader }
+  if (token) {
+    // 在白名单里的请求放过
+    if (consts.TOKEN_WHITE_LIST.includes(options.url)) {
+      return options
+    }
+    options.headers[consts.TOKEN_HEADER] = 'bearer ' + token
   }
+  return options
 }
 
-/**
- * 异常处理程序
- const codeMessage = {
-    200: '服务器成功返回请求的数据。',
-    201: '新建或修改数据成功。',
-    202: '一个请求已经进入后台排队(异步任务)。',
-    204: '删除数据成功。',
-    400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
-    401: '用户没有权限(令牌、用户名、密码错误)。',
-    403: '用户得到授权,但是访问是被禁止的。',
-    404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
-    405: '请求方法不被允许。',
-    406: '请求的格式不可得。',
-    410: '请求的资源被永久删除,且不会再得到的。',
-    422: '当创建一个对象时,发生一个验证错误。',
-    500: '服务器发生错误,请检查服务器。',
-    502: '网关错误。',
-    503: '服务不可用,服务器暂时过载或维护。',
-    504: '网关超时。',
- };
- * @see https://beta-pro.ant.design/docs/request-cn
- */
-export const request: RequestConfig = {
-  errorHandler: (error: ResponseError) => {
-    const { messages } = getIntl(getLocale())
-    const { response } = error
+const errorHandler = (error: any, opts: any) => {
+  if (opts?.skipErrorHandler) return
 
-    if (response && response.status) {
-      const { status, statusText, url } = response
-      const requestErrorMessage = messages['app.request.error']
-      const errorMessage = `${requestErrorMessage} ${status}: ${url}`
-      const errorDescription = messages[`app.request.${status}`] || statusText
+  const errorInfo = error.info
+  if (errorInfo) {
+    const { errorMessage = '请求失败', errorCode } = errorInfo
+    if (consts.TOKEN_INVALID_CODE.includes(errorCode) && window.location.pathname !== consts.loginPath) {
       notification.error({
-        message: errorMessage,
-        description: errorDescription
+        message: '用户信息过期',
+        description: '请重新登录'
       })
-    }
-
-    if (!response) {
-      notification.error({
-        description: '您的网络发生异常,无法连接服务器',
-        message: '网络异常'
+      history.replace({
+        pathname: consts.loginPath,
+        search: createSearchParams({
+          redirect: window.location.pathname
+        }).toString()
       })
+      return
     }
-    throw error
-  },
-  middlewares: [
-    async (ctx, next) => {
-      await next()
-      const { req, res } = ctx
-      // @ts-ignore
-      if (req.options?.skipErrorHandler) {
-        return
-      }
-      const errorAdaptor = req.options?.errorConfig.adaptor || (resData => resData)
-      const { options } = req
-      const { getResponse } = options
-      const resData = getResponse ? res.data : res
-      const errorInfo = errorAdaptor(resData, ctx)
-      if (resData.code !== consts.RET_CODE.SUCCESS) {
-        // 抛出错误到 errorHandler 中处理
-        const error: ResponseError = new Error(errorInfo.errorMessage)
-        error.name = 'BizError'
-        error.data = resData
-        error.info = errorInfo
-        error.response = res
-        throw error
-      }
-    }
-  ],
-  prefix: '/backstage',
+    notification.error({
+      message: '请求失败',
+      description: errorMessage
+    })
+  } else if (error.response) {
+    // Axios 的错误
+    // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
+    notification.error({
+      description: `状态码为${error.status}, 请联系管理员进行处理`,
+      message: '请求异常'
+    })
+  } else if (error.request) {
+    // 请求已经成功发起,但没有收到响应
+    // 或请求根本没有发送出去
+    notification.error({
+      description: '您的网络请求已经发起,但没有收到响应',
+      message: '响应超时'
+    })
+  } else {
+    notification.error({
+      description: '您的网络发生异常,无法连接服务器',
+      message: '网络异常'
+    })
+  }
+}
+
+export const request: RequestConfig = {
+  baseURL: consts.PREFIX_URL,
   errorConfig: {
-    adaptor: resData => {
-      return {
-        // success: resData.code === consts.RET_CODE.SUCCESS,
-        data: resData.data,
-        errorCode: resData.code,
-        errorMessage: resData.msg
-      }
-    }
+    errorHandler
   },
   responseInterceptors: [
-    async (response, options) => {
-      const errorAdaptor = options?.errorConfig.adaptor || (resData => resData)
-      const res = await response.clone().json()
-      const { getResponse } = options
-      const resData = getResponse ? res.data : res
-      const errorInfo = errorAdaptor(resData, { res: response, req: options })
-
-      if (res?.code !== consts.RET_CODE.SUCCESS) {
-        // 抛出错误到 errorHandler 中处理
-        const error: ResponseError = new Error(errorInfo.errorMessage)
-        error.name = 'BizError'
-        error.data = resData
-        error.info = errorInfo
-        error.response = res
-        throw error
+    async response => {
+      const { data, code: errorCode, msg: errorMessage } = response.data
+      if (!errorCode || errorCode !== consts.RET_CODE.SUCCESS) {
+        if (errorCode !== consts.RET_CODE.SUCCESS) {
+          const error: any = new Error(errorMessage)
+          error.name = 'BizError'
+          error.info = { errorCode, errorMessage, data }
+          throw error
+        }
       }
-      return response
+      return Promise.resolve(response)
     }
   ],
   requestInterceptors: [authHeaderInterceptor]
@@ -178,12 +132,8 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => {
     waterMarkProps: initialState.currentUser && {
       fontColor: 'rgba(0,0,0,.1)',
       offsetTop: 200,
-      content: `${initialState.currentUser?.username}  ${initialState.currentUser?.telephone.slice(
-        -4
-      )}`
+      content: `${initialState.currentUser?.username}  ${initialState.currentUser?.telephone.slice(-4)}`
     },
-
-    footerRender: () => <Footer />,
     onPageChange: () => {
       const { location } = history
       // 如果没有登录,重定向到 login
@@ -191,21 +141,9 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => {
         history.push(loginPath)
       }
     },
-    links: isDev
-      ? [
-          // <Link to="/umi/plugin/openapi" target="_blank">
-          //   <LinkOutlined />
-          //   <span>openAPI 文档</span>
-          // </Link>,
-          // <Link to="/~docs">
-          //   <BookOutlined />
-          //   <span>业务组件文档</span>
-          // </Link>
-        ]
-      : [],
     menuHeaderRender: undefined,
     // 自定义 403 页面
     // unAccessible: <div>unAccessible</div>,
-    ...initialState?.settings
+    ...defaultSettings
   }
 }

+ 1 - 1
src/components/Footer/index.tsx

@@ -1,4 +1,4 @@
-// import { useIntl } from 'umi'
+// import { useIntl } from '@umijs/max'
 // import { GithubOutlined } from '@ant-design/icons'
 // import { DefaultFooter } from '@ant-design/pro-layout'
 

+ 1 - 1
src/components/NoticeIcon/index.tsx

@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'
 import { Tag, message } from 'antd'
 import { groupBy } from 'lodash'
 import moment from 'moment'
-import { useModel } from 'umi'
+import { useModel } from '@umijs/max'
 import { getNotices } from '@/services/user/api'
 
 import NoticeIcon from './NoticeIcon'

+ 6 - 10
src/components/RightContent/AvatarDropdown.tsx

@@ -1,8 +1,7 @@
 import React, { useCallback } from 'react'
 import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons'
 import { Avatar, Menu, Spin } from 'antd'
-import { history, useModel } from 'umi'
-import { stringify } from 'querystring'
+import { createSearchParams, history, useModel } from '@umijs/max'
 import HeaderDropdown from '../HeaderDropdown'
 import styles from './index.less'
 import { outLogin } from '@/services/user/api'
@@ -15,16 +14,12 @@ export type GlobalHeaderRightProps = {
  * 退出登录,并且将当前的 url 保存
  */
 const loginOut = async () => {
-  await outLogin()
-  const { query = {}, pathname } = history.location
-  const { redirect } = query
-  // Note: There may be security issues, please note
-  if (window.location.pathname !== '/user/login' && !redirect) {
+  if (window.location.pathname !== '/user/login') {
     history.replace({
       pathname: '/user/login',
-      search: stringify({
-        redirect: pathname
-      })
+      search: createSearchParams({
+        redirect: window.location.pathname
+      }).toString()
     })
   }
 }
@@ -42,6 +37,7 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
       const { key } = event
       if (key === 'logout' && initialState) {
         setInitialState({ ...initialState, currentUser: undefined })
+        window.localStorage.removeItem('TOKEN_ID')
         loginOut()
         return
       }

+ 1 - 1
src/components/RightContent/index.tsx

@@ -1,7 +1,7 @@
 import { Tag, Space } from 'antd'
 // import { QuestionCircleOutlined } from '@ant-design/icons'
 import React from 'react'
-import { useModel, SelectLang } from 'umi'
+import { useModel, SelectLang } from '@umijs/max'
 import Avatar from './AvatarDropdown'
 // import HeaderSearch from '../HeaderSearch'
 import styles from './index.less'

+ 9 - 0
src/global.less

@@ -30,6 +30,15 @@ body {
 ul,
 ol {
   list-style: none;
+  margin: 0;
+  padding: 0;
+}
+
+*,
+:after,
+:before {
+  box-sizing: border-box;
+  border: 0 solid #e4e4e7;
 }
 
 @media (max-width: @screen-xs) {

+ 1 - 2
src/global.tsx

@@ -1,8 +1,7 @@
 import { Button, message, notification } from 'antd'
-import { useIntl } from 'umi'
+import { useIntl } from '@umijs/max'
 import defaultSettings from '../config/defaultSettings'
 
-import 'windi.css'
 import '@icon-park/react/styles/index.less'
 
 const { pwa } = defaultSettings

+ 2 - 4
src/hooks/core/useWebSocketFn.ts

@@ -1,7 +1,7 @@
 /* eslint-disable react-hooks/rules-of-hooks */
 import { useWebSocket } from 'ahooks'
 import { useEffect, useState } from 'react'
-import { useModel } from 'umi'
+import { useModel } from '@umijs/max'
 
 export enum cmdType {
   Single = 10,
@@ -48,9 +48,7 @@ export default function useWebSocketFn() {
   }, [])
 
   function sendMsg(cmd: cmdType, options: any) {
-    webSocketIns?.send(
-      JSON.stringify({ cmd, userid: `${currentUser.staffId}_${copyCount}`, ...options })
-    )
+    webSocketIns?.send(JSON.stringify({ cmd, userid: `${currentUser.staffId}_${copyCount}`, ...options }))
   }
   return { webSocketIns, sendMsg }
 }

+ 1 - 1
src/models/user.ts

@@ -1,5 +1,5 @@
 import { useLocalStorageState } from 'ahooks'
-// import { history } from 'umi'
+// import { history } from '@umijs/max'
 
 export default () => {
   const [, setTokenId] = useLocalStorageState('TOKEN_ID')

+ 1 - 1
src/pages/404.tsx

@@ -1,6 +1,6 @@
 import React from 'react'
 import { Button, Result } from 'antd'
-import { history } from 'umi'
+import { history } from '@umijs/max'
 
 const NoFoundPage: React.FC = () => (
   <Result

+ 4 - 11
src/pages/Business/Attendance/index.tsx

@@ -1,6 +1,6 @@
 import React, { useState, useEffect, useRef } from 'react'
 import ShowTitleMenu from './components/ShowTitleMenu'
-import { useRequest } from 'umi'
+import { useRequest } from '@umijs/max'
 import { Plus, Delete } from '@icon-park/react'
 import { Table, Tag, Popconfirm, Button, Alert, message } from 'antd'
 import type { FormInstance } from 'antd'
@@ -170,9 +170,7 @@ const Attendance: React.FC = () => {
                 <div className="absolute right-7 top-7 z-100">
                   <Button
                     type="primary"
-                    onClick={() =>
-                      setState({ ...state, visible: true, type: modalType.addobjectModal })
-                    }>
+                    onClick={() => setState({ ...state, visible: true, type: modalType.addobjectModal })}>
                     添加新申请人
                   </Button>
                   <ConnectModal
@@ -181,9 +179,7 @@ const Attendance: React.FC = () => {
                     onShowChange={(visible: boolean) => setState({ ...state, visible })}
                     onReload={() => tryGetRoleStaffList()}
                     postUrl={
-                      state.type === modalType.addobjectModal
-                        ? '/attendance/add'
-                        : '/attendance/linkStaff'
+                      state.type === modalType.addobjectModal ? '/attendance/add' : '/attendance/linkStaff'
                     }
                     showButton={false}
                   />
@@ -210,10 +206,7 @@ const Attendance: React.FC = () => {
                     initialValues={{ parametersType: 1 }}>
                     <h3 className="font-bold">销假参数</h3>
                     <div className="mt-4 mb-4">
-                      <Alert
-                        type="warning"
-                        message="超过当前设置销假参数(不包含当前所写的)不计算考勤"
-                      />
+                      <Alert type="warning" message="超过当前设置销假参数(不包含当前所写的)不计算考勤" />
                     </div>
                     <ProForm.Group>
                       <ProFormText name="parametersType" hidden />

+ 1 - 1
src/pages/Business/CommonSetting/index.tsx

@@ -1,6 +1,6 @@
 import { PageContainer } from '@ant-design/pro-layout'
 import React, { useEffect, useRef, useState } from 'react'
-import { useRequest } from 'umi'
+import { useRequest } from '@umijs/max'
 import ShowTitleMenu from '../Attendance/components/ShowTitleMenu'
 import type { FormInstance } from 'antd'
 import { message } from 'antd'

+ 3 - 10
src/pages/Business/Contact/index.tsx

@@ -5,7 +5,7 @@ import ProForm, { ModalForm, ProFormText } from '@ant-design/pro-form'
 import type { ProFormColumnsType } from '@ant-design/pro-form'
 import { EditableProTable } from '@ant-design/pro-table'
 import ShowTitleMenu from '../Attendance/components/ShowTitleMenu'
-import { useModel, useRequest } from 'umi'
+import { useModel, useRequest } from '@umijs/max'
 import {
   addBusinessgroup,
   changeBusinessGroupStatus,
@@ -333,12 +333,7 @@ const Contact: React.FC = () => {
                     添加新组
                   </Button>
                 </div>
-                <Table
-                  columns={mainColumns}
-                  dataSource={state.dataSource}
-                  bordered
-                  rowKey={row => row.id}
-                />
+                <Table columns={mainColumns} dataSource={state.dataSource} bordered rowKey={row => row.id} />
               </>
             ) : null}
             {state.menuId === 2 ? (
@@ -365,9 +360,7 @@ const Contact: React.FC = () => {
           visible={state.visible}
           formRef={formRef}
           onVisibleChange={show => setState({ ...state, visible: show })}
-          title={`${state.type === modalType.CREATE ? '创建' : '更新'}${
-            modalTitleType[state.menuId]
-          }`}
+          title={`${state.type === modalType.CREATE ? '创建' : '更新'}${modalTitleType[state.menuId]}`}
           onFinish={async value => {
             try {
               if (state.type === modalType.CREATE && state.menuId === 1) {

+ 6 - 19
src/pages/Business/Invoice/index.tsx

@@ -14,7 +14,7 @@ import {
   deleteInvoiceItem,
   sortInvoiceItem
 } from '@/services/user/system'
-import { useRequest } from 'umi'
+import { useRequest } from '@umijs/max'
 import classNames from 'classnames'
 import './index.less'
 import { PageContainer } from '@ant-design/pro-layout'
@@ -112,9 +112,7 @@ const Invoice: React.FC = () => {
       dataIndex: 'enable',
       title: '状态',
       render: enable => (
-        <span className={classNames({ 'text-red-500': enable === 'close' })}>
-          {isEnableEnum[enable]}
-        </span>
+        <span className={classNames({ 'text-red-500': enable === 'close' })}>{isEnableEnum[enable]}</span>
       )
     },
     {
@@ -187,9 +185,7 @@ const Invoice: React.FC = () => {
   const onSortEnd = ({ oldIndex, newIndex }) => {
     const { dataSource } = state
     if (oldIndex !== newIndex) {
-      const newData = arrayMoveImmutable([].concat(dataSource), oldIndex, newIndex).filter(
-        el => !!el
-      )
+      const newData = arrayMoveImmutable([].concat(dataSource), oldIndex, newIndex).filter(el => !!el)
       // console.log('Sorted items: ', newData)
       setState({ ...state, dataSource: newData })
       const oldIndexItem = dataSource?.find(item => item.index === oldIndex)
@@ -219,11 +215,7 @@ const Invoice: React.FC = () => {
   return (
     <PageContainer title={false} breadcrumb={false}>
       <div className="h-full w-full flex flex-row">
-        <ShowTitleMenu
-          onSelect={onSelect}
-          options={[{ label: '开票内容', value: 1 }]}
-          defaultValue={1}
-        />
+        <ShowTitleMenu onSelect={onSelect} options={[{ label: '开票内容', value: 1 }]} defaultValue={1} />
         <div className="w-max-3/4">
           <div className="ml-8 bg-white p-4 shadow-md shadow-hex-3e2c5a relative">
             <div className="absolute right-4 top-4 z-100">
@@ -234,10 +226,7 @@ const Invoice: React.FC = () => {
               </Button>
             </div>
             {state.menuId === 1 ? (
-              <Tabs
-                defaultActiveKey="6"
-                type="card"
-                onChange={key => setState({ ...state, activeKey: key })}>
+              <Tabs defaultActiveKey="6" type="card" onChange={key => setState({ ...state, activeKey: key })}>
                 <TabPane tab="开票内容 1" key="6">
                   <Table<API.InvoiceList>
                     pagination={false}
@@ -299,9 +288,7 @@ const Invoice: React.FC = () => {
           visible={state.visible}
           formRef={formRef}
           onVisibleChange={show => setState({ ...state, visible: show })}
-          title={`${state.type === modalType.CREATE ? '新增' : '编辑'}${
-            modalTitleType[state.menuId]
-          }`}
+          title={`${state.type === modalType.CREATE ? '新增' : '编辑'}${modalTitleType[state.menuId]}`}
           onFinish={async value => {
             try {
               if (state.type === modalType.CREATE && state.menuId === 1) {

+ 3 - 10
src/pages/Business/Notification/index.tsx

@@ -1,17 +1,11 @@
 import React, { useRef } from 'react'
 import { Button, message, Form } from 'antd'
-import {
-  ModalForm,
-  ProFormDependency,
-  ProFormRadio,
-  ProFormSelect,
-  ProFormText
-} from '@ant-design/pro-form'
+import { ModalForm, ProFormDependency, ProFormRadio, ProFormSelect, ProFormText } from '@ant-design/pro-form'
 import type { ProFormColumnsType } from '@ant-design/pro-form'
 import ProTable from '@ant-design/pro-table'
 import type { ActionType } from '@ant-design/pro-table'
 import ShowTitleMenu from '../Attendance/components/ShowTitleMenu'
-import { useRequest } from 'umi'
+import { useRequest } from '@umijs/max'
 import { queryNoticeList, sendNotice } from '@/services/user/api'
 import consts from '@/utils/consts'
 import { PlusOutlined } from '@ant-design/icons'
@@ -158,8 +152,7 @@ const Notification: React.FC = () => {
                     </ProFormDependency>
                     <ProFormDependency name={['msgType', 'media']}>
                       {({ msgType, media }) =>
-                        msgType === msgTypeEnum.Notification &&
-                        media === mediaType.VersionUpdate ? (
+                        msgType === msgTypeEnum.Notification && media === mediaType.VersionUpdate ? (
                           <ProFormRadio.Group
                             name="refresh"
                             rules={[{ required: true, message: '请选择刷新机制' }]}

+ 8 - 16
src/pages/Role/Customer/index.tsx

@@ -1,4 +1,4 @@
-import { useModel, useRequest } from 'umi'
+import { useModel, useRequest } from '@umijs/max'
 import { Delete, EveryUser } from '@icon-park/react'
 import ProForm, { ProFormCheckbox, ProFormDependency, ProFormSwitch } from '@ant-design/pro-form'
 import type { FormInstance } from 'antd'
@@ -69,15 +69,12 @@ const Customer = () => {
     setState({ ...state, id })
   }
 
-  const { run: tryGetRoleStaffList } = useRequest(
-    (id: string) => fetchRoleStaffListByRoleId({ id }),
-    {
-      manual: true,
-      onSuccess: result => {
-        setState({ ...state, roleStaff: result })
-      }
+  const { run: tryGetRoleStaffList } = useRequest((id: string) => fetchRoleStaffListByRoleId({ id }), {
+    manual: true,
+    onSuccess: result => {
+      setState({ ...state, roleStaff: result })
     }
-  )
+  })
 
   const { run: tryGetRolePermissions } = useRequest((id: string) => getRolePermissions({ id }), {
     manual: true,
@@ -95,9 +92,7 @@ const Customer = () => {
       })
 
       formRef.current?.setFieldsValue({ ...values })
-      formRef2.current?.setFieldsValue(
-        result.dataPermission ? JSON.parse(result.dataPermission) : null
-      )
+      formRef2.current?.setFieldsValue(result.dataPermission ? JSON.parse(result.dataPermission) : null)
     }
   })
 
@@ -188,10 +183,7 @@ const Customer = () => {
                 />
               )}
             </div>
-            <Tabs
-              defaultActiveKey="1"
-              type="card"
-              onChange={key => setState({ ...state, activeKey: key })}>
+            <Tabs defaultActiveKey="1" type="card" onChange={key => setState({ ...state, activeKey: key })}>
               <TabPane tab="员工列表" key="1">
                 <Table<API.RoleStaffListItem>
                   dataSource={state.roleStaff}

+ 8 - 16
src/pages/Role/Hr/index.tsx

@@ -1,4 +1,4 @@
-import { useModel, useRequest } from 'umi'
+import { useModel, useRequest } from '@umijs/max'
 import { Delete, EveryUser } from '@icon-park/react'
 import ProForm, { ProFormCheckbox, ProFormDependency, ProFormSwitch } from '@ant-design/pro-form'
 import type { FormInstance } from 'antd'
@@ -65,15 +65,12 @@ const Hr = () => {
     setState({ ...state, id })
   }
 
-  const { run: tryGetRoleStaffList } = useRequest(
-    (id: string) => fetchRoleStaffListByRoleId({ id }),
-    {
-      manual: true,
-      onSuccess: result => {
-        setState({ ...state, roleStaff: result })
-      }
+  const { run: tryGetRoleStaffList } = useRequest((id: string) => fetchRoleStaffListByRoleId({ id }), {
+    manual: true,
+    onSuccess: result => {
+      setState({ ...state, roleStaff: result })
     }
-  )
+  })
 
   const { run: tryGetRolePermissions } = useRequest((id: string) => getRolePermissions({ id }), {
     manual: true,
@@ -85,9 +82,7 @@ const Hr = () => {
         dataPermission: result.dataPermission ? JSON.parse(result.dataPermission) : null
       })
       formRef.current?.setFieldsValue({ ...values })
-      formRef2.current?.setFieldsValue(
-        result.dataPermission ? JSON.parse(result.dataPermission) : null
-      )
+      formRef2.current?.setFieldsValue(result.dataPermission ? JSON.parse(result.dataPermission) : null)
     }
   })
 
@@ -179,10 +174,7 @@ const Hr = () => {
                 />
               )}
             </div>
-            <Tabs
-              defaultActiveKey="1"
-              type="card"
-              onChange={key => setState({ ...state, activeKey: key })}>
+            <Tabs defaultActiveKey="1" type="card" onChange={key => setState({ ...state, activeKey: key })}>
               <TabPane tab="员工列表" key="1">
                 <Table<API.RoleStaffListItem>
                   dataSource={state.roleStaff}

+ 12 - 28
src/pages/Role/Product/index.tsx

@@ -1,4 +1,4 @@
-import { useModel, useRequest } from 'umi'
+import { useModel, useRequest } from '@umijs/max'
 import { Delete, DataLock } from '@icon-park/react'
 import ProForm, { ProFormCheckbox, ProFormDependency, ProFormSwitch } from '@ant-design/pro-form'
 import type { FormInstance } from 'antd'
@@ -42,15 +42,12 @@ const Product = () => {
     setState({ ...state, id })
   }
 
-  const { run: tryGetRoleStaffList } = useRequest(
-    (id: string) => fetchRoleStaffListByRoleId({ id }),
-    {
-      manual: true,
-      onSuccess: result => {
-        setState({ ...state, roleStaff: result })
-      }
+  const { run: tryGetRoleStaffList } = useRequest((id: string) => fetchRoleStaffListByRoleId({ id }), {
+    manual: true,
+    onSuccess: result => {
+      setState({ ...state, roleStaff: result })
     }
-  )
+  })
 
   const { run: tryGetRolePermissions } = useRequest((id: string) => getRolePermissions({ id }), {
     manual: true,
@@ -87,9 +84,7 @@ const Product = () => {
       })
 
       formRef.current?.setFieldsValue({ ...values })
-      formRef2.current?.setFieldsValue(
-        result.dataPermission ? JSON.parse(result.dataPermission) : null
-      )
+      formRef2.current?.setFieldsValue(result.dataPermission ? JSON.parse(result.dataPermission) : null)
     }
   })
 
@@ -180,10 +175,7 @@ const Product = () => {
                 />
               )}
             </div>
-            <Tabs
-              defaultActiveKey="1"
-              type="card"
-              onChange={key => setState({ ...state, activeKey: key })}>
+            <Tabs defaultActiveKey="1" type="card" onChange={key => setState({ ...state, activeKey: key })}>
               <TabPane tab="员工列表" key="1">
                 <Table<API.RoleStaffListItem>
                   dataSource={state.roleStaff}
@@ -258,9 +250,7 @@ const Product = () => {
                               <ProFormCheckbox.Group
                                 wrapperCol={{ offset: 1 }}
                                 name="building"
-                                options={[
-                                  { value: 'access', label: '查看', disabled: !showBuilding }
-                                ]}
+                                options={[{ value: 'access', label: '查看', disabled: !showBuilding }]}
                               />
                             )}
                           </ProFormDependency>
@@ -284,9 +274,7 @@ const Product = () => {
                               <ProFormCheckbox.Group
                                 wrapperCol={{ offset: 1 }}
                                 name="curing"
-                                options={[
-                                  { value: 'access', label: '查看', disabled: !showCuring }
-                                ]}
+                                options={[{ value: 'access', label: '查看', disabled: !showCuring }]}
                               />
                             )}
                           </ProFormDependency>
@@ -310,9 +298,7 @@ const Product = () => {
                               <ProFormCheckbox.Group
                                 wrapperCol={{ offset: 1 }}
                                 name="highway"
-                                options={[
-                                  { value: 'access', label: '查看', disabled: !showHighway }
-                                ]}
+                                options={[{ value: 'access', label: '查看', disabled: !showHighway }]}
                               />
                             )}
                           </ProFormDependency>
@@ -363,9 +349,7 @@ const Product = () => {
                               <ProFormCheckbox.Group
                                 wrapperCol={{ offset: 1 }}
                                 name="personal"
-                                options={[
-                                  { value: 'access', label: '查看', disabled: !showPersonal }
-                                ]}
+                                options={[{ value: 'access', label: '查看', disabled: !showPersonal }]}
                               />
                             )}
                           </ProFormDependency>

+ 15 - 39
src/pages/Role/Statistic/index.tsx

@@ -1,4 +1,4 @@
-import { useModel, useRequest } from 'umi'
+import { useModel, useRequest } from '@umijs/max'
 import { Delete } from '@icon-park/react'
 import ProForm, { ProFormDependency, ProFormSwitch, ProFormCheckbox } from '@ant-design/pro-form'
 import type { FormInstance } from 'antd'
@@ -44,15 +44,12 @@ const Statistic = () => {
     setState({ ...state, id })
   }
 
-  const { run: tryGetRoleStaffList } = useRequest(
-    (id: string) => fetchRoleStaffListByRoleId({ id }),
-    {
-      manual: true,
-      onSuccess: result => {
-        setState({ ...state, roleStaff: result })
-      }
+  const { run: tryGetRoleStaffList } = useRequest((id: string) => fetchRoleStaffListByRoleId({ id }), {
+    manual: true,
+    onSuccess: result => {
+      setState({ ...state, roleStaff: result })
     }
-  )
+  })
 
   const { run: tryGetRolePermissions } = useRequest((id: string) => getRolePermissions({ id }), {
     manual: true,
@@ -88,9 +85,7 @@ const Statistic = () => {
       })
 
       formRef.current?.setFieldsValue({ ...values })
-      formRef2.current?.setFieldsValue(
-        result.dataPermission ? JSON.parse(result.dataPermission) : null
-      )
+      formRef2.current?.setFieldsValue(result.dataPermission ? JSON.parse(result.dataPermission) : null)
     }
   })
 
@@ -181,10 +176,7 @@ const Statistic = () => {
                 />
               )}
             </div>
-            <Tabs
-              defaultActiveKey="1"
-              type="card"
-              onChange={key => setState({ ...state, activeKey: key })}>
+            <Tabs defaultActiveKey="1" type="card" onChange={key => setState({ ...state, activeKey: key })}>
               <TabPane tab="员工列表" key="1">
                 <Table<API.RoleStaffListItem>
                   dataSource={state.roleStaff}
@@ -223,10 +215,7 @@ const Statistic = () => {
                         name="showProduct"
                         label={
                           <span className="flex items-center">
-                            <PieChartOutlined
-                              theme="outline"
-                              className="flex items-baseline mr-1"
-                            />
+                            <PieChartOutlined theme="outline" className="flex items-baseline mr-1" />
                             产品销售
                           </span>
                         }
@@ -238,30 +227,22 @@ const Statistic = () => {
                               <ProFormCheckbox.Group
                                 name="usage"
                                 label="软件锁用量"
-                                options={[
-                                  { value: 'access', label: '查看', disabled: !showProduct }
-                                ]}
+                                options={[{ value: 'access', label: '查看', disabled: !showProduct }]}
                               />
                               <ProFormCheckbox.Group
                                 name="aggregate"
                                 label="发票收款入账汇总"
-                                options={[
-                                  { value: 'access', label: '查看', disabled: !showProduct }
-                                ]}
+                                options={[{ value: 'access', label: '查看', disabled: !showProduct }]}
                               />
                               <ProFormCheckbox.Group
                                 name="trends"
                                 label="发票收款入账趋势"
-                                options={[
-                                  { value: 'access', label: '查看', disabled: !showProduct }
-                                ]}
+                                options={[{ value: 'access', label: '查看', disabled: !showProduct }]}
                               />
                               <ProFormCheckbox.Group
                                 name="receivables"
                                 label="应收款统计"
-                                options={[
-                                  { value: 'access', label: '查看', disabled: !showProduct }
-                                ]}
+                                options={[{ value: 'access', label: '查看', disabled: !showProduct }]}
                               />
                             </>
                           )}
@@ -280,10 +261,7 @@ const Statistic = () => {
                         name="showCustomer"
                         label={
                           <span className="flex items-center">
-                            <PieChartOutlined
-                              theme="outline"
-                              className="flex items-baseline mr-1"
-                            />
+                            <PieChartOutlined theme="outline" className="flex items-baseline mr-1" />
                             客户数据
                           </span>
                         }
@@ -294,9 +272,7 @@ const Statistic = () => {
                             <ProFormCheckbox.Group
                               name="additions"
                               label="客户新增"
-                              options={[
-                                { value: 'access', label: '查看', disabled: !showCustomer }
-                              ]}
+                              options={[{ value: 'access', label: '查看', disabled: !showCustomer }]}
                             />
                           )}
                         </ProFormDependency>

+ 4 - 12
src/pages/Role/System/components/ConnectModal/index.tsx

@@ -1,5 +1,5 @@
 import React, { useState, useRef, useEffect } from 'react'
-import { useRequest, request } from 'umi'
+import { useRequest, request } from '@umijs/max'
 import { Button, Input, message, Modal, Spin } from 'antd'
 import { fetchStaffList } from '@/services/user/api'
 import { useDebounceFn } from 'ahooks'
@@ -56,9 +56,7 @@ const ConnectModal: React.FC<ConnectModalProps> = ({
   )
 
   const initData = async params => {
-    const { data: { list, total } = { list: [], total: 0 }, code = -1 } = await fetchStaffList(
-      params
-    )
+    const { data: { list, total } = { list: [], total: 0 }, code = -1 } = await fetchStaffList(params)
     if (code === consts.RET_CODE.SUCCESS) {
       if (params?.current === 1) {
         scrollRef.current?.scrollTo({ top: 0 })
@@ -122,10 +120,7 @@ const ConnectModal: React.FC<ConnectModalProps> = ({
 
   const handleListScroll = () => {
     // 未滚动到底部
-    if (
-      scrollRef.current.scrollHeight - scrollRef.current.clientHeight <=
-      scrollRef.current.scrollTop
-    ) {
+    if (scrollRef.current.scrollHeight - scrollRef.current.clientHeight <= scrollRef.current.scrollTop) {
       // 已到底部
       if (state.current * state.pageSize > state.total) {
         setState({ ...state, noMore: true })
@@ -157,10 +152,7 @@ const ConnectModal: React.FC<ConnectModalProps> = ({
             allowClear={true}
           />
         }>
-        <div
-          ref={scrollRef}
-          onScroll={handleListScroll}
-          className="h-60vh overflow-y-auto overflow-x-hidden">
+        <div ref={scrollRef} onScroll={handleListScroll} className="h-60vh overflow-y-auto overflow-x-hidden">
           <Spin spinning={state.laoding}>
             {state.list.map(item => (
               <div className="group-item-card" key={item.id}>

+ 10 - 21
src/pages/Role/System/components/RoleMenu/index.tsx

@@ -1,13 +1,8 @@
 import React, { useState, useEffect, useRef } from 'react'
 import { PlusOutlined, InfoCircleOutlined, FormOutlined, DeleteOutlined } from '@ant-design/icons'
 import { Button, message, Popconfirm, Switch, Tooltip } from 'antd'
-import { useModel, useRequest } from 'umi'
-import {
-  createRoleWithMenuId,
-  fetchRoleListByMenuId,
-  deleteRole,
-  updateStaff
-} from '@/services/user/api'
+import { useModel, useRequest } from '@umijs/max'
+import { createRoleWithMenuId, fetchRoleListByMenuId, deleteRole, updateStaff } from '@/services/user/api'
 import { ProFormDependency, ProFormSelect } from '@ant-design/pro-form'
 import { ModalForm, ProFormText } from '@ant-design/pro-form'
 import classNames from 'classnames'
@@ -71,16 +66,13 @@ const RoleMenu: React.FC<RoleMenuProps> = ({ menuId, onSelect, itemCount }) => {
     }
   })
 
-  const { run: tryAddRole } = useRequest(
-    (params: API.CreateRoleParams) => createRoleWithMenuId(params),
-    {
-      manual: true,
-      onSuccess: () => {
-        tryFetchMenuRoles(menuId)
-        message.success('添加成功')
-      }
+  const { run: tryAddRole } = useRequest((params: API.CreateRoleParams) => createRoleWithMenuId(params), {
+    manual: true,
+    onSuccess: () => {
+      tryFetchMenuRoles(menuId)
+      message.success('添加成功')
     }
-  )
+  })
   useEffect(() => {
     tryFetchMenuRoles(menuId)
   }, [])
@@ -102,7 +94,7 @@ const RoleMenu: React.FC<RoleMenuProps> = ({ menuId, onSelect, itemCount }) => {
   }
   return (
     <div
-      className="w-max-234px rounded-4px"
+      className="max-w-234px rounded-4px"
       style={{
         height: `calc(100vh - 96px)`
       }}>
@@ -135,10 +127,7 @@ const RoleMenu: React.FC<RoleMenuProps> = ({ menuId, onSelect, itemCount }) => {
                 {item.name}
               </div>
               <div className={styles.extra}>
-                <FormOutlined
-                  className="pr-2"
-                  onClick={() => handleEditIconClick(item.id, item.name)}
-                />
+                <FormOutlined className="pr-2" onClick={() => handleEditIconClick(item.id, item.name)} />
                 <Popconfirm
                   title="确认删除吗?"
                   okText="确认"

+ 8 - 14
src/pages/Role/System/index.tsx

@@ -1,4 +1,4 @@
-import { useModel, useRequest } from 'umi'
+import { useModel, useRequest } from '@umijs/max'
 import { Association, Delete, EveryUser } from '@icon-park/react'
 import ProForm, { ProFormCheckbox, ProFormDependency, ProFormSwitch } from '@ant-design/pro-form'
 import type { FormInstance } from 'antd'
@@ -36,15 +36,12 @@ const System = () => {
     setState({ ...state, id })
   }
 
-  const { run: tryGetRoleStaffList } = useRequest(
-    (id: string) => fetchRoleStaffListByRoleId({ id }),
-    {
-      manual: true,
-      onSuccess: result => {
-        setState({ ...state, roleStaff: result })
-      }
+  const { run: tryGetRoleStaffList } = useRequest((id: string) => fetchRoleStaffListByRoleId({ id }), {
+    manual: true,
+    onSuccess: result => {
+      setState({ ...state, roleStaff: result })
     }
-  )
+  })
 
   const { run: tryGetRolePermissions } = useRequest((id: string) => getRolePermissions({ id }), {
     manual: true,
@@ -135,7 +132,7 @@ const System = () => {
     <PageContainer title={false} breadcrumb={false}>
       <div className="h-full w-full flex flex-row">
         <RoleMenu menuId={menuId} onSelect={onSelect} itemCount={state.roleStaff?.length || 0} />
-        <div className={classNames('w-max-3/4', styles.formItemWrap)}>
+        <div className={classNames(styles.formItemWrap)}>
           <div className="ml-8 bg-white p-4 shadow-md shadow-hex-3e2c5a relative">
             <div className="absolute right-4 top-4 z-100">
               {state.id && (
@@ -148,10 +145,7 @@ const System = () => {
                 />
               )}
             </div>
-            <Tabs
-              defaultActiveKey="1"
-              type="card"
-              onChange={key => setState({ ...state, activeKey: key })}>
+            <Tabs defaultActiveKey="1" type="card" onChange={key => setState({ ...state, activeKey: key })}>
               <TabPane tab="员工列表" key="1">
                 <Table<API.RoleStaffListItem>
                   dataSource={state.roleStaff}

+ 8 - 16
src/pages/Role/Workbench/index.tsx

@@ -1,4 +1,4 @@
-import { useModel, useRequest } from 'umi'
+import { useModel, useRequest } from '@umijs/max'
 import { Delete } from '@icon-park/react'
 import ProForm from '@ant-design/pro-form'
 import type { FormInstance } from 'antd'
@@ -39,15 +39,12 @@ const Workbench = () => {
     setState({ ...state, id })
   }
 
-  const { run: tryGetRoleStaffList } = useRequest(
-    (id: string) => fetchRoleStaffListByRoleId({ id }),
-    {
-      manual: true,
-      onSuccess: result => {
-        setState({ ...state, roleStaff: result })
-      }
+  const { run: tryGetRoleStaffList } = useRequest((id: string) => fetchRoleStaffListByRoleId({ id }), {
+    manual: true,
+    onSuccess: result => {
+      setState({ ...state, roleStaff: result })
     }
-  )
+  })
 
   const { run: tryGetRolePermissions } = useRequest((id: string) => getRolePermissions({ id }), {
     manual: true,
@@ -61,9 +58,7 @@ const Workbench = () => {
 
       // formRef.current?.setFieldsValue({ ...values })
 
-      formRef2.current?.setFieldsValue(
-        result.dataPermission ? JSON.parse(result.dataPermission) : null
-      )
+      formRef2.current?.setFieldsValue(result.dataPermission ? JSON.parse(result.dataPermission) : null)
     }
   })
 
@@ -159,10 +154,7 @@ const Workbench = () => {
                 />
               )}
             </div>
-            <Tabs
-              defaultActiveKey="1"
-              type="card"
-              onChange={key => setState({ ...state, activeKey: key })}>
+            <Tabs defaultActiveKey="1" type="card" onChange={key => setState({ ...state, activeKey: key })}>
               <TabPane tab="员工列表" key="1">
                 <Table<API.RoleStaffListItem>
                   dataSource={state.roleStaff}

+ 25 - 23
src/pages/user/Login/index.tsx

@@ -1,8 +1,16 @@
 import { LockOutlined, UserOutlined } from '@ant-design/icons'
 import { Alert, message, Tabs } from 'antd'
-import React, { useState } from 'react'
+import React, { useState, useTransition } from 'react'
 import ProForm, { ProFormCheckbox, ProFormText } from '@ant-design/pro-form'
-import { useIntl, history, FormattedMessage, SelectLang, useModel, useRequest } from 'umi'
+import {
+  useIntl,
+  history,
+  FormattedMessage,
+  SelectLang,
+  useModel,
+  useRequest,
+  createSearchParams
+} from '@umijs/max'
 import Footer from '@/components/Footer'
 import { login } from '@/services/user/api'
 // import { getFakeCaptcha } from '@/services/ant-design-pro/login'
@@ -24,18 +32,16 @@ const LoginMessage: React.FC<{
 )
 
 /** 此方法会跳转到 redirect 参数所在的位置 */
-const goto = () => {
-  if (!history) return
-  setTimeout(() => {
-    const { query } = history.location
-    const { redirect } = query as { redirect: string }
-    history.push(redirect || '/')
-  }, 10)
+const goto = userInfo => {
+  if (!history || !userInfo) return
+  const searchParams = createSearchParams(window.location.search)
+  const redirect = searchParams.get('redirect')
+  history.replace(redirect || '/')
 }
 
 const Login: React.FC = () => {
   const { setAuthToken } = useModel('user')
-  // const [submitting, setSubmitting] = useState(false)
+  const [, startTransition] = useTransition()
   const [userLoginState, setUserLoginState] = useState<API.LoginResult>({})
   const [type, setType] = useState<string>('account')
   const { initialState, setInitialState } = useModel('@@initialState')
@@ -51,7 +57,9 @@ const Login: React.FC = () => {
         menuList: result.menus,
         roles: result.staff?.roles || []
       })
-      goto()
+      startTransition(() => {
+        goto(result.staff)
+      })
     }
   })
 
@@ -63,7 +71,9 @@ const Login: React.FC = () => {
       await run()
       // await fetchUserInfo()
     },
-    onError: () => {
+    onError: error => {
+      console.log(error)
+
       setUserLoginState({ ...userLoginState, code: -1 })
     }
   })
@@ -88,9 +98,7 @@ const Login: React.FC = () => {
               <span className={styles.title}>CLD.V2</span>
             </div>
           </div>
-          <div className={styles.desc}>
-            {intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}
-          </div>
+          <div className={styles.desc}>{intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}</div>
         </div>
 
         <div className={styles.main}>
@@ -149,10 +157,7 @@ const Login: React.FC = () => {
                     {
                       required: true,
                       message: (
-                        <FormattedMessage
-                          id="pages.login.username.required"
-                          defaultMessage="请输入用户名!"
-                        />
+                        <FormattedMessage id="pages.login.username.required" defaultMessage="请输入用户名!" />
                       )
                     }
                   ]}
@@ -168,10 +173,7 @@ const Login: React.FC = () => {
                     {
                       required: true,
                       message: (
-                        <FormattedMessage
-                          id="pages.login.password.required"
-                          defaultMessage="请输入密码!"
-                        />
+                        <FormattedMessage id="pages.login.password.required" defaultMessage="请输入密码!" />
                       )
                     }
                   ]}

+ 2 - 15
src/services/user/api.ts

@@ -1,7 +1,4 @@
-// @ts-ignore
-/* eslint-disable */
-import { Api } from '@icon-park/react'
-import { request } from 'umi'
+import { request } from '@umijs/max'
 
 /** 获取当前的用户 GET /backstage/currentUser */
 export async function currentUser(options?: { [key: string]: any }) {
@@ -11,14 +8,6 @@ export async function currentUser(options?: { [key: string]: any }) {
   })
 }
 
-/** 退出登录接口 POST /login/outLogin */
-export async function outLogin(options?: { [key: string]: any }) {
-  // return request<Record<string, any>>('/login/outLogin', {
-  //   method: 'POST',
-  //   ...(options || {})
-  // })
-}
-
 /** 登录接口 POST /login */
 export async function login(body: API.LoginParams, options?: { [key: string]: any }) {
   return request<API.LoginResult>('/login', {
@@ -172,9 +161,7 @@ export async function updateBusinessGroup(params: API.UpdateBusinessgroupParam)
 }
 
 /** 获取通知列表 */
-export async function queryNoticeList(
-  params: API.QueryNoticeListParams
-): API.QueryNoticeListResult {
+export async function queryNoticeList(params: API.QueryNoticeListParams): API.QueryNoticeListResult {
   return request('/message/list', {
     params
   })

+ 1 - 1
src/services/user/system.ts

@@ -1,4 +1,4 @@
-import { request } from 'umi'
+import { request } from '@umijs/max'
 
 /** 获取角色id下员工列表 */
 export async function queryRoleStaffList() {

+ 5 - 1
src/utils/consts.ts

@@ -1,3 +1,7 @@
 export default {
-  RET_CODE: { SUCCESS: 0, ERROR: -1 }
+  RET_CODE: { SUCCESS: 0, ERROR: -1 },
+  PREFIX_URL: '/backstage',
+  TOKEN_HEADER: 'Authorization',
+  TOKEN_INVALID_CODE: [2, 3], // 接口返回码如果是2, 3 则表明token过期或无效 需要自动刷新token
+  TOKEN_WHITE_LIST: ['/api/login'] // 不需要设置token的白名单
 }

+ 18 - 23
windi.config.ts

@@ -1,16 +1,11 @@
-// windi.config.js
-import { defineConfig } from 'windicss/helpers'
-import lineClamp from 'windicss/plugin/line-clamp'
-import colors from 'windicss/colors'
+import { defineConfig, presetWind, transformerDirectives } from 'unocss'
 import proSettings from './config/defaultSettings'
-
-export default defineConfig({
-  darkMode: 'class',
-  plugins: [lineClamp, createEnterPlugin()],
-  theme: {
-    extend: {
+export function createConfig({ dev = true } = {}) {
+  return defineConfig({
+    envMode: dev ? 'dev' : 'build',
+    presets: [presetWind()],
+    theme: {
       colors: {
-        ...colors,
         primary: proSettings.primaryColor
       },
       screens: {
@@ -23,14 +18,14 @@ export default defineConfig({
       boxShadow: {
         card: '0 0 13px 0 rgba(74, 53, 107, 0.08)'
       }
-    }
-  },
-  shortcuts: {
-    'btn-outline':
-      'text-xs text-primary bg-white border border-primary rounded py-1 px-1 cursor-pointer hover:text-white hover:bg-primary'
-  }
-})
+    },
+    transformers: [transformerDirectives()]
+    // rules: [createEnterPlugin()]
+    // variants: [createEnterPlugin()]
+  })
+}
 
+export default createConfig()
 /**
  * Used for animation when the element is displayed
  * @param maxOutput The larger the maxOutput output, the larger the generated css volume
@@ -54,15 +49,15 @@ function createEnterPlugin(maxOutput = 10) {
       }
     }
   }
-  const handler = ({ addBase }) => {
+  const handler = () => {
     const addRawCss = {}
     for (let index = 1; index < maxOutput; index++) {
-      Object.assign(addRawCss, {
+      Object.assign(m, {
         ...createCss(index, 'x'),
         ...createCss(index, 'y')
       })
     }
-    addBase({
+    return {
       ...addRawCss,
       [`@keyframes enter-x-animation`]: {
         to: {
@@ -76,7 +71,7 @@ function createEnterPlugin(maxOutput = 10) {
           transform: 'translateY(0)'
         }
       }
-    })
+    }
   }
-  return { handler }
+  return [/^enter-(x|y)/, () => handler()]
 }