Commit 7101587b9676c91e9079044a096df08848f1f602
1 parent
c0692b0f
feat: add error handle
Showing
32 changed files
with
674 additions
and
116 deletions
.env.production
README.en-US.md
... | ... | @@ -225,17 +225,17 @@ yarn clean:lib # Delete node_modules, supported window |
225 | 225 | - [x] First screen loading waiting animation |
226 | 226 | - [x] Extract the production environment profile |
227 | 227 | - [x] Build Gzip |
228 | +- [x] System performance optimization | |
229 | +- [x] Data import and export | |
230 | +- [x] Global error handling | |
228 | 231 | |
229 | 232 | ## Developing features |
230 | 233 | |
231 | 234 | - [ ] Upload component |
232 | 235 | - [ ] Rich text component |
233 | -- [ ] Data import and export | |
234 | -- [ ] Global error handling | |
235 | 236 | - [ ] Theme configuration |
236 | 237 | - [ ] Dark theme |
237 | 238 | - [ ] Build CDN |
238 | -- [ ] System performance optimization | |
239 | 239 | |
240 | 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 | 223 | - [x] 首屏加载等待动画 |
224 | 224 | - [x] 抽取生产环境配置文件 |
225 | 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 | 236 | - [ ] 打包 CDN |
236 | -- [ ] 系统性能优化 | |
237 | 237 | |
238 | 238 | 更多组件/功能/建议/bug/欢迎提交 pr 或者 issue |
239 | 239 | ... | ... |
build/config/vite/proxy.ts
... | ... | @@ -2,13 +2,17 @@ type ProxyItem = [string, string]; |
2 | 2 | |
3 | 3 | type ProxyList = ProxyItem[]; |
4 | 4 | |
5 | +const reg = /^https:\/\//; | |
5 | 6 | export function createProxy(list: ProxyList = []) { |
6 | 7 | const ret: any = {}; |
7 | 8 | for (const [prefix, target] of list) { |
9 | + const isHttps = reg.test(target); | |
10 | + | |
8 | 11 | ret[prefix] = { |
9 | 12 | target: target, |
10 | 13 | changeOrigin: true, |
11 | 14 | rewrite: (path: string) => path.replace(new RegExp(`^${prefix}`), ''), |
15 | + ...(isHttps ? { secure: false } : {}), | |
12 | 16 | }; |
13 | 17 | } |
14 | 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 | 41 | "devDependencies": { |
42 | 42 | "@commitlint/cli": "^11.0.0", |
43 | 43 | "@commitlint/config-conventional": "^11.0.0", |
44 | - "@iconify/json": "^1.1.242", | |
44 | + "@iconify/json": "^1.1.243", | |
45 | 45 | "@ls-lint/ls-lint": "^1.9.2", |
46 | 46 | "@purge-icons/generated": "^0.4.1", |
47 | - "@types/echarts": "^4.8.1", | |
47 | + "@types/echarts": "^4.8.3", | |
48 | 48 | "@types/fs-extra": "^9.0.2", |
49 | 49 | "@types/html-minifier": "^4.0.0", |
50 | 50 | "@types/inquirer": "^7.3.1", |
... | ... | @@ -55,7 +55,7 @@ |
55 | 55 | "@types/qrcode": "^1.3.5", |
56 | 56 | "@types/rollup-plugin-visualizer": "^2.6.0", |
57 | 57 | "@types/shelljs": "^0.8.8", |
58 | - "@types/yargs": "^15.0.8", | |
58 | + "@types/yargs": "^15.0.9", | |
59 | 59 | "@types/zxcvbn": "^4.4.0", |
60 | 60 | "@typescript-eslint/eslint-plugin": "^4.4.1", |
61 | 61 | "@typescript-eslint/parser": "^4.4.1", |
... | ... | @@ -67,7 +67,7 @@ |
67 | 67 | "cross-env": "^7.0.2", |
68 | 68 | "dotenv": "^8.2.0", |
69 | 69 | "eslint": "^7.10.0", |
70 | - "eslint-config-prettier": "^6.12.0", | |
70 | + "eslint-config-prettier": "^6.13.0", | |
71 | 71 | "eslint-plugin-prettier": "^3.1.4", |
72 | 72 | "eslint-plugin-vue": "^7.0.1", |
73 | 73 | "fs-extra": "^9.0.1", |
... | ... | @@ -76,7 +76,7 @@ |
76 | 76 | "inquirer": "^7.3.3", |
77 | 77 | "koa-static": "^5.0.0", |
78 | 78 | "less": "^3.12.2", |
79 | - "lint-staged": "^10.4.0", | |
79 | + "lint-staged": "^10.4.2", | |
80 | 80 | "portfinder": "^1.0.28", |
81 | 81 | "postcss-import": "^12.0.1", |
82 | 82 | "prettier": "^2.1.2", |
... | ... | @@ -95,7 +95,7 @@ |
95 | 95 | "vite-plugin-mock": "^1.0.2", |
96 | 96 | "vite-plugin-purge-icons": "^0.4.4", |
97 | 97 | "vue-eslint-parser": "^7.1.1", |
98 | - "yargs": "^16.0.3" | |
98 | + "yargs": "^16.1.0" | |
99 | 99 | }, |
100 | 100 | "repository": { |
101 | 101 | "type": "git", | ... | ... |
src/App.vue
src/api/demo/error.ts
0 → 100644
src/components/Table/src/BasicTable.vue
src/components/Table/src/components/TableAction.tsx
... | ... | @@ -29,7 +29,6 @@ export default defineComponent({ |
29 | 29 | const { |
30 | 30 | disabled = false, |
31 | 31 | label, |
32 | - props, | |
33 | 32 | icon, |
34 | 33 | color = '', |
35 | 34 | type = 'link', |
... | ... | @@ -41,7 +40,7 @@ export default defineComponent({ |
41 | 40 | size="small" |
42 | 41 | disabled={disabled} |
43 | 42 | color={color} |
44 | - {...props} | |
43 | + {...action} | |
45 | 44 | key={index} |
46 | 45 | > |
47 | 46 | {() => ( |
... | ... | @@ -101,7 +100,6 @@ export default defineComponent({ |
101 | 100 | const { |
102 | 101 | disabled = false, |
103 | 102 | label, |
104 | - props, | |
105 | 103 | icon, |
106 | 104 | color = '', |
107 | 105 | type = 'link', |
... | ... | @@ -112,7 +110,7 @@ export default defineComponent({ |
112 | 110 | <Button |
113 | 111 | type={type} |
114 | 112 | size="small" |
115 | - {...props} | |
113 | + {...action} | |
116 | 114 | disabled={disabled} |
117 | 115 | color={color} |
118 | 116 | > | ... | ... |
src/enums/exceptionEnum.ts
... | ... | @@ -23,3 +23,11 @@ export enum ExceptionEnum { |
23 | 23 | // No data on the page. In fact, it is not an exception page |
24 | 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 | 19 | // page switch |
20 | 20 | export function useGo() { |
21 | 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 | 23 | if (isString(opt)) { |
24 | 24 | isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError); |
25 | 25 | } else { | ... | ... |
src/layouts/default/LayoutHeader.tsx
1 | 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 | 3 | import Logo from '/@/layouts/Logo.vue'; |
4 | 4 | import UserDropdown from './UserDropdown'; |
5 | 5 | import LayoutMenu from './LayoutMenu'; |
... | ... | @@ -12,12 +12,15 @@ import { |
12 | 12 | FullscreenOutlined, |
13 | 13 | GithubFilled, |
14 | 14 | LockOutlined, |
15 | + BugOutlined, | |
15 | 16 | } from '@ant-design/icons-vue'; |
16 | 17 | import { useFullscreen } from '/@/hooks/web/useFullScreen'; |
17 | 18 | import { useTabs } from '/@/hooks/web/useTabs'; |
18 | 19 | import { GITHUB_URL } from '/@/settings/siteSetting'; |
19 | 20 | import LockAction from './actions/LockActionItem'; |
20 | 21 | import { useModal } from '/@/components/Modal/index'; |
22 | +import { errorStore } from '/@/store/modules/error'; | |
23 | +import { useGo } from '/@/hooks/web/usePage'; | |
21 | 24 | |
22 | 25 | export default defineComponent({ |
23 | 26 | name: 'DefaultLayoutHeader', |
... | ... | @@ -25,6 +28,7 @@ export default defineComponent({ |
25 | 28 | const { refreshPage } = useTabs(); |
26 | 29 | const [register, { openModal }] = useModal(); |
27 | 30 | const { toggleFullscreen, isFullscreenRef } = useFullscreen(); |
31 | + const go = useGo(); | |
28 | 32 | const getProjectConfigRef = computed(() => { |
29 | 33 | return appStore.getProjectConfig; |
30 | 34 | }); |
... | ... | @@ -37,6 +41,12 @@ export default defineComponent({ |
37 | 41 | const theme = unref(getProjectConfigRef).headerSetting.theme; |
38 | 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 | 51 | * @description: 锁定屏幕 |
42 | 52 | */ |
... | ... | @@ -46,9 +56,9 @@ export default defineComponent({ |
46 | 56 | return () => { |
47 | 57 | const getProjectConfig = unref(getProjectConfigRef); |
48 | 58 | const { |
49 | - // useErrorHandle, | |
59 | + useErrorHandle, | |
50 | 60 | showLogo, |
51 | - headerSetting: { theme: headerTheme, showRedo, showGithub, showFullScreen }, | |
61 | + headerSetting: { theme: headerTheme, useLockPage, showRedo, showGithub, showFullScreen }, | |
52 | 62 | menuSetting: { mode, type: menuType, split: splitMenu, topMenuAlign }, |
53 | 63 | showBreadCrumb, |
54 | 64 | } = getProjectConfig; |
... | ... | @@ -77,8 +87,28 @@ export default defineComponent({ |
77 | 87 | </div> |
78 | 88 | |
79 | 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 | 111 | {showGithub && ( |
81 | - // @ts-ignore | |
82 | 112 | <Tooltip> |
83 | 113 | {{ |
84 | 114 | title: () => 'github', |
... | ... | @@ -90,8 +120,7 @@ export default defineComponent({ |
90 | 120 | }} |
91 | 121 | </Tooltip> |
92 | 122 | )} |
93 | - {showGithub && ( | |
94 | - // @ts-ignore | |
123 | + {useLockPage && ( | |
95 | 124 | <Tooltip> |
96 | 125 | {{ |
97 | 126 | title: () => '锁定屏幕', |
... | ... | @@ -104,7 +133,6 @@ export default defineComponent({ |
104 | 133 | </Tooltip> |
105 | 134 | )} |
106 | 135 | {showRedo && ( |
107 | - // @ts-ignore | |
108 | 136 | <Tooltip> |
109 | 137 | {{ |
110 | 138 | title: () => '刷新', |
... | ... | @@ -117,7 +145,6 @@ export default defineComponent({ |
117 | 145 | </Tooltip> |
118 | 146 | )} |
119 | 147 | {showFullScreen && ( |
120 | - // @ts-ignore | |
121 | 148 | <Tooltip> |
122 | 149 | {{ |
123 | 150 | title: () => (unref(isFullscreenRef) ? '退出全屏' : '全屏'), | ... | ... |
src/layouts/default/actions/LockActionItem.tsx
... | ... | @@ -40,10 +40,11 @@ export default defineComponent({ |
40 | 40 | let password: string | undefined = ''; |
41 | 41 | |
42 | 42 | try { |
43 | - const values = (await validateFields()) as any; | |
44 | - password = values.password; | |
45 | 43 | if (!valid) { |
46 | 44 | password = undefined; |
45 | + } else { | |
46 | + const values = (await validateFields()) as any; | |
47 | + password = values.password; | |
47 | 48 | } |
48 | 49 | setModalProps({ |
49 | 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 | 102 | .setting-button { |
103 | 103 | top: 45%; |
104 | 104 | right: 0; |
105 | - padding: 14px; | |
105 | + padding: 8px; | |
106 | 106 | border-radius: 6px 0 0 6px; |
107 | 107 | |
108 | 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
src/layouts/page/index.tsx
src/main.ts
... | ... | @@ -3,6 +3,7 @@ import { createApp } from 'vue'; |
3 | 3 | import router, { setupRouter } from '/@/router'; |
4 | 4 | import { setupStore } from '/@/store'; |
5 | 5 | import { setupAntd } from '/@/setup/ant-design-vue'; |
6 | +import { setupErrorHandle } from '/@/setup/error-handle/index'; | |
6 | 7 | import { setupDirectives } from '/@/setup/directives/index'; |
7 | 8 | |
8 | 9 | import { registerGlobComp } from '/@/components/registerGlobComp'; |
... | ... | @@ -21,10 +22,12 @@ setupRouter(app); |
21 | 22 | // store |
22 | 23 | setupStore(app); |
23 | 24 | |
24 | -registerGlobComp(app); | |
25 | - | |
26 | 25 | setupDirectives(app); |
27 | 26 | |
27 | +setupErrorHandle(app); | |
28 | + | |
29 | +registerGlobComp(app); | |
30 | + | |
28 | 31 | router.isReady().then(() => { |
29 | 32 | app.mount('#app'); |
30 | 33 | }); | ... | ... |
src/router/menus/modules/demo/exception.ts
src/router/routes/modules/demo/exception.ts
... | ... | @@ -78,5 +78,13 @@ export default { |
78 | 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 | 90 | } as AppRouteModule; | ... | ... |
src/settings/projectSetting.ts
... | ... | @@ -30,7 +30,7 @@ const setting: ProjectConfig = { |
30 | 30 | // theme |
31 | 31 | theme: MenuThemeEnum.LIGHT, |
32 | 32 | // 开启锁屏功能 |
33 | - useLockPage: isProdMode(), | |
33 | + useLockPage: true, | |
34 | 34 | // 显示刷新按钮 |
35 | 35 | showRedo: true, |
36 | 36 | // 显示全屏按钮 |
... | ... | @@ -86,7 +86,7 @@ const setting: ProjectConfig = { |
86 | 86 | // 是否开启KeepAlive缓存 开发时候最好关闭,不然每次都需要清除缓存 |
87 | 87 | openKeepAlive: true, |
88 | 88 | |
89 | - // 自动锁屏时间,为0不锁屏。 单位分钟 默认1个小时 | |
89 | + // 自动锁屏时间,为0不锁屏。 单位分钟 默认0 | |
90 | 90 | lockTime: 0, |
91 | 91 | // 显示面包屑 |
92 | 92 | showBreadCrumb: true, |
... | ... | @@ -96,6 +96,7 @@ const setting: ProjectConfig = { |
96 | 96 | |
97 | 97 | // 开启页面切换动画 |
98 | 98 | openRouterTransition: true, |
99 | + | |
99 | 100 | // 路由切换动画 |
100 | 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 | 1 | import store from '/@/store'; |
2 | 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 | 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 | 9 | export interface ErrorInfo { |
15 | 10 | type: ErrorTypeEnum; |
... | ... | @@ -43,10 +38,11 @@ class Error extends VuexModule implements ErrorState { |
43 | 38 | |
44 | 39 | @Mutation |
45 | 40 | commitErrorInfoState(info: ErrorInfo): void { |
46 | - this.errorInfoState.unshift({ | |
41 | + const item = { | |
47 | 42 | ...info, |
48 | 43 | time: formatToDateTime(new Date()), |
49 | - }); | |
44 | + }; | |
45 | + this.errorInfoState = [item, ...this.errorInfoState]; | |
50 | 46 | this.errorListCountState += 1; |
51 | 47 | } |
52 | 48 | |
... | ... | @@ -54,6 +50,30 @@ class Error extends VuexModule implements ErrorState { |
54 | 50 | commitErrorListCountState(count: number): void { |
55 | 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 | 78 | export { Error }; |
59 | 79 | export const errorStore = getModule<Error>(Error); | ... | ... |
src/utils/http/axios/index.ts
... | ... | @@ -18,36 +18,13 @@ import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum'; |
18 | 18 | import { isString } from '/@/utils/is'; |
19 | 19 | import { formatRequestDate } from '/@/utils/dateUtil'; |
20 | 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 | 22 | import { errorResult } from './const'; |
24 | 23 | |
25 | 24 | const { globSetting } = useSetting(); |
26 | 25 | const prefix = globSetting.urlPrefix; |
27 | 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 | 29 | * @description: 数据处理,方便区分多种处理方式 |
53 | 30 | */ |
... | ... | @@ -175,7 +152,7 @@ const transform: AxiosTransform = { |
175 | 152 | * @description: 响应错误处理 |
176 | 153 | */ |
177 | 154 | responseInterceptorsCatch: (error: any) => { |
178 | - setupErrorHandle(error); | |
155 | + errorStore.setupErrorHandle(error); | |
179 | 156 | const { response, code, message } = error || {}; |
180 | 157 | const msg: string = |
181 | 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 | 118 | &__entry { |
119 | 119 | position: relative; |
120 | 120 | width: 400px; |
121 | - height: 260px; | |
122 | - padding: 80px 50px 0 50px; | |
121 | + // height: 260px; | |
122 | + padding: 80px 50px 50px 50px; | |
123 | 123 | margin-right: 50px; |
124 | 124 | background: #fff; |
125 | 125 | border-radius: 6px; | ... | ... |
vite.config.ts
... | ... | @@ -13,7 +13,7 @@ import { createProxy } from './build/config/vite/proxy'; |
13 | 13 | import { createMockServer } from 'vite-plugin-mock'; |
14 | 14 | import PurgeIcons from 'vite-plugin-purge-icons'; |
15 | 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 | 18 | import { isDevFn, isReportMode, isProdFn, loadEnv, isBuildGzip, isSiteMode } from './build/utils'; |
19 | 19 | const pkg = require('./package.json'); | ... | ... |
yarn.lock
... | ... | @@ -386,10 +386,10 @@ |
386 | 386 | resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.1.tgz#a8bae29d71016d5af98c69f56a73c4a040217b3a" |
387 | 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 | 394 | "@ls-lint/ls-lint@^1.9.2": |
395 | 395 | version "1.9.2" |
... | ... | @@ -577,10 +577,10 @@ |
577 | 577 | "@types/keygrip" "*" |
578 | 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 | 584 | dependencies: |
585 | 585 | "@types/zrender" "*" |
586 | 586 | |
... | ... | @@ -849,10 +849,10 @@ |
849 | 849 | resolved "https://registry.npm.taobao.org/@types/yargs-parser/download/@types/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" |
850 | 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 | 856 | dependencies: |
857 | 857 | "@types/yargs-parser" "*" |
858 | 858 | |
... | ... | @@ -1735,10 +1735,10 @@ cliui@^6.0.0: |
1735 | 1735 | strip-ansi "^6.0.0" |
1736 | 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 | 1742 | dependencies: |
1743 | 1743 | string-width "^4.2.0" |
1744 | 1744 | strip-ansi "^6.0.0" |
... | ... | @@ -2537,11 +2537,16 @@ esbuild@^0.7.1: |
2537 | 2537 | resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.7.14.tgz#9de555e75669187c2315317fbf489b229b1a4cbb" |
2538 | 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 | 2541 | version "3.1.0" |
2542 | 2542 | resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" |
2543 | 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 | 2550 | escape-goat@^2.0.0: |
2546 | 2551 | version "2.1.1" |
2547 | 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 | 2562 | resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" |
2558 | 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 | 2569 | dependencies: |
2565 | 2570 | get-stdin "^6.0.0" |
2566 | 2571 | |
... | ... | @@ -4207,10 +4212,10 @@ lines-and-columns@^1.1.6: |
4207 | 4212 | resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" |
4208 | 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 | 4219 | dependencies: |
4215 | 4220 | chalk "^4.1.0" |
4216 | 4221 | cli-truncate "^2.1.0" |
... | ... | @@ -7268,10 +7273,10 @@ y18n@^4.0.0: |
7268 | 7273 | resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" |
7269 | 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 | 7281 | yallist@^3.0.2: |
7277 | 7282 | version "3.1.1" |
... | ... | @@ -7304,10 +7309,10 @@ yargs-parser@^18.1.2, yargs-parser@^18.1.3: |
7304 | 7309 | camelcase "^5.0.0" |
7305 | 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 | 7317 | yargs@^13.2.4: |
7313 | 7318 | version "13.3.2" |
... | ... | @@ -7342,18 +7347,18 @@ yargs@^15.0.0, yargs@^15.1.0: |
7342 | 7347 | y18n "^4.0.0" |
7343 | 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 | 7354 | dependencies: |
7350 | - cliui "^7.0.0" | |
7351 | - escalade "^3.0.2" | |
7355 | + cliui "^7.0.2" | |
7356 | + escalade "^3.1.1" | |
7352 | 7357 | get-caller-file "^2.0.5" |
7353 | 7358 | require-directory "^2.1.1" |
7354 | 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 | 7363 | ylru@^1.2.0: |
7359 | 7364 | version "1.2.1" | ... | ... |