mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-17 17:26:38 +08:00
feat(projects): make branch main
tiny & modify request retry times to 0
This commit is contained in:
parent
cf9fc7d31f
commit
793b16e9ba
@ -8,20 +8,6 @@ export function setupElegantRouter() {
|
|||||||
base: 'src/layouts/base-layout/index.vue',
|
base: 'src/layouts/base-layout/index.vue',
|
||||||
blank: 'src/layouts/blank-layout/index.vue'
|
blank: 'src/layouts/blank-layout/index.vue'
|
||||||
},
|
},
|
||||||
customRoutes: {
|
|
||||||
names: [
|
|
||||||
'exception_403',
|
|
||||||
'exception_404',
|
|
||||||
'exception_500',
|
|
||||||
'document_project',
|
|
||||||
'document_project-link',
|
|
||||||
'document_vue',
|
|
||||||
'document_vite',
|
|
||||||
'document_unocss',
|
|
||||||
'document_naive',
|
|
||||||
'document_antd'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
routePathTransformer(routeName, routePath) {
|
routePathTransformer(routeName, routePath) {
|
||||||
const key = routeName as RouteKey;
|
const key = routeName as RouteKey;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export function createDefaultOptions<ResponseData = any>(options?: Partial<Reque
|
|||||||
|
|
||||||
export function createRetryOptions(config?: Partial<CreateAxiosDefaults>) {
|
export function createRetryOptions(config?: Partial<CreateAxiosDefaults>) {
|
||||||
const retryConfig: IAxiosRetryConfig = {
|
const retryConfig: IAxiosRetryConfig = {
|
||||||
retries: 3
|
retries: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(retryConfig, config);
|
Object.assign(retryConfig, config);
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import { transformRecordToOption } from '@/utils/common';
|
|
||||||
|
|
||||||
export const enableStatusRecord: Record<Api.Common.EnableStatus, App.I18n.I18nKey> = {
|
|
||||||
'1': 'page.manage.common.status.enable',
|
|
||||||
'2': 'page.manage.common.status.disable'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const enableStatusOptions = transformRecordToOption(enableStatusRecord);
|
|
||||||
|
|
||||||
export const userGenderRecord: Record<Api.SystemManage.UserGender, App.I18n.I18nKey> = {
|
|
||||||
'1': 'page.manage.user.gender.male',
|
|
||||||
'2': 'page.manage.user.gender.female'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const userGenderOptions = transformRecordToOption(userGenderRecord);
|
|
||||||
|
|
||||||
export const menuTypeRecord: Record<Api.SystemManage.MenuType, App.I18n.I18nKey> = {
|
|
||||||
'1': 'page.manage.menu.type.directory',
|
|
||||||
'2': 'page.manage.menu.type.menu'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const menuTypeOptions = transformRecordToOption(menuTypeRecord);
|
|
||||||
|
|
||||||
export const menuIconTypeRecord: Record<Api.SystemManage.IconType, App.I18n.I18nKey> = {
|
|
||||||
'1': 'page.manage.menu.iconType.iconify',
|
|
||||||
'2': 'page.manage.menu.iconType.local'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const menuIconTypeOptions = transformRecordToOption(menuIconTypeRecord);
|
|
@ -18,7 +18,7 @@ function loginOrRegister() {
|
|||||||
toLogin();
|
toLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
type DropdownKey = 'user-center' | 'logout';
|
type DropdownKey = 'logout';
|
||||||
|
|
||||||
type DropdownOption =
|
type DropdownOption =
|
||||||
| {
|
| {
|
||||||
@ -33,15 +33,6 @@ type DropdownOption =
|
|||||||
|
|
||||||
const options = computed(() => {
|
const options = computed(() => {
|
||||||
const opts: DropdownOption[] = [
|
const opts: DropdownOption[] = [
|
||||||
{
|
|
||||||
label: $t('common.userCenter'),
|
|
||||||
key: 'user-center',
|
|
||||||
icon: SvgIconVNode({ icon: 'ph:user-circle', fontSize: 18 })
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'divider',
|
|
||||||
key: 'divider'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: $t('common.logout'),
|
label: $t('common.logout'),
|
||||||
key: 'logout',
|
key: 'logout',
|
||||||
@ -68,6 +59,7 @@ function handleDropdown(key: DropdownKey) {
|
|||||||
if (key === 'logout') {
|
if (key === 'logout') {
|
||||||
logout();
|
logout();
|
||||||
} else {
|
} else {
|
||||||
|
// If your other options are jumps from other routes, they will be directly supported here
|
||||||
routerPushByKey(key);
|
routerPushByKey(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ const local: App.I18n.Schema = {
|
|||||||
deleteSuccess: 'Delete Success',
|
deleteSuccess: 'Delete Success',
|
||||||
confirmDelete: 'Are you sure you want to delete?',
|
confirmDelete: 'Are you sure you want to delete?',
|
||||||
edit: 'Edit',
|
edit: 'Edit',
|
||||||
|
warning: 'Warning',
|
||||||
error: 'Error',
|
error: 'Error',
|
||||||
index: 'Index',
|
index: 'Index',
|
||||||
keywordSearch: 'Please enter keyword',
|
keywordSearch: 'Please enter keyword',
|
||||||
@ -147,42 +148,7 @@ const local: App.I18n.Schema = {
|
|||||||
404: 'Page Not Found',
|
404: 'Page Not Found',
|
||||||
500: 'Server Error',
|
500: 'Server Error',
|
||||||
'iframe-page': 'Iframe',
|
'iframe-page': 'Iframe',
|
||||||
home: 'Home',
|
home: 'Home'
|
||||||
document: 'Document',
|
|
||||||
document_project: 'Project Document',
|
|
||||||
'document_project-link': 'Project Document(External Link)',
|
|
||||||
document_vue: 'Vue Document',
|
|
||||||
document_vite: 'Vite Document',
|
|
||||||
document_unocss: 'UnoCSS Document',
|
|
||||||
document_naive: 'Naive UI Document',
|
|
||||||
document_antd: 'Ant Design Vue Document',
|
|
||||||
'user-center': 'User Center',
|
|
||||||
about: 'About',
|
|
||||||
function: 'System Function',
|
|
||||||
function_tab: 'Tab',
|
|
||||||
'function_multi-tab': 'Multi Tab',
|
|
||||||
'function_hide-child': 'Hide Child',
|
|
||||||
'function_hide-child_one': 'Hide Child',
|
|
||||||
'function_hide-child_two': 'Two',
|
|
||||||
'function_hide-child_three': 'Three',
|
|
||||||
function_request: 'Request',
|
|
||||||
'function_toggle-auth': 'Toggle Auth',
|
|
||||||
'function_super-page': 'Super Admin Visible',
|
|
||||||
manage: 'System Manage',
|
|
||||||
manage_user: 'User Manage',
|
|
||||||
'manage_user-detail': 'User Detail',
|
|
||||||
manage_role: 'Role Manage',
|
|
||||||
manage_menu: 'Menu Manage',
|
|
||||||
'multi-menu': 'Multi Menu',
|
|
||||||
'multi-menu_first': 'Menu One',
|
|
||||||
'multi-menu_first_child': 'Menu One Child',
|
|
||||||
'multi-menu_second': 'Menu Two',
|
|
||||||
'multi-menu_second_child': 'Menu Two Child',
|
|
||||||
'multi-menu_second_child_home': 'Menu Two Child Home',
|
|
||||||
exception: 'Exception',
|
|
||||||
exception_403: '403',
|
|
||||||
exception_404: '404',
|
|
||||||
exception_500: '500'
|
|
||||||
},
|
},
|
||||||
page: {
|
page: {
|
||||||
login: {
|
login: {
|
||||||
@ -231,20 +197,9 @@ const local: App.I18n.Schema = {
|
|||||||
title: 'Bind WeChat'
|
title: 'Bind WeChat'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
about: {
|
|
||||||
title: 'About',
|
|
||||||
introduction: `SoybeanAdmin is an elegant and powerful admin template, based on the latest front-end technology stack, including Vue3, Vite5, TypeScript, Pinia and UnoCSS. It has built-in rich theme configuration and components, strict code specifications, and an automated file routing system. In addition, it also uses the online mock data solution based on ApiFox. SoybeanAdmin provides you with a one-stop admin solution, no additional configuration, and out of the box. It is also a best practice for learning cutting-edge technologies quickly.`,
|
|
||||||
projectInfo: {
|
|
||||||
title: 'Project Info',
|
|
||||||
version: 'Version',
|
|
||||||
latestBuildTime: 'Latest Build Time',
|
|
||||||
githubLink: 'Github Link',
|
|
||||||
previewLink: 'Preview Link'
|
|
||||||
},
|
|
||||||
prdDep: 'Production Dependency',
|
|
||||||
devDep: 'Development Dependency'
|
|
||||||
},
|
|
||||||
home: {
|
home: {
|
||||||
|
branchDesc:
|
||||||
|
'For the convenience of everyone in developing and updating the merge, we have streamlined the code of the main branch, only retaining the homepage menu, and the rest of the content has been moved to the example branch for maintenance. The preview address displays the content of the example branch.',
|
||||||
greeting: 'Good morning, {userName}, today is another day full of vitality!',
|
greeting: 'Good morning, {userName}, today is another day full of vitality!',
|
||||||
weatherDesc: 'Today is cloudy to clear, 20℃ - 25℃!',
|
weatherDesc: 'Today is cloudy to clear, 20℃ - 25℃!',
|
||||||
projectCount: 'Project Count',
|
projectCount: 'Project Count',
|
||||||
@ -270,163 +225,6 @@ const local: App.I18n.Schema = {
|
|||||||
desc5: 'Soybean just wrote some of the workbench pages casually, and it was enough to see!'
|
desc5: 'Soybean just wrote some of the workbench pages casually, and it was enough to see!'
|
||||||
},
|
},
|
||||||
creativity: 'Creativity'
|
creativity: 'Creativity'
|
||||||
},
|
|
||||||
function: {
|
|
||||||
tab: {
|
|
||||||
tabOperate: {
|
|
||||||
title: 'Tab Operation',
|
|
||||||
addTab: 'Add Tab',
|
|
||||||
addTabDesc: 'To about page',
|
|
||||||
closeTab: 'Close Tab',
|
|
||||||
closeCurrentTab: 'Close Current Tab',
|
|
||||||
closeAboutTab: 'Close "About" Tab',
|
|
||||||
addMultiTab: 'Add Multi Tab',
|
|
||||||
addMultiTabDesc1: 'To MultiTab page',
|
|
||||||
addMultiTabDesc2: 'To MultiTab page(with query params)'
|
|
||||||
},
|
|
||||||
tabTitle: {
|
|
||||||
title: 'Tab Title',
|
|
||||||
changeTitle: 'Change Title',
|
|
||||||
change: 'Change',
|
|
||||||
resetTitle: 'Reset Title',
|
|
||||||
reset: 'Reset'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
multiTab: {
|
|
||||||
routeParam: 'Route Param',
|
|
||||||
backTab: 'Back function_tab'
|
|
||||||
},
|
|
||||||
toggleAuth: {
|
|
||||||
toggleAccount: 'Toggle Account',
|
|
||||||
authHook: 'Auth Hook Function `hasAuth`',
|
|
||||||
superAdminVisible: 'Super Admin Visible',
|
|
||||||
adminVisible: 'Admin Visible',
|
|
||||||
adminOrUserVisible: 'Admin and User Visible'
|
|
||||||
},
|
|
||||||
request: {
|
|
||||||
repeatedErrorOccurOnce: 'Repeated Request Error Occurs Once',
|
|
||||||
repeatedError: 'Repeated Request Error',
|
|
||||||
repeatedErrorMsg1: 'Custom Request Error 1',
|
|
||||||
repeatedErrorMsg2: 'Custom Request Error 2'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
manage: {
|
|
||||||
common: {
|
|
||||||
status: {
|
|
||||||
enable: 'Enable',
|
|
||||||
disable: 'Disable'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
title: 'Role List',
|
|
||||||
roleName: 'Role Name',
|
|
||||||
roleCode: 'Role Code',
|
|
||||||
roleStatus: 'Role Status',
|
|
||||||
roleDesc: 'Role Description',
|
|
||||||
menuAuth: 'Menu Auth',
|
|
||||||
buttonAuth: 'Button Auth',
|
|
||||||
form: {
|
|
||||||
roleName: 'Please enter role name',
|
|
||||||
roleCode: 'Please enter role code',
|
|
||||||
roleStatus: 'Please select role status',
|
|
||||||
roleDesc: 'Please enter role description'
|
|
||||||
},
|
|
||||||
addRole: 'Add Role',
|
|
||||||
editRole: 'Edit Role'
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
title: 'User List',
|
|
||||||
userName: 'User Name',
|
|
||||||
userGender: 'Gender',
|
|
||||||
nickName: 'Nick Name',
|
|
||||||
userPhone: 'Phone Number',
|
|
||||||
userEmail: 'Email',
|
|
||||||
userStatus: 'User Status',
|
|
||||||
userRole: 'User Role',
|
|
||||||
form: {
|
|
||||||
userName: 'Please enter user name',
|
|
||||||
userGender: 'Please select gender',
|
|
||||||
nickName: 'Please enter nick name',
|
|
||||||
userPhone: 'Please enter phone number',
|
|
||||||
userEmail: 'Please enter email',
|
|
||||||
userStatus: 'Please select user status',
|
|
||||||
userRole: 'Please select user role'
|
|
||||||
},
|
|
||||||
addUser: 'Add User',
|
|
||||||
editUser: 'Edit User',
|
|
||||||
gender: {
|
|
||||||
male: 'Male',
|
|
||||||
female: 'Female'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
menu: {
|
|
||||||
home: 'Home',
|
|
||||||
title: 'Menu List',
|
|
||||||
id: 'ID',
|
|
||||||
parentId: 'Parent ID',
|
|
||||||
menuType: 'Menu Type',
|
|
||||||
menuName: 'Menu Name',
|
|
||||||
routeName: 'Route Name',
|
|
||||||
routePath: 'Route Path',
|
|
||||||
pathParam: 'Path Param',
|
|
||||||
layout: 'Layout Component',
|
|
||||||
page: 'Page Component',
|
|
||||||
i18nKey: 'I18n Key',
|
|
||||||
icon: 'Icon',
|
|
||||||
localIcon: 'Local Icon',
|
|
||||||
iconTypeTitle: 'Icon Type',
|
|
||||||
order: 'Order',
|
|
||||||
constant: 'Constant',
|
|
||||||
keepAlive: 'Keep Alive',
|
|
||||||
href: 'Href',
|
|
||||||
hideInMenu: 'Hide In Menu',
|
|
||||||
activeMenu: 'Active Menu',
|
|
||||||
multiTab: 'Multi Tab',
|
|
||||||
fixedIndexInTab: 'Fixed Index In Tab',
|
|
||||||
query: 'Query Params',
|
|
||||||
button: 'Button',
|
|
||||||
buttonCode: 'Button Code',
|
|
||||||
buttonDesc: 'Button Desc',
|
|
||||||
menuStatus: 'Menu Status',
|
|
||||||
form: {
|
|
||||||
home: 'Please select home',
|
|
||||||
menuType: 'Please select menu type',
|
|
||||||
menuName: 'Please enter menu name',
|
|
||||||
routeName: 'Please enter route name',
|
|
||||||
routePath: 'Please enter route path',
|
|
||||||
pathParam: 'Please enter path param',
|
|
||||||
page: 'Please select page component',
|
|
||||||
layout: 'Please select layout component',
|
|
||||||
i18nKey: 'Please enter i18n key',
|
|
||||||
icon: 'Please enter iconify name',
|
|
||||||
localIcon: 'Please enter local icon name',
|
|
||||||
order: 'Please enter order',
|
|
||||||
keepAlive: 'Please select whether to cache route',
|
|
||||||
href: 'Please enter href',
|
|
||||||
hideInMenu: 'Please select whether to hide menu',
|
|
||||||
activeMenu: 'Please select route name of the highlighted menu',
|
|
||||||
multiTab: 'Please select whether to support multiple tabs',
|
|
||||||
fixedInTab: 'Please select whether to fix in the tab',
|
|
||||||
fixedIndexInTab: 'Please enter the index fixed in the tab',
|
|
||||||
queryKey: 'Please enter route parameter Key',
|
|
||||||
queryValue: 'Please enter route parameter Value',
|
|
||||||
button: 'Please select whether it is a button',
|
|
||||||
buttonCode: 'Please enter button code',
|
|
||||||
buttonDesc: 'Please enter button description',
|
|
||||||
menuStatus: 'Please select menu status'
|
|
||||||
},
|
|
||||||
addMenu: 'Add Menu',
|
|
||||||
editMenu: 'Edit Menu',
|
|
||||||
addChildMenu: 'Add Child Menu',
|
|
||||||
type: {
|
|
||||||
directory: 'Directory',
|
|
||||||
menu: 'Menu'
|
|
||||||
},
|
|
||||||
iconType: {
|
|
||||||
iconify: 'Iconify Icon',
|
|
||||||
local: 'Local Icon'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
|
@ -23,6 +23,7 @@ const local: App.I18n.Schema = {
|
|||||||
deleteSuccess: '删除成功',
|
deleteSuccess: '删除成功',
|
||||||
confirmDelete: '确认删除吗?',
|
confirmDelete: '确认删除吗?',
|
||||||
edit: '编辑',
|
edit: '编辑',
|
||||||
|
warning: '警告',
|
||||||
error: '错误',
|
error: '错误',
|
||||||
index: '序号',
|
index: '序号',
|
||||||
keywordSearch: '请输入关键词搜索',
|
keywordSearch: '请输入关键词搜索',
|
||||||
@ -147,42 +148,7 @@ const local: App.I18n.Schema = {
|
|||||||
404: '页面不存在',
|
404: '页面不存在',
|
||||||
500: '服务器错误',
|
500: '服务器错误',
|
||||||
'iframe-page': '外链页面',
|
'iframe-page': '外链页面',
|
||||||
home: '首页',
|
home: '首页'
|
||||||
document: '文档',
|
|
||||||
document_project: '项目文档',
|
|
||||||
'document_project-link': '项目文档(外链)',
|
|
||||||
document_vue: 'Vue文档',
|
|
||||||
document_vite: 'Vite文档',
|
|
||||||
document_unocss: 'UnoCSS文档',
|
|
||||||
document_naive: 'Naive UI文档',
|
|
||||||
document_antd: 'Ant Design Vue文档',
|
|
||||||
'user-center': '个人中心',
|
|
||||||
about: '关于',
|
|
||||||
function: '系统功能',
|
|
||||||
function_tab: '标签页',
|
|
||||||
'function_multi-tab': '多标签页',
|
|
||||||
'function_hide-child': '隐藏子菜单',
|
|
||||||
'function_hide-child_one': '隐藏子菜单',
|
|
||||||
'function_hide-child_two': '菜单二',
|
|
||||||
'function_hide-child_three': '菜单三',
|
|
||||||
function_request: '请求',
|
|
||||||
'function_toggle-auth': '切换权限',
|
|
||||||
'function_super-page': '超级管理员可见',
|
|
||||||
manage: '系统管理',
|
|
||||||
manage_user: '用户管理',
|
|
||||||
'manage_user-detail': '用户详情',
|
|
||||||
manage_role: '角色管理',
|
|
||||||
manage_menu: '菜单管理',
|
|
||||||
'multi-menu': '多级菜单',
|
|
||||||
'multi-menu_first': '菜单一',
|
|
||||||
'multi-menu_first_child': '菜单一子菜单',
|
|
||||||
'multi-menu_second': '菜单二',
|
|
||||||
'multi-menu_second_child': '菜单二子菜单',
|
|
||||||
'multi-menu_second_child_home': '菜单二子菜单首页',
|
|
||||||
exception: '异常页',
|
|
||||||
exception_403: '403',
|
|
||||||
exception_404: '404',
|
|
||||||
exception_500: '500'
|
|
||||||
},
|
},
|
||||||
page: {
|
page: {
|
||||||
login: {
|
login: {
|
||||||
@ -231,20 +197,9 @@ const local: App.I18n.Schema = {
|
|||||||
title: '绑定微信'
|
title: '绑定微信'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
about: {
|
|
||||||
title: '关于',
|
|
||||||
introduction: `SoybeanAdmin 是一个优雅且功能强大的后台管理模板,基于最新的前端技术栈,包括 Vue3, Vite5, TypeScript, Pinia 和 UnoCSS。它内置了丰富的主题配置和组件,代码规范严谨,实现了自动化的文件路由系统。此外,它还采用了基于 ApiFox 的在线Mock数据方案。SoybeanAdmin 为您提供了一站式的后台管理解决方案,无需额外配置,开箱即用。同样是一个快速学习前沿技术的最佳实践。`,
|
|
||||||
projectInfo: {
|
|
||||||
title: '项目信息',
|
|
||||||
version: '版本',
|
|
||||||
latestBuildTime: '最新构建时间',
|
|
||||||
githubLink: 'Github 地址',
|
|
||||||
previewLink: '预览地址'
|
|
||||||
},
|
|
||||||
prdDep: '生产依赖',
|
|
||||||
devDep: '开发依赖'
|
|
||||||
},
|
|
||||||
home: {
|
home: {
|
||||||
|
branchDesc:
|
||||||
|
'为了方便大家开发和更新合并,我们对main分支的代码进行了精简,只保留了首页菜单,其余内容已移至example分支进行维护。预览地址显示的内容即为example分支的内容。',
|
||||||
greeting: '早安,{userName}, 今天又是充满活力的一天!',
|
greeting: '早安,{userName}, 今天又是充满活力的一天!',
|
||||||
weatherDesc: '今日多云转晴,20℃ - 25℃!',
|
weatherDesc: '今日多云转晴,20℃ - 25℃!',
|
||||||
projectCount: '项目数',
|
projectCount: '项目数',
|
||||||
@ -270,163 +225,6 @@ const local: App.I18n.Schema = {
|
|||||||
desc5: 'Soybean 刚才把工作台页面随便写了一些,凑合能看了!'
|
desc5: 'Soybean 刚才把工作台页面随便写了一些,凑合能看了!'
|
||||||
},
|
},
|
||||||
creativity: '创意'
|
creativity: '创意'
|
||||||
},
|
|
||||||
function: {
|
|
||||||
tab: {
|
|
||||||
tabOperate: {
|
|
||||||
title: '标签页操作',
|
|
||||||
addTab: '添加标签页',
|
|
||||||
addTabDesc: '跳转到关于页面',
|
|
||||||
closeTab: '关闭标签页',
|
|
||||||
closeCurrentTab: '关闭当前标签页',
|
|
||||||
closeAboutTab: '关闭"关于"标签页',
|
|
||||||
addMultiTab: '添加多标签页',
|
|
||||||
addMultiTabDesc1: '跳转到多标签页页面',
|
|
||||||
addMultiTabDesc2: '跳转到多标签页页面(带有查询参数)'
|
|
||||||
},
|
|
||||||
tabTitle: {
|
|
||||||
title: '标签页标题',
|
|
||||||
changeTitle: '修改标题',
|
|
||||||
change: '修改',
|
|
||||||
resetTitle: '重置标题',
|
|
||||||
reset: '重置'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
multiTab: {
|
|
||||||
routeParam: '路由参数',
|
|
||||||
backTab: '返回 function_tab'
|
|
||||||
},
|
|
||||||
toggleAuth: {
|
|
||||||
toggleAccount: '切换账号',
|
|
||||||
authHook: '权限钩子函数 `hasAuth`',
|
|
||||||
superAdminVisible: '超级管理员可见',
|
|
||||||
adminVisible: '管理员可见',
|
|
||||||
adminOrUserVisible: '管理员和用户可见'
|
|
||||||
},
|
|
||||||
request: {
|
|
||||||
repeatedErrorOccurOnce: '重复请求错误只出现一次',
|
|
||||||
repeatedError: '重复请求错误',
|
|
||||||
repeatedErrorMsg1: '自定义请求错误 1',
|
|
||||||
repeatedErrorMsg2: '自定义请求错误 2'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
manage: {
|
|
||||||
common: {
|
|
||||||
status: {
|
|
||||||
enable: '启用',
|
|
||||||
disable: '禁用'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
title: '角色列表',
|
|
||||||
roleName: '角色名称',
|
|
||||||
roleCode: '角色编码',
|
|
||||||
roleStatus: '角色状态',
|
|
||||||
roleDesc: '角色描述',
|
|
||||||
menuAuth: '菜单权限',
|
|
||||||
buttonAuth: '按钮权限',
|
|
||||||
form: {
|
|
||||||
roleName: '请输入角色名称',
|
|
||||||
roleCode: '请输入角色编码',
|
|
||||||
roleStatus: '请选择角色状态',
|
|
||||||
roleDesc: '请输入角色描述'
|
|
||||||
},
|
|
||||||
addRole: '新增角色',
|
|
||||||
editRole: '编辑角色'
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
title: '用户列表',
|
|
||||||
userName: '用户名',
|
|
||||||
userGender: '性别',
|
|
||||||
nickName: '昵称',
|
|
||||||
userPhone: '手机号',
|
|
||||||
userEmail: '邮箱',
|
|
||||||
userStatus: '用户状态',
|
|
||||||
userRole: '用户角色',
|
|
||||||
form: {
|
|
||||||
userName: '请输入用户名',
|
|
||||||
userGender: '请选择性别',
|
|
||||||
nickName: '请输入昵称',
|
|
||||||
userPhone: '请输入手机号',
|
|
||||||
userEmail: '请输入邮箱',
|
|
||||||
userStatus: '请选择用户状态',
|
|
||||||
userRole: '请选择用户角色'
|
|
||||||
},
|
|
||||||
addUser: '新增用户',
|
|
||||||
editUser: '编辑用户',
|
|
||||||
gender: {
|
|
||||||
male: '男',
|
|
||||||
female: '女'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
menu: {
|
|
||||||
home: '首页',
|
|
||||||
title: '菜单列表',
|
|
||||||
id: 'ID',
|
|
||||||
parentId: '父级菜单ID',
|
|
||||||
menuType: '菜单类型',
|
|
||||||
menuName: '菜单名称',
|
|
||||||
routeName: '路由名称',
|
|
||||||
routePath: '路由路径',
|
|
||||||
pathParam: '路径参数',
|
|
||||||
layout: '布局',
|
|
||||||
page: '页面组件',
|
|
||||||
i18nKey: '国际化key',
|
|
||||||
icon: '图标',
|
|
||||||
localIcon: '本地图标',
|
|
||||||
iconTypeTitle: '图标类型',
|
|
||||||
order: '排序',
|
|
||||||
constant: '常量路由',
|
|
||||||
keepAlive: '缓存路由',
|
|
||||||
href: '外链',
|
|
||||||
hideInMenu: '隐藏菜单',
|
|
||||||
activeMenu: '高亮的菜单',
|
|
||||||
multiTab: '支持多页签',
|
|
||||||
fixedIndexInTab: '固定在页签中的序号',
|
|
||||||
query: '路由参数',
|
|
||||||
button: '按钮',
|
|
||||||
buttonCode: '按钮编码',
|
|
||||||
buttonDesc: '按钮描述',
|
|
||||||
menuStatus: '菜单状态',
|
|
||||||
form: {
|
|
||||||
home: '请选择首页',
|
|
||||||
menuType: '请选择菜单类型',
|
|
||||||
menuName: '请输入菜单名称',
|
|
||||||
routeName: '请输入路由名称',
|
|
||||||
routePath: '请输入路由路径',
|
|
||||||
pathParam: '请输入路径参数',
|
|
||||||
page: '请选择页面组件',
|
|
||||||
layout: '请选择布局组件',
|
|
||||||
i18nKey: '请输入国际化key',
|
|
||||||
icon: '请输入图标',
|
|
||||||
localIcon: '请选择本地图标',
|
|
||||||
order: '请输入排序',
|
|
||||||
keepAlive: '请选择是否缓存路由',
|
|
||||||
href: '请输入外链',
|
|
||||||
hideInMenu: '请选择是否隐藏菜单',
|
|
||||||
activeMenu: '请选择高亮的菜单的路由名称',
|
|
||||||
multiTab: '请选择是否支持多标签',
|
|
||||||
fixedInTab: '请选择是否固定在页签中',
|
|
||||||
fixedIndexInTab: '请输入固定在页签中的序号',
|
|
||||||
queryKey: '请输入路由参数Key',
|
|
||||||
queryValue: '请输入路由参数Value',
|
|
||||||
button: '请选择是否按钮',
|
|
||||||
buttonCode: '请输入按钮编码',
|
|
||||||
buttonDesc: '请输入按钮描述',
|
|
||||||
menuStatus: '请选择菜单状态'
|
|
||||||
},
|
|
||||||
addMenu: '新增菜单',
|
|
||||||
editMenu: '编辑菜单',
|
|
||||||
addChildMenu: '新增子菜单',
|
|
||||||
type: {
|
|
||||||
directory: '目录',
|
|
||||||
menu: '菜单'
|
|
||||||
},
|
|
||||||
iconType: {
|
|
||||||
iconify: 'iconify图标',
|
|
||||||
local: '本地图标'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
|
@ -20,21 +20,5 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
|||||||
500: () => import("@/views/_builtin/500/index.vue"),
|
500: () => import("@/views/_builtin/500/index.vue"),
|
||||||
"iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"),
|
"iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"),
|
||||||
login: () => import("@/views/_builtin/login/index.vue"),
|
login: () => import("@/views/_builtin/login/index.vue"),
|
||||||
about: () => import("@/views/about/index.vue"),
|
|
||||||
"function_hide-child_one": () => import("@/views/function/hide-child/one/index.vue"),
|
|
||||||
"function_hide-child_three": () => import("@/views/function/hide-child/three/index.vue"),
|
|
||||||
"function_hide-child_two": () => import("@/views/function/hide-child/two/index.vue"),
|
|
||||||
"function_multi-tab": () => import("@/views/function/multi-tab/index.vue"),
|
|
||||||
function_request: () => import("@/views/function/request/index.vue"),
|
|
||||||
"function_super-page": () => import("@/views/function/super-page/index.vue"),
|
|
||||||
function_tab: () => import("@/views/function/tab/index.vue"),
|
|
||||||
"function_toggle-auth": () => import("@/views/function/toggle-auth/index.vue"),
|
|
||||||
home: () => import("@/views/home/index.vue"),
|
home: () => import("@/views/home/index.vue"),
|
||||||
manage_menu: () => import("@/views/manage/menu/index.vue"),
|
|
||||||
manage_role: () => import("@/views/manage/role/index.vue"),
|
|
||||||
"manage_user-detail": () => import("@/views/manage/user-detail/[id].vue"),
|
|
||||||
manage_user: () => import("@/views/manage/user/index.vue"),
|
|
||||||
"multi-menu_first_child": () => import("@/views/multi-menu/first_child/index.vue"),
|
|
||||||
"multi-menu_second_child_home": () => import("@/views/multi-menu/second_child_home/index.vue"),
|
|
||||||
"user-center": () => import("@/views/user-center/index.vue"),
|
|
||||||
};
|
};
|
||||||
|
@ -39,135 +39,6 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
hideInMenu: true
|
hideInMenu: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'about',
|
|
||||||
path: '/about',
|
|
||||||
component: 'layout.base$view.about',
|
|
||||||
meta: {
|
|
||||||
title: 'about',
|
|
||||||
i18nKey: 'route.about',
|
|
||||||
icon: 'fluent:book-information-24-regular',
|
|
||||||
order: 10
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function',
|
|
||||||
path: '/function',
|
|
||||||
component: 'layout.base',
|
|
||||||
meta: {
|
|
||||||
title: 'function',
|
|
||||||
i18nKey: 'route.function',
|
|
||||||
icon: 'icon-park-outline:all-application',
|
|
||||||
order: 6
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'function_hide-child',
|
|
||||||
path: '/function/hide-child',
|
|
||||||
meta: {
|
|
||||||
title: 'function_hide-child',
|
|
||||||
i18nKey: 'route.function_hide-child',
|
|
||||||
icon: 'material-symbols:filter-list-off',
|
|
||||||
order: 2
|
|
||||||
},
|
|
||||||
redirect: '/function/hide-child/one',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'function_hide-child_one',
|
|
||||||
path: '/function/hide-child/one',
|
|
||||||
component: 'view.function_hide-child_one',
|
|
||||||
meta: {
|
|
||||||
title: 'function_hide-child_one',
|
|
||||||
i18nKey: 'route.function_hide-child_one',
|
|
||||||
icon: 'material-symbols:filter-list-off',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: 'function_hide-child'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_hide-child_three',
|
|
||||||
path: '/function/hide-child/three',
|
|
||||||
component: 'view.function_hide-child_three',
|
|
||||||
meta: {
|
|
||||||
title: 'function_hide-child_three',
|
|
||||||
i18nKey: 'route.function_hide-child_three',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: 'function_hide-child'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_hide-child_two',
|
|
||||||
path: '/function/hide-child/two',
|
|
||||||
component: 'view.function_hide-child_two',
|
|
||||||
meta: {
|
|
||||||
title: 'function_hide-child_two',
|
|
||||||
i18nKey: 'route.function_hide-child_two',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: 'function_hide-child'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_multi-tab',
|
|
||||||
path: '/function/multi-tab',
|
|
||||||
component: 'view.function_multi-tab',
|
|
||||||
meta: {
|
|
||||||
title: 'function_multi-tab',
|
|
||||||
i18nKey: 'route.function_multi-tab',
|
|
||||||
icon: 'ic:round-tab',
|
|
||||||
multiTab: true,
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: 'function_tab'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_request',
|
|
||||||
path: '/function/request',
|
|
||||||
component: 'view.function_request',
|
|
||||||
meta: {
|
|
||||||
title: 'function_request',
|
|
||||||
i18nKey: 'route.function_request',
|
|
||||||
icon: 'carbon:network-overlay',
|
|
||||||
order: 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_super-page',
|
|
||||||
path: '/function/super-page',
|
|
||||||
component: 'view.function_super-page',
|
|
||||||
meta: {
|
|
||||||
title: 'function_super-page',
|
|
||||||
i18nKey: 'route.function_super-page',
|
|
||||||
icon: 'ic:round-supervisor-account',
|
|
||||||
order: 5,
|
|
||||||
roles: ['R_SUPER']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_tab',
|
|
||||||
path: '/function/tab',
|
|
||||||
component: 'view.function_tab',
|
|
||||||
meta: {
|
|
||||||
title: 'function_tab',
|
|
||||||
i18nKey: 'route.function_tab',
|
|
||||||
icon: 'ic:round-tab',
|
|
||||||
order: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_toggle-auth',
|
|
||||||
path: '/function/toggle-auth',
|
|
||||||
component: 'view.function_toggle-auth',
|
|
||||||
meta: {
|
|
||||||
title: 'function_toggle-auth',
|
|
||||||
i18nKey: 'route.function_toggle-auth',
|
|
||||||
icon: 'ic:round-construction',
|
|
||||||
order: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'home',
|
name: 'home',
|
||||||
path: '/home',
|
path: '/home',
|
||||||
@ -203,141 +74,5 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
constant: true,
|
constant: true,
|
||||||
hideInMenu: true
|
hideInMenu: true
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'manage',
|
|
||||||
path: '/manage',
|
|
||||||
component: 'layout.base',
|
|
||||||
meta: {
|
|
||||||
title: 'manage',
|
|
||||||
i18nKey: 'route.manage',
|
|
||||||
icon: 'carbon:cloud-service-management',
|
|
||||||
order: 9,
|
|
||||||
roles: ['R_ADMIN']
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'manage_menu',
|
|
||||||
path: '/manage/menu',
|
|
||||||
component: 'view.manage_menu',
|
|
||||||
meta: {
|
|
||||||
title: 'manage_menu',
|
|
||||||
i18nKey: 'route.manage_menu',
|
|
||||||
icon: 'material-symbols:route',
|
|
||||||
order: 3,
|
|
||||||
roles: ['R_ADMIN'],
|
|
||||||
keepAlive: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'manage_role',
|
|
||||||
path: '/manage/role',
|
|
||||||
component: 'view.manage_role',
|
|
||||||
meta: {
|
|
||||||
title: 'manage_role',
|
|
||||||
i18nKey: 'route.manage_role',
|
|
||||||
icon: 'carbon:user-role',
|
|
||||||
order: 2,
|
|
||||||
roles: ['R_SUPER']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'manage_user',
|
|
||||||
path: '/manage/user',
|
|
||||||
component: 'view.manage_user',
|
|
||||||
meta: {
|
|
||||||
title: 'manage_user',
|
|
||||||
i18nKey: 'route.manage_user',
|
|
||||||
icon: 'ic:round-manage-accounts',
|
|
||||||
order: 1,
|
|
||||||
roles: ['R_ADMIN']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'manage_user-detail',
|
|
||||||
path: '/manage/user-detail/:id',
|
|
||||||
component: 'view.manage_user-detail',
|
|
||||||
props: true,
|
|
||||||
meta: {
|
|
||||||
title: 'manage_user-detail',
|
|
||||||
i18nKey: 'route.manage_user-detail',
|
|
||||||
hideInMenu: true,
|
|
||||||
roles: ['R_ADMIN'],
|
|
||||||
activeMenu: 'manage_user'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'multi-menu',
|
|
||||||
path: '/multi-menu',
|
|
||||||
component: 'layout.base',
|
|
||||||
meta: {
|
|
||||||
title: 'multi-menu',
|
|
||||||
i18nKey: 'route.multi-menu',
|
|
||||||
order: 8
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'multi-menu_first',
|
|
||||||
path: '/multi-menu/first',
|
|
||||||
meta: {
|
|
||||||
title: 'multi-menu_first',
|
|
||||||
i18nKey: 'route.multi-menu_first',
|
|
||||||
order: 1
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'multi-menu_first_child',
|
|
||||||
path: '/multi-menu/first/child',
|
|
||||||
component: 'view.multi-menu_first_child',
|
|
||||||
meta: {
|
|
||||||
title: 'multi-menu_first_child',
|
|
||||||
i18nKey: 'route.multi-menu_first_child'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'multi-menu_second',
|
|
||||||
path: '/multi-menu/second',
|
|
||||||
meta: {
|
|
||||||
title: 'multi-menu_second',
|
|
||||||
i18nKey: 'route.multi-menu_second',
|
|
||||||
order: 2
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'multi-menu_second_child',
|
|
||||||
path: '/multi-menu/second/child',
|
|
||||||
meta: {
|
|
||||||
title: 'multi-menu_second_child',
|
|
||||||
i18nKey: 'route.multi-menu_second_child'
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'multi-menu_second_child_home',
|
|
||||||
path: '/multi-menu/second/child/home',
|
|
||||||
component: 'view.multi-menu_second_child_home',
|
|
||||||
meta: {
|
|
||||||
title: 'multi-menu_second_child_home',
|
|
||||||
i18nKey: 'route.multi-menu_second_child_home'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'user-center',
|
|
||||||
path: '/user-center',
|
|
||||||
component: 'layout.base$view.user-center',
|
|
||||||
meta: {
|
|
||||||
title: 'user-center',
|
|
||||||
i18nKey: 'route.user-center',
|
|
||||||
hideInMenu: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -161,47 +161,12 @@ function transformElegantRouteToVueRoute(
|
|||||||
const routeMap: RouteMap = {
|
const routeMap: RouteMap = {
|
||||||
"root": "/",
|
"root": "/",
|
||||||
"not-found": "/:pathMatch(.*)*",
|
"not-found": "/:pathMatch(.*)*",
|
||||||
"exception": "/exception",
|
|
||||||
"exception_403": "/exception/403",
|
|
||||||
"exception_404": "/exception/404",
|
|
||||||
"exception_500": "/exception/500",
|
|
||||||
"document": "/document",
|
|
||||||
"document_project": "/document/project",
|
|
||||||
"document_project-link": "/document/project-link",
|
|
||||||
"document_vue": "/document/vue",
|
|
||||||
"document_vite": "/document/vite",
|
|
||||||
"document_unocss": "/document/unocss",
|
|
||||||
"document_naive": "/document/naive",
|
|
||||||
"document_antd": "/document/antd",
|
|
||||||
"403": "/403",
|
"403": "/403",
|
||||||
"404": "/404",
|
"404": "/404",
|
||||||
"500": "/500",
|
"500": "/500",
|
||||||
"about": "/about",
|
|
||||||
"function": "/function",
|
|
||||||
"function_hide-child": "/function/hide-child",
|
|
||||||
"function_hide-child_one": "/function/hide-child/one",
|
|
||||||
"function_hide-child_three": "/function/hide-child/three",
|
|
||||||
"function_hide-child_two": "/function/hide-child/two",
|
|
||||||
"function_multi-tab": "/function/multi-tab",
|
|
||||||
"function_request": "/function/request",
|
|
||||||
"function_super-page": "/function/super-page",
|
|
||||||
"function_tab": "/function/tab",
|
|
||||||
"function_toggle-auth": "/function/toggle-auth",
|
|
||||||
"home": "/home",
|
"home": "/home",
|
||||||
"iframe-page": "/iframe-page/:url",
|
"iframe-page": "/iframe-page/:url",
|
||||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
|
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?"
|
||||||
"manage": "/manage",
|
|
||||||
"manage_menu": "/manage/menu",
|
|
||||||
"manage_role": "/manage/role",
|
|
||||||
"manage_user": "/manage/user",
|
|
||||||
"manage_user-detail": "/manage/user-detail/:id",
|
|
||||||
"multi-menu": "/multi-menu",
|
|
||||||
"multi-menu_first": "/multi-menu/first",
|
|
||||||
"multi-menu_first_child": "/multi-menu/first/child",
|
|
||||||
"multi-menu_second": "/multi-menu/second",
|
|
||||||
"multi-menu_second_child": "/multi-menu/second/child",
|
|
||||||
"multi-menu_second_child_home": "/multi-menu/second/child/home",
|
|
||||||
"user-center": "/user-center"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,160 +8,7 @@ import { transformElegantRoutesToVueRoutes } from '../elegant/transform';
|
|||||||
*
|
*
|
||||||
* @link https://github.com/soybeanjs/elegant-router?tab=readme-ov-file#custom-route
|
* @link https://github.com/soybeanjs/elegant-router?tab=readme-ov-file#custom-route
|
||||||
*/
|
*/
|
||||||
const customRoutes: CustomRoute[] = [
|
const customRoutes: CustomRoute[] = [];
|
||||||
{
|
|
||||||
name: 'exception',
|
|
||||||
path: '/exception',
|
|
||||||
component: 'layout.base',
|
|
||||||
meta: {
|
|
||||||
title: 'exception',
|
|
||||||
i18nKey: 'route.exception',
|
|
||||||
icon: 'ant-design:exception-outlined',
|
|
||||||
order: 7
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'exception_403',
|
|
||||||
path: '/exception/403',
|
|
||||||
component: 'view.403',
|
|
||||||
meta: {
|
|
||||||
title: 'exception_403',
|
|
||||||
i18nKey: 'route.exception_403',
|
|
||||||
icon: 'ic:baseline-block'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'exception_404',
|
|
||||||
path: '/exception/404',
|
|
||||||
component: 'view.404',
|
|
||||||
meta: {
|
|
||||||
title: 'exception_404',
|
|
||||||
i18nKey: 'route.exception_404',
|
|
||||||
icon: 'ic:baseline-web-asset-off'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'exception_500',
|
|
||||||
path: '/exception/500',
|
|
||||||
component: 'view.500',
|
|
||||||
meta: {
|
|
||||||
title: 'exception_500',
|
|
||||||
i18nKey: 'route.exception_500',
|
|
||||||
icon: 'ic:baseline-wifi-off'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'document',
|
|
||||||
path: '/document',
|
|
||||||
component: 'layout.base',
|
|
||||||
meta: {
|
|
||||||
title: 'document',
|
|
||||||
i18nKey: 'route.document',
|
|
||||||
order: 2,
|
|
||||||
icon: 'mdi:file-document-multiple-outline'
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'document_antd',
|
|
||||||
path: '/document/antd',
|
|
||||||
component: 'view.iframe-page',
|
|
||||||
props: {
|
|
||||||
url: 'https://antdv.com/components/overview-cn'
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
title: 'document_antd',
|
|
||||||
i18nKey: 'route.document_antd',
|
|
||||||
order: 7,
|
|
||||||
icon: 'logos:ant-design'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'document_naive',
|
|
||||||
path: '/document/naive',
|
|
||||||
component: 'view.iframe-page',
|
|
||||||
props: {
|
|
||||||
url: 'https://www.naiveui.com/zh-CN/os-theme/docs/introduction'
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
title: 'document_naive',
|
|
||||||
i18nKey: 'route.document_naive',
|
|
||||||
order: 6,
|
|
||||||
icon: 'logos:naiveui'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'document_project',
|
|
||||||
path: '/document/project',
|
|
||||||
component: 'view.iframe-page',
|
|
||||||
props: {
|
|
||||||
url: 'https://docs.soybeanjs.cn/zh'
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
title: 'document_project',
|
|
||||||
i18nKey: 'route.document_project',
|
|
||||||
order: 1,
|
|
||||||
localIcon: 'logo'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'document_project-link',
|
|
||||||
path: '/document/project-link',
|
|
||||||
component: 'view.iframe-page',
|
|
||||||
meta: {
|
|
||||||
title: 'document_project-link',
|
|
||||||
i18nKey: 'route.document_project-link',
|
|
||||||
order: 2,
|
|
||||||
localIcon: 'logo',
|
|
||||||
href: 'https://docs.soybeanjs.cn/zh'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'document_unocss',
|
|
||||||
path: '/document/unocss',
|
|
||||||
component: 'view.iframe-page',
|
|
||||||
props: {
|
|
||||||
url: 'https://unocss.dev/'
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
title: 'document_unocss',
|
|
||||||
i18nKey: 'route.document_unocss',
|
|
||||||
order: 5,
|
|
||||||
icon: 'logos:unocss'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'document_vite',
|
|
||||||
path: '/document/vite',
|
|
||||||
component: 'view.iframe-page',
|
|
||||||
props: {
|
|
||||||
url: 'https://cn.vitejs.dev/'
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
title: 'document_vite',
|
|
||||||
i18nKey: 'route.document_vite',
|
|
||||||
order: 4,
|
|
||||||
icon: 'logos:vitejs'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'document_vue',
|
|
||||||
path: '/document/vue',
|
|
||||||
component: 'view.iframe-page',
|
|
||||||
props: {
|
|
||||||
url: 'https://cn.vuejs.org/'
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
title: 'document_vue',
|
|
||||||
i18nKey: 'route.document_vue',
|
|
||||||
order: 3,
|
|
||||||
icon: 'logos:vue'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
/** create routes when the auth route mode is static */
|
/** create routes when the auth route mode is static */
|
||||||
export function createStaticRoutes() {
|
export function createStaticRoutes() {
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
export * from './auth';
|
export * from './auth';
|
||||||
export * from './route';
|
export * from './route';
|
||||||
export * from './system-manage';
|
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
import { request } from '../request';
|
|
||||||
|
|
||||||
/** get role list */
|
|
||||||
export function fetchGetRoleList(params?: Api.SystemManage.RoleSearchParams) {
|
|
||||||
return request<Api.SystemManage.RoleList>({
|
|
||||||
url: '/systemManage/getRoleList',
|
|
||||||
method: 'get',
|
|
||||||
params
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get all roles
|
|
||||||
*
|
|
||||||
* these roles are all enabled
|
|
||||||
*/
|
|
||||||
export function fetchGetAllRoles() {
|
|
||||||
return request<Api.SystemManage.AllRole[]>({
|
|
||||||
url: '/systemManage/getAllRoles',
|
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get user list */
|
|
||||||
export function fetchGetUserList(params?: Api.SystemManage.UserSearchParams) {
|
|
||||||
return request<Api.SystemManage.UserList>({
|
|
||||||
url: '/systemManage/getUserList',
|
|
||||||
method: 'get',
|
|
||||||
params
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get menu list */
|
|
||||||
export function fetchGetMenuList() {
|
|
||||||
return request<Api.SystemManage.MenuList>({
|
|
||||||
url: '/systemManage/getMenuList/v2',
|
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get all pages */
|
|
||||||
export function fetchGetAllPages() {
|
|
||||||
return request<string[]>({
|
|
||||||
url: '/systemManage/getAllPages',
|
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get menu tree */
|
|
||||||
export function fetchGetMenuTree() {
|
|
||||||
return request<Api.SystemManage.MenuTree[]>({
|
|
||||||
url: '/systemManage/getMenuTree',
|
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
}
|
|
172
src/typings/app.d.ts
vendored
172
src/typings/app.d.ts
vendored
@ -273,6 +273,7 @@ declare namespace App {
|
|||||||
deleteSuccess: string;
|
deleteSuccess: string;
|
||||||
confirmDelete: string;
|
confirmDelete: string;
|
||||||
edit: string;
|
edit: string;
|
||||||
|
warning: string;
|
||||||
error: string;
|
error: string;
|
||||||
index: string;
|
index: string;
|
||||||
keywordSearch: string;
|
keywordSearch: string;
|
||||||
@ -406,20 +407,8 @@ declare namespace App {
|
|||||||
title: string;
|
title: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
about: {
|
|
||||||
title: string;
|
|
||||||
introduction: string;
|
|
||||||
projectInfo: {
|
|
||||||
title: string;
|
|
||||||
version: string;
|
|
||||||
latestBuildTime: string;
|
|
||||||
githubLink: string;
|
|
||||||
previewLink: string;
|
|
||||||
};
|
|
||||||
prdDep: string;
|
|
||||||
devDep: string;
|
|
||||||
};
|
|
||||||
home: {
|
home: {
|
||||||
|
branchDesc: string;
|
||||||
greeting: string;
|
greeting: string;
|
||||||
weatherDesc: string;
|
weatherDesc: string;
|
||||||
projectCount: string;
|
projectCount: string;
|
||||||
@ -446,163 +435,6 @@ declare namespace App {
|
|||||||
};
|
};
|
||||||
creativity: string;
|
creativity: string;
|
||||||
};
|
};
|
||||||
function: {
|
|
||||||
tab: {
|
|
||||||
tabOperate: {
|
|
||||||
title: string;
|
|
||||||
addTab: string;
|
|
||||||
addTabDesc: string;
|
|
||||||
closeTab: string;
|
|
||||||
closeCurrentTab: string;
|
|
||||||
closeAboutTab: string;
|
|
||||||
addMultiTab: string;
|
|
||||||
addMultiTabDesc1: string;
|
|
||||||
addMultiTabDesc2: string;
|
|
||||||
};
|
|
||||||
tabTitle: {
|
|
||||||
title: string;
|
|
||||||
changeTitle: string;
|
|
||||||
change: string;
|
|
||||||
resetTitle: string;
|
|
||||||
reset: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
multiTab: {
|
|
||||||
routeParam: string;
|
|
||||||
backTab: string;
|
|
||||||
};
|
|
||||||
toggleAuth: {
|
|
||||||
toggleAccount: string;
|
|
||||||
authHook: string;
|
|
||||||
superAdminVisible: string;
|
|
||||||
adminVisible: string;
|
|
||||||
adminOrUserVisible: string;
|
|
||||||
};
|
|
||||||
request: {
|
|
||||||
repeatedErrorOccurOnce: string;
|
|
||||||
repeatedError: string;
|
|
||||||
repeatedErrorMsg1: string;
|
|
||||||
repeatedErrorMsg2: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
manage: {
|
|
||||||
common: {
|
|
||||||
status: {
|
|
||||||
enable: string;
|
|
||||||
disable: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
role: {
|
|
||||||
title: string;
|
|
||||||
roleName: string;
|
|
||||||
roleCode: string;
|
|
||||||
roleStatus: string;
|
|
||||||
roleDesc: string;
|
|
||||||
form: {
|
|
||||||
roleName: string;
|
|
||||||
roleCode: string;
|
|
||||||
roleStatus: string;
|
|
||||||
roleDesc: string;
|
|
||||||
};
|
|
||||||
addRole: string;
|
|
||||||
editRole: string;
|
|
||||||
menuAuth: string;
|
|
||||||
buttonAuth: string;
|
|
||||||
};
|
|
||||||
user: {
|
|
||||||
title: string;
|
|
||||||
userName: string;
|
|
||||||
userGender: string;
|
|
||||||
nickName: string;
|
|
||||||
userPhone: string;
|
|
||||||
userEmail: string;
|
|
||||||
userStatus: string;
|
|
||||||
userRole: string;
|
|
||||||
form: {
|
|
||||||
userName: string;
|
|
||||||
userGender: string;
|
|
||||||
nickName: string;
|
|
||||||
userPhone: string;
|
|
||||||
userEmail: string;
|
|
||||||
userStatus: string;
|
|
||||||
userRole: string;
|
|
||||||
};
|
|
||||||
addUser: string;
|
|
||||||
editUser: string;
|
|
||||||
gender: {
|
|
||||||
male: string;
|
|
||||||
female: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
menu: {
|
|
||||||
home: string;
|
|
||||||
title: string;
|
|
||||||
id: string;
|
|
||||||
parentId: string;
|
|
||||||
menuType: string;
|
|
||||||
menuName: string;
|
|
||||||
routeName: string;
|
|
||||||
routePath: string;
|
|
||||||
pathParam: string;
|
|
||||||
layout: string;
|
|
||||||
page: string;
|
|
||||||
i18nKey: string;
|
|
||||||
icon: string;
|
|
||||||
localIcon: string;
|
|
||||||
iconTypeTitle: string;
|
|
||||||
order: string;
|
|
||||||
constant: string;
|
|
||||||
keepAlive: string;
|
|
||||||
href: string;
|
|
||||||
hideInMenu: string;
|
|
||||||
activeMenu: string;
|
|
||||||
multiTab: string;
|
|
||||||
fixedIndexInTab: string;
|
|
||||||
query: string;
|
|
||||||
button: string;
|
|
||||||
buttonCode: string;
|
|
||||||
buttonDesc: string;
|
|
||||||
menuStatus: string;
|
|
||||||
form: {
|
|
||||||
home: string;
|
|
||||||
menuType: string;
|
|
||||||
menuName: string;
|
|
||||||
routeName: string;
|
|
||||||
routePath: string;
|
|
||||||
pathParam: string;
|
|
||||||
layout: string;
|
|
||||||
page: string;
|
|
||||||
i18nKey: string;
|
|
||||||
icon: string;
|
|
||||||
localIcon: string;
|
|
||||||
order: string;
|
|
||||||
keepAlive: string;
|
|
||||||
href: string;
|
|
||||||
hideInMenu: string;
|
|
||||||
activeMenu: string;
|
|
||||||
multiTab: string;
|
|
||||||
fixedInTab: string;
|
|
||||||
fixedIndexInTab: string;
|
|
||||||
queryKey: string;
|
|
||||||
queryValue: string;
|
|
||||||
button: string;
|
|
||||||
buttonCode: string;
|
|
||||||
buttonDesc: string;
|
|
||||||
menuStatus: string;
|
|
||||||
};
|
|
||||||
addMenu: string;
|
|
||||||
editMenu: string;
|
|
||||||
addChildMenu: string;
|
|
||||||
type: {
|
|
||||||
directory: string;
|
|
||||||
menu: string;
|
|
||||||
};
|
|
||||||
iconType: {
|
|
||||||
iconify: string;
|
|
||||||
local: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
form: {
|
form: {
|
||||||
required: string;
|
required: string;
|
||||||
|
1
src/typings/components.d.ts
vendored
1
src/typings/components.d.ts
vendored
@ -37,6 +37,7 @@ declare module 'vue' {
|
|||||||
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']
|
||||||
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']
|
||||||
|
80
src/typings/elegant-router.d.ts
vendored
80
src/typings/elegant-router.d.ts
vendored
@ -17,47 +17,12 @@ declare module "@elegant-router/types" {
|
|||||||
export type RouteMap = {
|
export type RouteMap = {
|
||||||
"root": "/";
|
"root": "/";
|
||||||
"not-found": "/:pathMatch(.*)*";
|
"not-found": "/:pathMatch(.*)*";
|
||||||
"exception": "/exception";
|
|
||||||
"exception_403": "/exception/403";
|
|
||||||
"exception_404": "/exception/404";
|
|
||||||
"exception_500": "/exception/500";
|
|
||||||
"document": "/document";
|
|
||||||
"document_project": "/document/project";
|
|
||||||
"document_project-link": "/document/project-link";
|
|
||||||
"document_vue": "/document/vue";
|
|
||||||
"document_vite": "/document/vite";
|
|
||||||
"document_unocss": "/document/unocss";
|
|
||||||
"document_naive": "/document/naive";
|
|
||||||
"document_antd": "/document/antd";
|
|
||||||
"403": "/403";
|
"403": "/403";
|
||||||
"404": "/404";
|
"404": "/404";
|
||||||
"500": "/500";
|
"500": "/500";
|
||||||
"about": "/about";
|
|
||||||
"function": "/function";
|
|
||||||
"function_hide-child": "/function/hide-child";
|
|
||||||
"function_hide-child_one": "/function/hide-child/one";
|
|
||||||
"function_hide-child_three": "/function/hide-child/three";
|
|
||||||
"function_hide-child_two": "/function/hide-child/two";
|
|
||||||
"function_multi-tab": "/function/multi-tab";
|
|
||||||
"function_request": "/function/request";
|
|
||||||
"function_super-page": "/function/super-page";
|
|
||||||
"function_tab": "/function/tab";
|
|
||||||
"function_toggle-auth": "/function/toggle-auth";
|
|
||||||
"home": "/home";
|
"home": "/home";
|
||||||
"iframe-page": "/iframe-page/:url";
|
"iframe-page": "/iframe-page/:url";
|
||||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
|
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
|
||||||
"manage": "/manage";
|
|
||||||
"manage_menu": "/manage/menu";
|
|
||||||
"manage_role": "/manage/role";
|
|
||||||
"manage_user": "/manage/user";
|
|
||||||
"manage_user-detail": "/manage/user-detail/:id";
|
|
||||||
"multi-menu": "/multi-menu";
|
|
||||||
"multi-menu_first": "/multi-menu/first";
|
|
||||||
"multi-menu_first_child": "/multi-menu/first/child";
|
|
||||||
"multi-menu_second": "/multi-menu/second";
|
|
||||||
"multi-menu_second_child": "/multi-menu/second/child";
|
|
||||||
"multi-menu_second_child_home": "/multi-menu/second/child/home";
|
|
||||||
"user-center": "/user-center";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,18 +42,6 @@ declare module "@elegant-router/types" {
|
|||||||
RouteKey,
|
RouteKey,
|
||||||
| "root"
|
| "root"
|
||||||
| "not-found"
|
| "not-found"
|
||||||
| "exception"
|
|
||||||
| "exception_403"
|
|
||||||
| "exception_404"
|
|
||||||
| "exception_500"
|
|
||||||
| "document"
|
|
||||||
| "document_project"
|
|
||||||
| "document_project-link"
|
|
||||||
| "document_vue"
|
|
||||||
| "document_vite"
|
|
||||||
| "document_unocss"
|
|
||||||
| "document_naive"
|
|
||||||
| "document_antd"
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,14 +57,9 @@ declare module "@elegant-router/types" {
|
|||||||
| "403"
|
| "403"
|
||||||
| "404"
|
| "404"
|
||||||
| "500"
|
| "500"
|
||||||
| "about"
|
|
||||||
| "function"
|
|
||||||
| "home"
|
| "home"
|
||||||
| "iframe-page"
|
| "iframe-page"
|
||||||
| "login"
|
| "login"
|
||||||
| "manage"
|
|
||||||
| "multi-menu"
|
|
||||||
| "user-center"
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,8 +69,6 @@ declare module "@elegant-router/types" {
|
|||||||
CustomRouteKey,
|
CustomRouteKey,
|
||||||
| "root"
|
| "root"
|
||||||
| "not-found"
|
| "not-found"
|
||||||
| "exception"
|
|
||||||
| "document"
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,23 +81,7 @@ declare module "@elegant-router/types" {
|
|||||||
| "500"
|
| "500"
|
||||||
| "iframe-page"
|
| "iframe-page"
|
||||||
| "login"
|
| "login"
|
||||||
| "about"
|
|
||||||
| "function_hide-child_one"
|
|
||||||
| "function_hide-child_three"
|
|
||||||
| "function_hide-child_two"
|
|
||||||
| "function_multi-tab"
|
|
||||||
| "function_request"
|
|
||||||
| "function_super-page"
|
|
||||||
| "function_tab"
|
|
||||||
| "function_toggle-auth"
|
|
||||||
| "home"
|
| "home"
|
||||||
| "manage_menu"
|
|
||||||
| "manage_role"
|
|
||||||
| "manage_user-detail"
|
|
||||||
| "manage_user"
|
|
||||||
| "multi-menu_first_child"
|
|
||||||
| "multi-menu_second_child_home"
|
|
||||||
| "user-center"
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,16 +91,6 @@ declare module "@elegant-router/types" {
|
|||||||
CustomRouteKey,
|
CustomRouteKey,
|
||||||
| "root"
|
| "root"
|
||||||
| "not-found"
|
| "not-found"
|
||||||
| "exception_403"
|
|
||||||
| "exception_404"
|
|
||||||
| "exception_500"
|
|
||||||
| "document_project"
|
|
||||||
| "document_project-link"
|
|
||||||
| "document_vue"
|
|
||||||
| "document_vite"
|
|
||||||
| "document_unocss"
|
|
||||||
| "document_naive"
|
|
||||||
| "document_antd"
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { useAppStore } from '@/store/modules/app';
|
|
||||||
import pkg from '~/package.json';
|
|
||||||
|
|
||||||
const appStore = useAppStore();
|
|
||||||
|
|
||||||
const column = computed(() => (appStore.isMobile ? 1 : 2));
|
|
||||||
|
|
||||||
interface PkgJson {
|
|
||||||
name: string;
|
|
||||||
version: string;
|
|
||||||
dependencies: PkgVersionInfo[];
|
|
||||||
devDependencies: PkgVersionInfo[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PkgVersionInfo {
|
|
||||||
name: string;
|
|
||||||
version: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { name, version, dependencies, devDependencies } = pkg;
|
|
||||||
|
|
||||||
function transformVersionData(tuple: [string, string]): PkgVersionInfo {
|
|
||||||
const [$name, $version] = tuple;
|
|
||||||
return {
|
|
||||||
name: $name,
|
|
||||||
version: $version
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const pkgJson: PkgJson = {
|
|
||||||
name,
|
|
||||||
version,
|
|
||||||
dependencies: Object.entries(dependencies).map(item => transformVersionData(item)),
|
|
||||||
devDependencies: Object.entries(devDependencies).map(item => transformVersionData(item))
|
|
||||||
};
|
|
||||||
|
|
||||||
const latestBuildTime = BUILD_TIME;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NSpace vertical :size="16">
|
|
||||||
<NCard :title="$t('page.about.title')" :bordered="false" size="small" segmented class="card-wrapper">
|
|
||||||
<p>{{ $t('page.about.introduction') }}</p>
|
|
||||||
</NCard>
|
|
||||||
<NCard :title="$t('page.about.projectInfo.title')" :bordered="false" size="small" segmented class="card-wrapper">
|
|
||||||
<NDescriptions label-placement="left" bordered size="small" :column="column">
|
|
||||||
<NDescriptionsItem :label="$t('page.about.projectInfo.version')">
|
|
||||||
<NTag type="primary">{{ pkgJson.version }}</NTag>
|
|
||||||
</NDescriptionsItem>
|
|
||||||
<NDescriptionsItem :label="$t('page.about.projectInfo.latestBuildTime')">
|
|
||||||
<NTag type="primary">{{ latestBuildTime }}</NTag>
|
|
||||||
</NDescriptionsItem>
|
|
||||||
<NDescriptionsItem :label="$t('page.about.projectInfo.githubLink')">
|
|
||||||
<a class="text-primary" :href="pkg.homepage" target="_blank" rel="noopener noreferrer">
|
|
||||||
{{ $t('page.about.projectInfo.githubLink') }}
|
|
||||||
</a>
|
|
||||||
</NDescriptionsItem>
|
|
||||||
<NDescriptionsItem :label="$t('page.about.projectInfo.previewLink')">
|
|
||||||
<a class="text-primary" :href="pkg.website" target="_blank" rel="noopener noreferrer">
|
|
||||||
{{ $t('page.about.projectInfo.previewLink') }}
|
|
||||||
</a>
|
|
||||||
</NDescriptionsItem>
|
|
||||||
</NDescriptions>
|
|
||||||
</NCard>
|
|
||||||
<NCard :title="$t('page.about.prdDep')" :bordered="false" size="small" segmented class="card-wrapper">
|
|
||||||
<NDescriptions label-placement="left" bordered size="small" :column="column">
|
|
||||||
<NDescriptionsItem v-for="item in pkgJson.dependencies" :key="item.name" :label="item.name">
|
|
||||||
{{ item.version }}
|
|
||||||
</NDescriptionsItem>
|
|
||||||
</NDescriptions>
|
|
||||||
</NCard>
|
|
||||||
<NCard :title="$t('page.about.devDep')" :bordered="false" size="small" segmented class="card-wrapper">
|
|
||||||
<NDescriptions label-placement="left" bordered size="small" :column="column">
|
|
||||||
<NDescriptionsItem v-for="item in pkgJson.devDependencies" :key="item.name" :label="item.name">
|
|
||||||
{{ item.version }}
|
|
||||||
</NDescriptionsItem>
|
|
||||||
</NDescriptions>
|
|
||||||
</NCard>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,7 +0,0 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LookForward />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,7 +0,0 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LookForward />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,7 +0,0 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LookForward />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,24 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import { computed } from 'vue';
|
|
||||||
import { useRouterPush } from '@/hooks/common/router';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
const { routerPushByKey } = useRouterPush();
|
|
||||||
|
|
||||||
const routeQuery = computed(() => JSON.stringify(route.query));
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<LookForward>
|
|
||||||
<div>
|
|
||||||
<NButton @click="routerPushByKey('function_tab')">{{ $t('page.function.multiTab.backTab') }}</NButton>
|
|
||||||
<div class="py-24px">{{ $t('page.function.multiTab.routeParam') }}: {{ routeQuery }}</div>
|
|
||||||
</div>
|
|
||||||
</LookForward>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,63 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { fetchCustomBackendError } from '@/service/api';
|
|
||||||
|
|
||||||
async function logout() {
|
|
||||||
await fetchCustomBackendError('8888', $t('request.logoutMsg'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function logoutWithModal() {
|
|
||||||
await fetchCustomBackendError('7777', $t('request.logoutWithModalMsg'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function refreshToken() {
|
|
||||||
await fetchCustomBackendError('9999', $t('request.tokenExpired'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleRepeatedMessageError() {
|
|
||||||
await Promise.all([
|
|
||||||
fetchCustomBackendError('2222', $t('page.function.request.repeatedErrorMsg1')),
|
|
||||||
fetchCustomBackendError('2222', $t('page.function.request.repeatedErrorMsg1')),
|
|
||||||
fetchCustomBackendError('2222', $t('page.function.request.repeatedErrorMsg1')),
|
|
||||||
fetchCustomBackendError('3333', $t('page.function.request.repeatedErrorMsg2')),
|
|
||||||
fetchCustomBackendError('3333', $t('page.function.request.repeatedErrorMsg2')),
|
|
||||||
fetchCustomBackendError('3333', $t('page.function.request.repeatedErrorMsg2'))
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleRepeatedModalError() {
|
|
||||||
await Promise.all([
|
|
||||||
fetchCustomBackendError('7777', $t('request.logoutWithModalMsg')),
|
|
||||||
fetchCustomBackendError('7777', $t('request.logoutWithModalMsg')),
|
|
||||||
fetchCustomBackendError('7777', $t('request.logoutWithModalMsg'))
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NSpace vertical :size="16">
|
|
||||||
<NCard :title="$t('request.logout')" :bordered="false" size="small" segmented class="card-wrapper">
|
|
||||||
<NButton @click="logout">{{ $t('common.trigger') }}</NButton>
|
|
||||||
</NCard>
|
|
||||||
<NCard :title="$t('request.logoutWithModal')" :bordered="false" size="small" segmented class="card-wrapper">
|
|
||||||
<NButton @click="logoutWithModal">{{ $t('common.trigger') }}</NButton>
|
|
||||||
</NCard>
|
|
||||||
<NCard :title="$t('request.refreshToken')" :bordered="false" size="small" segmented class="card-wrapper">
|
|
||||||
<NButton @click="refreshToken">{{ $t('common.trigger') }}</NButton>
|
|
||||||
</NCard>
|
|
||||||
<NCard
|
|
||||||
:title="$t('page.function.request.repeatedErrorOccurOnce')"
|
|
||||||
:bordered="false"
|
|
||||||
size="small"
|
|
||||||
segmented
|
|
||||||
class="card-wrapper"
|
|
||||||
>
|
|
||||||
<NButton @click="handleRepeatedMessageError">{{ $t('page.function.request.repeatedError') }}(Message)</NButton>
|
|
||||||
<NButton class="ml-12px" @click="handleRepeatedModalError">
|
|
||||||
{{ $t('page.function.request.repeatedError') }}(Modal)
|
|
||||||
</NButton>
|
|
||||||
</NCard>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,7 +0,0 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LookForward />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,71 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { useRouterPush } from '@/hooks/common/router';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { useTabStore } from '@/store/modules/tab';
|
|
||||||
|
|
||||||
const tabStore = useTabStore();
|
|
||||||
const { routerPushByKey } = useRouterPush();
|
|
||||||
|
|
||||||
const tabLabel = ref('');
|
|
||||||
|
|
||||||
function changeTabLabel() {
|
|
||||||
tabStore.setTabLabel(tabLabel.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetTabLabel() {
|
|
||||||
tabStore.resetTabLabel();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NSpace vertical :size="16">
|
|
||||||
<NCard
|
|
||||||
:title="$t('page.function.tab.tabOperate.title')"
|
|
||||||
:bordered="false"
|
|
||||||
size="small"
|
|
||||||
segmented
|
|
||||||
class="card-wrapper"
|
|
||||||
>
|
|
||||||
<NDivider title-placement="left">{{ $t('page.function.tab.tabOperate.addTab') }}</NDivider>
|
|
||||||
<NButton @click="routerPushByKey('about')">{{ $t('page.function.tab.tabOperate.addTabDesc') }}</NButton>
|
|
||||||
<NDivider title-placement="left">{{ $t('page.function.tab.tabOperate.closeTab') }}</NDivider>
|
|
||||||
<NSpace>
|
|
||||||
<NButton @click="tabStore.removeActiveTab">
|
|
||||||
{{ $t('page.function.tab.tabOperate.closeCurrentTab') }}
|
|
||||||
</NButton>
|
|
||||||
<NButton @click="tabStore.removeTabByRouteName('about')">
|
|
||||||
{{ $t('page.function.tab.tabOperate.closeAboutTab') }}
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
<NDivider title-placement="left">{{ $t('page.function.tab.tabOperate.addMultiTab') }}</NDivider>
|
|
||||||
<NSpace>
|
|
||||||
<NButton @click="routerPushByKey('function_multi-tab')">
|
|
||||||
{{ $t('page.function.tab.tabOperate.addMultiTabDesc1') }}
|
|
||||||
</NButton>
|
|
||||||
<NButton @click="routerPushByKey('function_multi-tab', { query: { a: '1' } })">
|
|
||||||
{{ $t('page.function.tab.tabOperate.addMultiTabDesc2') }}
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</NCard>
|
|
||||||
<NCard
|
|
||||||
:title="$t('page.function.tab.tabTitle.title')"
|
|
||||||
:bordered="false"
|
|
||||||
size="small"
|
|
||||||
segmented
|
|
||||||
class="card-wrapper"
|
|
||||||
>
|
|
||||||
<NDivider title-placement="left">{{ $t('page.function.tab.tabTitle.changeTitle') }}</NDivider>
|
|
||||||
<NInputGroup class="max-w-240px">
|
|
||||||
<NInput v-model:value="tabLabel" />
|
|
||||||
<NButton type="primary" @click="changeTabLabel">{{ $t('page.function.tab.tabTitle.change') }}</NButton>
|
|
||||||
</NInputGroup>
|
|
||||||
<NDivider title-placement="left">{{ $t('page.function.tab.tabTitle.resetTitle') }}</NDivider>
|
|
||||||
<NButton type="error" ghost class="w-80px" @click="resetTabLabel">
|
|
||||||
{{ $t('page.function.tab.tabTitle.reset') }}
|
|
||||||
</NButton>
|
|
||||||
</NCard>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,103 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import { useLoading } from '@sa/hooks';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { useAppStore } from '@/store/modules/app';
|
|
||||||
import { useAuthStore } from '@/store/modules/auth';
|
|
||||||
import { useTabStore } from '@/store/modules/tab';
|
|
||||||
import { useAuth } from '@/hooks/business/auth';
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
const appStore = useAppStore();
|
|
||||||
const authStore = useAuthStore();
|
|
||||||
const tabStore = useTabStore();
|
|
||||||
const { hasAuth } = useAuth();
|
|
||||||
const { loading, startLoading, endLoading } = useLoading();
|
|
||||||
|
|
||||||
type AccountKey = 'super' | 'admin' | 'user';
|
|
||||||
|
|
||||||
interface Account {
|
|
||||||
key: AccountKey;
|
|
||||||
label: string;
|
|
||||||
userName: string;
|
|
||||||
password: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const accounts = computed<Account[]>(() => [
|
|
||||||
{
|
|
||||||
key: 'super',
|
|
||||||
label: $t('page.login.pwdLogin.superAdmin'),
|
|
||||||
userName: 'Super',
|
|
||||||
password: '123456'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'admin',
|
|
||||||
label: $t('page.login.pwdLogin.admin'),
|
|
||||||
userName: 'Admin',
|
|
||||||
password: '123456'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'user',
|
|
||||||
label: $t('page.login.pwdLogin.user'),
|
|
||||||
userName: 'User',
|
|
||||||
password: '123456'
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
const loginAccount = ref<AccountKey>('super');
|
|
||||||
|
|
||||||
async function handleToggleAccount(account: Account) {
|
|
||||||
loginAccount.value = account.key;
|
|
||||||
|
|
||||||
startLoading();
|
|
||||||
await authStore.login(account.userName, account.password, false);
|
|
||||||
tabStore.initTabStore(route);
|
|
||||||
endLoading();
|
|
||||||
appStore.reloadPage();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NSpace vertical :size="16">
|
|
||||||
<NCard :title="$t('route.function_toggle-auth')" :bordered="false" size="small" segmented class="card-wrapper">
|
|
||||||
<NDescriptions bordered :column="1">
|
|
||||||
<NDescriptionsItem :label="$t('page.manage.user.userRole')">
|
|
||||||
<NSpace>
|
|
||||||
<NTag v-for="role in authStore.userInfo.roles" :key="role">{{ role }}</NTag>
|
|
||||||
</NSpace>
|
|
||||||
</NDescriptionsItem>
|
|
||||||
<NDescriptionsItem ions-item :label="$t('page.function.toggleAuth.toggleAccount')">
|
|
||||||
<NSpace>
|
|
||||||
<NButton
|
|
||||||
v-for="account in accounts"
|
|
||||||
:key="account.key"
|
|
||||||
:loading="loading && loginAccount === account.key"
|
|
||||||
:disabled="loading && loginAccount !== account.key"
|
|
||||||
@click="handleToggleAccount(account)"
|
|
||||||
>
|
|
||||||
{{ account.label }}
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</NDescriptionsItem>
|
|
||||||
</NDescriptions>
|
|
||||||
</NCard>
|
|
||||||
<NCard
|
|
||||||
:title="$t('page.function.toggleAuth.authHook')"
|
|
||||||
:bordered="false"
|
|
||||||
size="small"
|
|
||||||
segmented
|
|
||||||
class="card-wrapper"
|
|
||||||
>
|
|
||||||
<NSpace>
|
|
||||||
<NButton v-if="hasAuth('B_CODE1')">{{ $t('page.function.toggleAuth.superAdminVisible') }}</NButton>
|
|
||||||
<NButton v-if="hasAuth('B_CODE2')">{{ $t('page.function.toggleAuth.adminVisible') }}</NButton>
|
|
||||||
<NButton v-if="hasAuth('B_CODE3')">
|
|
||||||
{{ $t('page.function.toggleAuth.adminOrUserVisible') }}
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</NCard>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -15,6 +15,9 @@ const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpace vertical :size="16">
|
<NSpace vertical :size="16">
|
||||||
|
<NAlert :title="$t('common.warning')" type="warning" closable>
|
||||||
|
{{ $t('page.home.branchDesc') }}
|
||||||
|
</NAlert>
|
||||||
<HeaderBanner />
|
<HeaderBanner />
|
||||||
<CardData />
|
<CardData />
|
||||||
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
|
@ -1,266 +0,0 @@
|
|||||||
<script setup lang="tsx">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
|
||||||
import { useBoolean } from '@sa/hooks';
|
|
||||||
import { fetchGetAllPages, fetchGetMenuList } from '@/service/api';
|
|
||||||
import { useAppStore } from '@/store/modules/app';
|
|
||||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { yesOrNoRecord } from '@/constants/common';
|
|
||||||
import { enableStatusRecord, menuTypeRecord } from '@/constants/business';
|
|
||||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
|
||||||
import MenuOperateModal, { type OperateType } from './modules/menu-operate-modal.vue';
|
|
||||||
|
|
||||||
const appStore = useAppStore();
|
|
||||||
|
|
||||||
const { bool: visible, setTrue: openModal } = useBoolean();
|
|
||||||
|
|
||||||
const wrapperRef = ref<HTMLElement | null>(null);
|
|
||||||
|
|
||||||
const { columns, columnChecks, data, loading, pagination, getData, getDataByPage } = useTable({
|
|
||||||
apiFn: fetchGetMenuList,
|
|
||||||
columns: () => [
|
|
||||||
{
|
|
||||||
type: 'selection',
|
|
||||||
align: 'center',
|
|
||||||
width: 48
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'id',
|
|
||||||
title: $t('page.manage.menu.id'),
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'menuType',
|
|
||||||
title: $t('page.manage.menu.menuType'),
|
|
||||||
align: 'center',
|
|
||||||
width: 80,
|
|
||||||
render: row => {
|
|
||||||
const tagMap: Record<Api.SystemManage.MenuType, NaiveUI.ThemeColor> = {
|
|
||||||
1: 'default',
|
|
||||||
2: 'primary'
|
|
||||||
};
|
|
||||||
|
|
||||||
const label = $t(menuTypeRecord[row.menuType]);
|
|
||||||
|
|
||||||
return <NTag type={tagMap[row.menuType]}>{label}</NTag>;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'menuName',
|
|
||||||
title: $t('page.manage.menu.menuName'),
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 120,
|
|
||||||
render: row => {
|
|
||||||
const { i18nKey, menuName } = row;
|
|
||||||
|
|
||||||
const label = i18nKey ? $t(i18nKey) : menuName;
|
|
||||||
|
|
||||||
return <span>{label}</span>;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'icon',
|
|
||||||
title: $t('page.manage.menu.icon'),
|
|
||||||
align: 'center',
|
|
||||||
width: 60,
|
|
||||||
render: row => {
|
|
||||||
const icon = row.iconType === '1' ? row.icon : undefined;
|
|
||||||
|
|
||||||
const localIcon = row.iconType === '2' ? row.icon : undefined;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class="flex-center">
|
|
||||||
<SvgIcon icon={icon} localIcon={localIcon} class="text-icon" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'routeName',
|
|
||||||
title: $t('page.manage.menu.routeName'),
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'routePath',
|
|
||||||
title: $t('page.manage.menu.routePath'),
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'status',
|
|
||||||
title: $t('page.manage.menu.menuStatus'),
|
|
||||||
align: 'center',
|
|
||||||
width: 80,
|
|
||||||
render: row => {
|
|
||||||
if (row.status === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagMap: Record<Api.Common.EnableStatus, NaiveUI.ThemeColor> = {
|
|
||||||
1: 'success',
|
|
||||||
2: 'warning'
|
|
||||||
};
|
|
||||||
|
|
||||||
const label = $t(enableStatusRecord[row.status]);
|
|
||||||
|
|
||||||
return <NTag type={tagMap[row.status]}>{label}</NTag>;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'hideInMenu',
|
|
||||||
title: $t('page.manage.menu.hideInMenu'),
|
|
||||||
align: 'center',
|
|
||||||
width: 80,
|
|
||||||
render: row => {
|
|
||||||
const hide: CommonType.YesOrNo = row.hideInMenu ? 'Y' : 'N';
|
|
||||||
|
|
||||||
const tagMap: Record<CommonType.YesOrNo, NaiveUI.ThemeColor> = {
|
|
||||||
Y: 'error',
|
|
||||||
N: 'default'
|
|
||||||
};
|
|
||||||
|
|
||||||
const label = $t(yesOrNoRecord[hide]);
|
|
||||||
|
|
||||||
return <NTag type={tagMap[hide]}>{label}</NTag>;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'parentId',
|
|
||||||
title: $t('page.manage.menu.parentId'),
|
|
||||||
width: 90,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'order',
|
|
||||||
title: $t('page.manage.menu.order'),
|
|
||||||
align: 'center',
|
|
||||||
width: 60
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'operate',
|
|
||||||
title: $t('common.operate'),
|
|
||||||
align: 'center',
|
|
||||||
width: 230,
|
|
||||||
render: row => (
|
|
||||||
<div class="flex-center justify-end gap-8px">
|
|
||||||
{row.menuType === '1' && (
|
|
||||||
<NButton type="primary" ghost size="small" onClick={() => handleAddChildMenu(row)}>
|
|
||||||
{$t('page.manage.menu.addChildMenu')}
|
|
||||||
</NButton>
|
|
||||||
)}
|
|
||||||
<NButton type="primary" ghost size="small" onClick={() => handleEdit(row)}>
|
|
||||||
{$t('common.edit')}
|
|
||||||
</NButton>
|
|
||||||
<NPopconfirm onPositiveClick={() => handleDelete(row.id)}>
|
|
||||||
{{
|
|
||||||
default: () => $t('common.confirmDelete'),
|
|
||||||
trigger: () => (
|
|
||||||
<NButton type="error" ghost size="small">
|
|
||||||
{$t('common.delete')}
|
|
||||||
</NButton>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</NPopconfirm>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);
|
|
||||||
|
|
||||||
const operateType = ref<OperateType>('add');
|
|
||||||
|
|
||||||
function handleAdd() {
|
|
||||||
operateType.value = 'add';
|
|
||||||
openModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleBatchDelete() {
|
|
||||||
// request
|
|
||||||
console.log(checkedRowKeys.value);
|
|
||||||
|
|
||||||
onBatchDeleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDelete(id: number) {
|
|
||||||
// request
|
|
||||||
console.log(id);
|
|
||||||
|
|
||||||
onDeleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** the edit menu data or the parent menu data when adding a child menu */
|
|
||||||
const editingData: Ref<Api.SystemManage.Menu | null> = ref(null);
|
|
||||||
|
|
||||||
function handleEdit(item: Api.SystemManage.Menu) {
|
|
||||||
operateType.value = 'edit';
|
|
||||||
editingData.value = { ...item };
|
|
||||||
|
|
||||||
openModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleAddChildMenu(item: Api.SystemManage.Menu) {
|
|
||||||
operateType.value = 'addChild';
|
|
||||||
|
|
||||||
editingData.value = { ...item };
|
|
||||||
|
|
||||||
openModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
const allPages = ref<string[]>([]);
|
|
||||||
|
|
||||||
async function getAllPages() {
|
|
||||||
const { data: pages } = await fetchGetAllPages();
|
|
||||||
allPages.value = pages || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
getAllPages();
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
|
||||||
init();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div ref="wrapperRef" class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
|
||||||
<NCard :title="$t('page.manage.menu.title')" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
|
|
||||||
<template #header-extra>
|
|
||||||
<TableHeaderOperation
|
|
||||||
v-model:columns="columnChecks"
|
|
||||||
:disabled-delete="checkedRowKeys.length === 0"
|
|
||||||
:loading="loading"
|
|
||||||
@add="handleAdd"
|
|
||||||
@delete="handleBatchDelete"
|
|
||||||
@refresh="getData"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<NDataTable
|
|
||||||
v-model:checked-row-keys="checkedRowKeys"
|
|
||||||
:columns="columns"
|
|
||||||
:data="data"
|
|
||||||
size="small"
|
|
||||||
:flex-height="!appStore.isMobile"
|
|
||||||
:scroll-x="1088"
|
|
||||||
:loading="loading"
|
|
||||||
:row-key="row => row.id"
|
|
||||||
remote
|
|
||||||
:pagination="pagination"
|
|
||||||
class="sm:h-full"
|
|
||||||
/>
|
|
||||||
<MenuOperateModal
|
|
||||||
v-model:visible="visible"
|
|
||||||
:operate-type="operateType"
|
|
||||||
:row-data="editingData"
|
|
||||||
:all-pages="allPages"
|
|
||||||
@submitted="getDataByPage"
|
|
||||||
/>
|
|
||||||
</NCard>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,467 +0,0 @@
|
|||||||
<script setup lang="tsx">
|
|
||||||
import { computed, reactive, ref, watch } from 'vue';
|
|
||||||
import type { SelectOption } from 'naive-ui';
|
|
||||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { enableStatusOptions, menuIconTypeOptions, menuTypeOptions } from '@/constants/business';
|
|
||||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
|
||||||
import { getLocalIcons } from '@/utils/icon';
|
|
||||||
import { fetchGetAllRoles } from '@/service/api';
|
|
||||||
import {
|
|
||||||
getLayoutAndPage,
|
|
||||||
getPathParamFromRoutePath,
|
|
||||||
getRoutePathByRouteName,
|
|
||||||
getRoutePathWithParam,
|
|
||||||
transformLayoutAndPageToComponent
|
|
||||||
} from './shared';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'MenuOperateModal'
|
|
||||||
});
|
|
||||||
|
|
||||||
export type OperateType = NaiveUI.TableOperateType | 'addChild';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** the type of operation */
|
|
||||||
operateType: OperateType;
|
|
||||||
/** the edit menu data or the parent menu data when adding a child menu */
|
|
||||||
rowData?: Api.SystemManage.Menu | null;
|
|
||||||
/** all pages */
|
|
||||||
allPages: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
|
|
||||||
interface Emits {
|
|
||||||
(e: 'submitted'): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
|
||||||
|
|
||||||
const visible = defineModel<boolean>('visible', {
|
|
||||||
default: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
|
||||||
const { defaultRequiredRule } = useFormRules();
|
|
||||||
|
|
||||||
const title = computed(() => {
|
|
||||||
const titles: Record<OperateType, string> = {
|
|
||||||
add: $t('page.manage.menu.addMenu'),
|
|
||||||
addChild: $t('page.manage.menu.addChildMenu'),
|
|
||||||
edit: $t('page.manage.menu.editMenu')
|
|
||||||
};
|
|
||||||
return titles[props.operateType];
|
|
||||||
});
|
|
||||||
|
|
||||||
type Model = Pick<
|
|
||||||
Api.SystemManage.Menu,
|
|
||||||
| 'menuType'
|
|
||||||
| 'menuName'
|
|
||||||
| 'routeName'
|
|
||||||
| 'routePath'
|
|
||||||
| 'component'
|
|
||||||
| 'order'
|
|
||||||
| 'i18nKey'
|
|
||||||
| 'icon'
|
|
||||||
| 'iconType'
|
|
||||||
| 'status'
|
|
||||||
| 'parentId'
|
|
||||||
| 'keepAlive'
|
|
||||||
| 'constant'
|
|
||||||
| 'href'
|
|
||||||
| 'hideInMenu'
|
|
||||||
| 'activeMenu'
|
|
||||||
| 'multiTab'
|
|
||||||
| 'fixedIndexInTab'
|
|
||||||
> & {
|
|
||||||
query: NonNullable<Api.SystemManage.Menu['query']>;
|
|
||||||
buttons: NonNullable<Api.SystemManage.Menu['buttons']>;
|
|
||||||
layout: string;
|
|
||||||
page: string;
|
|
||||||
pathParam: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const model: Model = reactive(createDefaultModel());
|
|
||||||
|
|
||||||
function createDefaultModel(): Model {
|
|
||||||
return {
|
|
||||||
menuType: '1',
|
|
||||||
menuName: '',
|
|
||||||
routeName: '',
|
|
||||||
routePath: '',
|
|
||||||
pathParam: '',
|
|
||||||
component: '',
|
|
||||||
layout: '',
|
|
||||||
page: '',
|
|
||||||
i18nKey: null,
|
|
||||||
icon: '',
|
|
||||||
iconType: '1',
|
|
||||||
parentId: 0,
|
|
||||||
status: '1',
|
|
||||||
keepAlive: false,
|
|
||||||
constant: false,
|
|
||||||
order: 0,
|
|
||||||
href: null,
|
|
||||||
hideInMenu: false,
|
|
||||||
activeMenu: null,
|
|
||||||
multiTab: false,
|
|
||||||
fixedIndexInTab: null,
|
|
||||||
query: [],
|
|
||||||
buttons: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
type RuleKey = Extract<keyof Model, 'menuName' | 'status' | 'routeName' | 'routePath'>;
|
|
||||||
|
|
||||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
|
||||||
menuName: defaultRequiredRule,
|
|
||||||
status: defaultRequiredRule,
|
|
||||||
routeName: defaultRequiredRule,
|
|
||||||
routePath: defaultRequiredRule
|
|
||||||
};
|
|
||||||
|
|
||||||
const disabledMenuType = computed(() => props.operateType === 'edit');
|
|
||||||
|
|
||||||
const localIcons = getLocalIcons();
|
|
||||||
const localIconOptions = localIcons.map<SelectOption>(item => ({
|
|
||||||
label: () => (
|
|
||||||
<div class="flex-y-center gap-16px">
|
|
||||||
<SvgIcon localIcon={item} class="text-icon" />
|
|
||||||
<span>{item}</span>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
value: item
|
|
||||||
}));
|
|
||||||
|
|
||||||
const showLayout = computed(() => model.parentId === 0);
|
|
||||||
|
|
||||||
const showPage = computed(() => model.menuType === '2');
|
|
||||||
|
|
||||||
const pageOptions = computed(() => {
|
|
||||||
const allPages = [...props.allPages];
|
|
||||||
|
|
||||||
if (model.routeName && !allPages.includes(model.routeName)) {
|
|
||||||
allPages.unshift(model.routeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
const opts: CommonType.Option[] = allPages.map(page => ({
|
|
||||||
label: page,
|
|
||||||
value: page
|
|
||||||
}));
|
|
||||||
|
|
||||||
return opts;
|
|
||||||
});
|
|
||||||
|
|
||||||
const layoutOptions: CommonType.Option[] = [
|
|
||||||
{
|
|
||||||
label: 'base',
|
|
||||||
value: 'base'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'blank',
|
|
||||||
value: 'blank'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
/** the enabled role options */
|
|
||||||
const roleOptions = ref<CommonType.Option<string>[]>([]);
|
|
||||||
|
|
||||||
async function getRoleOptions() {
|
|
||||||
const { error, data } = await fetchGetAllRoles();
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
const options = data.map(item => ({
|
|
||||||
label: item.roleName,
|
|
||||||
value: item.roleCode
|
|
||||||
}));
|
|
||||||
|
|
||||||
roleOptions.value = [...options];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleInitModel() {
|
|
||||||
Object.assign(model, createDefaultModel());
|
|
||||||
|
|
||||||
if (!props.rowData) return;
|
|
||||||
|
|
||||||
if (props.operateType === 'addChild') {
|
|
||||||
const { id } = props.rowData;
|
|
||||||
|
|
||||||
Object.assign(model, { parentId: id });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.operateType === 'edit') {
|
|
||||||
const { component, ...rest } = props.rowData;
|
|
||||||
|
|
||||||
const { layout, page } = getLayoutAndPage(component);
|
|
||||||
const { path, param } = getPathParamFromRoutePath(rest.routePath);
|
|
||||||
|
|
||||||
Object.assign(model, rest, { layout, page, routePath: path, pathParam: param });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!model.query) {
|
|
||||||
model.query = [];
|
|
||||||
}
|
|
||||||
if (!model.buttons) {
|
|
||||||
model.buttons = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDrawer() {
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleUpdateRoutePathByRouteName() {
|
|
||||||
if (model.routeName) {
|
|
||||||
model.routePath = getRoutePathByRouteName(model.routeName);
|
|
||||||
} else {
|
|
||||||
model.routePath = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleUpdateI18nKeyByRouteName() {
|
|
||||||
if (model.routeName) {
|
|
||||||
model.i18nKey = `route.${model.routeName}` as App.I18n.I18nKey;
|
|
||||||
} else {
|
|
||||||
model.i18nKey = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCreateButton() {
|
|
||||||
const buttonItem: Api.SystemManage.MenuButton = {
|
|
||||||
code: '',
|
|
||||||
desc: ''
|
|
||||||
};
|
|
||||||
|
|
||||||
return buttonItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSubmitParams() {
|
|
||||||
const { layout, page, pathParam, ...params } = model;
|
|
||||||
|
|
||||||
const component = transformLayoutAndPageToComponent(layout, page);
|
|
||||||
const routePath = getRoutePathWithParam(model.routePath, pathParam);
|
|
||||||
|
|
||||||
params.component = component;
|
|
||||||
params.routePath = routePath;
|
|
||||||
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSubmit() {
|
|
||||||
await validate();
|
|
||||||
|
|
||||||
const params = getSubmitParams();
|
|
||||||
|
|
||||||
console.log('params: ', params);
|
|
||||||
|
|
||||||
// request
|
|
||||||
window.$message?.success($t('common.updateSuccess'));
|
|
||||||
closeDrawer();
|
|
||||||
emit('submitted');
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(visible, () => {
|
|
||||||
if (visible.value) {
|
|
||||||
handleInitModel();
|
|
||||||
restoreValidation();
|
|
||||||
getRoleOptions();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => model.routeName,
|
|
||||||
() => {
|
|
||||||
handleUpdateRoutePathByRouteName();
|
|
||||||
handleUpdateI18nKeyByRouteName();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NModal v-model:show="visible" :title="title" preset="card" class="w-800px">
|
|
||||||
<NScrollbar class="h-480px pr-20px">
|
|
||||||
<NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="100">
|
|
||||||
<NGrid responsive="screen" item-responsive>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.menuType')" path="menuType">
|
|
||||||
<NRadioGroup v-model:value="model.menuType" :disabled="disabledMenuType">
|
|
||||||
<NRadio v-for="item in menuTypeOptions" :key="item.value" :value="item.value" :label="$t(item.label)" />
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.menuName')" path="menuName">
|
|
||||||
<NInput v-model:value="model.menuName" :placeholder="$t('page.manage.menu.form.menuName')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.routeName')" path="routeName">
|
|
||||||
<NInput v-model:value="model.routeName" :placeholder="$t('page.manage.menu.form.routeName')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.routePath')" path="routePath">
|
|
||||||
<NInput v-model:value="model.routePath" disabled :placeholder="$t('page.manage.menu.form.routePath')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.pathParam')" path="pathParam">
|
|
||||||
<NInput v-model:value="model.pathParam" :placeholder="$t('page.manage.menu.form.pathParam')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi v-if="showLayout" span="24 m:12" :label="$t('page.manage.menu.layout')" path="layout">
|
|
||||||
<NSelect
|
|
||||||
v-model:value="model.layout"
|
|
||||||
:options="layoutOptions"
|
|
||||||
:placeholder="$t('page.manage.menu.form.layout')"
|
|
||||||
/>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi v-if="showPage" span="24 m:12" :label="$t('page.manage.menu.page')" path="page">
|
|
||||||
<NSelect
|
|
||||||
v-model:value="model.page"
|
|
||||||
:options="pageOptions"
|
|
||||||
:placeholder="$t('page.manage.menu.form.page')"
|
|
||||||
/>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.i18nKey')" path="i18nKey">
|
|
||||||
<NInput v-model:value="model.i18nKey" :placeholder="$t('page.manage.menu.form.i18nKey')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.order')" path="order">
|
|
||||||
<NInputNumber v-model:value="model.order" class="w-full" :placeholder="$t('page.manage.menu.form.order')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.iconTypeTitle')" path="iconType">
|
|
||||||
<NRadioGroup v-model:value="model.iconType">
|
|
||||||
<NRadio
|
|
||||||
v-for="item in menuIconTypeOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
:label="$t(item.label)"
|
|
||||||
/>
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.icon')" path="icon">
|
|
||||||
<template v-if="model.iconType === '1'">
|
|
||||||
<NInput v-model:value="model.icon" :placeholder="$t('page.manage.menu.form.icon')" class="flex-1">
|
|
||||||
<template #suffix>
|
|
||||||
<SvgIcon v-if="model.icon" :icon="model.icon" class="text-icon" />
|
|
||||||
</template>
|
|
||||||
</NInput>
|
|
||||||
</template>
|
|
||||||
<template v-if="model.iconType === '2'">
|
|
||||||
<NSelect
|
|
||||||
v-model:value="model.icon"
|
|
||||||
:placeholder="$t('page.manage.menu.form.localIcon')"
|
|
||||||
:options="localIconOptions"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.menuStatus')" path="status">
|
|
||||||
<NRadioGroup v-model:value="model.status">
|
|
||||||
<NRadio
|
|
||||||
v-for="item in enableStatusOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
:label="$t(item.label)"
|
|
||||||
/>
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.keepAlive')" path="keepAlive">
|
|
||||||
<NRadioGroup v-model:value="model.keepAlive">
|
|
||||||
<NRadio :value="true" :label="$t('common.yesOrNo.yes')" />
|
|
||||||
<NRadio :value="false" :label="$t('common.yesOrNo.no')" />
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.constant')" path="constant">
|
|
||||||
<NRadioGroup v-model:value="model.constant">
|
|
||||||
<NRadio :value="true" :label="$t('common.yesOrNo.yes')" />
|
|
||||||
<NRadio :value="false" :label="$t('common.yesOrNo.no')" />
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.href')" path="href">
|
|
||||||
<NInput v-model:value="model.href" :placeholder="$t('page.manage.menu.form.href')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.hideInMenu')" path="hideInMenu">
|
|
||||||
<NRadioGroup v-model:value="model.hideInMenu">
|
|
||||||
<NRadio :value="true" :label="$t('common.yesOrNo.yes')" />
|
|
||||||
<NRadio :value="false" :label="$t('common.yesOrNo.no')" />
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi
|
|
||||||
v-if="model.hideInMenu"
|
|
||||||
span="24 m:12"
|
|
||||||
:label="$t('page.manage.menu.activeMenu')"
|
|
||||||
path="activeMenu"
|
|
||||||
>
|
|
||||||
<NSelect
|
|
||||||
v-model:value="model.activeMenu"
|
|
||||||
:options="pageOptions"
|
|
||||||
clearable
|
|
||||||
:placeholder="$t('page.manage.menu.form.activeMenu')"
|
|
||||||
/>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.multiTab')" path="multiTab">
|
|
||||||
<NRadioGroup v-model:value="model.multiTab">
|
|
||||||
<NRadio :value="true" :label="$t('common.yesOrNo.yes')" />
|
|
||||||
<NRadio :value="false" :label="$t('common.yesOrNo.no')" />
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" :label="$t('page.manage.menu.fixedIndexInTab')" path="fixedIndexInTab">
|
|
||||||
<NInputNumber
|
|
||||||
v-model:value="model.fixedIndexInTab"
|
|
||||||
class="w-full"
|
|
||||||
clearable
|
|
||||||
:placeholder="$t('page.manage.menu.form.fixedIndexInTab')"
|
|
||||||
/>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24" :label="$t('page.manage.menu.query')">
|
|
||||||
<NDynamicInput
|
|
||||||
v-model:value="model.query"
|
|
||||||
preset="pair"
|
|
||||||
:key-placeholder="$t('page.manage.menu.form.queryKey')"
|
|
||||||
:value-placeholder="$t('page.manage.menu.form.queryValue')"
|
|
||||||
>
|
|
||||||
<template #action="{ index, create, remove }">
|
|
||||||
<NSpace class="ml-12px">
|
|
||||||
<NButton size="medium" @click="() => create(index)">
|
|
||||||
<icon-ic:round-plus class="text-icon" />
|
|
||||||
</NButton>
|
|
||||||
<NButton size="medium" @click="() => remove(index)">
|
|
||||||
<icon-ic-round-remove class="text-icon" />
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
</NDynamicInput>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24" :label="$t('page.manage.menu.button')">
|
|
||||||
<NDynamicInput v-model:value="model.buttons" :on-create="handleCreateButton">
|
|
||||||
<template #default="{ value }">
|
|
||||||
<div class="ml-8px flex-y-center flex-1 gap-12px">
|
|
||||||
<NInput
|
|
||||||
v-model:value="value.code"
|
|
||||||
:placeholder="$t('page.manage.menu.form.buttonCode')"
|
|
||||||
class="flex-1"
|
|
||||||
/>
|
|
||||||
<NInput
|
|
||||||
v-model:value="value.desc"
|
|
||||||
:placeholder="$t('page.manage.menu.form.buttonDesc')"
|
|
||||||
class="flex-1"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #action="{ index, create, remove }">
|
|
||||||
<NSpace class="ml-12px">
|
|
||||||
<NButton size="medium" @click="() => create(index)">
|
|
||||||
<icon-ic:round-plus class="text-icon" />
|
|
||||||
</NButton>
|
|
||||||
<NButton size="medium" @click="() => remove(index)">
|
|
||||||
<icon-ic-round-remove class="text-icon" />
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
</NDynamicInput>
|
|
||||||
</NFormItemGi>
|
|
||||||
</NGrid>
|
|
||||||
</NForm>
|
|
||||||
</NScrollbar>
|
|
||||||
<template #footer>
|
|
||||||
<NSpace justify="end" :size="16">
|
|
||||||
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
|
|
||||||
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
</NModal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,79 +0,0 @@
|
|||||||
const LAYOUT_PREFIX = 'layout.';
|
|
||||||
const VIEW_PREFIX = 'view.';
|
|
||||||
const FIRST_LEVEL_ROUTE_COMPONENT_SPLIT = '$';
|
|
||||||
|
|
||||||
export function getLayoutAndPage(component?: string | null) {
|
|
||||||
let layout = '';
|
|
||||||
let page = '';
|
|
||||||
|
|
||||||
const [layoutOrPage = '', pageItem = ''] = component?.split(FIRST_LEVEL_ROUTE_COMPONENT_SPLIT) || [];
|
|
||||||
|
|
||||||
layout = getLayout(layoutOrPage);
|
|
||||||
page = getPage(pageItem || layoutOrPage);
|
|
||||||
|
|
||||||
return { layout, page };
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLayout(layout: string) {
|
|
||||||
return layout.startsWith(LAYOUT_PREFIX) ? layout.replace(LAYOUT_PREFIX, '') : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPage(page: string) {
|
|
||||||
return page.startsWith(VIEW_PREFIX) ? page.replace(VIEW_PREFIX, '') : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformLayoutAndPageToComponent(layout: string, page: string) {
|
|
||||||
const hasLayout = Boolean(layout);
|
|
||||||
const hasPage = Boolean(page);
|
|
||||||
|
|
||||||
if (hasLayout && hasPage) {
|
|
||||||
return `${LAYOUT_PREFIX}${layout}${FIRST_LEVEL_ROUTE_COMPONENT_SPLIT}${VIEW_PREFIX}${page}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasLayout) {
|
|
||||||
return `${LAYOUT_PREFIX}${layout}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasPage) {
|
|
||||||
return `${VIEW_PREFIX}${page}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get route name by route path
|
|
||||||
*
|
|
||||||
* @param routeName
|
|
||||||
*/
|
|
||||||
export function getRoutePathByRouteName(routeName: string) {
|
|
||||||
return `/${routeName.replace(/_/g, '/')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get path param from route path
|
|
||||||
*
|
|
||||||
* @param routePath route path
|
|
||||||
*/
|
|
||||||
export function getPathParamFromRoutePath(routePath: string) {
|
|
||||||
const [path, param = ''] = routePath.split('/:');
|
|
||||||
|
|
||||||
return {
|
|
||||||
path,
|
|
||||||
param
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get route path with param
|
|
||||||
*
|
|
||||||
* @param routePath route path
|
|
||||||
* @param param path param
|
|
||||||
*/
|
|
||||||
export function getRoutePathWithParam(routePath: string, param: string) {
|
|
||||||
if (param.trim()) {
|
|
||||||
return `${routePath}/:${param}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return routePath;
|
|
||||||
}
|
|
@ -1,177 +0,0 @@
|
|||||||
<script setup lang="tsx">
|
|
||||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
|
||||||
import { fetchGetRoleList } from '@/service/api';
|
|
||||||
import { useAppStore } from '@/store/modules/app';
|
|
||||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { enableStatusRecord } from '@/constants/business';
|
|
||||||
import RoleOperateDrawer from './modules/role-operate-drawer.vue';
|
|
||||||
import RoleSearch from './modules/role-search.vue';
|
|
||||||
|
|
||||||
const appStore = useAppStore();
|
|
||||||
|
|
||||||
const {
|
|
||||||
columns,
|
|
||||||
columnChecks,
|
|
||||||
data,
|
|
||||||
loading,
|
|
||||||
getData,
|
|
||||||
getDataByPage,
|
|
||||||
mobilePagination,
|
|
||||||
searchParams,
|
|
||||||
resetSearchParams
|
|
||||||
} = useTable({
|
|
||||||
apiFn: fetchGetRoleList,
|
|
||||||
apiParams: {
|
|
||||||
current: 1,
|
|
||||||
size: 10,
|
|
||||||
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
|
|
||||||
// the value can not be undefined, otherwise the property in Form will not be reactive
|
|
||||||
status: null,
|
|
||||||
roleName: null,
|
|
||||||
roleCode: null
|
|
||||||
},
|
|
||||||
columns: () => [
|
|
||||||
{
|
|
||||||
type: 'selection',
|
|
||||||
align: 'center',
|
|
||||||
width: 48
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'index',
|
|
||||||
title: $t('common.index'),
|
|
||||||
width: 64,
|
|
||||||
align: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'roleName',
|
|
||||||
title: $t('page.manage.role.roleName'),
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'roleCode',
|
|
||||||
title: $t('page.manage.role.roleCode'),
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'roleDesc',
|
|
||||||
title: $t('page.manage.role.roleDesc'),
|
|
||||||
minWidth: 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'status',
|
|
||||||
title: $t('page.manage.role.roleStatus'),
|
|
||||||
align: 'center',
|
|
||||||
width: 100,
|
|
||||||
render: row => {
|
|
||||||
if (row.status === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagMap: Record<Api.Common.EnableStatus, NaiveUI.ThemeColor> = {
|
|
||||||
1: 'success',
|
|
||||||
2: 'warning'
|
|
||||||
};
|
|
||||||
|
|
||||||
const label = $t(enableStatusRecord[row.status]);
|
|
||||||
|
|
||||||
return <NTag type={tagMap[row.status]}>{label}</NTag>;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'operate',
|
|
||||||
title: $t('common.operate'),
|
|
||||||
align: 'center',
|
|
||||||
width: 130,
|
|
||||||
render: row => (
|
|
||||||
<div class="flex-center gap-8px">
|
|
||||||
<NButton type="primary" ghost size="small" onClick={() => edit(row.id)}>
|
|
||||||
{$t('common.edit')}
|
|
||||||
</NButton>
|
|
||||||
<NPopconfirm onPositiveClick={() => handleDelete(row.id)}>
|
|
||||||
{{
|
|
||||||
default: () => $t('common.confirmDelete'),
|
|
||||||
trigger: () => (
|
|
||||||
<NButton type="error" ghost size="small">
|
|
||||||
{$t('common.delete')}
|
|
||||||
</NButton>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</NPopconfirm>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
drawerVisible,
|
|
||||||
operateType,
|
|
||||||
editingData,
|
|
||||||
handleAdd,
|
|
||||||
handleEdit,
|
|
||||||
checkedRowKeys,
|
|
||||||
onBatchDeleted,
|
|
||||||
onDeleted
|
|
||||||
// closeDrawer
|
|
||||||
} = useTableOperate(data, getData);
|
|
||||||
|
|
||||||
async function handleBatchDelete() {
|
|
||||||
// request
|
|
||||||
console.log(checkedRowKeys.value);
|
|
||||||
|
|
||||||
onBatchDeleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDelete(id: number) {
|
|
||||||
// request
|
|
||||||
console.log(id);
|
|
||||||
|
|
||||||
onDeleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
function edit(id: number) {
|
|
||||||
handleEdit(id);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
|
||||||
<RoleSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
|
|
||||||
<NCard :title="$t('page.manage.role.title')" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
|
|
||||||
<template #header-extra>
|
|
||||||
<TableHeaderOperation
|
|
||||||
v-model:columns="columnChecks"
|
|
||||||
:disabled-delete="checkedRowKeys.length === 0"
|
|
||||||
:loading="loading"
|
|
||||||
@add="handleAdd"
|
|
||||||
@delete="handleBatchDelete"
|
|
||||||
@refresh="getData"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<NDataTable
|
|
||||||
v-model:checked-row-keys="checkedRowKeys"
|
|
||||||
:columns="columns"
|
|
||||||
:data="data"
|
|
||||||
size="small"
|
|
||||||
:flex-height="!appStore.isMobile"
|
|
||||||
:scroll-x="702"
|
|
||||||
:loading="loading"
|
|
||||||
remote
|
|
||||||
:row-key="row => row.id"
|
|
||||||
:pagination="mobilePagination"
|
|
||||||
class="sm:h-full"
|
|
||||||
/>
|
|
||||||
<RoleOperateDrawer
|
|
||||||
v-model:visible="drawerVisible"
|
|
||||||
:operate-type="operateType"
|
|
||||||
:row-data="editingData"
|
|
||||||
@submitted="getDataByPage"
|
|
||||||
/>
|
|
||||||
</NCard>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,101 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { computed, shallowRef } from 'vue';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'ButtonAuthModal'
|
|
||||||
});
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** the roleId */
|
|
||||||
roleId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
|
|
||||||
const visible = defineModel<boolean>('visible', {
|
|
||||||
default: false
|
|
||||||
});
|
|
||||||
|
|
||||||
function closeModal() {
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const title = computed(() => $t('common.edit') + $t('page.manage.role.buttonAuth'));
|
|
||||||
|
|
||||||
type ButtonConfig = {
|
|
||||||
id: number;
|
|
||||||
label: string;
|
|
||||||
code: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const tree = shallowRef<ButtonConfig[]>([]);
|
|
||||||
|
|
||||||
async function getAllButtons() {
|
|
||||||
// request
|
|
||||||
tree.value = [
|
|
||||||
{ id: 1, label: 'button1', code: 'code1' },
|
|
||||||
{ id: 2, label: 'button2', code: 'code2' },
|
|
||||||
{ id: 3, label: 'button3', code: 'code3' },
|
|
||||||
{ id: 4, label: 'button4', code: 'code4' },
|
|
||||||
{ id: 5, label: 'button5', code: 'code5' },
|
|
||||||
{ id: 6, label: 'button6', code: 'code6' },
|
|
||||||
{ id: 7, label: 'button7', code: 'code7' },
|
|
||||||
{ id: 8, label: 'button8', code: 'code8' },
|
|
||||||
{ id: 9, label: 'button9', code: 'code9' },
|
|
||||||
{ id: 10, label: 'button10', code: 'code10' }
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const checks = shallowRef<number[]>([]);
|
|
||||||
|
|
||||||
async function getChecks() {
|
|
||||||
console.log(props.roleId);
|
|
||||||
// request
|
|
||||||
checks.value = [1, 2, 3, 4, 5];
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmit() {
|
|
||||||
console.log(checks.value, props.roleId);
|
|
||||||
// request
|
|
||||||
|
|
||||||
window.$message?.success?.($t('common.modifySuccess'));
|
|
||||||
|
|
||||||
closeModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
getAllButtons();
|
|
||||||
getChecks();
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
|
||||||
init();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NModal v-model:show="visible" :title="title" preset="card" class="w-480px">
|
|
||||||
<NTree
|
|
||||||
v-model:checked-keys="checks"
|
|
||||||
:data="tree"
|
|
||||||
key-field="id"
|
|
||||||
block-line
|
|
||||||
checkable
|
|
||||||
expand-on-click
|
|
||||||
virtual-scroll
|
|
||||||
class="h-280px"
|
|
||||||
/>
|
|
||||||
<template #footer>
|
|
||||||
<NSpace justify="end">
|
|
||||||
<NButton size="small" class="mt-16px" @click="closeModal">
|
|
||||||
{{ $t('common.cancel') }}
|
|
||||||
</NButton>
|
|
||||||
<NButton type="primary" size="small" class="mt-16px" @click="handleSubmit">
|
|
||||||
{{ $t('common.confirm') }}
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
</NModal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,130 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { computed, shallowRef, watch } from 'vue';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { fetchGetAllPages, fetchGetMenuTree } from '@/service/api';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'MenuAuthModal'
|
|
||||||
});
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** the roleId */
|
|
||||||
roleId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
|
|
||||||
const visible = defineModel<boolean>('visible', {
|
|
||||||
default: false
|
|
||||||
});
|
|
||||||
|
|
||||||
function closeModal() {
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const title = computed(() => $t('common.edit') + $t('page.manage.role.menuAuth'));
|
|
||||||
|
|
||||||
const home = shallowRef('');
|
|
||||||
|
|
||||||
async function getHome() {
|
|
||||||
console.log(props.roleId);
|
|
||||||
|
|
||||||
home.value = 'home';
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateHome(val: string) {
|
|
||||||
// request
|
|
||||||
|
|
||||||
home.value = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pages = shallowRef<string[]>([]);
|
|
||||||
|
|
||||||
async function getPages() {
|
|
||||||
const { error, data } = await fetchGetAllPages();
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
pages.value = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const pageSelectOptions = computed(() => {
|
|
||||||
const opts: CommonType.Option[] = pages.value.map(page => ({
|
|
||||||
label: page,
|
|
||||||
value: page
|
|
||||||
}));
|
|
||||||
|
|
||||||
return opts;
|
|
||||||
});
|
|
||||||
|
|
||||||
const tree = shallowRef<Api.SystemManage.MenuTree[]>([]);
|
|
||||||
|
|
||||||
async function getTree() {
|
|
||||||
const { error, data } = await fetchGetMenuTree();
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
tree.value = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checks = shallowRef<number[]>([]);
|
|
||||||
|
|
||||||
async function getChecks() {
|
|
||||||
console.log(props.roleId);
|
|
||||||
// request
|
|
||||||
checks.value = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21];
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmit() {
|
|
||||||
console.log(checks.value, props.roleId);
|
|
||||||
// request
|
|
||||||
|
|
||||||
window.$message?.success?.($t('common.modifySuccess'));
|
|
||||||
|
|
||||||
closeModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
getHome();
|
|
||||||
getPages();
|
|
||||||
getTree();
|
|
||||||
getChecks();
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(visible, val => {
|
|
||||||
if (val) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NModal v-model:show="visible" :title="title" preset="card" class="w-480px">
|
|
||||||
<div class="flex-y-center gap-16px pb-12px">
|
|
||||||
<div>{{ $t('page.manage.menu.home') }}</div>
|
|
||||||
<NSelect :value="home" :options="pageSelectOptions" size="small" class="w-160px" @update:value="updateHome" />
|
|
||||||
</div>
|
|
||||||
<NTree
|
|
||||||
v-model:checked-keys="checks"
|
|
||||||
:data="tree"
|
|
||||||
key-field="id"
|
|
||||||
checkable
|
|
||||||
expand-on-click
|
|
||||||
virtual-scroll
|
|
||||||
block-line
|
|
||||||
class="h-280px"
|
|
||||||
/>
|
|
||||||
<template #footer>
|
|
||||||
<NSpace justify="end">
|
|
||||||
<NButton size="small" class="mt-16px" @click="closeModal">
|
|
||||||
{{ $t('common.cancel') }}
|
|
||||||
</NButton>
|
|
||||||
<NButton type="primary" size="small" class="mt-16px" @click="handleSubmit">
|
|
||||||
{{ $t('common.confirm') }}
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
</NModal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,134 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { computed, reactive, watch } from 'vue';
|
|
||||||
import { useBoolean } from '@sa/hooks';
|
|
||||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { enableStatusOptions } from '@/constants/business';
|
|
||||||
import MenuAuthModal from './menu-auth-modal.vue';
|
|
||||||
import ButtonAuthModal from './button-auth-modal.vue';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'RoleOperateDrawer'
|
|
||||||
});
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** the type of operation */
|
|
||||||
operateType: NaiveUI.TableOperateType;
|
|
||||||
/** the edit row data */
|
|
||||||
rowData?: Api.SystemManage.Role | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
|
|
||||||
interface Emits {
|
|
||||||
(e: 'submitted'): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
|
||||||
|
|
||||||
const visible = defineModel<boolean>('visible', {
|
|
||||||
default: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
|
||||||
const { defaultRequiredRule } = useFormRules();
|
|
||||||
const { bool: menuAuthVisible, setTrue: openMenuAuthModal } = useBoolean();
|
|
||||||
const { bool: buttonAuthVisible, setTrue: openButtonAuthModal } = useBoolean();
|
|
||||||
|
|
||||||
const title = computed(() => {
|
|
||||||
const titles: Record<NaiveUI.TableOperateType, string> = {
|
|
||||||
add: $t('page.manage.role.addRole'),
|
|
||||||
edit: $t('page.manage.role.editRole')
|
|
||||||
};
|
|
||||||
return titles[props.operateType];
|
|
||||||
});
|
|
||||||
|
|
||||||
type Model = Pick<Api.SystemManage.Role, 'roleName' | 'roleCode' | 'roleDesc' | 'status'>;
|
|
||||||
|
|
||||||
const model: Model = reactive(createDefaultModel());
|
|
||||||
|
|
||||||
function createDefaultModel(): Model {
|
|
||||||
return {
|
|
||||||
roleName: '',
|
|
||||||
roleCode: '',
|
|
||||||
roleDesc: '',
|
|
||||||
status: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
type RuleKey = Exclude<keyof Model, 'roleDesc'>;
|
|
||||||
|
|
||||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
|
||||||
roleName: defaultRequiredRule,
|
|
||||||
roleCode: defaultRequiredRule,
|
|
||||||
status: defaultRequiredRule
|
|
||||||
};
|
|
||||||
|
|
||||||
const roleId = computed(() => props.rowData?.id || -1);
|
|
||||||
|
|
||||||
const isEdit = computed(() => props.operateType === 'edit');
|
|
||||||
|
|
||||||
function handleInitModel() {
|
|
||||||
Object.assign(model, createDefaultModel());
|
|
||||||
|
|
||||||
if (props.operateType === 'edit' && props.rowData) {
|
|
||||||
Object.assign(model, props.rowData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDrawer() {
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSubmit() {
|
|
||||||
await validate();
|
|
||||||
// request
|
|
||||||
window.$message?.success($t('common.updateSuccess'));
|
|
||||||
closeDrawer();
|
|
||||||
emit('submitted');
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(visible, () => {
|
|
||||||
if (visible.value) {
|
|
||||||
handleInitModel();
|
|
||||||
restoreValidation();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NDrawer v-model:show="visible" display-directive="show" :width="360">
|
|
||||||
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
|
||||||
<NForm ref="formRef" :model="model" :rules="rules">
|
|
||||||
<NFormItem :label="$t('page.manage.role.roleName')" path="roleName">
|
|
||||||
<NInput v-model:value="model.roleName" :placeholder="$t('page.manage.role.form.roleName')" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.role.roleCode')" path="roleCode">
|
|
||||||
<NInput v-model:value="model.roleCode" :placeholder="$t('page.manage.role.form.roleCode')" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.role.roleStatus')" path="status">
|
|
||||||
<NRadioGroup v-model:value="model.status">
|
|
||||||
<NRadio v-for="item in enableStatusOptions" :key="item.value" :value="item.value" :label="$t(item.label)" />
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.role.roleDesc')" path="roleDesc">
|
|
||||||
<NInput v-model:value="model.roleDesc" :placeholder="$t('page.manage.role.form.roleDesc')" />
|
|
||||||
</NFormItem>
|
|
||||||
</NForm>
|
|
||||||
<NSpace v-if="isEdit">
|
|
||||||
<NButton @click="openMenuAuthModal">{{ $t('page.manage.role.menuAuth') }}</NButton>
|
|
||||||
<MenuAuthModal v-model:visible="menuAuthVisible" :role-id="roleId" />
|
|
||||||
<NButton @click="openButtonAuthModal">{{ $t('page.manage.role.buttonAuth') }}</NButton>
|
|
||||||
<ButtonAuthModal v-model:visible="buttonAuthVisible" :role-id="roleId" />
|
|
||||||
</NSpace>
|
|
||||||
<template #footer>
|
|
||||||
<NSpace :size="16">
|
|
||||||
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
|
|
||||||
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
</NDrawerContent>
|
|
||||||
</NDrawer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,67 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { enableStatusOptions } from '@/constants/business';
|
|
||||||
import { translateOptions } from '@/utils/common';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'RoleSearch'
|
|
||||||
});
|
|
||||||
|
|
||||||
interface Emits {
|
|
||||||
(e: 'reset'): void;
|
|
||||||
(e: 'search'): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
|
||||||
|
|
||||||
const model = defineModel<Api.SystemManage.RoleSearchParams>('model', { required: true });
|
|
||||||
|
|
||||||
function reset() {
|
|
||||||
emit('reset');
|
|
||||||
}
|
|
||||||
|
|
||||||
function search() {
|
|
||||||
emit('search');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NCard :title="$t('common.search')" :bordered="false" size="small" class="card-wrapper">
|
|
||||||
<NForm :model="model" label-placement="left" :label-width="80">
|
|
||||||
<NGrid responsive="screen" item-responsive>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.role.roleName')" path="roleName" class="pr-24px">
|
|
||||||
<NInput v-model:value="model.roleName" :placeholder="$t('page.manage.role.form.roleName')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.role.roleCode')" path="roleCode" class="pr-24px">
|
|
||||||
<NInput v-model:value="model.roleCode" :placeholder="$t('page.manage.role.form.roleCode')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.role.roleStatus')" path="status" class="pr-24px">
|
|
||||||
<NSelect
|
|
||||||
v-model:value="model.status"
|
|
||||||
:placeholder="$t('page.manage.role.form.roleStatus')"
|
|
||||||
:options="translateOptions(enableStatusOptions)"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 s:12 m:6">
|
|
||||||
<NSpace class="w-full" justify="end">
|
|
||||||
<NButton @click="reset">
|
|
||||||
<template #icon>
|
|
||||||
<icon-ic-round-refresh class="text-icon" />
|
|
||||||
</template>
|
|
||||||
{{ $t('common.reset') }}
|
|
||||||
</NButton>
|
|
||||||
<NButton type="primary" ghost @click="search">
|
|
||||||
<template #icon>
|
|
||||||
<icon-ic-round-search class="text-icon" />
|
|
||||||
</template>
|
|
||||||
{{ $t('common.search') }}
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</NFormItemGi>
|
|
||||||
</NGrid>
|
|
||||||
</NForm>
|
|
||||||
</NCard>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,13 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
interface Props {
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
defineProps<Props>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LookForward />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,208 +0,0 @@
|
|||||||
<script setup lang="tsx">
|
|
||||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
|
||||||
import { fetchGetUserList } from '@/service/api';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { useAppStore } from '@/store/modules/app';
|
|
||||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
|
||||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
|
||||||
import UserOperateDrawer from './modules/user-operate-drawer.vue';
|
|
||||||
import UserSearch from './modules/user-search.vue';
|
|
||||||
|
|
||||||
const appStore = useAppStore();
|
|
||||||
|
|
||||||
const {
|
|
||||||
columns,
|
|
||||||
columnChecks,
|
|
||||||
data,
|
|
||||||
getData,
|
|
||||||
getDataByPage,
|
|
||||||
loading,
|
|
||||||
mobilePagination,
|
|
||||||
searchParams,
|
|
||||||
resetSearchParams
|
|
||||||
} = useTable({
|
|
||||||
apiFn: fetchGetUserList,
|
|
||||||
showTotal: true,
|
|
||||||
apiParams: {
|
|
||||||
current: 1,
|
|
||||||
size: 10,
|
|
||||||
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
|
|
||||||
// the value can not be undefined, otherwise the property in Form will not be reactive
|
|
||||||
status: null,
|
|
||||||
userName: null,
|
|
||||||
userGender: null,
|
|
||||||
nickName: null,
|
|
||||||
userPhone: null,
|
|
||||||
userEmail: null
|
|
||||||
},
|
|
||||||
columns: () => [
|
|
||||||
{
|
|
||||||
type: 'selection',
|
|
||||||
align: 'center',
|
|
||||||
width: 48
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'index',
|
|
||||||
title: $t('common.index'),
|
|
||||||
align: 'center',
|
|
||||||
width: 64
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'userName',
|
|
||||||
title: $t('page.manage.user.userName'),
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'userGender',
|
|
||||||
title: $t('page.manage.user.userGender'),
|
|
||||||
align: 'center',
|
|
||||||
width: 100,
|
|
||||||
render: row => {
|
|
||||||
if (row.userGender === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagMap: Record<Api.SystemManage.UserGender, NaiveUI.ThemeColor> = {
|
|
||||||
1: 'primary',
|
|
||||||
2: 'error'
|
|
||||||
};
|
|
||||||
|
|
||||||
const label = $t(userGenderRecord[row.userGender]);
|
|
||||||
|
|
||||||
return <NTag type={tagMap[row.userGender]}>{label}</NTag>;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'nickName',
|
|
||||||
title: $t('page.manage.user.nickName'),
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'userPhone',
|
|
||||||
title: $t('page.manage.user.userPhone'),
|
|
||||||
align: 'center',
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'userEmail',
|
|
||||||
title: $t('page.manage.user.userEmail'),
|
|
||||||
align: 'center',
|
|
||||||
minWidth: 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'status',
|
|
||||||
title: $t('page.manage.user.userStatus'),
|
|
||||||
align: 'center',
|
|
||||||
width: 100,
|
|
||||||
render: row => {
|
|
||||||
if (row.status === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagMap: Record<Api.Common.EnableStatus, NaiveUI.ThemeColor> = {
|
|
||||||
1: 'success',
|
|
||||||
2: 'warning'
|
|
||||||
};
|
|
||||||
|
|
||||||
const label = $t(enableStatusRecord[row.status]);
|
|
||||||
|
|
||||||
return <NTag type={tagMap[row.status]}>{label}</NTag>;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'operate',
|
|
||||||
title: $t('common.operate'),
|
|
||||||
align: 'center',
|
|
||||||
width: 130,
|
|
||||||
render: row => (
|
|
||||||
<div class="flex-center gap-8px">
|
|
||||||
<NButton type="primary" ghost size="small" onClick={() => edit(row.id)}>
|
|
||||||
{$t('common.edit')}
|
|
||||||
</NButton>
|
|
||||||
<NPopconfirm onPositiveClick={() => handleDelete(row.id)}>
|
|
||||||
{{
|
|
||||||
default: () => $t('common.confirmDelete'),
|
|
||||||
trigger: () => (
|
|
||||||
<NButton type="error" ghost size="small">
|
|
||||||
{$t('common.delete')}
|
|
||||||
</NButton>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</NPopconfirm>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
drawerVisible,
|
|
||||||
operateType,
|
|
||||||
editingData,
|
|
||||||
handleAdd,
|
|
||||||
handleEdit,
|
|
||||||
checkedRowKeys,
|
|
||||||
onBatchDeleted,
|
|
||||||
onDeleted
|
|
||||||
// closeDrawer
|
|
||||||
} = useTableOperate(data, getData);
|
|
||||||
|
|
||||||
async function handleBatchDelete() {
|
|
||||||
// request
|
|
||||||
console.log(checkedRowKeys.value);
|
|
||||||
|
|
||||||
onBatchDeleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDelete(id: number) {
|
|
||||||
// request
|
|
||||||
console.log(id);
|
|
||||||
|
|
||||||
onDeleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
function edit(id: number) {
|
|
||||||
handleEdit(id);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
|
||||||
<UserSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
|
|
||||||
<NCard :title="$t('page.manage.user.title')" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
|
|
||||||
<template #header-extra>
|
|
||||||
<TableHeaderOperation
|
|
||||||
v-model:columns="columnChecks"
|
|
||||||
:disabled-delete="checkedRowKeys.length === 0"
|
|
||||||
:loading="loading"
|
|
||||||
@add="handleAdd"
|
|
||||||
@delete="handleBatchDelete"
|
|
||||||
@refresh="getData"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<NDataTable
|
|
||||||
v-model:checked-row-keys="checkedRowKeys"
|
|
||||||
:columns="columns"
|
|
||||||
:data="data"
|
|
||||||
size="small"
|
|
||||||
:flex-height="!appStore.isMobile"
|
|
||||||
:scroll-x="962"
|
|
||||||
:loading="loading"
|
|
||||||
remote
|
|
||||||
:row-key="row => row.id"
|
|
||||||
:pagination="mobilePagination"
|
|
||||||
class="sm:h-full"
|
|
||||||
/>
|
|
||||||
<UserOperateDrawer
|
|
||||||
v-model:visible="drawerVisible"
|
|
||||||
:operate-type="operateType"
|
|
||||||
:row-data="editingData"
|
|
||||||
@submitted="getDataByPage"
|
|
||||||
/>
|
|
||||||
</NCard>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,166 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { computed, reactive, ref, watch } from 'vue';
|
|
||||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
|
||||||
import { fetchGetAllRoles } from '@/service/api';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'UserOperateDrawer'
|
|
||||||
});
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
/** the type of operation */
|
|
||||||
operateType: NaiveUI.TableOperateType;
|
|
||||||
/** the edit row data */
|
|
||||||
rowData?: Api.SystemManage.User | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
|
|
||||||
interface Emits {
|
|
||||||
(e: 'submitted'): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
|
||||||
|
|
||||||
const visible = defineModel<boolean>('visible', {
|
|
||||||
default: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
|
||||||
const { defaultRequiredRule } = useFormRules();
|
|
||||||
|
|
||||||
const title = computed(() => {
|
|
||||||
const titles: Record<NaiveUI.TableOperateType, string> = {
|
|
||||||
add: $t('page.manage.user.addUser'),
|
|
||||||
edit: $t('page.manage.user.editUser')
|
|
||||||
};
|
|
||||||
return titles[props.operateType];
|
|
||||||
});
|
|
||||||
|
|
||||||
type Model = Pick<
|
|
||||||
Api.SystemManage.User,
|
|
||||||
'userName' | 'userGender' | 'nickName' | 'userPhone' | 'userEmail' | 'userRoles' | 'status'
|
|
||||||
>;
|
|
||||||
|
|
||||||
const model: Model = reactive(createDefaultModel());
|
|
||||||
|
|
||||||
function createDefaultModel(): Model {
|
|
||||||
return {
|
|
||||||
userName: '',
|
|
||||||
userGender: null,
|
|
||||||
nickName: '',
|
|
||||||
userPhone: '',
|
|
||||||
userEmail: '',
|
|
||||||
userRoles: [],
|
|
||||||
status: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
type RuleKey = Extract<keyof Model, 'userName' | 'status'>;
|
|
||||||
|
|
||||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
|
||||||
userName: defaultRequiredRule,
|
|
||||||
status: defaultRequiredRule
|
|
||||||
};
|
|
||||||
|
|
||||||
/** the enabled role options */
|
|
||||||
const roleOptions = ref<CommonType.Option<string>[]>([]);
|
|
||||||
|
|
||||||
async function getRoleOptions() {
|
|
||||||
const { error, data } = await fetchGetAllRoles();
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
const options = data.map(item => ({
|
|
||||||
label: item.roleName,
|
|
||||||
value: item.roleCode
|
|
||||||
}));
|
|
||||||
|
|
||||||
// the mock data does not have the roleCode, so fill it
|
|
||||||
// if the real request, remove the following code
|
|
||||||
const userRoleOptions = model.userRoles.map(item => ({
|
|
||||||
label: item,
|
|
||||||
value: item
|
|
||||||
}));
|
|
||||||
// end
|
|
||||||
|
|
||||||
roleOptions.value = [...userRoleOptions, ...options];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleInitModel() {
|
|
||||||
Object.assign(model, createDefaultModel());
|
|
||||||
|
|
||||||
if (props.operateType === 'edit' && props.rowData) {
|
|
||||||
Object.assign(model, props.rowData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDrawer() {
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSubmit() {
|
|
||||||
await validate();
|
|
||||||
// request
|
|
||||||
window.$message?.success($t('common.updateSuccess'));
|
|
||||||
closeDrawer();
|
|
||||||
emit('submitted');
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(visible, () => {
|
|
||||||
if (visible.value) {
|
|
||||||
handleInitModel();
|
|
||||||
restoreValidation();
|
|
||||||
getRoleOptions();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NDrawer v-model:show="visible" display-directive="show" :width="360">
|
|
||||||
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
|
||||||
<NForm ref="formRef" :model="model" :rules="rules">
|
|
||||||
<NFormItem :label="$t('page.manage.user.userName')" path="userName">
|
|
||||||
<NInput v-model:value="model.userName" :placeholder="$t('page.manage.user.form.userName')" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.user.userGender')" path="userGender">
|
|
||||||
<NRadioGroup v-model:value="model.userGender">
|
|
||||||
<NRadio v-for="item in userGenderOptions" :key="item.value" :value="item.value" :label="$t(item.label)" />
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.user.nickName')" path="nickName">
|
|
||||||
<NInput v-model:value="model.nickName" :placeholder="$t('page.manage.user.form.nickName')" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.user.userPhone')" path="userPhone">
|
|
||||||
<NInput v-model:value="model.userPhone" :placeholder="$t('page.manage.user.form.userPhone')" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.user.userEmail')" path="email">
|
|
||||||
<NInput v-model:value="model.userEmail" :placeholder="$t('page.manage.user.form.userEmail')" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.user.userStatus')" path="status">
|
|
||||||
<NRadioGroup v-model:value="model.status">
|
|
||||||
<NRadio v-for="item in enableStatusOptions" :key="item.value" :value="item.value" :label="$t(item.label)" />
|
|
||||||
</NRadioGroup>
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem :label="$t('page.manage.user.userRole')" path="roles">
|
|
||||||
<NSelect
|
|
||||||
v-model:value="model.userRoles"
|
|
||||||
multiple
|
|
||||||
:options="roleOptions"
|
|
||||||
:placeholder="$t('page.manage.user.form.userRole')"
|
|
||||||
/>
|
|
||||||
</NFormItem>
|
|
||||||
</NForm>
|
|
||||||
<template #footer>
|
|
||||||
<NSpace :size="16">
|
|
||||||
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
|
|
||||||
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</template>
|
|
||||||
</NDrawerContent>
|
|
||||||
</NDrawer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,98 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
|
||||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
|
||||||
import { translateOptions } from '@/utils/common';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'UserSearch'
|
|
||||||
});
|
|
||||||
|
|
||||||
interface Emits {
|
|
||||||
(e: 'reset'): void;
|
|
||||||
(e: 'search'): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
|
||||||
|
|
||||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
|
||||||
|
|
||||||
const model = defineModel<Api.SystemManage.UserSearchParams>('model', { required: true });
|
|
||||||
|
|
||||||
type RuleKey = Extract<keyof Api.SystemManage.UserSearchParams, 'userEmail' | 'userPhone'>;
|
|
||||||
|
|
||||||
const rules = computed<Record<RuleKey, App.Global.FormRule>>(() => {
|
|
||||||
const { patternRules } = useFormRules(); // inside computed to make locale reactive
|
|
||||||
|
|
||||||
return {
|
|
||||||
userEmail: patternRules.email,
|
|
||||||
userPhone: patternRules.phone
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
async function reset() {
|
|
||||||
await restoreValidation();
|
|
||||||
emit('reset');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function search() {
|
|
||||||
await validate();
|
|
||||||
emit('search');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NCard :title="$t('common.search')" :bordered="false" size="small" class="card-wrapper">
|
|
||||||
<NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="80">
|
|
||||||
<NGrid responsive="screen" item-responsive>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.userName')" path="userName" class="pr-24px">
|
|
||||||
<NInput v-model:value="model.userName" :placeholder="$t('page.manage.user.form.userName')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.userGender')" path="userGender" class="pr-24px">
|
|
||||||
<NSelect
|
|
||||||
v-model:value="model.userGender"
|
|
||||||
:placeholder="$t('page.manage.user.form.userGender')"
|
|
||||||
:options="translateOptions(userGenderOptions)"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.nickName')" path="nickName" class="pr-24px">
|
|
||||||
<NInput v-model:value="model.nickName" :placeholder="$t('page.manage.user.form.nickName')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.userPhone')" path="userPhone" class="pr-24px">
|
|
||||||
<NInput v-model:value="model.userPhone" :placeholder="$t('page.manage.user.form.userPhone')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.userEmail')" path="userEmail" class="pr-24px">
|
|
||||||
<NInput v-model:value="model.userEmail" :placeholder="$t('page.manage.user.form.userEmail')" />
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.userStatus')" path="userStatus" class="pr-24px">
|
|
||||||
<NSelect
|
|
||||||
v-model:value="model.status"
|
|
||||||
:placeholder="$t('page.manage.user.form.userStatus')"
|
|
||||||
:options="translateOptions(enableStatusOptions)"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
</NFormItemGi>
|
|
||||||
<NFormItemGi span="24 m:12" class="pr-24px">
|
|
||||||
<NSpace class="w-full" justify="end">
|
|
||||||
<NButton @click="reset">
|
|
||||||
<template #icon>
|
|
||||||
<icon-ic-round-refresh class="text-icon" />
|
|
||||||
</template>
|
|
||||||
{{ $t('common.reset') }}
|
|
||||||
</NButton>
|
|
||||||
<NButton type="primary" ghost @click="search">
|
|
||||||
<template #icon>
|
|
||||||
<icon-ic-round-search class="text-icon" />
|
|
||||||
</template>
|
|
||||||
{{ $t('common.search') }}
|
|
||||||
</NButton>
|
|
||||||
</NSpace>
|
|
||||||
</NFormItemGi>
|
|
||||||
</NGrid>
|
|
||||||
</NForm>
|
|
||||||
</NCard>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,7 +0,0 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LookForward />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,7 +0,0 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LookForward />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,7 +0,0 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LookForward />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
Loading…
Reference in New Issue
Block a user