角色管理和审批模板管理完成
This commit is contained in:
Generated
+7
-7
@@ -2855,8 +2855,8 @@ packages:
|
|||||||
date-fns@3.6.0:
|
date-fns@3.6.0:
|
||||||
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
|
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
|
||||||
|
|
||||||
date-fns@4.1.0:
|
date-fns@4.4.0:
|
||||||
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==}
|
||||||
|
|
||||||
dayjs@1.11.20:
|
dayjs@1.11.20:
|
||||||
resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
|
resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
|
||||||
@@ -8119,13 +8119,13 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
is-data-view: 1.0.2
|
is-data-view: 1.0.2
|
||||||
|
|
||||||
date-fns-tz@3.2.0(date-fns@4.1.0):
|
date-fns-tz@3.2.0(date-fns@4.4.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
date-fns: 4.1.0
|
date-fns: 4.4.0
|
||||||
|
|
||||||
date-fns@3.6.0: {}
|
date-fns@3.6.0: {}
|
||||||
|
|
||||||
date-fns@4.1.0: {}
|
date-fns@4.4.0: {}
|
||||||
|
|
||||||
dayjs@1.11.20: {}
|
dayjs@1.11.20: {}
|
||||||
|
|
||||||
@@ -9418,8 +9418,8 @@ snapshots:
|
|||||||
async-validator: 4.2.5
|
async-validator: 4.2.5
|
||||||
css-render: 0.15.14
|
css-render: 0.15.14
|
||||||
csstype: 3.2.3
|
csstype: 3.2.3
|
||||||
date-fns: 4.1.0
|
date-fns: 4.4.0
|
||||||
date-fns-tz: 3.2.0(date-fns@4.1.0)
|
date-fns-tz: 3.2.0(date-fns@4.4.0)
|
||||||
evtd: 0.2.4
|
evtd: 0.2.4
|
||||||
highlight.js: 11.11.1
|
highlight.js: 11.11.1
|
||||||
lodash: 4.18.1
|
lodash: 4.18.1
|
||||||
|
|||||||
@@ -238,6 +238,10 @@ const local: App.I18n.Schema = {
|
|||||||
docs: '资料管理',
|
docs: '资料管理',
|
||||||
docs_archives: '资料档案库',
|
docs_archives: '资料档案库',
|
||||||
docs_query: '变更归档查询',
|
docs_query: '变更归档查询',
|
||||||
|
systemmanage: '系统设置',
|
||||||
|
systemmanage_user: '架构及用户管理',
|
||||||
|
systemmanage_role: '角色管理',
|
||||||
|
systemmanage_template: '审批模板管理',
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
required: '不能为空',
|
required: '不能为空',
|
||||||
|
|||||||
@@ -30,4 +30,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
|||||||
home_process: () => import("@/views/home/process/index.vue"),
|
home_process: () => import("@/views/home/process/index.vue"),
|
||||||
home_processdetail: () => import("@/views/home/processDetail/index.vue"),
|
home_processdetail: () => import("@/views/home/processDetail/index.vue"),
|
||||||
login: () => import("@/views/login/index.vue"),
|
login: () => import("@/views/login/index.vue"),
|
||||||
|
systemmanage_role: () => import("@/views/systemManage/role/index.vue"),
|
||||||
|
systemmanage_template: () => import("@/views/systemManage/template/index.vue"),
|
||||||
|
systemmanage_user: () => import("@/views/systemManage/user/index.vue"),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -202,5 +202,48 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
constant: true,
|
constant: true,
|
||||||
hideInMenu: true
|
hideInMenu: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'systemmanage',
|
||||||
|
path: '/systemmanage',
|
||||||
|
component: 'layout.base',
|
||||||
|
meta: {
|
||||||
|
title: 'systemmanage',
|
||||||
|
i18nKey: 'route.systemmanage',
|
||||||
|
icon: 'uil:setting',
|
||||||
|
order: 5
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: 'systemmanage_role',
|
||||||
|
path: '/systemmanage/role',
|
||||||
|
component: 'view.systemmanage_role',
|
||||||
|
meta: {
|
||||||
|
title: 'systemmanage_role',
|
||||||
|
i18nKey: 'route.systemmanage_role',
|
||||||
|
icon: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'systemmanage_template',
|
||||||
|
path: '/systemmanage/template',
|
||||||
|
component: 'view.systemmanage_template',
|
||||||
|
meta: {
|
||||||
|
title: 'systemmanage_template',
|
||||||
|
i18nKey: 'route.systemmanage_template',
|
||||||
|
icon: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'systemmanage_user',
|
||||||
|
path: '/systemmanage/user',
|
||||||
|
component: 'view.systemmanage_user',
|
||||||
|
meta: {
|
||||||
|
title: 'systemmanage_user',
|
||||||
|
i18nKey: 'route.systemmanage_user',
|
||||||
|
icon: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -180,7 +180,11 @@ const routeMap: RouteMap = {
|
|||||||
"home_pending": "/home/pending",
|
"home_pending": "/home/pending",
|
||||||
"home_process": "/home/process",
|
"home_process": "/home/process",
|
||||||
"home_processdetail": "/home/processdetail",
|
"home_processdetail": "/home/processdetail",
|
||||||
"login": "/login/:module(pwd-login)?"
|
"login": "/login/:module(pwd-login)?",
|
||||||
|
"systemmanage": "/systemmanage",
|
||||||
|
"systemmanage_role": "/systemmanage/role",
|
||||||
|
"systemmanage_template": "/systemmanage/template",
|
||||||
|
"systemmanage_user": "/systemmanage/user"
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Vendored
+2
-120
@@ -23,118 +23,59 @@ declare module 'vue' {
|
|||||||
GithubLink: typeof import('./../components/custom/github-link.vue')['default']
|
GithubLink: typeof import('./../components/custom/github-link.vue')['default']
|
||||||
IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
|
IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
|
||||||
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
||||||
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
|
||||||
IconCarbonPlay: typeof import('~icons/carbon/play')['default']
|
|
||||||
IconCarbonStop: typeof import('~icons/carbon/stop')['default']
|
|
||||||
IconCharmDownload: typeof import('~icons/charm/download')['default']
|
|
||||||
IconF7CircleFill: typeof import('~icons/f7/circle-fill')['default']
|
|
||||||
IconF7FlagCircleFill: typeof import('~icons/f7/flag-circle-fill')['default']
|
|
||||||
IconFeQuestion: typeof import('~icons/fe/question')['default']
|
|
||||||
IconFileIconsMicrosoftExcel: typeof import('~icons/file-icons/microsoft-excel')['default']
|
|
||||||
IconGgRatio: typeof import('~icons/gg/ratio')['default']
|
|
||||||
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
||||||
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
||||||
IconIconParkOutlineEqualRatio: typeof import('~icons/icon-park-outline/equal-ratio')['default']
|
|
||||||
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
|
|
||||||
IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
|
|
||||||
IconIcRoundRefresh: typeof import('~icons/ic/round-refresh')['default']
|
|
||||||
IconIcRoundRemove: typeof import('~icons/ic/round-remove')['default']
|
|
||||||
IconIcRoundSearch: typeof import('~icons/ic/round-search')['default']
|
|
||||||
IconLocalActivity: typeof import('~icons/local/activity')['default']
|
|
||||||
IconLocalBanner: typeof import('~icons/local/banner')['default']
|
|
||||||
IconLocalCast: typeof import('~icons/local/cast')['default']
|
|
||||||
IconMaterialSymbolsLightRotate90DegreesCcwOutlineRounded: typeof import('~icons/material-symbols-light/rotate90-degrees-ccw-outline-rounded')['default']
|
|
||||||
IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
|
IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
|
||||||
IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
|
IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
|
||||||
IconMdiDrag: typeof import('~icons/mdi/drag')['default']
|
|
||||||
IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
||||||
IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
||||||
IconMdiPrinter: typeof import('~icons/mdi/printer')['default']
|
|
||||||
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
|
||||||
IconMingcuteZoomInLine: typeof import('~icons/mingcute/zoom-in-line')['default']
|
|
||||||
IconMingcuteZoomOutLine: typeof import('~icons/mingcute/zoom-out-line')['default']
|
|
||||||
IconOcticonPin16: typeof import('~icons/octicon/pin16')['default']
|
|
||||||
IconOcticonPinSlash16: typeof import('~icons/octicon/pin-slash16')['default']
|
|
||||||
IconTooltip: typeof import('./../components/common/icon-tooltip.vue')['default']
|
IconTooltip: typeof import('./../components/common/icon-tooltip.vue')['default']
|
||||||
IconUilSearch: typeof import('~icons/uil/search')['default']
|
IconUilSearch: typeof import('~icons/uil/search')['default']
|
||||||
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
|
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
|
||||||
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
|
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
|
||||||
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
|
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
|
||||||
NAlert: typeof import('naive-ui')['NAlert']
|
|
||||||
NBadge: typeof import('naive-ui')['NBadge']
|
NBadge: typeof import('naive-ui')['NBadge']
|
||||||
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
|
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
|
||||||
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
|
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
|
||||||
NButton: typeof import('naive-ui')['NButton']
|
NButton: typeof import('naive-ui')['NButton']
|
||||||
NButtonGroup: typeof import('naive-ui')['NButtonGroup']
|
|
||||||
NCard: typeof import('naive-ui')['NCard']
|
NCard: typeof import('naive-ui')['NCard']
|
||||||
|
NCascader: typeof import('naive-ui')['NCascader']
|
||||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||||
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
|
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
|
||||||
NCollapse: typeof import('naive-ui')['NCollapse']
|
|
||||||
NCollapseItem: typeof import('naive-ui')['NCollapseItem']
|
|
||||||
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
||||||
NDataTable: typeof import('naive-ui')['NDataTable']
|
NDataTable: typeof import('naive-ui')['NDataTable']
|
||||||
NDatePicker: typeof import('naive-ui')['NDatePicker']
|
NDatePicker: typeof import('naive-ui')['NDatePicker']
|
||||||
NDescriptions: typeof import('naive-ui')['NDescriptions']
|
|
||||||
NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem']
|
|
||||||
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
||||||
NDivider: typeof import('naive-ui')['NDivider']
|
NDivider: typeof import('naive-ui')['NDivider']
|
||||||
NDrawer: typeof import('naive-ui')['NDrawer']
|
NDrawer: typeof import('naive-ui')['NDrawer']
|
||||||
NDrawerContent: typeof import('naive-ui')['NDrawerContent']
|
NDrawerContent: typeof import('naive-ui')['NDrawerContent']
|
||||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||||
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
|
||||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||||
NFlex: typeof import('naive-ui')['NFlex']
|
|
||||||
NForm: typeof import('naive-ui')['NForm']
|
NForm: typeof import('naive-ui')['NForm']
|
||||||
NFormItem: typeof import('naive-ui')['NFormItem']
|
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||||
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||||
NGi: typeof import('naive-ui')['NGi']
|
NGi: typeof import('naive-ui')['NGi']
|
||||||
NGrid: typeof import('naive-ui')['NGrid']
|
NGrid: typeof import('naive-ui')['NGrid']
|
||||||
NIcon: typeof import('naive-ui')['NIcon']
|
|
||||||
NInput: typeof import('naive-ui')['NInput']
|
NInput: typeof import('naive-ui')['NInput']
|
||||||
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||||
NIput: typeof import('naive-ui')['NIput']
|
|
||||||
NList: typeof import('naive-ui')['NList']
|
|
||||||
NListItem: typeof import('naive-ui')['NListItem']
|
|
||||||
NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
|
NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
|
||||||
NMenu: typeof import('naive-ui')['NMenu']
|
NMenu: typeof import('naive-ui')['NMenu']
|
||||||
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||||
NModal: typeof import('naive-ui')['NModal']
|
NModal: typeof import('naive-ui')['NModal']
|
||||||
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
||||||
NPagination: typeof import('naive-ui')['NPagination']
|
|
||||||
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
|
|
||||||
NPopover: typeof import('naive-ui')['NPopover']
|
|
||||||
NProgress: typeof import('naive-ui')['NProgress']
|
|
||||||
NRadio: typeof import('naive-ui')['NRadio']
|
NRadio: typeof import('naive-ui')['NRadio']
|
||||||
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
|
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
|
||||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
NSelect: typeof import('naive-ui')['NSelect']
|
NSelect: typeof import('naive-ui')['NSelect']
|
||||||
NSkeleton: typeof import('naive-ui')['NSkeleton']
|
|
||||||
NSpace: typeof import('naive-ui')['NSpace']
|
NSpace: typeof import('naive-ui')['NSpace']
|
||||||
NSpin: typeof import('naive-ui')['NSpin']
|
|
||||||
NStatistic: typeof import('naive-ui')['NStatistic']
|
|
||||||
NStep: typeof import('naive-ui')['NStep']
|
|
||||||
NSteps: typeof import('naive-ui')['NSteps']
|
|
||||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||||
NTab: typeof import('naive-ui')['NTab']
|
NTab: typeof import('naive-ui')['NTab']
|
||||||
NTabPane: typeof import('naive-ui')['NTabPane']
|
|
||||||
NTabs: typeof import('naive-ui')['NTabs']
|
NTabs: typeof import('naive-ui')['NTabs']
|
||||||
NTag: typeof import('naive-ui')['NTag']
|
NTag: typeof import('naive-ui')['NTag']
|
||||||
NThing: typeof import('naive-ui')['NThing']
|
|
||||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
NTooltip: typeof import('naive-ui')['NTooltip']
|
||||||
NTree: typeof import('naive-ui')['NTree']
|
|
||||||
NWatermark: typeof import('naive-ui')['NWatermark']
|
NWatermark: typeof import('naive-ui')['NWatermark']
|
||||||
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
|
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
|
||||||
ProCard: typeof import('pro-naive-ui')['ProCard']
|
|
||||||
ProConfigProvider: typeof import('pro-naive-ui')['ProConfigProvider']
|
|
||||||
ProDataTable: typeof import('pro-naive-ui')['ProDataTable']
|
|
||||||
ProDate: typeof import('pro-naive-ui')['ProDate']
|
|
||||||
ProEditDataTable: typeof import('pro-naive-ui')['ProEditDataTable']
|
|
||||||
ProForm: typeof import('pro-naive-ui')['ProForm']
|
|
||||||
ProFormList: typeof import('pro-naive-ui')['ProFormList']
|
|
||||||
ProInput: typeof import('pro-naive-ui')['ProInput']
|
|
||||||
ProSearchForm: typeof import('pro-naive-ui')['ProSearchForm']
|
|
||||||
ProSelect: typeof import('pro-naive-ui')['ProSelect']
|
|
||||||
ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
|
ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
@@ -162,118 +103,59 @@ declare global {
|
|||||||
const GithubLink: typeof import('./../components/custom/github-link.vue')['default']
|
const GithubLink: typeof import('./../components/custom/github-link.vue')['default']
|
||||||
const IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
|
const IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
|
||||||
const IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
const IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
||||||
const IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
|
||||||
const IconCarbonPlay: typeof import('~icons/carbon/play')['default']
|
|
||||||
const IconCarbonStop: typeof import('~icons/carbon/stop')['default']
|
|
||||||
const IconCharmDownload: typeof import('~icons/charm/download')['default']
|
|
||||||
const IconF7CircleFill: typeof import('~icons/f7/circle-fill')['default']
|
|
||||||
const IconF7FlagCircleFill: typeof import('~icons/f7/flag-circle-fill')['default']
|
|
||||||
const IconFeQuestion: typeof import('~icons/fe/question')['default']
|
|
||||||
const IconFileIconsMicrosoftExcel: typeof import('~icons/file-icons/microsoft-excel')['default']
|
|
||||||
const IconGgRatio: typeof import('~icons/gg/ratio')['default']
|
|
||||||
const IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
const IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
||||||
const IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
const IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
||||||
const IconIconParkOutlineEqualRatio: typeof import('~icons/icon-park-outline/equal-ratio')['default']
|
|
||||||
const IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
|
|
||||||
const IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
|
|
||||||
const IconIcRoundRefresh: typeof import('~icons/ic/round-refresh')['default']
|
|
||||||
const IconIcRoundRemove: typeof import('~icons/ic/round-remove')['default']
|
|
||||||
const IconIcRoundSearch: typeof import('~icons/ic/round-search')['default']
|
|
||||||
const IconLocalActivity: typeof import('~icons/local/activity')['default']
|
|
||||||
const IconLocalBanner: typeof import('~icons/local/banner')['default']
|
|
||||||
const IconLocalCast: typeof import('~icons/local/cast')['default']
|
|
||||||
const IconMaterialSymbolsLightRotate90DegreesCcwOutlineRounded: typeof import('~icons/material-symbols-light/rotate90-degrees-ccw-outline-rounded')['default']
|
|
||||||
const IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
|
const IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
|
||||||
const IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
|
const IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
|
||||||
const IconMdiDrag: typeof import('~icons/mdi/drag')['default']
|
|
||||||
const IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
const IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
||||||
const IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
const IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
||||||
const IconMdiPrinter: typeof import('~icons/mdi/printer')['default']
|
|
||||||
const IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
|
||||||
const IconMingcuteZoomInLine: typeof import('~icons/mingcute/zoom-in-line')['default']
|
|
||||||
const IconMingcuteZoomOutLine: typeof import('~icons/mingcute/zoom-out-line')['default']
|
|
||||||
const IconOcticonPin16: typeof import('~icons/octicon/pin16')['default']
|
|
||||||
const IconOcticonPinSlash16: typeof import('~icons/octicon/pin-slash16')['default']
|
|
||||||
const IconTooltip: typeof import('./../components/common/icon-tooltip.vue')['default']
|
const IconTooltip: typeof import('./../components/common/icon-tooltip.vue')['default']
|
||||||
const IconUilSearch: typeof import('~icons/uil/search')['default']
|
const IconUilSearch: typeof import('~icons/uil/search')['default']
|
||||||
const LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
|
const LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
|
||||||
const LookForward: typeof import('./../components/custom/look-forward.vue')['default']
|
const LookForward: typeof import('./../components/custom/look-forward.vue')['default']
|
||||||
const MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
|
const MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
|
||||||
const NAlert: typeof import('naive-ui')['NAlert']
|
|
||||||
const NBadge: typeof import('naive-ui')['NBadge']
|
const NBadge: typeof import('naive-ui')['NBadge']
|
||||||
const NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
|
const NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
|
||||||
const NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
|
const NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
|
||||||
const NButton: typeof import('naive-ui')['NButton']
|
const NButton: typeof import('naive-ui')['NButton']
|
||||||
const NButtonGroup: typeof import('naive-ui')['NButtonGroup']
|
|
||||||
const NCard: typeof import('naive-ui')['NCard']
|
const NCard: typeof import('naive-ui')['NCard']
|
||||||
|
const NCascader: typeof import('naive-ui')['NCascader']
|
||||||
const NCheckbox: typeof import('naive-ui')['NCheckbox']
|
const NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||||
const NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
|
const NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
|
||||||
const NCollapse: typeof import('naive-ui')['NCollapse']
|
|
||||||
const NCollapseItem: typeof import('naive-ui')['NCollapseItem']
|
|
||||||
const NColorPicker: typeof import('naive-ui')['NColorPicker']
|
const NColorPicker: typeof import('naive-ui')['NColorPicker']
|
||||||
const NDataTable: typeof import('naive-ui')['NDataTable']
|
const NDataTable: typeof import('naive-ui')['NDataTable']
|
||||||
const NDatePicker: typeof import('naive-ui')['NDatePicker']
|
const NDatePicker: typeof import('naive-ui')['NDatePicker']
|
||||||
const NDescriptions: typeof import('naive-ui')['NDescriptions']
|
|
||||||
const NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem']
|
|
||||||
const NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
const NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
||||||
const NDivider: typeof import('naive-ui')['NDivider']
|
const NDivider: typeof import('naive-ui')['NDivider']
|
||||||
const NDrawer: typeof import('naive-ui')['NDrawer']
|
const NDrawer: typeof import('naive-ui')['NDrawer']
|
||||||
const NDrawerContent: typeof import('naive-ui')['NDrawerContent']
|
const NDrawerContent: typeof import('naive-ui')['NDrawerContent']
|
||||||
const NDropdown: typeof import('naive-ui')['NDropdown']
|
const NDropdown: typeof import('naive-ui')['NDropdown']
|
||||||
const NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
|
||||||
const NEmpty: typeof import('naive-ui')['NEmpty']
|
const NEmpty: typeof import('naive-ui')['NEmpty']
|
||||||
const NFlex: typeof import('naive-ui')['NFlex']
|
|
||||||
const NForm: typeof import('naive-ui')['NForm']
|
const NForm: typeof import('naive-ui')['NForm']
|
||||||
const NFormItem: typeof import('naive-ui')['NFormItem']
|
const NFormItem: typeof import('naive-ui')['NFormItem']
|
||||||
const NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
const NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||||
const NGi: typeof import('naive-ui')['NGi']
|
const NGi: typeof import('naive-ui')['NGi']
|
||||||
const NGrid: typeof import('naive-ui')['NGrid']
|
const NGrid: typeof import('naive-ui')['NGrid']
|
||||||
const NIcon: typeof import('naive-ui')['NIcon']
|
|
||||||
const NInput: typeof import('naive-ui')['NInput']
|
const NInput: typeof import('naive-ui')['NInput']
|
||||||
const NInputGroup: typeof import('naive-ui')['NInputGroup']
|
const NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||||
const NInputNumber: typeof import('naive-ui')['NInputNumber']
|
const NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||||
const NIput: typeof import('naive-ui')['NIput']
|
|
||||||
const NList: typeof import('naive-ui')['NList']
|
|
||||||
const NListItem: typeof import('naive-ui')['NListItem']
|
|
||||||
const NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
|
const NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
|
||||||
const NMenu: typeof import('naive-ui')['NMenu']
|
const NMenu: typeof import('naive-ui')['NMenu']
|
||||||
const NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
const NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||||
const NModal: typeof import('naive-ui')['NModal']
|
const NModal: typeof import('naive-ui')['NModal']
|
||||||
const NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
const NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
||||||
const NPagination: typeof import('naive-ui')['NPagination']
|
|
||||||
const NPopconfirm: typeof import('naive-ui')['NPopconfirm']
|
|
||||||
const NPopover: typeof import('naive-ui')['NPopover']
|
|
||||||
const NProgress: typeof import('naive-ui')['NProgress']
|
|
||||||
const NRadio: typeof import('naive-ui')['NRadio']
|
const NRadio: typeof import('naive-ui')['NRadio']
|
||||||
const NRadioGroup: typeof import('naive-ui')['NRadioGroup']
|
const NRadioGroup: typeof import('naive-ui')['NRadioGroup']
|
||||||
const NScrollbar: typeof import('naive-ui')['NScrollbar']
|
const NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
const NSelect: typeof import('naive-ui')['NSelect']
|
const NSelect: typeof import('naive-ui')['NSelect']
|
||||||
const NSkeleton: typeof import('naive-ui')['NSkeleton']
|
|
||||||
const NSpace: typeof import('naive-ui')['NSpace']
|
const NSpace: typeof import('naive-ui')['NSpace']
|
||||||
const NSpin: typeof import('naive-ui')['NSpin']
|
|
||||||
const NStatistic: typeof import('naive-ui')['NStatistic']
|
|
||||||
const NStep: typeof import('naive-ui')['NStep']
|
|
||||||
const NSteps: typeof import('naive-ui')['NSteps']
|
|
||||||
const NSwitch: typeof import('naive-ui')['NSwitch']
|
const NSwitch: typeof import('naive-ui')['NSwitch']
|
||||||
const NTab: typeof import('naive-ui')['NTab']
|
const NTab: typeof import('naive-ui')['NTab']
|
||||||
const NTabPane: typeof import('naive-ui')['NTabPane']
|
|
||||||
const NTabs: typeof import('naive-ui')['NTabs']
|
const NTabs: typeof import('naive-ui')['NTabs']
|
||||||
const NTag: typeof import('naive-ui')['NTag']
|
const NTag: typeof import('naive-ui')['NTag']
|
||||||
const NThing: typeof import('naive-ui')['NThing']
|
|
||||||
const NTooltip: typeof import('naive-ui')['NTooltip']
|
const NTooltip: typeof import('naive-ui')['NTooltip']
|
||||||
const NTree: typeof import('naive-ui')['NTree']
|
|
||||||
const NWatermark: typeof import('naive-ui')['NWatermark']
|
const NWatermark: typeof import('naive-ui')['NWatermark']
|
||||||
const PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
|
const PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
|
||||||
const ProCard: typeof import('pro-naive-ui')['ProCard']
|
|
||||||
const ProConfigProvider: typeof import('pro-naive-ui')['ProConfigProvider']
|
|
||||||
const ProDataTable: typeof import('pro-naive-ui')['ProDataTable']
|
|
||||||
const ProDate: typeof import('pro-naive-ui')['ProDate']
|
|
||||||
const ProEditDataTable: typeof import('pro-naive-ui')['ProEditDataTable']
|
|
||||||
const ProForm: typeof import('pro-naive-ui')['ProForm']
|
|
||||||
const ProFormList: typeof import('pro-naive-ui')['ProFormList']
|
|
||||||
const ProInput: typeof import('pro-naive-ui')['ProInput']
|
|
||||||
const ProSearchForm: typeof import('pro-naive-ui')['ProSearchForm']
|
|
||||||
const ProSelect: typeof import('pro-naive-ui')['ProSelect']
|
|
||||||
const ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
|
const ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
|
||||||
const RouterLink: typeof import('vue-router')['RouterLink']
|
const RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
const RouterView: typeof import('vue-router')['RouterView']
|
const RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
|||||||
Vendored
+8
@@ -35,6 +35,10 @@ declare module "@elegant-router/types" {
|
|||||||
"home_process": "/home/process";
|
"home_process": "/home/process";
|
||||||
"home_processdetail": "/home/processdetail";
|
"home_processdetail": "/home/processdetail";
|
||||||
"login": "/login/:module(pwd-login)?";
|
"login": "/login/:module(pwd-login)?";
|
||||||
|
"systemmanage": "/systemmanage";
|
||||||
|
"systemmanage_role": "/systemmanage/role";
|
||||||
|
"systemmanage_template": "/systemmanage/template";
|
||||||
|
"systemmanage_user": "/systemmanage/user";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,6 +78,7 @@ declare module "@elegant-router/types" {
|
|||||||
| "docs"
|
| "docs"
|
||||||
| "home"
|
| "home"
|
||||||
| "login"
|
| "login"
|
||||||
|
| "systemmanage"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,6 +110,9 @@ declare module "@elegant-router/types" {
|
|||||||
| "home_process"
|
| "home_process"
|
||||||
| "home_processdetail"
|
| "home_processdetail"
|
||||||
| "login"
|
| "login"
|
||||||
|
| "systemmanage_role"
|
||||||
|
| "systemmanage_template"
|
||||||
|
| "systemmanage_user"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ const downloadFile = (file:any) => {
|
|||||||
<Tag v-if="p.supplement" class="border-amber-200 bg-amber-100 px-1 py-0 text-[10px] text-amber-700">补充</Tag>
|
<Tag v-if="p.supplement" class="border-amber-200 bg-amber-100 px-1 py-0 text-[10px] text-amber-700">补充</Tag>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="scroll-left">
|
<template v-else>
|
||||||
<div v-for="u in tree" :key="u.unit">
|
<div v-for="u in tree" :key="u.unit">
|
||||||
<button @click="openUnits[u.unit] = !openUnits[u.unit]"
|
<button @click="openUnits[u.unit] = !openUnits[u.unit]"
|
||||||
class="flex w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left text-xs font-medium hover:bg-slate-50 bg-transparent">
|
class="flex w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left text-xs font-medium hover:bg-slate-50 bg-transparent">
|
||||||
@@ -246,7 +246,8 @@ const downloadFile = (file:any) => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右:归档包详情 -->
|
<!-- 右:归档包详情 -->
|
||||||
<div v-if="sel" class="rounded-lg border col-span-2">
|
<div v-if="sel" class="rounded-lg border col-span-2">
|
||||||
@@ -324,10 +325,6 @@ const downloadFile = (file:any) => {
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.scroll-left {
|
|
||||||
height: calc(100vh - 365px);
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
.scroll-right {
|
.scroll-right {
|
||||||
height: calc(100vh - 460px);
|
height: calc(100vh - 460px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@@ -42,22 +42,24 @@ const progressPct = (p: string) => {
|
|||||||
<NSpace vertical :size="16">
|
<NSpace vertical :size="16">
|
||||||
<!-- 我的草稿箱 -->
|
<!-- 我的草稿箱 -->
|
||||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive class="pb-[16px]">
|
<div class="border mb-3 py-3 px-4" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
<NGi span="24 s:24 m:16">
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
<div class="h-100% flex items-center gap-2">
|
<NGi span="24 s:24 m:16">
|
||||||
<Icon icon="akar-icons:file" class="size-16px" :style="{ color: themeStore.themeColor }" />
|
<div class="h-100% flex items-center gap-2">
|
||||||
<p class="text-sm font-600">我的草稿箱</p>
|
<Icon icon="akar-icons:file" class="size-16px" :style="{ color: themeStore.themeColor }" />
|
||||||
<span class="rounded bg-slate-100 px-1.5 text-xs font-semibold text-slate-700">{{ drafts.length }}</span>
|
<p class="text-sm font-600">我的草稿箱</p>
|
||||||
<p class="text-xs text-#94a3b8">草稿仅本人可见,提交后自动从草稿箱移除</p>
|
<span class="rounded bg-slate-100 px-1.5 text-xs font-semibold text-slate-700">{{ drafts.length }}</span>
|
||||||
</div>
|
<p class="text-xs text-#94a3b8">草稿仅本人可见,提交后自动从草稿箱移除</p>
|
||||||
</NGi>
|
</div>
|
||||||
<NGi span="24 s:24 m:8" class="flex items-center justify-end gap-12px">
|
</NGi>
|
||||||
<NButton type="primary" size="small" @click="emit('go', 'apply')">
|
<NGi span="24 s:24 m:8" class="flex items-center justify-end gap-12px">
|
||||||
<Icon icon="ic:round-plus" class="size-18px" />
|
<NButton type="primary" size="small" @click="emit('go', 'apply')">
|
||||||
新建空白变更
|
<Icon icon="ic:round-plus" class="size-16px" />
|
||||||
</NButton>
|
新建空白变更
|
||||||
</NGi>
|
</NButton>
|
||||||
</NGrid>
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
</div>
|
||||||
<div class="space-y-2 scroll">
|
<div class="space-y-2 scroll">
|
||||||
<div v-for="d in drafts" :key="d.id" class="rounded-lg border px-4 py-3">
|
<div v-for="d in drafts" :key="d.id" class="rounded-lg border px-4 py-3">
|
||||||
<div class="flex flex-wrap items-start gap-3">
|
<div class="flex flex-wrap items-start gap-3">
|
||||||
@@ -95,7 +97,7 @@ const progressPct = (p: string) => {
|
|||||||
</style>
|
</style>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.scroll {
|
.scroll {
|
||||||
height: calc(100vh - 190px);
|
height: calc(100vh - 212px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, h, onMounted } from 'vue';
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
import { Icon } from '@iconify/vue'
|
||||||
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { NButton, NPopconfirm } from 'naive-ui';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const themeStore = useThemeStore();
|
||||||
|
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||||
|
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const btnLoading = ref<boolean>(false);
|
||||||
|
const currentType = ref<string>('add');
|
||||||
|
const formRef = ref<any>(null);
|
||||||
|
const currentRole = ref<{ id: number, name: string }>({
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
});
|
||||||
|
const rules = ref({
|
||||||
|
name: { required: true, message: '角色名称不能为空', trigger: ['blur'] }
|
||||||
|
})
|
||||||
|
const roleModal = ref<boolean>(false);
|
||||||
|
const permissionModal = ref<boolean>(false);
|
||||||
|
const pagination = ref<{ page: number, pageSize: number, pageCount: number }>({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
pageCount: 0,
|
||||||
|
})
|
||||||
|
const columns = ref([
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
key: 'index',
|
||||||
|
width: 5,
|
||||||
|
align: 'center',
|
||||||
|
render: (_row: any, index: number) => {
|
||||||
|
return h('span', {}, { default: () => (pagination.value.page - 1) * pagination.value.pageSize + index + 1 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '角色名称',
|
||||||
|
key: 'name',
|
||||||
|
width: 44,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 8,
|
||||||
|
align: 'center',
|
||||||
|
render: (row: any) => {
|
||||||
|
return h('div', { class: 'flex items-center justify-center gap-3' }, {
|
||||||
|
default: () => [
|
||||||
|
h(NButton, {
|
||||||
|
text: true,
|
||||||
|
size: 'tiny',
|
||||||
|
type: 'primary',
|
||||||
|
onClick: () => handleSetPermission(row)
|
||||||
|
}, {
|
||||||
|
// 渲染按钮文本
|
||||||
|
default: () => '设置权限'
|
||||||
|
}),
|
||||||
|
h(NButton, {
|
||||||
|
text: true,
|
||||||
|
size: 'tiny',
|
||||||
|
type: 'primary',
|
||||||
|
onClick: () => handleEdit(row)
|
||||||
|
}, {
|
||||||
|
// 渲染按钮文本
|
||||||
|
default: () => '编辑'
|
||||||
|
}),
|
||||||
|
h(NPopconfirm, {
|
||||||
|
// 组件 Props
|
||||||
|
positiveText: '确定',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: () => {
|
||||||
|
handleDelete(row)
|
||||||
|
},
|
||||||
|
// 可选:自定义确认/取消按钮的样式
|
||||||
|
positiveButtonProps: { size: 'tiny', type: 'primary' },
|
||||||
|
negativeButtonProps: { size: 'tiny' }
|
||||||
|
}, {
|
||||||
|
// 插槽 (Slots)
|
||||||
|
trigger: () => h(NButton,
|
||||||
|
{
|
||||||
|
text: true,
|
||||||
|
size: 'tiny',
|
||||||
|
type: 'error',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => '删除' // 按钮文字
|
||||||
|
}
|
||||||
|
),
|
||||||
|
default: () => '确定要删除吗?' // 弹出框的提示内容
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const list = ref<{ id: number, name: string }[]>([])
|
||||||
|
|
||||||
|
// 获取列表
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false;
|
||||||
|
list.value = [
|
||||||
|
{id:1,name:'角色名称1'},
|
||||||
|
{id:2,name:'角色名称2'},
|
||||||
|
{id:3,name:'角色名称3'},
|
||||||
|
{id:4,name:'角色名称4'},
|
||||||
|
{id:5,name:'角色名称5'},
|
||||||
|
{id:6,name:'角色名称6'},
|
||||||
|
{id:7,name:'角色名称7'},
|
||||||
|
{id:8,name:'角色名称8'},
|
||||||
|
{id:9,name:'角色名称9'},
|
||||||
|
{id:10,name:'角色名称10'},
|
||||||
|
{id:11,name:'角色名称11'},
|
||||||
|
{id:12,name:'角色名称12'},
|
||||||
|
]
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开添加角色弹框
|
||||||
|
const addRole = () => {
|
||||||
|
currentType.value = 'add';
|
||||||
|
currentRole.value = {
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
};
|
||||||
|
roleModal.value = true;
|
||||||
|
}
|
||||||
|
// 设置权限
|
||||||
|
const handleSetPermission = (row: any) => {
|
||||||
|
currentRole.value = {
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
};
|
||||||
|
permissionModal.value = true;
|
||||||
|
}
|
||||||
|
// 编辑角色
|
||||||
|
const handleEdit = (row: any) => {
|
||||||
|
currentType.value = 'edit';
|
||||||
|
currentRole.value = {
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
};
|
||||||
|
roleModal.value = true;
|
||||||
|
}
|
||||||
|
// 删除角色
|
||||||
|
const handleDelete = (row: any) => {
|
||||||
|
loading.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false;
|
||||||
|
list.value = list.value.filter((item: any) => item.id !== row.id);
|
||||||
|
window.$message?.success('删除成功')
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
// 保存角色
|
||||||
|
const saveRole = async (e: MouseEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
formRef.value?.validate((errors: any) => {
|
||||||
|
if (!errors) {
|
||||||
|
btnLoading.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
// 新增
|
||||||
|
if(currentType.value === 'add'){
|
||||||
|
list.value.push({id:list.value.length+1,name:currentRole.value?.name})
|
||||||
|
}
|
||||||
|
// 编辑
|
||||||
|
if(currentType.value === 'edit'){
|
||||||
|
const target = list.value.find((item:any) => item.id === currentRole.value.id);
|
||||||
|
if (target) {
|
||||||
|
target.name = currentRole.value?.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.$message?.success('操作成功')
|
||||||
|
btnLoading.value = false;
|
||||||
|
roleModal.value = false;
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const allRoutes = router.getRoutes();
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NSpace vertical :size="16">
|
||||||
|
<!-- 角色管理 -->
|
||||||
|
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
|
<div class="border mb-3 py-2 px-3" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
|
<NGi span="24 s:12 m:12">
|
||||||
|
<div class="h-100% flex items-center gap-2">
|
||||||
|
<Icon icon="lucide:user" class="size-16px" :style="{ color: themeStore.themeColor }" />
|
||||||
|
<p class="text-[16px] font-600">角色管理</p>
|
||||||
|
</div>
|
||||||
|
</NGi>
|
||||||
|
<NGi span="24 s:12 m:12" class="flex items-center justify-end gap-12px">
|
||||||
|
<NButton type="primary" size="small" @click="addRole">
|
||||||
|
<Icon icon="ic:round-plus" class="size-16px" />
|
||||||
|
添加角色
|
||||||
|
</NButton>
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
</div>
|
||||||
|
<div class="scroll">
|
||||||
|
<NDataTable
|
||||||
|
size="small"
|
||||||
|
:loading="loading"
|
||||||
|
:single-line="false"
|
||||||
|
:columns="columns"
|
||||||
|
:data="list"
|
||||||
|
:pagination="pagination"
|
||||||
|
max-height="calc(100vh - 290px)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- 新增或编辑弹框 -->
|
||||||
|
<NModal
|
||||||
|
v-model:show="roleModal"
|
||||||
|
preset="card"
|
||||||
|
:title="currentType === 'add' ? '新增角色' : '编辑角色'"
|
||||||
|
:auto-focus="false"
|
||||||
|
:style="{ width: '450px', height: 'auto' }"
|
||||||
|
:segmented="{ content: true, footer: true }"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<NForm ref="formRef" :model="currentRole" :rules="rules" label-placement="left" label-width="auto">
|
||||||
|
<NFormItem label="角色名称" path="name">
|
||||||
|
<NInput
|
||||||
|
v-model:value="currentRole.name"
|
||||||
|
placeholder="请输入角色名称"
|
||||||
|
/>
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex justify-end gap-[10px]">
|
||||||
|
<NButton @click="roleModal = false">取消</NButton>
|
||||||
|
<NButton type="primary" :loading="btnLoading" @click="saveRole">确定</NButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</NModal>
|
||||||
|
<!-- 设置权限抽屉 -->
|
||||||
|
<NDrawer v-model:show="permissionModal" :width="502" placement="right">
|
||||||
|
<NDrawerContent :title="`设置权限-${currentRole.name}`" closable>
|
||||||
|
|
||||||
|
</NDrawerContent>
|
||||||
|
</NDrawer>
|
||||||
|
</NCard>
|
||||||
|
</NSpace>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.scroll {
|
||||||
|
height: calc(100vh - 205px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,547 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, h, onMounted } from 'vue';
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
import { Icon } from '@iconify/vue'
|
||||||
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const themeStore = useThemeStore();
|
||||||
|
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||||
|
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const btnLoading = ref<boolean>(false);
|
||||||
|
const currentType = ref<string>('add');
|
||||||
|
const readonly = computed(() => currentType.value === "view");
|
||||||
|
const formRef = ref<any>(null);
|
||||||
|
const currentTemplate = ref<{ id: number, category: string | null, level: string | null, timeLimit: string | null, steps: any[] }>({
|
||||||
|
id: 0,
|
||||||
|
category: null,
|
||||||
|
level: null,
|
||||||
|
timeLimit: null,
|
||||||
|
steps: [],
|
||||||
|
});
|
||||||
|
const rules = ref({
|
||||||
|
category: { required: true, message: '变更类别不能为空', trigger: ['blur'] },
|
||||||
|
level: { required: true, message: '变更等级不能为空', trigger: ['blur'] },
|
||||||
|
timeLimit: { required: true, message: '变更时效不能为空', trigger: ['blur'] },
|
||||||
|
step: { required: true, message: '审批步骤不能为空', trigger: ['blur'] }
|
||||||
|
})
|
||||||
|
const templateModal = ref<boolean>(false);
|
||||||
|
|
||||||
|
const categoryOptions = ref([
|
||||||
|
{
|
||||||
|
label: '工艺',
|
||||||
|
value: '工艺'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备',
|
||||||
|
value: '设备'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '管理',
|
||||||
|
value: '管理'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const levelOptions = ref([
|
||||||
|
{
|
||||||
|
label: '一般',
|
||||||
|
value: '一般'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '重要',
|
||||||
|
value: '重要'
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const timeLimitOptions = ref([
|
||||||
|
{
|
||||||
|
label: '永久',
|
||||||
|
value: '永久'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '临时',
|
||||||
|
value: '临时'
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const SPECIALTIES = ref<{ label: string, value: string }[]>([
|
||||||
|
{ label: '工艺', value: 'process' },
|
||||||
|
{ label: '设备', value: 'equipment' },
|
||||||
|
{ label: '仪表', value: 'instrument' },
|
||||||
|
{ label: '电气', value: 'electrical' },
|
||||||
|
{ label: '安全', value: 'safety' },
|
||||||
|
{ label: '质量', value: 'quality' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const pagination = ref<{ page: number, pageSize: number, pageCount: number }>({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
pageCount: 0,
|
||||||
|
})
|
||||||
|
const columns = ref([
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
key: 'index',
|
||||||
|
width: 6,
|
||||||
|
align: 'center',
|
||||||
|
render: (row: any, index: number) => {
|
||||||
|
return h('span', {}, { default: () => (pagination.value.page - 1) * pagination.value.pageSize + index + 1 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '变更类别',
|
||||||
|
key: 'category',
|
||||||
|
width: 8,
|
||||||
|
align: 'center',
|
||||||
|
render: (row: any, index: number) => {
|
||||||
|
return h(NTag, {
|
||||||
|
size: 'small',
|
||||||
|
type: 'default'
|
||||||
|
}, { default: () => `${row.category}` })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '变更等级',
|
||||||
|
key: 'level',
|
||||||
|
width: 8,
|
||||||
|
align: 'center',
|
||||||
|
render: (row: any, index: number) => {
|
||||||
|
return h(NTag, {
|
||||||
|
size: 'small',
|
||||||
|
type: `${row.level==='重要'?'error':'default'}`
|
||||||
|
}, { default: () => `${row.level}` })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '变更时效',
|
||||||
|
key: 'timeLimit',
|
||||||
|
width: 8,
|
||||||
|
align: 'center',
|
||||||
|
render: (row: any, index: number) => {
|
||||||
|
return h(NTag, {
|
||||||
|
size: 'small',
|
||||||
|
type: `${row.timeLimit==='临时'?'warning':'info'}`
|
||||||
|
}, { default: () => `${row.timeLimit}` })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '审批步骤',
|
||||||
|
key: 'step',
|
||||||
|
width: 44,
|
||||||
|
align: 'center',
|
||||||
|
render: (row: any) => {
|
||||||
|
const stepNames = row.steps?.map((step: any) => step.name) || [];
|
||||||
|
const text = stepNames.join(' → ');
|
||||||
|
return h('p', { class: 'text-left text-xs' }, text || '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 12,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
render: (row: any) => {
|
||||||
|
return h('div', { class: 'flex items-center justify-center gap-3' }, {
|
||||||
|
default: () => [
|
||||||
|
h(NButton, {
|
||||||
|
text: true,
|
||||||
|
size: 'tiny',
|
||||||
|
type: 'primary',
|
||||||
|
onClick: () => handleView(row)
|
||||||
|
}, {
|
||||||
|
// 渲染按钮文本
|
||||||
|
default: () => '查看'
|
||||||
|
}),
|
||||||
|
h(NButton, {
|
||||||
|
text: true,
|
||||||
|
size: 'tiny',
|
||||||
|
type: 'primary',
|
||||||
|
onClick: () => handleEdit(row)
|
||||||
|
}, {
|
||||||
|
// 渲染按钮文本
|
||||||
|
default: () => '编辑'
|
||||||
|
}),
|
||||||
|
h(NPopconfirm, {
|
||||||
|
// 组件 Props
|
||||||
|
positiveText: '确定',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: () => {
|
||||||
|
handleDelete(row)
|
||||||
|
},
|
||||||
|
// 可选:自定义确认/取消按钮的样式
|
||||||
|
positiveButtonProps: { size: 'tiny', type: 'primary' },
|
||||||
|
negativeButtonProps: { size: 'tiny' }
|
||||||
|
}, {
|
||||||
|
// 插槽 (Slots)
|
||||||
|
trigger: () => h(NButton,
|
||||||
|
{
|
||||||
|
text: true,
|
||||||
|
size: 'tiny',
|
||||||
|
type: 'error',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => '删除' // 按钮文字
|
||||||
|
}
|
||||||
|
),
|
||||||
|
default: () => '确定要删除吗?' // 弹出框的提示内容
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const list = ref<{ id: number, category: string, level: string, timeLimit: string, steps: any[] }[]>([])
|
||||||
|
|
||||||
|
// 获取列表
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false;
|
||||||
|
list.value = [
|
||||||
|
{id:1,category:'工艺',level:'重要',timeLimit:'临时',steps: [
|
||||||
|
{
|
||||||
|
id:101,
|
||||||
|
name:'部门审核',
|
||||||
|
countersign: false,
|
||||||
|
members: [{person:'测试人员01',specialty:'',countersign:false}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:102,
|
||||||
|
name:'专业审批',
|
||||||
|
countersign: false,
|
||||||
|
members: [{person:'测试人员02',specialty:'',countersign:false}]
|
||||||
|
},
|
||||||
|
{id: 103,
|
||||||
|
name: "部门负责人批准",
|
||||||
|
countersign: false,
|
||||||
|
members: [ {person:'测试人员03',specialty:'',countersign:false}]
|
||||||
|
}
|
||||||
|
]},
|
||||||
|
{id:2,category:'设备',level:'一般',timeLimit:'临时',steps:[
|
||||||
|
|
||||||
|
]},
|
||||||
|
{id:3,category:'管理',level:'重要',timeLimit:'永久',steps:[
|
||||||
|
|
||||||
|
]},
|
||||||
|
{id:4,category:'工艺',level:'重要',timeLimit:'临时',steps:[
|
||||||
|
|
||||||
|
]},
|
||||||
|
|
||||||
|
]
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开添加模板弹框
|
||||||
|
const addTemplate = () => {
|
||||||
|
currentType.value = 'add';
|
||||||
|
currentTemplate.value = {
|
||||||
|
id: 0,
|
||||||
|
category: null,
|
||||||
|
level: null,
|
||||||
|
timeLimit: null,
|
||||||
|
steps: [],
|
||||||
|
};
|
||||||
|
templateModal.value = true;
|
||||||
|
}
|
||||||
|
// 查看模板
|
||||||
|
const handleView = (row: any) => {
|
||||||
|
currentType.value = 'view';
|
||||||
|
currentTemplate.value = {
|
||||||
|
id: row.id,
|
||||||
|
category: row.category,
|
||||||
|
level: row.level,
|
||||||
|
timeLimit: row.timeLimit,
|
||||||
|
steps: row.steps,
|
||||||
|
};
|
||||||
|
templateModal.value = true;
|
||||||
|
}
|
||||||
|
// 编辑角色
|
||||||
|
const handleEdit = (row: any) => {
|
||||||
|
currentType.value = 'edit';
|
||||||
|
currentTemplate.value = {
|
||||||
|
id: row.id,
|
||||||
|
category: row.category,
|
||||||
|
level: row.level,
|
||||||
|
timeLimit: row.timeLimit,
|
||||||
|
steps: row.steps,
|
||||||
|
};
|
||||||
|
templateModal.value = true;
|
||||||
|
}
|
||||||
|
// 删除角色
|
||||||
|
const handleDelete = (row: any) => {
|
||||||
|
loading.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false;
|
||||||
|
list.value = list.value.filter((item: any) => item.id !== row.id);
|
||||||
|
window.$message?.success('删除成功')
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
// 保存角色
|
||||||
|
const saveRole = async (e: MouseEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
formRef.value?.validate((errors: any) => {
|
||||||
|
if (!errors) {
|
||||||
|
btnLoading.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
// 新增
|
||||||
|
if(currentType.value === 'add'){
|
||||||
|
list.value.push({
|
||||||
|
id:list.value.length+1,
|
||||||
|
category:currentTemplate.value?.category as string,
|
||||||
|
level:currentTemplate.value?.level as string,
|
||||||
|
timeLimit:currentTemplate.value?.timeLimit as string,
|
||||||
|
steps:currentTemplate.value?.steps as any[]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 编辑
|
||||||
|
if(currentType.value === 'edit'){
|
||||||
|
const target = list.value.find((item:any) => item.id === currentTemplate.value.id);
|
||||||
|
if (target) {
|
||||||
|
target.category = currentTemplate.value?.category as string;
|
||||||
|
target.level = currentTemplate.value?.level as string;
|
||||||
|
target.timeLimit = currentTemplate.value?.timeLimit as string;
|
||||||
|
target.steps = currentTemplate.value?.steps as any[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.$message?.success('操作成功')
|
||||||
|
btnLoading.value = false;
|
||||||
|
templateModal.value = false;
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 会签步骤:一个模板最多一步;只有会签步骤能选专业。
|
||||||
|
// 勾选/取消后,所有非会签步骤的人员专业与「必须会签」标记一并清空
|
||||||
|
const setStepCountersign = (target: any, v: boolean) => {
|
||||||
|
currentTemplate.value.steps.forEach((s:any) => {
|
||||||
|
s.countersign = s === target ? v : false;
|
||||||
|
if (!s.countersign) s.members.forEach((m:any) => { m.specialty = ""; m.countersign = false; });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 当前打开人员选择器的步骤(步骤行「+」按钮切换)
|
||||||
|
const pickerStepId = ref<number | null>(null);
|
||||||
|
const pick = ref<string | null>(null);
|
||||||
|
const togglePicker = (s: any) => {
|
||||||
|
pickerStepId.value = pickerStepId.value === s.id ? null : s.id;
|
||||||
|
pick.value = null;
|
||||||
|
}
|
||||||
|
const addMember = (s: any, v: string | null) => {
|
||||||
|
if (v && !s.members.some((m:any) => m.person === v)) s.members.push({ person: v, specialty: "", countersign: false });
|
||||||
|
pick.value = null;
|
||||||
|
pickerStepId.value = null;
|
||||||
|
}
|
||||||
|
const delMember = (s: any, p: string) => {
|
||||||
|
s.members = s.members.filter((m:any) => m.person !== p);
|
||||||
|
}
|
||||||
|
const removeStep = (idx: number) => {
|
||||||
|
currentTemplate.value.steps.splice(idx, 1);
|
||||||
|
}
|
||||||
|
let sid = 100;
|
||||||
|
const mkStep = (name: string, extra: Partial<any> = {}): any => ({ id: ++sid, name, countersign: false, members: [], ...extra });
|
||||||
|
const addStepAfter = (idx: number) => {
|
||||||
|
currentTemplate.value.steps.splice(idx + 1, 0, mkStep(""));
|
||||||
|
}
|
||||||
|
const ORG_TREE = [
|
||||||
|
{
|
||||||
|
id: "factory", name: "演示工厂", short: "YS", leaf: false, sort: 0,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: "scb", name: "生产部", short: "SCB", leaf: false, sort: 0,
|
||||||
|
children: [
|
||||||
|
{ id: "cj1", name: "测试车间一", short: "CJ1", leaf: true, sort: 0 },
|
||||||
|
{ id: "cj2", name: "测试车间二", short: "CJ2", leaf: true, sort: 1 },
|
||||||
|
{ id: "cj3", name: "测试车间三", short: "CJ3", leaf: true, sort: 2 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ahb", name: "安环部", short: "AHB", leaf: false, sort: 1,
|
||||||
|
children: [
|
||||||
|
{ id: "aqk", name: "安全科", short: "AQK", leaf: true, sort: 0 },
|
||||||
|
{ id: "hbk", name: "环保科", short: "HBK", leaf: true, sort: 1 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "sbb", name: "设备部", short: "SBB", leaf: false, sort: 2,
|
||||||
|
children: [
|
||||||
|
{ id: "sbk", name: "设备科", short: "SBK", leaf: true, sort: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "zlb", name: "质量部", short: "ZLB", leaf: false, sort: 3,
|
||||||
|
children: [
|
||||||
|
{ id: "zjk", name: "质检科", short: "ZJK", leaf: true, sort: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const LEVEL2_ORGS = ORG_TREE[0]?.children ?? [];
|
||||||
|
const ORG_MEMBERS = [
|
||||||
|
{ id: 1, name: "测试人员01", dept: "测试车间一", gender: "男", phone: "13800000001", email: "test01@demo.com", account: "TEST001", role: "操作人员", scope: ["factory"], enabled: true },
|
||||||
|
{ id: 2, name: "测试人员02", dept: "测试车间二", gender: "女", phone: "13800000002", email: "test02@demo.com", account: "TEST002", role: "班长", scope: ["factory"], enabled: true },
|
||||||
|
{ id: 3, name: "测试人员03", dept: "测试车间三", gender: "男", phone: "13800000003", email: "test03@demo.com", account: "TEST003", role: "车间主任", scope: ["factory"], enabled: true },
|
||||||
|
{ id: 4, name: "测试人员04", dept: "安全科", gender: "女", phone: "13800000004", email: "test04@demo.com", account: "TEST004", role: "安全工程师", scope: ["factory"], enabled: true },
|
||||||
|
{ id: 5, name: "测试人员05", dept: "环保科", gender: "男", phone: "13800000005", email: "test05@demo.com", account: "TEST005", role: "环保专员", scope: ["factory"], enabled: true },
|
||||||
|
{ id: 6, name: "测试人员06", dept: "设备科", gender: "男", phone: "13800000006", email: "test06@demo.com", account: "TEST006", role: "设备工程师", scope: ["factory"], enabled: true },
|
||||||
|
{ id: 7, name: "测试人员07", dept: "质检科", gender: "女", phone: "13800000007", email: "test07@demo.com", account: "TEST007", role: "质量工程师", scope: ["factory"], enabled: true },
|
||||||
|
];
|
||||||
|
function orgSubtreeNames(n: any): string[] {
|
||||||
|
return [n.name, ...(n.children ?? []).flatMap(orgSubtreeNames)];
|
||||||
|
}
|
||||||
|
// 预设人员:级联选项(第二层组织 → 组织下可选成员,已选成员不再出现,空组织不展示)
|
||||||
|
const peopleOpts = (s: any) =>
|
||||||
|
LEVEL2_ORGS.map((o) => ({
|
||||||
|
label: o.name,
|
||||||
|
value: o.id,
|
||||||
|
children: ORG_MEMBERS
|
||||||
|
.filter((m) => m.enabled && orgSubtreeNames(o).includes(m.dept) && !s.members.some((x) => x.person === m.name))
|
||||||
|
.map((m) => ({ label: m.name, value: m.name })),
|
||||||
|
})).filter((o) => o.children.length > 0);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NSpace vertical :size="16">
|
||||||
|
<!-- 角色管理 -->
|
||||||
|
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
|
<div class="border mb-3 py-2 px-3" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
|
<NGi span="24 s:12 m:12">
|
||||||
|
<div class="h-100% flex items-center gap-2">
|
||||||
|
<Icon icon="carbon:flow-connection" class="size-18px" :style="{ color: themeStore.themeColor }" />
|
||||||
|
<p class="text-[16px] font-600">审批模板管理</p>
|
||||||
|
</div>
|
||||||
|
</NGi>
|
||||||
|
<NGi span="24 s:12 m:12" class="flex items-center justify-end gap-12px">
|
||||||
|
<NButton type="primary" size="small" @click="addTemplate">
|
||||||
|
<Icon icon="ic:round-plus" class="size-16px" />
|
||||||
|
添加模板
|
||||||
|
</NButton>
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
</div>
|
||||||
|
<div class="scroll">
|
||||||
|
<NDataTable
|
||||||
|
size="small"
|
||||||
|
:loading="loading"
|
||||||
|
:single-line="false"
|
||||||
|
:columns="columns"
|
||||||
|
:data="list"
|
||||||
|
:pagination="pagination"
|
||||||
|
max-height="calc(100vh - 290px)"
|
||||||
|
:scroll-x="820"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- 新增/编辑/查看弹框 -->
|
||||||
|
<NModal
|
||||||
|
v-model:show="templateModal"
|
||||||
|
preset="card"
|
||||||
|
:title="currentType === 'add' ? '新增模板' : currentType === 'edit' ? '编辑模板':'查看模板'"
|
||||||
|
:auto-focus="false"
|
||||||
|
:style="{ width: '800px', height: 'auto' }"
|
||||||
|
:segmented="{ content: true, footer: true }"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<NForm class="w-full" ref="formRef" :model="currentTemplate" :rules="rules" label-placement="left" label-width="auto">
|
||||||
|
<NGrid :cols="24" :x-gap="24">
|
||||||
|
<NFormItemGi :span="8" label="变更类别" path="category">
|
||||||
|
<NSelect
|
||||||
|
v-model:value="currentTemplate.category"
|
||||||
|
:options="categoryOptions"
|
||||||
|
:disabled="readonly"
|
||||||
|
placeholder="请选择"
|
||||||
|
/>
|
||||||
|
</NFormItemGi>
|
||||||
|
<NFormItemGi :span="8" label="变更等级" path="level">
|
||||||
|
<NSelect
|
||||||
|
v-model:value="currentTemplate.level"
|
||||||
|
:options="levelOptions"
|
||||||
|
:disabled="readonly"
|
||||||
|
placeholder="请选择"
|
||||||
|
/>
|
||||||
|
</NFormItemGi>
|
||||||
|
<NFormItemGi :span="8" label="变更时效" path="timeLimit">
|
||||||
|
<NSelect
|
||||||
|
v-model:value="currentTemplate.timeLimit"
|
||||||
|
:options="timeLimitOptions"
|
||||||
|
:disabled="readonly"
|
||||||
|
placeholder="请选择"
|
||||||
|
/>
|
||||||
|
</NFormItemGi>
|
||||||
|
</NGrid>
|
||||||
|
<!-- 审批步骤 -->
|
||||||
|
<div class="flex flex-col gap-3 mb-3">
|
||||||
|
<div v-for="(s, idx) in currentTemplate.steps" :key="s.id" class="rounded-lg border border-slate-100 bg-slate-50/40 p-3">
|
||||||
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
|
<span class="w-7 shrink-0 text-center text-xs text-slate-400">{{ idx + 1 }}</span>
|
||||||
|
<NInput v-model:value="s.name" maxlength="12" :disabled="readonly" placeholder="步骤名称(如:部门审核)" class="!w-48 text-sm" />
|
||||||
|
<NCheckbox :checked="s.countersign" :disabled="readonly" size="small" @update:checked="(v) => setStepCountersign(s, v)">
|
||||||
|
<span class="text-xs text-slate-500">专业会签步骤</span>
|
||||||
|
</NCheckbox>
|
||||||
|
<NButton v-if="!readonly" ghost type="primary" size="tiny" @click="togglePicker(s)" title="添加预设人员" class="ml-auto">
|
||||||
|
<Icon icon="ic:round-plus" class="size-16px" />
|
||||||
|
</NButton>
|
||||||
|
<NButton v-if="!readonly" text type="error" @click="removeStep(idx)" title="删除该步骤">
|
||||||
|
<Icon icon="iconamoon:trash" class="size-16px" />
|
||||||
|
</NButton>
|
||||||
|
</div>
|
||||||
|
<!-- 预设人员:人员必选;仅会签步骤可选择专业(必选),且人员可勾选「必须进行专业会签」 -->
|
||||||
|
<div class="mt-2 flex gap-2 pl-10">
|
||||||
|
<span class="shrink-0 text-xs leading-7 text-slate-400">预设人员:</span>
|
||||||
|
<div class="min-w-0 flex-1 space-y-1.5">
|
||||||
|
<div v-for="m in s.members" :key="m.person" class="flex min-h-7 flex-wrap items-center gap-2">
|
||||||
|
<span class="w-20 shrink-0 truncate text-xs font-medium text-slate-700">{{ m.person }}</span>
|
||||||
|
<template v-if="s.countersign">
|
||||||
|
<span class="text-xs text-slate-400"><span class="mr-0.5 text-red-500">*</span>专业:</span>
|
||||||
|
<NSelect :value="m.specialty || null" clearable size="small" placeholder="请选择专业" class="w-28"
|
||||||
|
:options="SPECIALTIES"
|
||||||
|
@update:value="(v) => m.specialty = v ?? ''"
|
||||||
|
/>
|
||||||
|
<NCheckbox :checked="m.countersign" size="small"
|
||||||
|
@update:checked="(v) => m.countersign = v"
|
||||||
|
>
|
||||||
|
<span class="text-xs text-slate-500">必须参与会签</span>
|
||||||
|
</NCheckbox>
|
||||||
|
</template>
|
||||||
|
<NButton v-if="!readonly" text type="error" @click="delMember(s, m.person)" title="删除该人员">
|
||||||
|
<Icon icon="iconamoon:trash" class="size-16px" />
|
||||||
|
</NButton>
|
||||||
|
</div>
|
||||||
|
<p v-if="s.countersign && s.members.length" class="text-[11px] leading-5 text-slate-400">
|
||||||
|
必须参与会签:勾选的人员必须参与专业会签,未勾选的人员为可选会签(按需参加)
|
||||||
|
</p>
|
||||||
|
<NCascader v-if="!readonly && pickerStepId === s.id" :value="pick" :options="peopleOpts(s)"
|
||||||
|
placeholder="请选择人员" size="small" check-strategy="child" :show-path="false" expand-trigger="click"
|
||||||
|
class="w-56" @update:value="(v) => addMember(s, v == null ? null : String(v))" />
|
||||||
|
<span v-if="readonly && s.members.length === 0" class="text-xs leading-7 text-slate-300">未预设</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NButton v-if="!readonly" size="small" ghost dashed class="text-xs" @click="addStepAfter(currentTemplate.steps.length - 1)"><Icon icon="ic:round-plus" class="size-14px" />添加审批步骤</NButton>
|
||||||
|
</NForm>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div v-if="!readonly" class="flex justify-end gap-[10px]">
|
||||||
|
<NButton @click="templateModal = false">取消</NButton>
|
||||||
|
<NButton type="primary" :loading="btnLoading" @click="saveRole">确定</NButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</NModal>
|
||||||
|
</NCard>
|
||||||
|
</NSpace>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.scroll {
|
||||||
|
height: calc(100vh - 205px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, h, onMounted } from 'vue';
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
import { Icon } from '@iconify/vue'
|
||||||
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { NButton, NPopconfirm } from 'naive-ui';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const themeStore = useThemeStore();
|
||||||
|
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NSpace vertical :size="16">
|
||||||
|
用户
|
||||||
|
</NSpace>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.scroll {
|
||||||
|
height: calc(100vh - 205px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user