Commit 7101587b9676c91e9079044a096df08848f1f602

Authored by vben
1 parent c0692b0f

feat: add error handle

.env.production
@@ -7,7 +7,7 @@ VITE_PUBLIC_PATH = ./ @@ -7,7 +7,7 @@ VITE_PUBLIC_PATH = ./
7 # Delete console 7 # Delete console
8 VITE_DROP_CONSOLE = true 8 VITE_DROP_CONSOLE = true
9 9
10 -# Delete console 10 +# Whether to output gz file for packaging
11 VITE_BUILD_GZIP = false 11 VITE_BUILD_GZIP = false
12 12
13 # Basic interface address SPA 13 # Basic interface address SPA
README.en-US.md
@@ -225,17 +225,17 @@ yarn clean:lib # Delete node_modules, supported window @@ -225,17 +225,17 @@ yarn clean:lib # Delete node_modules, supported window
225 - [x] First screen loading waiting animation 225 - [x] First screen loading waiting animation
226 - [x] Extract the production environment profile 226 - [x] Extract the production environment profile
227 - [x] Build Gzip 227 - [x] Build Gzip
  228 +- [x] System performance optimization
  229 +- [x] Data import and export
  230 +- [x] Global error handling
228 231
229 ## Developing features 232 ## Developing features
230 233
231 - [ ] Upload component 234 - [ ] Upload component
232 - [ ] Rich text component 235 - [ ] Rich text component
233 -- [ ] Data import and export  
234 -- [ ] Global error handling  
235 - [ ] Theme configuration 236 - [ ] Theme configuration
236 - [ ] Dark theme 237 - [ ] Dark theme
237 - [ ] Build CDN 238 - [ ] Build CDN
238 -- [ ] System performance optimization  
239 239
240 If you have more components/functions/suggestions/bugs/, welcome to submit pr or issue. 240 If you have more components/functions/suggestions/bugs/, welcome to submit pr or issue.
241 241
README.md
@@ -223,17 +223,17 @@ yarn clean:lib # 删除node_modules,兼容window系统 @@ -223,17 +223,17 @@ yarn clean:lib # 删除node_modules,兼容window系统
223 - [x] 首屏加载等待动画 223 - [x] 首屏加载等待动画
224 - [x] 抽取生产环境配置文件 224 - [x] 抽取生产环境配置文件
225 - [x] 打包 Gzip 225 - [x] 打包 Gzip
  226 +- [x] 数据导入导出
  227 +- [x] 系统性能优化
  228 +- [x] 全局错误处理
226 229
227 ## 正在开发的功能 230 ## 正在开发的功能
228 231
229 - [ ] 上传组件 232 - [ ] 上传组件
230 - [ ] 富文本组件 233 - [ ] 富文本组件
231 -- [ ] 数据导入导出  
232 -- [ ] 全局错误处理  
233 - [ ] 主题配置 234 - [ ] 主题配置
234 - [ ] 黑暗主题 235 - [ ] 黑暗主题
235 - [ ] 打包 CDN 236 - [ ] 打包 CDN
236 -- [ ] 系统性能优化  
237 237
238 更多组件/功能/建议/bug/欢迎提交 pr 或者 issue 238 更多组件/功能/建议/bug/欢迎提交 pr 或者 issue
239 239
build/config/vite/proxy.ts
@@ -2,13 +2,17 @@ type ProxyItem = [string, string]; @@ -2,13 +2,17 @@ type ProxyItem = [string, string];
2 2
3 type ProxyList = ProxyItem[]; 3 type ProxyList = ProxyItem[];
4 4
  5 +const reg = /^https:\/\//;
5 export function createProxy(list: ProxyList = []) { 6 export function createProxy(list: ProxyList = []) {
6 const ret: any = {}; 7 const ret: any = {};
7 for (const [prefix, target] of list) { 8 for (const [prefix, target] of list) {
  9 + const isHttps = reg.test(target);
  10 +
8 ret[prefix] = { 11 ret[prefix] = {
9 target: target, 12 target: target,
10 changeOrigin: true, 13 changeOrigin: true,
11 rewrite: (path: string) => path.replace(new RegExp(`^${prefix}`), ''), 14 rewrite: (path: string) => path.replace(new RegExp(`^${prefix}`), ''),
  15 + ...(isHttps ? { secure: false } : {}),
12 }; 16 };
13 } 17 }
14 return ret; 18 return ret;
build/plugin/vite-plugin-context-plugin/transform.ts renamed to build/plugin/vite-plugin-context/transform.ts
package.json
@@ -41,10 +41,10 @@ @@ -41,10 +41,10 @@
41 "devDependencies": { 41 "devDependencies": {
42 "@commitlint/cli": "^11.0.0", 42 "@commitlint/cli": "^11.0.0",
43 "@commitlint/config-conventional": "^11.0.0", 43 "@commitlint/config-conventional": "^11.0.0",
44 - "@iconify/json": "^1.1.242", 44 + "@iconify/json": "^1.1.243",
45 "@ls-lint/ls-lint": "^1.9.2", 45 "@ls-lint/ls-lint": "^1.9.2",
46 "@purge-icons/generated": "^0.4.1", 46 "@purge-icons/generated": "^0.4.1",
47 - "@types/echarts": "^4.8.1", 47 + "@types/echarts": "^4.8.3",
48 "@types/fs-extra": "^9.0.2", 48 "@types/fs-extra": "^9.0.2",
49 "@types/html-minifier": "^4.0.0", 49 "@types/html-minifier": "^4.0.0",
50 "@types/inquirer": "^7.3.1", 50 "@types/inquirer": "^7.3.1",
@@ -55,7 +55,7 @@ @@ -55,7 +55,7 @@
55 "@types/qrcode": "^1.3.5", 55 "@types/qrcode": "^1.3.5",
56 "@types/rollup-plugin-visualizer": "^2.6.0", 56 "@types/rollup-plugin-visualizer": "^2.6.0",
57 "@types/shelljs": "^0.8.8", 57 "@types/shelljs": "^0.8.8",
58 - "@types/yargs": "^15.0.8", 58 + "@types/yargs": "^15.0.9",
59 "@types/zxcvbn": "^4.4.0", 59 "@types/zxcvbn": "^4.4.0",
60 "@typescript-eslint/eslint-plugin": "^4.4.1", 60 "@typescript-eslint/eslint-plugin": "^4.4.1",
61 "@typescript-eslint/parser": "^4.4.1", 61 "@typescript-eslint/parser": "^4.4.1",
@@ -67,7 +67,7 @@ @@ -67,7 +67,7 @@
67 "cross-env": "^7.0.2", 67 "cross-env": "^7.0.2",
68 "dotenv": "^8.2.0", 68 "dotenv": "^8.2.0",
69 "eslint": "^7.10.0", 69 "eslint": "^7.10.0",
70 - "eslint-config-prettier": "^6.12.0", 70 + "eslint-config-prettier": "^6.13.0",
71 "eslint-plugin-prettier": "^3.1.4", 71 "eslint-plugin-prettier": "^3.1.4",
72 "eslint-plugin-vue": "^7.0.1", 72 "eslint-plugin-vue": "^7.0.1",
73 "fs-extra": "^9.0.1", 73 "fs-extra": "^9.0.1",
@@ -76,7 +76,7 @@ @@ -76,7 +76,7 @@
76 "inquirer": "^7.3.3", 76 "inquirer": "^7.3.3",
77 "koa-static": "^5.0.0", 77 "koa-static": "^5.0.0",
78 "less": "^3.12.2", 78 "less": "^3.12.2",
79 - "lint-staged": "^10.4.0", 79 + "lint-staged": "^10.4.2",
80 "portfinder": "^1.0.28", 80 "portfinder": "^1.0.28",
81 "postcss-import": "^12.0.1", 81 "postcss-import": "^12.0.1",
82 "prettier": "^2.1.2", 82 "prettier": "^2.1.2",
@@ -95,7 +95,7 @@ @@ -95,7 +95,7 @@
95 "vite-plugin-mock": "^1.0.2", 95 "vite-plugin-mock": "^1.0.2",
96 "vite-plugin-purge-icons": "^0.4.4", 96 "vite-plugin-purge-icons": "^0.4.4",
97 "vue-eslint-parser": "^7.1.1", 97 "vue-eslint-parser": "^7.1.1",
98 - "yargs": "^16.0.3" 98 + "yargs": "^16.1.0"
99 }, 99 },
100 "repository": { 100 "repository": {
101 "type": "git", 101 "type": "git",
src/App.vue
@@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
33 const { on } = useLockPage(); 33 const { on } = useLockPage();
34 lockOn = on; 34 lockOn = on;
35 } 35 }
  36 +
36 return { 37 return {
37 transformCellText, 38 transformCellText,
38 zhCN, 39 zhCN,
src/api/demo/error.ts 0 → 100644
  1 +import { defHttp } from '/@/utils/http/axios';
  2 +
  3 +enum Api {
  4 + // 该地址不存在
  5 + Error = '/error',
  6 +}
  7 +
  8 +/**
  9 + * @description: 触发ajax错误
  10 + */
  11 +export function fireErrorApi() {
  12 + return defHttp.request({
  13 + url: Api.Error,
  14 + method: 'GET',
  15 + });
  16 +}
src/components/Table/src/BasicTable.vue
@@ -146,7 +146,7 @@ @@ -146,7 +146,7 @@
146 } 146 }
147 if (showSummary) { 147 if (showSummary) {
148 propsData.footer = renderFooter.bind(null, { 148 propsData.footer = renderFooter.bind(null, {
149 - scroll, 149 + scroll: scroll as any,
150 columnsRef: getColumnsRef, 150 columnsRef: getColumnsRef,
151 summaryFunc: unref(getMergeProps).summaryFunc, 151 summaryFunc: unref(getMergeProps).summaryFunc,
152 dataSourceRef: getDataSourceRef, 152 dataSourceRef: getDataSourceRef,
src/components/Table/src/components/TableAction.tsx
@@ -29,7 +29,6 @@ export default defineComponent({ @@ -29,7 +29,6 @@ export default defineComponent({
29 const { 29 const {
30 disabled = false, 30 disabled = false,
31 label, 31 label,
32 - props,  
33 icon, 32 icon,
34 color = '', 33 color = '',
35 type = 'link', 34 type = 'link',
@@ -41,7 +40,7 @@ export default defineComponent({ @@ -41,7 +40,7 @@ export default defineComponent({
41 size="small" 40 size="small"
42 disabled={disabled} 41 disabled={disabled}
43 color={color} 42 color={color}
44 - {...props} 43 + {...action}
45 key={index} 44 key={index}
46 > 45 >
47 {() => ( 46 {() => (
@@ -101,7 +100,6 @@ export default defineComponent({ @@ -101,7 +100,6 @@ export default defineComponent({
101 const { 100 const {
102 disabled = false, 101 disabled = false,
103 label, 102 label,
104 - props,  
105 icon, 103 icon,
106 color = '', 104 color = '',
107 type = 'link', 105 type = 'link',
@@ -112,7 +110,7 @@ export default defineComponent({ @@ -112,7 +110,7 @@ export default defineComponent({
112 <Button 110 <Button
113 type={type} 111 type={type}
114 size="small" 112 size="small"
115 - {...props} 113 + {...action}
116 disabled={disabled} 114 disabled={disabled}
117 color={color} 115 color={color}
118 > 116 >
src/enums/exceptionEnum.ts
@@ -23,3 +23,11 @@ export enum ExceptionEnum { @@ -23,3 +23,11 @@ export enum ExceptionEnum {
23 // No data on the page. In fact, it is not an exception page 23 // No data on the page. In fact, it is not an exception page
24 PAGE_NOT_DATA = 10400, 24 PAGE_NOT_DATA = 10400,
25 } 25 }
  26 +
  27 +export enum ErrorTypeEnum {
  28 + VUE = 'vue',
  29 + SCRIPT = 'script',
  30 + RESOURCE = 'resource',
  31 + AJAX = 'ajax',
  32 + PROMISE = 'promise',
  33 +}
src/hooks/web/usePage.ts
@@ -19,7 +19,7 @@ function handleError(e: Error) { @@ -19,7 +19,7 @@ function handleError(e: Error) {
19 // page switch 19 // page switch
20 export function useGo() { 20 export function useGo() {
21 const { push, replace } = useRouter(); 21 const { push, replace } = useRouter();
22 - function go(opt: PageEnum | RouteLocationRawEx = PageEnum.BASE_HOME, isReplace = false) { 22 + function go(opt: PageEnum | RouteLocationRawEx | string = PageEnum.BASE_HOME, isReplace = false) {
23 if (isString(opt)) { 23 if (isString(opt)) {
24 isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError); 24 isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError);
25 } else { 25 } else {
src/layouts/default/LayoutHeader.tsx
1 import { defineComponent, unref, computed } from 'vue'; 1 import { defineComponent, unref, computed } from 'vue';
2 -import { Layout, Tooltip } from 'ant-design-vue'; 2 +import { Layout, Tooltip, Badge } from 'ant-design-vue';
3 import Logo from '/@/layouts/Logo.vue'; 3 import Logo from '/@/layouts/Logo.vue';
4 import UserDropdown from './UserDropdown'; 4 import UserDropdown from './UserDropdown';
5 import LayoutMenu from './LayoutMenu'; 5 import LayoutMenu from './LayoutMenu';
@@ -12,12 +12,15 @@ import { @@ -12,12 +12,15 @@ import {
12 FullscreenOutlined, 12 FullscreenOutlined,
13 GithubFilled, 13 GithubFilled,
14 LockOutlined, 14 LockOutlined,
  15 + BugOutlined,
15 } from '@ant-design/icons-vue'; 16 } from '@ant-design/icons-vue';
16 import { useFullscreen } from '/@/hooks/web/useFullScreen'; 17 import { useFullscreen } from '/@/hooks/web/useFullScreen';
17 import { useTabs } from '/@/hooks/web/useTabs'; 18 import { useTabs } from '/@/hooks/web/useTabs';
18 import { GITHUB_URL } from '/@/settings/siteSetting'; 19 import { GITHUB_URL } from '/@/settings/siteSetting';
19 import LockAction from './actions/LockActionItem'; 20 import LockAction from './actions/LockActionItem';
20 import { useModal } from '/@/components/Modal/index'; 21 import { useModal } from '/@/components/Modal/index';
  22 +import { errorStore } from '/@/store/modules/error';
  23 +import { useGo } from '/@/hooks/web/usePage';
21 24
22 export default defineComponent({ 25 export default defineComponent({
23 name: 'DefaultLayoutHeader', 26 name: 'DefaultLayoutHeader',
@@ -25,6 +28,7 @@ export default defineComponent({ @@ -25,6 +28,7 @@ export default defineComponent({
25 const { refreshPage } = useTabs(); 28 const { refreshPage } = useTabs();
26 const [register, { openModal }] = useModal(); 29 const [register, { openModal }] = useModal();
27 const { toggleFullscreen, isFullscreenRef } = useFullscreen(); 30 const { toggleFullscreen, isFullscreenRef } = useFullscreen();
  31 + const go = useGo();
28 const getProjectConfigRef = computed(() => { 32 const getProjectConfigRef = computed(() => {
29 return appStore.getProjectConfig; 33 return appStore.getProjectConfig;
30 }); 34 });
@@ -37,6 +41,12 @@ export default defineComponent({ @@ -37,6 +41,12 @@ export default defineComponent({
37 const theme = unref(getProjectConfigRef).headerSetting.theme; 41 const theme = unref(getProjectConfigRef).headerSetting.theme;
38 return theme ? `layout-header__header--${theme}` : ''; 42 return theme ? `layout-header__header--${theme}` : '';
39 }); 43 });
  44 +
  45 + function handleToErrorList() {
  46 + errorStore.commitErrorListCountState(0);
  47 + go('/exception/error-log');
  48 + }
  49 +
40 /** 50 /**
41 * @description: 锁定屏幕 51 * @description: 锁定屏幕
42 */ 52 */
@@ -46,9 +56,9 @@ export default defineComponent({ @@ -46,9 +56,9 @@ export default defineComponent({
46 return () => { 56 return () => {
47 const getProjectConfig = unref(getProjectConfigRef); 57 const getProjectConfig = unref(getProjectConfigRef);
48 const { 58 const {
49 - // useErrorHandle, 59 + useErrorHandle,
50 showLogo, 60 showLogo,
51 - headerSetting: { theme: headerTheme, showRedo, showGithub, showFullScreen }, 61 + headerSetting: { theme: headerTheme, useLockPage, showRedo, showGithub, showFullScreen },
52 menuSetting: { mode, type: menuType, split: splitMenu, topMenuAlign }, 62 menuSetting: { mode, type: menuType, split: splitMenu, topMenuAlign },
53 showBreadCrumb, 63 showBreadCrumb,
54 } = getProjectConfig; 64 } = getProjectConfig;
@@ -77,8 +87,28 @@ export default defineComponent({ @@ -77,8 +87,28 @@ export default defineComponent({
77 </div> 87 </div>
78 88
79 <div class={`layout-header__action`}> 89 <div class={`layout-header__action`}>
  90 + {useErrorHandle && (
  91 + <Tooltip>
  92 + {{
  93 + title: () => '错误日志',
  94 + default: () => (
  95 + <Badge
  96 + count={errorStore.getErrorListCountState}
  97 + offset={[0, 10]}
  98 + overflowCount={99}
  99 + >
  100 + {() => (
  101 + <div class={`layout-header__action-item`} onClick={handleToErrorList}>
  102 + <BugOutlined class={`layout-header__action-icon`} />
  103 + </div>
  104 + )}
  105 + </Badge>
  106 + ),
  107 + }}
  108 + </Tooltip>
  109 + )}
  110 +
80 {showGithub && ( 111 {showGithub && (
81 - // @ts-ignore  
82 <Tooltip> 112 <Tooltip>
83 {{ 113 {{
84 title: () => 'github', 114 title: () => 'github',
@@ -90,8 +120,7 @@ export default defineComponent({ @@ -90,8 +120,7 @@ export default defineComponent({
90 }} 120 }}
91 </Tooltip> 121 </Tooltip>
92 )} 122 )}
93 - {showGithub && (  
94 - // @ts-ignore 123 + {useLockPage && (
95 <Tooltip> 124 <Tooltip>
96 {{ 125 {{
97 title: () => '锁定屏幕', 126 title: () => '锁定屏幕',
@@ -104,7 +133,6 @@ export default defineComponent({ @@ -104,7 +133,6 @@ export default defineComponent({
104 </Tooltip> 133 </Tooltip>
105 )} 134 )}
106 {showRedo && ( 135 {showRedo && (
107 - // @ts-ignore  
108 <Tooltip> 136 <Tooltip>
109 {{ 137 {{
110 title: () => '刷新', 138 title: () => '刷新',
@@ -117,7 +145,6 @@ export default defineComponent({ @@ -117,7 +145,6 @@ export default defineComponent({
117 </Tooltip> 145 </Tooltip>
118 )} 146 )}
119 {showFullScreen && ( 147 {showFullScreen && (
120 - // @ts-ignore  
121 <Tooltip> 148 <Tooltip>
122 {{ 149 {{
123 title: () => (unref(isFullscreenRef) ? '退出全屏' : '全屏'), 150 title: () => (unref(isFullscreenRef) ? '退出全屏' : '全屏'),
src/layouts/default/actions/LockActionItem.tsx
@@ -40,10 +40,11 @@ export default defineComponent({ @@ -40,10 +40,11 @@ export default defineComponent({
40 let password: string | undefined = ''; 40 let password: string | undefined = '';
41 41
42 try { 42 try {
43 - const values = (await validateFields()) as any;  
44 - password = values.password;  
45 if (!valid) { 43 if (!valid) {
46 password = undefined; 44 password = undefined;
  45 + } else {
  46 + const values = (await validateFields()) as any;
  47 + password = values.password;
47 } 48 }
48 setModalProps({ 49 setModalProps({
49 visible: false, 50 visible: false,
src/layouts/default/actions/notice/NoticeActionItem.tsx 0 → 100644
  1 +import { defineComponent } from 'vue';
  2 +import { Popover, Tabs } from 'ant-design-vue';
  3 +
  4 +import NoticeList from './NoticeList';
  5 +import { NoticeTabItem, NoticeListItem, noticeTabListData, noticeListData } from './data';
  6 +import './index.less';
  7 +
  8 +const prefixCls = 'notice-popover';
  9 +export default defineComponent({
  10 + name: 'NoticePopover',
  11 + props: {
  12 + visible: {
  13 + type: Boolean,
  14 + default: false,
  15 + },
  16 + },
  17 + setup(props, { attrs }) {
  18 + // 渲染卡片内容
  19 + function renderContent() {
  20 + return (
  21 + <Tabs class={`${prefixCls}__tabs`}>
  22 + {() => {
  23 + return noticeTabListData.map((item: NoticeTabItem) => {
  24 + const { key, name } = item;
  25 + return (
  26 + <Tabs.TabPane key={key} tab={renderTab(key, name)}>
  27 + {() => <NoticeList list={getListData(key)} />}
  28 + </Tabs.TabPane>
  29 + );
  30 + });
  31 + }}
  32 + </Tabs>
  33 + );
  34 + }
  35 +
  36 + // tab标题渲染
  37 + function renderTab(key: string, name: string) {
  38 + const list = getListData(key);
  39 + const unreadlist = list.filter((item: NoticeListItem) => !item.read);
  40 + return (
  41 + <div>
  42 + {name}
  43 + {unreadlist.length > 0 && <span>({unreadlist.length})</span>}
  44 + </div>
  45 + );
  46 + }
  47 +
  48 + // 获取数据
  49 + function getListData(type: string) {
  50 + return noticeListData.filter((item: NoticeListItem) => item.type === type);
  51 + }
  52 +
  53 + return () => {
  54 + const { visible } = props;
  55 + return (
  56 + <Popover
  57 + title=""
  58 + {...{
  59 + ...attrs,
  60 + visible,
  61 + }}
  62 + content={renderContent}
  63 + class={prefixCls}
  64 + />
  65 + );
  66 + };
  67 + },
  68 +});
src/layouts/default/actions/notice/NoticeList.tsx 0 → 100644
  1 +import { defineComponent } from 'vue';
  2 +import { List, Avatar, Tag } from 'ant-design-vue';
  3 +
  4 +import { NoticeListItem } from './data';
  5 +import './index.less';
  6 +
  7 +const prefixCls = 'notice-popover';
  8 +export default defineComponent({
  9 + name: 'NoticeList',
  10 + props: {
  11 + list: {
  12 + type: Array,
  13 + default: () => [],
  14 + },
  15 + },
  16 + setup(props) {
  17 + // 头像渲染
  18 + function renderAvatar(avatar: string) {
  19 + return avatar ? <Avatar class="avatar" src={avatar} /> : <span>{avatar}</span>;
  20 + }
  21 +
  22 + // 描述渲染
  23 + function renderDescription(description: string, datetime: string) {
  24 + return (
  25 + <div>
  26 + <div class="description">{description}</div>
  27 + <div class="datetime">{datetime}</div>
  28 + </div>
  29 + );
  30 + }
  31 +
  32 + // 标题渲染
  33 + function renderTitle(title: string, extra?: string, color?: string) {
  34 + return (
  35 + <div class="title">
  36 + {title}
  37 + {extra && (
  38 + <div class="extra">
  39 + <Tag class="tag" color={color}>
  40 + {() => extra}
  41 + </Tag>
  42 + </div>
  43 + )}
  44 + </div>
  45 + );
  46 + }
  47 +
  48 + return () => {
  49 + const { list } = props;
  50 + return (
  51 + <List dataSource={list} class={`${prefixCls}__list`}>
  52 + {() => {
  53 + return list.map((item: NoticeListItem) => {
  54 + const { id, avatar, title, description, datetime, extra, read, color } = item;
  55 + return (
  56 + <List.Item key={id} class={`${prefixCls}__list-item ${read ? 'read' : ''}`}>
  57 + {() => (
  58 + <List.Item.Meta
  59 + class="meta"
  60 + avatar={renderAvatar(avatar)}
  61 + title={renderTitle(title, extra, color)}
  62 + description={renderDescription(description, datetime)}
  63 + />
  64 + )}
  65 + </List.Item>
  66 + );
  67 + });
  68 + }}
  69 + </List>
  70 + );
  71 + };
  72 + },
  73 +});
src/layouts/default/index.less
@@ -102,12 +102,12 @@ @@ -102,12 +102,12 @@
102 .setting-button { 102 .setting-button {
103 top: 45%; 103 top: 45%;
104 right: 0; 104 right: 0;
105 - padding: 14px; 105 + padding: 8px;
106 border-radius: 6px 0 0 6px; 106 border-radius: 6px 0 0 6px;
107 107
108 svg { 108 svg {
109 - width: 1.2em;  
110 - height: 1.2em; 109 + width: 1em;
  110 + height: 1em;
111 } 111 }
112 } 112 }
113 113
src/layouts/default/setting/index.vue
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 position: absolute; 30 position: absolute;
31 z-index: 10; 31 z-index: 10;
32 display: flex; 32 display: flex;
33 - padding: 10px; 33 + // padding: 10px;
34 color: @white; 34 color: @white;
35 cursor: pointer; 35 cursor: pointer;
36 background: @primary-color; 36 background: @primary-color;
src/layouts/page/index.tsx
@@ -54,6 +54,7 @@ export default defineComponent({ @@ -54,6 +54,7 @@ export default defineComponent({
54 {...on} 54 {...on}
55 name={name || route.meta.transitionName || routerTransition} 55 name={name || route.meta.transitionName || routerTransition}
56 mode="out-in" 56 mode="out-in"
  57 + appear={true}
57 > 58 >
58 {() => Content} 59 {() => Content}
59 </Transition> 60 </Transition>
src/main.ts
@@ -3,6 +3,7 @@ import { createApp } from &#39;vue&#39;; @@ -3,6 +3,7 @@ import { createApp } from &#39;vue&#39;;
3 import router, { setupRouter } from '/@/router'; 3 import router, { setupRouter } from '/@/router';
4 import { setupStore } from '/@/store'; 4 import { setupStore } from '/@/store';
5 import { setupAntd } from '/@/setup/ant-design-vue'; 5 import { setupAntd } from '/@/setup/ant-design-vue';
  6 +import { setupErrorHandle } from '/@/setup/error-handle/index';
6 import { setupDirectives } from '/@/setup/directives/index'; 7 import { setupDirectives } from '/@/setup/directives/index';
7 8
8 import { registerGlobComp } from '/@/components/registerGlobComp'; 9 import { registerGlobComp } from '/@/components/registerGlobComp';
@@ -21,10 +22,12 @@ setupRouter(app); @@ -21,10 +22,12 @@ setupRouter(app);
21 // store 22 // store
22 setupStore(app); 23 setupStore(app);
23 24
24 -registerGlobComp(app);  
25 -  
26 setupDirectives(app); 25 setupDirectives(app);
27 26
  27 +setupErrorHandle(app);
  28 +
  29 +registerGlobComp(app);
  30 +
28 router.isReady().then(() => { 31 router.isReady().then(() => {
29 app.mount('#app'); 32 app.mount('#app');
30 }); 33 });
src/router/menus/modules/demo/exception.ts
@@ -25,6 +25,10 @@ const menu: MenuModule = { @@ -25,6 +25,10 @@ const menu: MenuModule = {
25 path: '/not-data', 25 path: '/not-data',
26 name: '无数据', 26 name: '无数据',
27 }, 27 },
  28 + {
  29 + path: '/error-log',
  30 + name: '错误日志',
  31 + },
28 ], 32 ],
29 }, 33 },
30 }; 34 };
src/router/routes/modules/demo/exception.ts
@@ -78,5 +78,13 @@ export default { @@ -78,5 +78,13 @@ export default {
78 afterCloseLoading: true, 78 afterCloseLoading: true,
79 }, 79 },
80 }, 80 },
  81 + {
  82 + path: '/error-log',
  83 + name: 'ErrorLog',
  84 + component: () => import('/@/views/sys/error-log/index.vue'),
  85 + meta: {
  86 + title: '错误日志',
  87 + },
  88 + },
81 ], 89 ],
82 } as AppRouteModule; 90 } as AppRouteModule;
src/settings/projectSetting.ts
@@ -30,7 +30,7 @@ const setting: ProjectConfig = { @@ -30,7 +30,7 @@ const setting: ProjectConfig = {
30 // theme 30 // theme
31 theme: MenuThemeEnum.LIGHT, 31 theme: MenuThemeEnum.LIGHT,
32 // 开启锁屏功能 32 // 开启锁屏功能
33 - useLockPage: isProdMode(), 33 + useLockPage: true,
34 // 显示刷新按钮 34 // 显示刷新按钮
35 showRedo: true, 35 showRedo: true,
36 // 显示全屏按钮 36 // 显示全屏按钮
@@ -86,7 +86,7 @@ const setting: ProjectConfig = { @@ -86,7 +86,7 @@ const setting: ProjectConfig = {
86 // 是否开启KeepAlive缓存 开发时候最好关闭,不然每次都需要清除缓存 86 // 是否开启KeepAlive缓存 开发时候最好关闭,不然每次都需要清除缓存
87 openKeepAlive: true, 87 openKeepAlive: true,
88 88
89 - // 自动锁屏时间,为0不锁屏。 单位分钟 默认1个小时 89 + // 自动锁屏时间,为0不锁屏。 单位分钟 默认0
90 lockTime: 0, 90 lockTime: 0,
91 // 显示面包屑 91 // 显示面包屑
92 showBreadCrumb: true, 92 showBreadCrumb: true,
@@ -96,6 +96,7 @@ const setting: ProjectConfig = { @@ -96,6 +96,7 @@ const setting: ProjectConfig = {
96 96
97 // 开启页面切换动画 97 // 开启页面切换动画
98 openRouterTransition: true, 98 openRouterTransition: true,
  99 +
99 // 路由切换动画 100 // 路由切换动画
100 routerTransition: RouterTransitionEnum.ZOOM_FADE, 101 routerTransition: RouterTransitionEnum.ZOOM_FADE,
101 102
src/setup/error-handle/index.ts 0 → 100644
  1 +import { errorStore, ErrorInfo } from '/@/store/modules/error';
  2 +import { useSetting } from '/@/hooks/core/useSetting';
  3 +import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
  4 +import { App } from 'vue';
  5 +function processStackMsg(error: Error) {
  6 + if (!error.stack) {
  7 + return '';
  8 + }
  9 + let stack = error.stack
  10 + .replace(/\n/gi, '') // 去掉换行,节省传输内容大小
  11 + .replace(/\bat\b/gi, '@') // chrome中是at,ff中是@
  12 + .split('@') // 以@分割信息
  13 + .slice(0, 9) // 最大堆栈长度(Error.stackTraceLimit = 10),所以只取前10条
  14 + .map((v) => v.replace(/^\s*|\s*$/g, '')) // 去除多余空格
  15 + .join('~') // 手动添加分隔符,便于后期展示
  16 + .replace(/\?[^:]+/gi, ''); // 去除js文件链接的多余参数(?x=1之类)
  17 + const msg = error.toString();
  18 + if (stack.indexOf(msg) < 0) {
  19 + stack = msg + '@' + stack;
  20 + }
  21 + return stack;
  22 +}
  23 +
  24 +function formatComponentName(vm: any) {
  25 + if (vm.$root === vm) {
  26 + return {
  27 + name: 'root',
  28 + path: 'root',
  29 + };
  30 + }
  31 +
  32 + const options = vm.$options as any;
  33 + if (!options) {
  34 + return {
  35 + name: 'anonymous',
  36 + path: 'anonymous',
  37 + };
  38 + }
  39 + const name = options.name || options._componentTag;
  40 + return {
  41 + name: name,
  42 + path: options.__file,
  43 + };
  44 +}
  45 +
  46 +function vueErrorHandler(err: Error, vm: any, info: string) {
  47 + const { name, path } = formatComponentName(vm);
  48 + errorStore.commitErrorInfoState({
  49 + type: ErrorTypeEnum.VUE,
  50 + name,
  51 + file: path,
  52 + message: err.message,
  53 + stack: processStackMsg(err),
  54 + detail: info,
  55 + url: window.location.href,
  56 + });
  57 +}
  58 +
  59 +export function scriptErrorHandler(
  60 + event: Event | string,
  61 + source?: string,
  62 + lineno?: number,
  63 + colno?: number,
  64 + error?: Error
  65 +) {
  66 + if (event === 'Script error.' && !source) {
  67 + return false;
  68 + }
  69 + setTimeout(function () {
  70 + const errorInfo: Partial<ErrorInfo> = {};
  71 + colno = colno || (window.event && (window.event as any).errorCharacter) || 0;
  72 + errorInfo.message = event as string;
  73 + if (error && error.stack) {
  74 + errorInfo.stack = error.stack;
  75 + } else {
  76 + errorInfo.stack = '';
  77 + }
  78 + const name = source ? source.substr(source.lastIndexOf('/') + 1) : 'script';
  79 + errorStore.commitErrorInfoState({
  80 + type: ErrorTypeEnum.SCRIPT,
  81 + name: name,
  82 + file: source as string,
  83 + detail: 'lineno' + lineno,
  84 + url: window.location.href,
  85 + ...(errorInfo as Pick<ErrorInfo, 'message' | 'stack'>),
  86 + });
  87 + }, 0);
  88 + return true;
  89 +}
  90 +
  91 +function registerPromiseErrorHandler() {
  92 + window.addEventListener(
  93 + 'unhandledrejection',
  94 + function (event: any) {
  95 + errorStore.commitErrorInfoState({
  96 + type: ErrorTypeEnum.PROMISE,
  97 + name: 'Promise Error!',
  98 + file: 'none',
  99 + detail: 'promise error!',
  100 + url: window.location.href,
  101 + stack: 'promise error!',
  102 + message: event.reason,
  103 + });
  104 + },
  105 + true
  106 + );
  107 +}
  108 +
  109 +function registerResourceErrorHandler() {
  110 + // 监控资源加载错误(img,script,css,以及jsonp)
  111 + window.addEventListener(
  112 + 'error',
  113 + function (e: Event) {
  114 + const target = e.target ? e.target : (e.srcElement as any);
  115 +
  116 + errorStore.commitErrorInfoState({
  117 + type: ErrorTypeEnum.RESOURCE,
  118 + name: 'Resouce Error!',
  119 + file: (e.target || ({} as any)).currentSrc,
  120 + detail: JSON.stringify({
  121 + tagName: target.localName,
  122 + html: target.outerHTML,
  123 + type: e.type,
  124 + }),
  125 + url: window.location.href,
  126 + stack: 'resouce is not found',
  127 + message: (e.target || ({} as any)).localName + ' is load error',
  128 + });
  129 + },
  130 + true
  131 + );
  132 +}
  133 +
  134 +export function setupErrorHandle(app: App) {
  135 + const { projectSetting } = useSetting();
  136 + const { useErrorHandle } = projectSetting;
  137 + if (!useErrorHandle) {
  138 + return;
  139 + }
  140 + // Vue异常监控;
  141 + app.config.errorHandler = vueErrorHandler;
  142 + // js错误
  143 + window.onerror = scriptErrorHandler;
  144 + // promise 异常
  145 + registerPromiseErrorHandler();
  146 +
  147 + // 静态资源异常
  148 + registerResourceErrorHandler();
  149 +}
src/store/modules/error.ts
1 import store from '/@/store'; 1 import store from '/@/store';
2 import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; 2 import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
3 -import { VuexModule, getModule, Module, Mutation } from 'vuex-module-decorators'; 3 +import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
4 4
5 import { formatToDateTime } from '/@/utils/dateUtil'; 5 import { formatToDateTime } from '/@/utils/dateUtil';
6 -export enum ErrorTypeEnum {  
7 - VUE = 'vue',  
8 - SCRIPT = 'script',  
9 - RESOURCE = 'resource',  
10 - AJAX = 'ajax',  
11 - PROMISE = 'promise',  
12 -} 6 +import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
  7 +import { useSetting } from '/@/hooks/core/useSetting';
13 8
14 export interface ErrorInfo { 9 export interface ErrorInfo {
15 type: ErrorTypeEnum; 10 type: ErrorTypeEnum;
@@ -43,10 +38,11 @@ class Error extends VuexModule implements ErrorState { @@ -43,10 +38,11 @@ class Error extends VuexModule implements ErrorState {
43 38
44 @Mutation 39 @Mutation
45 commitErrorInfoState(info: ErrorInfo): void { 40 commitErrorInfoState(info: ErrorInfo): void {
46 - this.errorInfoState.unshift({ 41 + const item = {
47 ...info, 42 ...info,
48 time: formatToDateTime(new Date()), 43 time: formatToDateTime(new Date()),
49 - }); 44 + };
  45 + this.errorInfoState = [item, ...this.errorInfoState];
50 this.errorListCountState += 1; 46 this.errorListCountState += 1;
51 } 47 }
52 48
@@ -54,6 +50,30 @@ class Error extends VuexModule implements ErrorState { @@ -54,6 +50,30 @@ class Error extends VuexModule implements ErrorState {
54 commitErrorListCountState(count: number): void { 50 commitErrorListCountState(count: number): void {
55 this.errorListCountState = count; 51 this.errorListCountState = count;
56 } 52 }
  53 +
  54 + @Action
  55 + setupErrorHandle(error: any) {
  56 + const { projectSetting } = useSetting();
  57 + const { useErrorHandle } = projectSetting;
  58 + if (!useErrorHandle) return;
  59 +
  60 + const errInfo: Partial<ErrorInfo> = {
  61 + message: error.message,
  62 + type: ErrorTypeEnum.AJAX,
  63 + };
  64 + if (error.response) {
  65 + const {
  66 + config: { url = '', data: params = '', method = 'get', headers = {} } = {},
  67 + data = {},
  68 + } = error.response;
  69 + errInfo.url = url;
  70 + errInfo.name = 'Ajax Error!';
  71 + errInfo.file = '-';
  72 + errInfo.stack = JSON.stringify(data);
  73 + errInfo.detail = JSON.stringify({ params, method, headers });
  74 + }
  75 + this.commitErrorInfoState(errInfo as ErrorInfo);
  76 + }
57 } 77 }
58 export { Error }; 78 export { Error };
59 export const errorStore = getModule<Error>(Error); 79 export const errorStore = getModule<Error>(Error);
src/utils/http/axios/index.ts
@@ -18,36 +18,13 @@ import { RequestEnum, ResultEnum, ContentTypeEnum } from &#39;/@/enums/httpEnum&#39;; @@ -18,36 +18,13 @@ import { RequestEnum, ResultEnum, ContentTypeEnum } from &#39;/@/enums/httpEnum&#39;;
18 import { isString } from '/@/utils/is'; 18 import { isString } from '/@/utils/is';
19 import { formatRequestDate } from '/@/utils/dateUtil'; 19 import { formatRequestDate } from '/@/utils/dateUtil';
20 import { setObjToUrlParams, deepMerge } from '/@/utils'; 20 import { setObjToUrlParams, deepMerge } from '/@/utils';
21 -import { errorStore, ErrorTypeEnum, ErrorInfo } from '/@/store/modules/error';  
22 -import { appStore } from '/@/store/modules/app'; 21 +import { errorStore } from '/@/store/modules/error';
23 import { errorResult } from './const'; 22 import { errorResult } from './const';
24 23
25 const { globSetting } = useSetting(); 24 const { globSetting } = useSetting();
26 const prefix = globSetting.urlPrefix; 25 const prefix = globSetting.urlPrefix;
27 const { createMessage, createErrorModal } = useMessage(); 26 const { createMessage, createErrorModal } = useMessage();
28 27
29 -function setupErrorHandle(error: any) {  
30 - const { useErrorHandle } = appStore.getProjectConfig;  
31 - if (!useErrorHandle) return;  
32 -  
33 - const errInfo: Partial<ErrorInfo> = {  
34 - message: error.message,  
35 - type: ErrorTypeEnum.AJAX,  
36 - };  
37 - if (error.response) {  
38 - const {  
39 - config: { url = '', data: params = '', method = 'get', headers = {} } = {},  
40 - data = {},  
41 - } = error.response;  
42 - errInfo.url = url;  
43 - errInfo.name = 'Ajax Error!';  
44 - errInfo.file = '-';  
45 - errInfo.stack = JSON.stringify(data);  
46 - errInfo.detail = JSON.stringify({ params, method, headers });  
47 - }  
48 - errorStore.commitErrorInfoState(errInfo as ErrorInfo);  
49 -}  
50 -  
51 /** 28 /**
52 * @description: 数据处理,方便区分多种处理方式 29 * @description: 数据处理,方便区分多种处理方式
53 */ 30 */
@@ -175,7 +152,7 @@ const transform: AxiosTransform = { @@ -175,7 +152,7 @@ const transform: AxiosTransform = {
175 * @description: 响应错误处理 152 * @description: 响应错误处理
176 */ 153 */
177 responseInterceptorsCatch: (error: any) => { 154 responseInterceptorsCatch: (error: any) => {
178 - setupErrorHandle(error); 155 + errorStore.setupErrorHandle(error);
179 const { response, code, message } = error || {}; 156 const { response, code, message } = error || {};
180 const msg: string = 157 const msg: string =
181 response && response.data && response.data.error ? response.data.error.message : ''; 158 response && response.data && response.data.error ? response.data.error.message : '';
src/views/sys/error-log/DetailModal.vue 0 → 100644
  1 +<template>
  2 + <BasicModal :width="800" title="错误详情" v-bind="$attrs">
  3 + <Description :data="info" @register="register" />
  4 + </BasicModal>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent, PropType } from 'vue';
  8 + import { BasicModal } from '/@/components/Modal/index';
  9 + import { ErrorInfo } from '/@/store/modules/error';
  10 + import { Description, useDescription } from '/@/components/Description/index';
  11 + import { getDescSchema } from './data';
  12 +
  13 + export default defineComponent({
  14 + name: 'ErrorLogDetailModal',
  15 + components: { BasicModal, Description },
  16 + props: {
  17 + info: {
  18 + type: Object as PropType<ErrorInfo>,
  19 + default: null,
  20 + },
  21 + },
  22 + setup() {
  23 + const [register] = useDescription({
  24 + column: 2,
  25 + schema: getDescSchema(),
  26 + });
  27 + return {
  28 + register,
  29 + };
  30 + },
  31 + });
  32 +</script>
src/views/sys/error-log/data.tsx 0 → 100644
  1 +import { Tag } from 'ant-design-vue';
  2 +import { BasicColumn } from '/@/components/Table/index';
  3 +import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
  4 +
  5 +export function getColumns(): BasicColumn[] {
  6 + return [
  7 + {
  8 + dataIndex: 'type',
  9 + title: '类型',
  10 + width: 80,
  11 + customRender: ({ text }) => {
  12 + const color =
  13 + text === ErrorTypeEnum.VUE
  14 + ? 'green'
  15 + : text === ErrorTypeEnum.RESOURCE
  16 + ? 'cyan'
  17 + : text === ErrorTypeEnum.PROMISE
  18 + ? 'blue'
  19 + : ErrorTypeEnum.AJAX
  20 + ? 'red'
  21 + : 'purple';
  22 + return <Tag color={color}>{() => text}</Tag>;
  23 + },
  24 + },
  25 + {
  26 + dataIndex: 'url',
  27 + title: '地址',
  28 + width: 200,
  29 + },
  30 + {
  31 + dataIndex: 'time',
  32 + title: '时间',
  33 + width: 160,
  34 + },
  35 + {
  36 + dataIndex: 'file',
  37 + title: '文件',
  38 + width: 200,
  39 + },
  40 + {
  41 + dataIndex: 'name',
  42 + title: 'Name',
  43 + width: 200,
  44 + },
  45 + {
  46 + dataIndex: 'message',
  47 + title: '错误信息',
  48 + width: 300,
  49 + },
  50 + {
  51 + dataIndex: 'stack',
  52 + title: 'stack信息',
  53 + width: 300,
  54 + },
  55 + ];
  56 +}
  57 +
  58 +export function getDescSchema() {
  59 + return getColumns().map((column) => {
  60 + return {
  61 + field: column.dataIndex!,
  62 + label: column.title,
  63 + };
  64 + });
  65 +}
src/views/sys/error-log/index.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <template v-for="src in imgListRef" :key="src">
  4 + <img :src="src" v-show="false" />
  5 + </template>
  6 + <DetailModal :info="rowInfoRef" @register="registerModal" />
  7 + <BasicTable @register="register" class="error-handle-table">
  8 + <template #toolbar>
  9 + <a-button @click="fireVueError" type="primary"> 点击触发vue错误 </a-button>
  10 + <a-button @click="fireResourceError" type="primary"> 点击触发resource错误 </a-button>
  11 + <a-button @click="fireAjaxError" type="primary"> 点击触发ajax错误 </a-button>
  12 + </template>
  13 + <template #action="{ record }">
  14 + <TableAction :actions="[{ label: '详情', onClick: handleDetail.bind(null, record) }]" />
  15 + </template>
  16 + </BasicTable>
  17 + </div>
  18 +</template>
  19 +
  20 +<script lang="ts">
  21 + import { defineComponent, watch, ref, nextTick } from 'vue';
  22 +
  23 + import DetailModal from './DetailModal.vue';
  24 + import { useModal } from '/@/components/Modal/index';
  25 +
  26 + import { BasicTable, useTable, TableAction } from '/@/components/Table/index';
  27 +
  28 + import { errorStore, ErrorInfo } from '/@/store/modules/error';
  29 +
  30 + import { fireErrorApi } from '/@/api/demo/error';
  31 +
  32 + import { getColumns } from './data';
  33 +
  34 + import { cloneDeep } from 'lodash-es';
  35 +
  36 + export default defineComponent({
  37 + name: 'ErrorHandler',
  38 + components: { DetailModal, BasicTable, TableAction },
  39 + setup() {
  40 + const rowInfoRef = ref<ErrorInfo>();
  41 + const imgListRef = ref<string[]>([]);
  42 + const [register, { setTableData }] = useTable({
  43 + titleHelpMessage: '只在`/src/settings/projectSetting.ts` 内的useErrorHandle=true时生效!',
  44 + title: '错误日志列表',
  45 + columns: getColumns(),
  46 + actionColumn: {
  47 + width: 80,
  48 + title: '操作',
  49 + dataIndex: 'action',
  50 + slots: { customRender: 'action' },
  51 + },
  52 + });
  53 +
  54 + const [registerModal, { openModal }] = useModal();
  55 + watch(
  56 + () => errorStore.getErrorInfoState,
  57 + (list) => {
  58 + nextTick(() => {
  59 + setTableData(cloneDeep(list));
  60 + });
  61 + },
  62 + {
  63 + immediate: true,
  64 + }
  65 + );
  66 +
  67 + // 查看详情
  68 + function handleDetail(row: ErrorInfo) {
  69 + rowInfoRef.value = row;
  70 + openModal(true);
  71 + }
  72 +
  73 + function fireVueError() {
  74 + throw new Error('fire vue error!');
  75 + }
  76 +
  77 + function fireResourceError() {
  78 + imgListRef.value.push(`${new Date().getTime()}.png`);
  79 + }
  80 +
  81 + async function fireAjaxError() {
  82 + await fireErrorApi();
  83 + }
  84 +
  85 + return {
  86 + register,
  87 + registerModal,
  88 + handleDetail,
  89 + fireVueError,
  90 + fireResourceError,
  91 + fireAjaxError,
  92 + imgListRef,
  93 + rowInfoRef,
  94 + };
  95 + },
  96 + });
  97 +</script>
src/views/sys/lock/index.vue
@@ -118,8 +118,8 @@ @@ -118,8 +118,8 @@
118 &__entry { 118 &__entry {
119 position: relative; 119 position: relative;
120 width: 400px; 120 width: 400px;
121 - height: 260px;  
122 - padding: 80px 50px 0 50px; 121 + // height: 260px;
  122 + padding: 80px 50px 50px 50px;
123 margin-right: 50px; 123 margin-right: 50px;
124 background: #fff; 124 background: #fff;
125 border-radius: 6px; 125 border-radius: 6px;
vite.config.ts
@@ -13,7 +13,7 @@ import { createProxy } from &#39;./build/config/vite/proxy&#39;; @@ -13,7 +13,7 @@ import { createProxy } from &#39;./build/config/vite/proxy&#39;;
13 import { createMockServer } from 'vite-plugin-mock'; 13 import { createMockServer } from 'vite-plugin-mock';
14 import PurgeIcons from 'vite-plugin-purge-icons'; 14 import PurgeIcons from 'vite-plugin-purge-icons';
15 import gzipPlugin from './build/plugin/gzip/index'; 15 import gzipPlugin from './build/plugin/gzip/index';
16 -import globbyTransform from './build/plugin/vite-plugin-context-plugin/transform'; 16 +import globbyTransform from './build/plugin/vite-plugin-context/transform';
17 17
18 import { isDevFn, isReportMode, isProdFn, loadEnv, isBuildGzip, isSiteMode } from './build/utils'; 18 import { isDevFn, isReportMode, isProdFn, loadEnv, isBuildGzip, isSiteMode } from './build/utils';
19 const pkg = require('./package.json'); 19 const pkg = require('./package.json');
yarn.lock
@@ -386,10 +386,10 @@ @@ -386,10 +386,10 @@
386 resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.1.tgz#a8bae29d71016d5af98c69f56a73c4a040217b3a" 386 resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.1.tgz#a8bae29d71016d5af98c69f56a73c4a040217b3a"
387 integrity sha512-ji5H04VjYtR4seIEgVVLPxg1KRhrFquOiyfPyLVS6vYPkuqV6bcWdssi05YSmf/OAzG4E7Qsg80/bOKyd5tYTw== 387 integrity sha512-ji5H04VjYtR4seIEgVVLPxg1KRhrFquOiyfPyLVS6vYPkuqV6bcWdssi05YSmf/OAzG4E7Qsg80/bOKyd5tYTw==
388 388
389 -"@iconify/json@^1.1.242":  
390 - version "1.1.242"  
391 - resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.242.tgz#f43b83acb7c3fe7906eb46cbe174a946aa17f9ff"  
392 - integrity sha512-uxiUvrINyZlITzKxa2J/75AzReenah83XxQLyryVHjGCSqNWQjQICmBLlrCsch5PMr5nF9JeNMbIPDzxlS59Og== 389 +"@iconify/json@^1.1.243":
  390 + version "1.1.243"
  391 + resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.243.tgz#8013fc781621b2549e379aab4e3e945974ec8032"
  392 + integrity sha512-vf8N+fUJysvCoJknS4XqorlvWLqjw/+Mid8CuzxQxMX8/RlWRU1yMFIgRpGAkMnCYe38KUtHqFVu0FlVNGP/Lw==
393 393
394 "@ls-lint/ls-lint@^1.9.2": 394 "@ls-lint/ls-lint@^1.9.2":
395 version "1.9.2" 395 version "1.9.2"
@@ -577,10 +577,10 @@ @@ -577,10 +577,10 @@
577 "@types/keygrip" "*" 577 "@types/keygrip" "*"
578 "@types/node" "*" 578 "@types/node" "*"
579 579
580 -"@types/echarts@^4.8.1":  
581 - version "4.8.1"  
582 - resolved "https://registry.npmjs.org/@types/echarts/-/echarts-4.8.1.tgz#e03aed60bbf25b7629affab699175df2e980fbb2"  
583 - integrity sha512-+kyP8TUkyJgmIBioPBJiTay9G7f/xcW7/8CYgh3iWa8kQ/SbGmAIpXyyCXtiWqPXT+tnsIONLC4hcNfmxVfxAg== 580 +"@types/echarts@^4.8.3":
  581 + version "4.8.3"
  582 + resolved "https://registry.npmjs.org/@types/echarts/-/echarts-4.8.3.tgz#78ef1ede01c3705b52342da997b3d54571d3604e"
  583 + integrity sha512-5aFZ7/6f+SPonLh4Nuso6pEZWwX8VBMYh2e83x1GVEpGkcN3GC0HzxPoF6ZSZPwoe5Rg4bhNwD9f2TVYxgU/QQ==
584 dependencies: 584 dependencies:
585 "@types/zrender" "*" 585 "@types/zrender" "*"
586 586
@@ -849,10 +849,10 @@ @@ -849,10 +849,10 @@
849 resolved "https://registry.npm.taobao.org/@types/yargs-parser/download/@types/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" 849 resolved "https://registry.npm.taobao.org/@types/yargs-parser/download/@types/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
850 integrity sha1-yz+fdBhp4gzOMw/765JxWQSDiC0= 850 integrity sha1-yz+fdBhp4gzOMw/765JxWQSDiC0=
851 851
852 -"@types/yargs@^15.0.8":  
853 - version "15.0.8"  
854 - resolved "https://registry.npm.taobao.org/@types/yargs/download/@types/yargs-15.0.8.tgz?cache=0&sync_timestamp=1602182032636&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fyargs%2Fdownload%2F%40types%2Fyargs-15.0.8.tgz#7644904cad7427eb704331ea9bf1ee5499b82e23"  
855 - integrity sha1-dkSQTK10J+twQzHqm/HuVJm4LiM= 852 +"@types/yargs@^15.0.9":
  853 + version "15.0.9"
  854 + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.9.tgz#524cd7998fe810cdb02f26101b699cccd156ff19"
  855 + integrity sha512-HmU8SeIRhZCWcnRskCs36Q1Q00KBV6Cqh/ora8WN1+22dY07AZdn6Gel8QZ3t26XYPImtcL8WV/eqjhVmMEw4g==
856 dependencies: 856 dependencies:
857 "@types/yargs-parser" "*" 857 "@types/yargs-parser" "*"
858 858
@@ -1735,10 +1735,10 @@ cliui@^6.0.0: @@ -1735,10 +1735,10 @@ cliui@^6.0.0:
1735 strip-ansi "^6.0.0" 1735 strip-ansi "^6.0.0"
1736 wrap-ansi "^6.2.0" 1736 wrap-ansi "^6.2.0"
1737 1737
1738 -cliui@^7.0.0:  
1739 - version "7.0.1"  
1740 - resolved "https://registry.npm.taobao.org/cliui/download/cliui-7.0.1.tgz#a4cb67aad45cd83d8d05128fc9f4d8fbb887e6b3"  
1741 - integrity sha1-pMtnqtRc2D2NBRKPyfTY+7iH5rM= 1738 +cliui@^7.0.2:
  1739 + version "7.0.3"
  1740 + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.3.tgz#ef180f26c8d9bff3927ee52428bfec2090427981"
  1741 + integrity sha512-Gj3QHTkVMPKqwP3f7B4KPkBZRMR9r4rfi5bXFpg1a+Svvj8l7q5CnkBkVQzfxT5DFSsGk2+PascOgL0JYkL2kw==
1742 dependencies: 1742 dependencies:
1743 string-width "^4.2.0" 1743 string-width "^4.2.0"
1744 strip-ansi "^6.0.0" 1744 strip-ansi "^6.0.0"
@@ -2537,11 +2537,16 @@ esbuild@^0.7.1: @@ -2537,11 +2537,16 @@ esbuild@^0.7.1:
2537 resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.7.14.tgz#9de555e75669187c2315317fbf489b229b1a4cbb" 2537 resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.7.14.tgz#9de555e75669187c2315317fbf489b229b1a4cbb"
2538 integrity sha512-w2CEVeRcUhCGYMHnNNwb8q+9w42scL7RcNzJm85gZVzNBE3AF0sLq5YP/IdaTBJIFBphIKG3bGbwRH+zsgH/ig== 2538 integrity sha512-w2CEVeRcUhCGYMHnNNwb8q+9w42scL7RcNzJm85gZVzNBE3AF0sLq5YP/IdaTBJIFBphIKG3bGbwRH+zsgH/ig==
2539 2539
2540 -escalade@^3.0.2, escalade@^3.1.0: 2540 +escalade@^3.1.0:
2541 version "3.1.0" 2541 version "3.1.0"
2542 resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" 2542 resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e"
2543 integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== 2543 integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig==
2544 2544
  2545 +escalade@^3.1.1:
  2546 + version "3.1.1"
  2547 + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
  2548 + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
  2549 +
2545 escape-goat@^2.0.0: 2550 escape-goat@^2.0.0:
2546 version "2.1.1" 2551 version "2.1.1"
2547 resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" 2552 resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
@@ -2557,10 +2562,10 @@ escape-string-regexp@^1.0.5: @@ -2557,10 +2562,10 @@ escape-string-regexp@^1.0.5:
2557 resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 2562 resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
2558 integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 2563 integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
2559 2564
2560 -eslint-config-prettier@^6.12.0:  
2561 - version "6.12.0"  
2562 - resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.12.0.tgz#9eb2bccff727db1c52104f0b49e87ea46605a0d2"  
2563 - integrity sha512-9jWPlFlgNwRUYVoujvWTQ1aMO8o6648r+K7qU7K5Jmkbyqav1fuEZC0COYpGBxyiAJb65Ra9hrmFx19xRGwXWw== 2565 +eslint-config-prettier@^6.13.0:
  2566 + version "6.13.0"
  2567 + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.13.0.tgz#207d88796b5624e5bb815bbbdfc5891ceb9ebffa"
  2568 + integrity sha512-LcT0i0LSmnzqK2t764pyIt7kKH2AuuqKRTtJTdddWxOiUja9HdG5GXBVF2gmCTvVYWVsTu8J2MhJLVGRh+pj8w==
2564 dependencies: 2569 dependencies:
2565 get-stdin "^6.0.0" 2570 get-stdin "^6.0.0"
2566 2571
@@ -4207,10 +4212,10 @@ lines-and-columns@^1.1.6: @@ -4207,10 +4212,10 @@ lines-and-columns@^1.1.6:
4207 resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" 4212 resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
4208 integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= 4213 integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
4209 4214
4210 -lint-staged@^10.4.0:  
4211 - version "10.4.0"  
4212 - resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-10.4.0.tgz#d18628f737328e0bbbf87d183f4020930e9a984e"  
4213 - integrity sha512-uaiX4U5yERUSiIEQc329vhCTDDwUcSvKdRLsNomkYLRzijk3v8V9GWm2Nz0RMVB87VcuzLvtgy6OsjoH++QHIg== 4215 +lint-staged@^10.4.2:
  4216 + version "10.4.2"
  4217 + resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-10.4.2.tgz#9fee4635c4b5ddb845746f237c6d43494ccd21c1"
  4218 + integrity sha512-OLCA9K1hS+Sl179SO6kX0JtnsaKj/MZalEhUj5yAgXsb63qPI/Gfn6Ua1KuZdbfkZNEu3/n5C/obYCu70IMt9g==
4214 dependencies: 4219 dependencies:
4215 chalk "^4.1.0" 4220 chalk "^4.1.0"
4216 cli-truncate "^2.1.0" 4221 cli-truncate "^2.1.0"
@@ -7268,10 +7273,10 @@ y18n@^4.0.0: @@ -7268,10 +7273,10 @@ y18n@^4.0.0:
7268 resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 7273 resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
7269 integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== 7274 integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
7270 7275
7271 -y18n@^5.0.1:  
7272 - version "5.0.2"  
7273 - resolved "https://registry.npm.taobao.org/y18n/download/y18n-5.0.2.tgz?cache=0&sync_timestamp=1601576683926&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fy18n%2Fdownload%2Fy18n-5.0.2.tgz#48218df5da2731b4403115c39a1af709c873f829"  
7274 - integrity sha1-SCGN9donMbRAMRXDmhr3Cchz+Ck= 7276 +y18n@^5.0.2:
  7277 + version "5.0.4"
  7278 + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.4.tgz#0ab2db89dd5873b5ec4682d8e703e833373ea897"
  7279 + integrity sha512-deLOfD+RvFgrpAmSZgfGdWYE+OKyHcVHaRQ7NphG/63scpRvTHHeQMAxGGvaLVGJ+HYVcCXlzcTK0ZehFf+eHQ==
7275 7280
7276 yallist@^3.0.2: 7281 yallist@^3.0.2:
7277 version "3.1.1" 7282 version "3.1.1"
@@ -7304,10 +7309,10 @@ yargs-parser@^18.1.2, yargs-parser@^18.1.3: @@ -7304,10 +7309,10 @@ yargs-parser@^18.1.2, yargs-parser@^18.1.3:
7304 camelcase "^5.0.0" 7309 camelcase "^5.0.0"
7305 decamelize "^1.2.0" 7310 decamelize "^1.2.0"
7306 7311
7307 -yargs-parser@^20.0.0:  
7308 - version "20.2.1"  
7309 - resolved "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-20.2.1.tgz?cache=0&sync_timestamp=1601576684570&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-20.2.1.tgz#28f3773c546cdd8a69ddae68116b48a5da328e77"  
7310 - integrity sha1-KPN3PFRs3Ypp3a5oEWtIpdoyjnc= 7312 +yargs-parser@^20.2.2:
  7313 + version "20.2.3"
  7314 + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.3.tgz#92419ba867b858c868acf8bae9bf74af0dd0ce26"
  7315 + integrity sha512-emOFRT9WVHw03QSvN5qor9QQT9+sw5vwxfYweivSMHTcAXPefwVae2FjO7JJjj8hCE4CzPOPeFM83VwT29HCww==
7311 7316
7312 yargs@^13.2.4: 7317 yargs@^13.2.4:
7313 version "13.3.2" 7318 version "13.3.2"
@@ -7342,18 +7347,18 @@ yargs@^15.0.0, yargs@^15.1.0: @@ -7342,18 +7347,18 @@ yargs@^15.0.0, yargs@^15.1.0:
7342 y18n "^4.0.0" 7347 y18n "^4.0.0"
7343 yargs-parser "^18.1.2" 7348 yargs-parser "^18.1.2"
7344 7349
7345 -yargs@^16.0.3:  
7346 - version "16.0.3"  
7347 - resolved "https://registry.npm.taobao.org/yargs/download/yargs-16.0.3.tgz?cache=0&sync_timestamp=1600660006050&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-16.0.3.tgz#7a919b9e43c90f80d4a142a89795e85399a7e54c"  
7348 - integrity sha1-epGbnkPJD4DUoUKol5XoU5mn5Uw= 7350 +yargs@^16.1.0:
  7351 + version "16.1.0"
  7352 + resolved "https://registry.npmjs.org/yargs/-/yargs-16.1.0.tgz#fc333fe4791660eace5a894b39d42f851cd48f2a"
  7353 + integrity sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==
7349 dependencies: 7354 dependencies:
7350 - cliui "^7.0.0"  
7351 - escalade "^3.0.2" 7355 + cliui "^7.0.2"
  7356 + escalade "^3.1.1"
7352 get-caller-file "^2.0.5" 7357 get-caller-file "^2.0.5"
7353 require-directory "^2.1.1" 7358 require-directory "^2.1.1"
7354 string-width "^4.2.0" 7359 string-width "^4.2.0"
7355 - y18n "^5.0.1"  
7356 - yargs-parser "^20.0.0" 7360 + y18n "^5.0.2"
  7361 + yargs-parser "^20.2.2"
7357 7362
7358 ylru@^1.2.0: 7363 ylru@^1.2.0:
7359 version "1.2.1" 7364 version "1.2.1"