diff --git a/docs/template/soy.index.vue.vm b/docs/template/soy.index.vue.vm index 5ead75f9..a2803054 100644 --- a/docs/template/soy.index.vue.vm +++ b/docs/template/soy.index.vue.vm @@ -138,7 +138,7 @@ async function edit(#foreach($column in $columns)#if($column.isPk == '1')$column } async function handleExport() { - download('/${moduleName}/${businessName}/export', searchParams, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`); + download('/${moduleName}/${businessName}/export', searchParams, `${functionName}_#[[${new Date().getTime()}]]#.xlsx`); } diff --git a/src/components/custom/dict-tag.vue b/src/components/custom/dict-tag.vue index 9404a140..e3a41139 100644 --- a/src/components/custom/dict-tag.vue +++ b/src/components/custom/dict-tag.vue @@ -6,24 +6,39 @@ import { useDict } from '@/hooks/business/dict'; defineOptions({ name: 'DictTag' }); interface Props { - value: string; - dictCode: string; + value?: string; + dictCode?: string; immediate?: boolean; + dictData?: Api.System.DictData; [key: string]: any; } const props = withDefaults(defineProps(), { - immediate: false + immediate: false, + dictData: undefined, + dictCode: '', + value: '' }); -const attrs: TagProps = useAttrs(); -const { transformDictData } = useDict(props.dictCode, props.immediate); -const dictData = computed(() => transformDictData(props.value)); +const attrs = useAttrs() as TagProps; + +const dictTagData = computed(() => { + if (props.dictData) { + return props.dictData; + } + + if (props.dictCode && props.value) { + const { transformDictData } = useDict(props.dictCode, props.immediate); + return transformDictData(props.value); + } + + return null; +}); diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts index 69f8f0ea..d5444d83 100644 --- a/src/locales/langs/en-us.ts +++ b/src/locales/langs/en-us.ts @@ -169,7 +169,11 @@ const local: App.I18n.Schema = { system_menu: 'Menu Management', tool: 'System Tools', tool_gen: 'Code Generation', - system_user: 'User Management' + system_user: 'User Management', + system_dict: 'Dict Management', + system_dict_data: 'DictData MAnagement', + system_dict_type: 'DictType Management', + system_tenant: 'Tenant Management' }, page: { login: { diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts index e7068661..d423d016 100644 --- a/src/locales/langs/zh-cn.ts +++ b/src/locales/langs/zh-cn.ts @@ -169,7 +169,11 @@ const local: App.I18n.Schema = { system_menu: '菜单管理', tool: '系统工具', tool_gen: '代码生成', - system_user: '用户管理' + system_user: '用户管理', + system_dict: '字典管理', + system_dict_data: '字典数据管理', + system_dict_type: '字典类型管理', + system_tenant: '租户管理' }, page: { login: { diff --git a/src/router/elegant/imports.ts b/src/router/elegant/imports.ts index 7bfec1ad..852c8d60 100644 --- a/src/router/elegant/imports.ts +++ b/src/router/elegant/imports.ts @@ -21,6 +21,9 @@ export const views: Record Promise import("@/views/_builtin/iframe-page/[url].vue"), login: () => import("@/views/_builtin/login/index.vue"), home: () => import("@/views/home/index.vue"), + system_dict_data: () => import("@/views/system/dict/data/index.vue"), + system_dict: () => import("@/views/system/dict/index.vue"), + system_dict_type: () => import("@/views/system/dict/type/index.vue"), system_menu: () => import("@/views/system/menu/index.vue"), system_tenant: () => import("@/views/system/tenant/index.vue"), system_user: () => import("@/views/system/user/index.vue"), diff --git a/src/router/elegant/routes.ts b/src/router/elegant/routes.ts index 287b761c..d510e086 100644 --- a/src/router/elegant/routes.ts +++ b/src/router/elegant/routes.ts @@ -86,6 +86,35 @@ export const generatedRoutes: GeneratedRoute[] = [ order: 1 }, children: [ + { + name: 'system_dict', + path: '/system/dict', + component: 'view.system_dict', + meta: { + title: 'system_dict', + i18nKey: 'route.system_dict' + }, + children: [ + { + name: 'system_dict_data', + path: '/system/dict/data', + component: 'view.system_dict_data', + meta: { + title: 'system_dict_data', + i18nKey: 'route.system_dict_data' + } + }, + { + name: 'system_dict_type', + path: '/system/dict/type', + component: 'view.system_dict_type', + meta: { + title: 'system_dict_type', + i18nKey: 'route.system_dict_type' + } + } + ] + }, { name: 'system_menu', path: '/system/menu', diff --git a/src/router/elegant/transform.ts b/src/router/elegant/transform.ts index 317ab22f..d48f3649 100644 --- a/src/router/elegant/transform.ts +++ b/src/router/elegant/transform.ts @@ -170,6 +170,9 @@ const routeMap: RouteMap = { "iframe-page": "/iframe-page/:url", "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?", "system": "/system", + "system_dict": "/system/dict", + "system_dict_data": "/system/dict/data", + "system_dict_type": "/system/dict/type", "system_menu": "/system/menu", "system_tenant": "/system/tenant", "system_user": "/system/user", diff --git a/src/service/api/system/dict-data.ts b/src/service/api/system/dict-data.ts new file mode 100644 index 00000000..1a5d5893 --- /dev/null +++ b/src/service/api/system/dict-data.ts @@ -0,0 +1,36 @@ +import { request } from '@/service/request'; + +/** 获取字典数据列表 */ +export function fetchGetDictDataList(params?: Api.System.DictDataSearchParams) { + return request({ + url: '/system/dict/data/list', + method: 'get', + params + }); +} + +/** 新增字典数据 */ +export function fetchCreateDictData(data: Api.System.DictDataOperateParams) { + return request({ + url: '/system/dict/data', + method: 'post', + data + }); +} + +/** 修改字典数据 */ +export function fetchUpdateDictData(data: Api.System.DictDataOperateParams) { + return request({ + url: '/system/dict/data', + method: 'put', + data + }); +} + +/** 批量删除字典数据 */ +export function fetchBatchDeleteDictData(dictCodes: CommonType.IdType[]) { + return request({ + url: `/system/dict/data/${dictCodes.join(',')}`, + method: 'delete' + }); +} diff --git a/src/service/api/system/dict.ts b/src/service/api/system/dict.ts index 2fc54d55..0a8ec669 100644 --- a/src/service/api/system/dict.ts +++ b/src/service/api/system/dict.ts @@ -15,3 +15,37 @@ export function fetchGetDictTypeOption() { method: 'get' }); } +/** 获取字典类型列表 */ +export function fetchGetDictTypeList(params?: Api.System.DictTypeSearchParams) { + return request({ + url: '/system/dict/type/list', + method: 'get', + params + }); +} + +/** 新增字典类型 */ +export function fetchCreateDictType(data: Api.System.DictTypeOperateParams) { + return request({ + url: '/system/dict/type', + method: 'post', + data + }); +} + +/** 修改字典类型 */ +export function fetchUpdateDictType(data: Api.System.DictTypeOperateParams) { + return request({ + url: '/system/dict/type', + method: 'put', + data + }); +} + +/** 批量删除字典类型 */ +export function fetchBatchDeleteDictType(dictIds: CommonType.IdType[]) { + return request({ + url: `/system/dict/type/${dictIds.join(',')}`, + method: 'delete' + }); +} diff --git a/src/service/api/system/tenantPackage.ts b/src/service/api/system/tenant-package.ts similarity index 100% rename from src/service/api/system/tenantPackage.ts rename to src/service/api/system/tenant-package.ts diff --git a/src/store/modules/route/index.ts b/src/store/modules/route/index.ts index a6f91863..935ce603 100644 --- a/src/store/modules/route/index.ts +++ b/src/store/modules/route/index.ts @@ -239,7 +239,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => { /** Init auth route */ async function initAuthRoute() { // check if user info is initialized - if (!authStore.userInfo.userId) { + if (!authStore.userInfo.user?.userId) { await authStore.initUserInfo(); } diff --git a/src/typings/api/system.api.d.ts b/src/typings/api/system.api.d.ts index f538c0b7..49ce6b47 100644 --- a/src/typings/api/system.api.d.ts +++ b/src/typings/api/system.api.d.ts @@ -232,7 +232,7 @@ declare namespace Api { /** 字典类型 */ type DictType = Common.CommonRecord<{ /** 字典主键 */ - dictId: number; + dictId: CommonType.IdType; /** 字典名称 */ dictName: string; /** 字典类型 */ @@ -241,12 +241,25 @@ declare namespace Api { remark: string; }>; + /** dict type search params */ + type DictTypeSearchParams = CommonType.RecordNullable< + Pick & Api.Common.CommonSearchParams + >; + + /** dict type operate params */ + type DictTypeOperateParams = CommonType.RecordNullable< + Pick + >; + + /** dict type list */ + type DictTypeList = Api.Common.PaginatingQueryRecord; + /** 字典数据 */ type DictData = Common.CommonRecord<{ /** 样式属性(其他样式扩展) */ cssClass: string; /** 字典编码 */ - dictCode: number; + dictCode: CommonType.IdType; /** 字典标签 */ dictLabel: string; /** 字典排序 */ @@ -263,6 +276,30 @@ declare namespace Api { remark: string; }>; + /** dict data search params */ + type DictDataSearchParams = CommonType.RecordNullable< + Pick & Api.Common.CommonSearchParams + >; + + /** dict data operate params */ + type DictDataOperateParams = CommonType.RecordNullable< + Pick< + Api.System.DictData, + | 'dictCode' + | 'dictSort' + | 'dictLabel' + | 'dictValue' + | 'dictType' + | 'cssClass' + | 'listClass' + | 'isDefault' + | 'remark' + > + >; + + /** dict data list */ + type DictDataList = Api.Common.PaginatingQueryRecord; + /** dept */ type Dept = Api.Common.CommonRecord<{ /** 部门id */ diff --git a/src/typings/components.d.ts b/src/typings/components.d.ts index f8d63331..fdc6d6f3 100644 --- a/src/typings/components.d.ts +++ b/src/typings/components.d.ts @@ -39,6 +39,7 @@ declare module 'vue' { IconIcRoundUpload: typeof import('~icons/ic/round-upload')['default'] IconLocalBanner: typeof import('~icons/local/banner')['default'] IconLocalLogo: typeof import('~icons/local/logo')['default'] + 'IconMaterialSymbols:syncRounded': typeof import('~icons/material-symbols/sync-rounded')['default'] IconMaterialSymbolsHelpOutline: typeof import('~icons/material-symbols/help-outline')['default'] IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default'] IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default'] @@ -103,6 +104,7 @@ declare module 'vue' { NSelect: typeof import('naive-ui')['NSelect'] NSpace: typeof import('naive-ui')['NSpace'] NSpin: typeof import('naive-ui')['NSpin'] + NSplit: typeof import('naive-ui')['NSplit'] NStatistic: typeof import('naive-ui')['NStatistic'] NSwitch: typeof import('naive-ui')['NSwitch'] NTab: typeof import('naive-ui')['NTab'] diff --git a/src/typings/elegant-router.d.ts b/src/typings/elegant-router.d.ts index 7e6cbcc3..24f0c2de 100644 --- a/src/typings/elegant-router.d.ts +++ b/src/typings/elegant-router.d.ts @@ -24,6 +24,9 @@ declare module "@elegant-router/types" { "iframe-page": "/iframe-page/:url"; "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?"; "system": "/system"; + "system_dict": "/system/dict"; + "system_dict_data": "/system/dict/data"; + "system_dict_type": "/system/dict/type"; "system_menu": "/system/menu"; "system_tenant": "/system/tenant"; "system_user": "/system/user"; @@ -90,6 +93,9 @@ declare module "@elegant-router/types" { | "iframe-page" | "login" | "home" + | "system_dict_data" + | "system_dict" + | "system_dict_type" | "system_menu" | "system_tenant" | "system_user" diff --git a/src/views/system/dict/data/index.vue b/src/views/system/dict/data/index.vue new file mode 100644 index 00000000..74814bce --- /dev/null +++ b/src/views/system/dict/data/index.vue @@ -0,0 +1,218 @@ + + + + + diff --git a/src/views/system/dict/data/modules/dict-data-operate-drawer.vue b/src/views/system/dict/data/modules/dict-data-operate-drawer.vue new file mode 100644 index 00000000..b9e30f44 --- /dev/null +++ b/src/views/system/dict/data/modules/dict-data-operate-drawer.vue @@ -0,0 +1,169 @@ + + + + + +@/service/api/system/dict-data diff --git a/src/views/system/dict/data/modules/dict-data-search.vue b/src/views/system/dict/data/modules/dict-data-search.vue new file mode 100644 index 00000000..c9ae75e6 --- /dev/null +++ b/src/views/system/dict/data/modules/dict-data-search.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/views/system/dict/index.vue b/src/views/system/dict/index.vue new file mode 100644 index 00000000..f8a289d6 --- /dev/null +++ b/src/views/system/dict/index.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/src/views/system/dict/mitt.ts b/src/views/system/dict/mitt.ts new file mode 100644 index 00000000..39a32405 --- /dev/null +++ b/src/views/system/dict/mitt.ts @@ -0,0 +1,8 @@ +import mitt from 'mitt'; + +/** dictType: string */ +type Events = { + rowClick: string; +}; + +export const emitter = mitt(); diff --git a/src/views/system/dict/type/index.vue b/src/views/system/dict/type/index.vue new file mode 100644 index 00000000..50658ae1 --- /dev/null +++ b/src/views/system/dict/type/index.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/src/views/system/dict/type/modules/dict-type-operate-drawer.vue b/src/views/system/dict/type/modules/dict-type-operate-drawer.vue new file mode 100644 index 00000000..74ee5f09 --- /dev/null +++ b/src/views/system/dict/type/modules/dict-type-operate-drawer.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/src/views/system/dict/type/modules/dict-type-search.vue b/src/views/system/dict/type/modules/dict-type-search.vue new file mode 100644 index 00000000..1b06a0a2 --- /dev/null +++ b/src/views/system/dict/type/modules/dict-type-search.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/src/views/system/tenant/index.vue b/src/views/system/tenant/index.vue index 1ca0af5f..321fbc6f 100644 --- a/src/views/system/tenant/index.vue +++ b/src/views/system/tenant/index.vue @@ -192,7 +192,7 @@ async function handleSyncTenantDict() { } async function handleExport() { - download('/system/tenant/export', searchParams, '租户列表.xlsx'); + download('/system/tenant/export', searchParams, `租户列表_${new Date().getTime()}.xlsx`); } diff --git a/src/views/system/tenant/modules/tenant-operate-drawer.vue b/src/views/system/tenant/modules/tenant-operate-drawer.vue index 482fb98f..424ce4f2 100644 --- a/src/views/system/tenant/modules/tenant-operate-drawer.vue +++ b/src/views/system/tenant/modules/tenant-operate-drawer.vue @@ -4,7 +4,7 @@ import { useLoading } from '@sa/hooks'; import { useFormRules, useNaiveForm } from '@/hooks/common/form'; import { $t } from '@/locales'; import { fetchCreateTenant, fetchUpdateTenant } from '@/service/api/system/tenant'; -import { fetchGetTenantPackageSelectList } from '@/service/api/system/tenantPackage'; +import { fetchGetTenantPackageSelectList } from '@/service/api/system/tenant-package'; defineOptions({ name: 'TenantOperateDrawer' @@ -72,7 +72,7 @@ type RuleKey = Extract< const rules: Record = { id: createRequiredRule('id不能为空'), contactUserName: createRequiredRule('联系人不能为空'), - contactPhone: [createRequiredRule('联系电话不能为空'), patternRules.phone], + contactPhone: [createRequiredRule('联系电话不能为空'), { ...patternRules.phone, trigger: ['blur', 'change'] }], companyName: createRequiredRule('企业名称不能为空'), packageId: createRequiredRule('租户套餐不能为空'), accountCount: createRequiredRule('用户数量不能为空'), @@ -320,3 +320,4 @@ watch(visible, () => { +@/service/api/system/tenant-package \ No newline at end of file