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