mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-23 23:39:47 +08:00
feat: 测试代码生成
This commit is contained in:
@ -71,10 +71,10 @@ public class VelocityUtils {
|
||||
velocityContext.put("pkColumn", genTable.getPkColumn());
|
||||
velocityContext.put("importList", getImportList(genTable));
|
||||
velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
|
||||
velocityContext.put("columns", getColumns(genTable));
|
||||
velocityContext.put("table", genTable);
|
||||
velocityContext.put("dicts", getDicts(genTable));
|
||||
velocityContext.put("dictList", getDictList(genTable));
|
||||
velocityContext.put("columns", getColumns(genTable));
|
||||
velocityContext.put("table", genTable);
|
||||
setMenuVelocityContext(velocityContext, genTable);
|
||||
if (GenConstants.TPL_TREE.equals(tplCategory)) {
|
||||
setTreeVelocityContext(velocityContext, genTable);
|
||||
@ -178,7 +178,7 @@ public class VelocityUtils {
|
||||
if (template.contains("soy.index.vue.vm")) {
|
||||
fileName = StringUtils.format("soybean/views/{}/{}/index.vue", moduleName, businessName);
|
||||
} else if (template.contains("soy.api.d.ts.vm")) {
|
||||
fileName = StringUtils.format("soybean/typings/api/{}.d.ts", moduleName);
|
||||
fileName = StringUtils.format("soybean/typings/api/{}.api.d.ts", moduleName);
|
||||
} else if (template.contains("soy.api.ts.vm")) {
|
||||
fileName = StringUtils.format("soybean/api/{}/{}.ts", moduleName, businessName);
|
||||
} else if (template.contains("soy.search.vue.vm")) {
|
||||
|
2
docs/template/api/soy.api.ts.vm
vendored
2
docs/template/api/soy.api.ts.vm
vendored
@ -28,7 +28,7 @@ export function fetchUpdate${BusinessName} (data: Api.${ModuleName}.${BusinessNa
|
||||
}
|
||||
|
||||
/** 批量删除${functionName} */
|
||||
export function fetchDelete${BusinessName} (${pkColumn.javaField}s: CommonType.IdType[]) {
|
||||
export function fetchBatchDelete${BusinessName} (${pkColumn.javaField}s: CommonType.IdType[]) {
|
||||
return request<boolean>({
|
||||
url: `/${moduleName}/${businessName}/${${pkColumn.javaField}s.join(',')}`,
|
||||
method: 'delete'
|
||||
|
@ -3,6 +3,7 @@ import { computed, reactive, watch } from 'vue';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
import { fetchCreate${BusinessName}, fetchUpdate${BusinessName} } from '@/service/api/${moduleName}/${businessName}';
|
||||
#if($dictList && $dictList.size() > 0)import { useDict } from '@/hooks/business/dict';#end
|
||||
|
||||
defineOptions({
|
||||
name: '${BusinessName}OperateDrawer'
|
||||
|
5
docs/template/modules/soy.search.vue.vm
vendored
5
docs/template/modules/soy.search.vue.vm
vendored
@ -3,6 +3,7 @@
|
||||
import { ref } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { useNaiveForm } from '@/hooks/common/form';
|
||||
#if($dictList && $dictList.size() > 0)import { useDict } from '@/hooks/business/dict';#end
|
||||
|
||||
defineOptions({
|
||||
name: '${BusinessName}Search'
|
||||
@ -27,14 +28,14 @@ const model = defineModel<Api.$ModuleName.${BusinessName}SearchParams>('model',
|
||||
|
||||
#if($dictList && $dictList.size() > 0)
|
||||
#foreach($dict in $dictList)
|
||||
const { options: ${dict.name}Options } = useDict(${dict.type}#if($dict.immediate), false#end);
|
||||
const { options: ${dict.name}Options } = useDict('${dict.type}#if($dict.immediate)', false#end);
|
||||
#end#end
|
||||
|
||||
async function reset() {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
const dateRange${AttrName}.value = undefined;
|
||||
dateRange${AttrName}.value = undefined;
|
||||
#end
|
||||
#end
|
||||
await restoreValidation();
|
||||
|
6
docs/template/soy.index.vue.vm
vendored
6
docs/template/soy.index.vue.vm
vendored
@ -26,8 +26,8 @@ const {
|
||||
} = useTable({
|
||||
apiFn: fetchGet${BusinessName}List,
|
||||
apiParams: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
pageNum: 1,
|
||||
pageSize: 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
|
||||
#foreach ($column in $columns)
|
||||
@ -109,7 +109,7 @@ async function handleDelete(#foreach($column in $columns)#if($column.isPk == '1'
|
||||
onDeleted();
|
||||
}
|
||||
|
||||
async function edit(id: CommonType.IdType) {
|
||||
async function edit(#foreach($column in $columns)#if($column.isPk == '1')$column.javaField#end#end: CommonType.IdType) {
|
||||
handleEdit('#foreach($column in $columns)#if($column.isPk == '1')$column.javaField#end#end', #foreach($column in $columns)#if($column.isPk == '1')$column.javaField#end#end);
|
||||
}
|
||||
</script>
|
||||
|
28
src/components/custom/dict-radio.vue
Normal file
28
src/components/custom/dict-radio.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import { useDict } from '@/hooks/business/dict';
|
||||
|
||||
defineOptions({ name: 'DictRadio' });
|
||||
|
||||
interface Props {
|
||||
dictCode: string;
|
||||
immediate?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
immediate: true
|
||||
});
|
||||
|
||||
const value = defineModel<string | null>('value', { required: false });
|
||||
|
||||
const { options } = useDict(props.dictCode, props.immediate);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NRadioGroup v-model:value="value">
|
||||
<NSpace>
|
||||
<NRadio v-for="option in options" :key="option.value" :value="option.value" :label="option.label" />
|
||||
</NSpace>
|
||||
</NRadioGroup>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -1,46 +1,30 @@
|
||||
<script setup lang="tsx">
|
||||
import { ref, useAttrs } from 'vue';
|
||||
import { useLoading } from '@sa/hooks';
|
||||
import type { SelectOption, SelectProps } from 'naive-ui';
|
||||
import { fetchGetDictTypeOption } from '@/service/api/system';
|
||||
<script setup lang="ts">
|
||||
import { useAttrs } from 'vue';
|
||||
import type { SelectProps } from 'naive-ui';
|
||||
import { useDict } from '@/hooks/business/dict';
|
||||
|
||||
defineOptions({ name: 'DictSelect' });
|
||||
|
||||
interface Props {
|
||||
dictCode: string;
|
||||
immediate?: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
immediate: true
|
||||
});
|
||||
|
||||
const value = defineModel<string>('value', { required: true });
|
||||
const value = defineModel<string | null>('value', { required: true });
|
||||
|
||||
const attrs: SelectProps = useAttrs();
|
||||
const options = ref<SelectOption[]>([]);
|
||||
const { loading, startLoading, endLoading } = useLoading();
|
||||
|
||||
async function getDeptOptions() {
|
||||
startLoading();
|
||||
const { error, data } = await fetchGetDictTypeOption();
|
||||
if (error) return;
|
||||
options.value = data.map(dict => ({
|
||||
value: dict.dictType!,
|
||||
label: () => (
|
||||
<div class="w-520px flex justify-between">
|
||||
<span>{dict.dictType}</span>
|
||||
<span>{dict.dictName}</span>
|
||||
</div>
|
||||
)
|
||||
}));
|
||||
endLoading();
|
||||
}
|
||||
|
||||
getDeptOptions();
|
||||
const { options } = useDict(props.dictCode, props.immediate);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSelect
|
||||
v-model:value="value"
|
||||
:loading="loading"
|
||||
:loading="!options.length"
|
||||
:options="options"
|
||||
:clear-filter-after-select="false"
|
||||
v-bind="attrs"
|
||||
|
@ -19,8 +19,8 @@ export const menuTypeOptions = transformRecordToOption(menuTypeRecord);
|
||||
|
||||
/** menu is frame */
|
||||
export const menuIsFrameRecord: Record<Api.System.IsMenuFrame, string> = {
|
||||
'0': '缓存',
|
||||
'1': '不缓存',
|
||||
'0': '是',
|
||||
'1': '否',
|
||||
'2': 'iframe'
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@ export function useDownload() {
|
||||
window.$loading?.startLoading('正在下载数据,请稍候...');
|
||||
const token = localStg.get('token');
|
||||
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
|
||||
const now = new Date().getTime();
|
||||
const now = Date.now();
|
||||
const formData = new FormData();
|
||||
Object.keys(params).forEach(key => formData.append(key, params[key]));
|
||||
fetch(`${baseURL}${url}?t=${now}`, {
|
||||
@ -58,7 +58,7 @@ export function useDownload() {
|
||||
const token = localStg.get('token');
|
||||
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
|
||||
const url = `/resource/oss/download/${ossId}`;
|
||||
const now = new Date().getTime();
|
||||
const now = Date.now();
|
||||
let fileName = String(`${ossId}-${now}`);
|
||||
fetch(`${baseURL}${url}?t=${now}`, {
|
||||
method: 'get',
|
||||
@ -80,7 +80,7 @@ export function useDownload() {
|
||||
window.$loading?.startLoading('正在下载数据,请稍候...');
|
||||
const token = localStg.get('token');
|
||||
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
|
||||
const now = new Date().getTime();
|
||||
const now = Date.now();
|
||||
fetch(`${baseURL}${url}${url.includes('?') ? '&' : '?'}t=${now}`, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
|
@ -160,7 +160,8 @@ const local: App.I18n.Schema = {
|
||||
system: 'System Management',
|
||||
system_menu: 'Menu Management',
|
||||
tool: 'System Tools',
|
||||
tool_gen: 'Code Generation'
|
||||
tool_gen: 'Code Generation',
|
||||
system_user: 'User Management'
|
||||
},
|
||||
page: {
|
||||
login: {
|
||||
|
@ -160,7 +160,8 @@ const local: App.I18n.Schema = {
|
||||
system: '系统管理',
|
||||
system_menu: '菜单管理',
|
||||
tool: '系统工具',
|
||||
tool_gen: '代码生成'
|
||||
tool_gen: '代码生成',
|
||||
system_user: '用户管理'
|
||||
},
|
||||
page: {
|
||||
login: {
|
||||
|
@ -22,5 +22,6 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
||||
login: () => import("@/views/_builtin/login/index.vue"),
|
||||
home: () => import("@/views/home/index.vue"),
|
||||
system_menu: () => import("@/views/system/menu/index.vue"),
|
||||
system_user: () => import("@/views/system/user/index.vue"),
|
||||
tool_gen: () => import("@/views/tool/gen/index.vue"),
|
||||
};
|
||||
|
@ -96,6 +96,15 @@ export const generatedRoutes: GeneratedRoute[] = [
|
||||
localIcon: 'menu-tree-table',
|
||||
order: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'system_user',
|
||||
path: '/system/user',
|
||||
component: 'view.system_user',
|
||||
meta: {
|
||||
title: 'system_user',
|
||||
i18nKey: 'route.system_user'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -171,6 +171,7 @@ const routeMap: RouteMap = {
|
||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
|
||||
"system": "/system",
|
||||
"system_menu": "/system/menu",
|
||||
"system_user": "/system/user",
|
||||
"tool": "/tool",
|
||||
"tool_gen": "/tool/gen"
|
||||
};
|
||||
|
@ -1,2 +1,3 @@
|
||||
export * from './menu';
|
||||
export * from './dict';
|
||||
export * from './user';
|
||||
|
36
src/service/api/system/user.ts
Normal file
36
src/service/api/system/user.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { request } from '@/service/request';
|
||||
|
||||
/** 获取用户信息列表 */
|
||||
export function fetchGetUserList(params?: Api.System.UserSearchParams) {
|
||||
return request<Api.System.UserList>({
|
||||
url: '/system/user/list',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/** 新增用户信息 */
|
||||
export function fetchCreateUser(data: Api.System.UserOperateParams) {
|
||||
return request<boolean>({
|
||||
url: '/system/user',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改用户信息 */
|
||||
export function fetchUpdateUser(data: Api.System.UserOperateParams) {
|
||||
return request<boolean>({
|
||||
url: '/system/user',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除用户信息 */
|
||||
export function fetchBatchDeleteUser(userIds: CommonType.IdType[]) {
|
||||
return request<boolean>({
|
||||
url: `/system/user/${userIds.join(',')}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
7
src/typings/api/api.d.ts
vendored
7
src/typings/api/api.d.ts
vendored
@ -21,9 +21,9 @@ declare namespace Api {
|
||||
}
|
||||
|
||||
/** common search params of table */
|
||||
type CommonSearchParams<T = any> = Pick<Common.PaginatingCommonParams, 'pageNum' | 'pageSize'> &
|
||||
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'pageNum' | 'pageSize'> &
|
||||
CommonType.RecordNullable<{
|
||||
orderByColumn: keyof T;
|
||||
orderByColumn: string;
|
||||
isAsc: 'asc' | 'desc';
|
||||
params: { [key: string]: any };
|
||||
}>;
|
||||
@ -69,8 +69,7 @@ declare namespace Api {
|
||||
type CommonTenantRecord<T = any> = {
|
||||
/** record tenant id */
|
||||
tenantId: string;
|
||||
} & CommonRecord &
|
||||
T;
|
||||
} & CommonRecord<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
191
src/typings/api/system.api.d.ts
vendored
191
src/typings/api/system.api.d.ts
vendored
@ -13,32 +13,32 @@ declare namespace Api {
|
||||
/** role */
|
||||
type Role = Common.CommonRecord<{
|
||||
/** 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) */
|
||||
dataScope?: string;
|
||||
dataScope: string;
|
||||
/** 部门树选择项是否关联显示 */
|
||||
deptCheckStrictly?: boolean;
|
||||
deptCheckStrictly: boolean;
|
||||
/** 用户是否存在此角色标识 默认不存在 */
|
||||
flag?: boolean;
|
||||
flag: boolean;
|
||||
/** 菜单树选择项是否关联显示 */
|
||||
menuCheckStrictly?: boolean;
|
||||
menuCheckStrictly: boolean;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 角色ID */
|
||||
roleId?: number;
|
||||
roleId: number;
|
||||
/** 角色权限字符串 */
|
||||
roleKey?: string;
|
||||
roleKey: string;
|
||||
/** 角色名称 */
|
||||
roleName?: string;
|
||||
roleName: string;
|
||||
/** 显示顺序 */
|
||||
roleSort?: number;
|
||||
roleSort: number;
|
||||
/** 角色状态(0正常 1停用) */
|
||||
status?: string;
|
||||
status: string;
|
||||
/** 是否管理员 */
|
||||
superAdmin?: boolean;
|
||||
superAdmin: boolean;
|
||||
}>;
|
||||
|
||||
/** role search params */
|
||||
type RoleSearchParams = CommonType.RecordNullable<
|
||||
Pick<Role, 'roleName' | 'roleKey' | 'status'> & Common.CommonSearchParams<Role>
|
||||
Pick<Role, 'roleName' | 'roleKey' | 'status'> & Common.CommonSearchParams
|
||||
>;
|
||||
|
||||
/** role list */
|
||||
@ -58,40 +58,59 @@ declare namespace Api {
|
||||
/** user */
|
||||
type User = Common.CommonTenantRecord<{
|
||||
/** 用户ID */
|
||||
userId?: CommonType.IdType;
|
||||
userId: CommonType.IdType;
|
||||
/** 部门ID */
|
||||
deptId?: CommonType.IdType;
|
||||
deptId: CommonType.IdType;
|
||||
/** 部门名称 */
|
||||
deptName: string;
|
||||
/** 用户账号 */
|
||||
userName?: string;
|
||||
userName: string;
|
||||
/** 用户昵称 */
|
||||
nickName?: string;
|
||||
nickName: string;
|
||||
/** 用户类型(sys_user系统用户) */
|
||||
userType?: string;
|
||||
userType: string;
|
||||
/** 用户邮箱 */
|
||||
email?: string;
|
||||
email: string;
|
||||
/** 手机号码 */
|
||||
phonenumber?: string;
|
||||
phonenumber: string;
|
||||
/** 用户性别(0男 1女 2未知) */
|
||||
sex?: string;
|
||||
sex: string;
|
||||
/** 头像地址 */
|
||||
avatar?: number;
|
||||
avatar: string;
|
||||
/** 密码 */
|
||||
password?: string;
|
||||
password: string;
|
||||
/** 帐号状态(0正常 1停用) */
|
||||
status?: string;
|
||||
status: string;
|
||||
/** 删除标志(0代表存在 2代表删除) */
|
||||
delFlag?: string;
|
||||
delFlag: string;
|
||||
/** 最后登录IP */
|
||||
loginIp?: string;
|
||||
loginIp: string;
|
||||
/** 最后登录时间 */
|
||||
loginDate?: Date;
|
||||
loginDate: Date;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
}>;
|
||||
|
||||
/** user search params */
|
||||
type UserSearchParams = CommonType.RecordNullable<
|
||||
Pick<User, 'userName' | 'sex' | 'nickName' | 'phonenumber' | 'email' | 'status'> & Common.CommonSearchParams<User>
|
||||
Pick<User, 'deptId' | 'userName' | 'nickName' | 'phonenumber' | 'status'> & Common.CommonSearchParams
|
||||
>;
|
||||
|
||||
/** user operate params */
|
||||
type UserOperateParams = CommonType.RecordNullable<
|
||||
Pick<
|
||||
User,
|
||||
| 'userId'
|
||||
| 'deptId'
|
||||
| 'userName'
|
||||
| 'nickName'
|
||||
| 'email'
|
||||
| 'phonenumber'
|
||||
| 'sex'
|
||||
| 'password'
|
||||
| 'status'
|
||||
| 'remark'
|
||||
> & { roleIds: string[] }
|
||||
>;
|
||||
|
||||
/** user list */
|
||||
@ -100,33 +119,33 @@ declare namespace Api {
|
||||
/** tenant */
|
||||
interface Tenant {
|
||||
/** id */
|
||||
id?: CommonType.IdType;
|
||||
id: CommonType.IdType;
|
||||
/** 租户编号 */
|
||||
tenantId?: string;
|
||||
tenantId: string;
|
||||
/** 联系人 */
|
||||
contactUserName?: string;
|
||||
contactUserName: string;
|
||||
/** 联系电话 */
|
||||
contactPhone?: string;
|
||||
contactPhone: string;
|
||||
/** 企业名称 */
|
||||
companyName?: string;
|
||||
companyName: string;
|
||||
/** 统一社会信用代码 */
|
||||
licenseNumber?: string;
|
||||
licenseNumber: string;
|
||||
/** 地址 */
|
||||
address?: string;
|
||||
address: string;
|
||||
/** 域名 */
|
||||
domain?: string;
|
||||
domain: string;
|
||||
/** 企业简介 */
|
||||
intro?: string;
|
||||
intro: string;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 租户套餐编号 */
|
||||
packageId?: number;
|
||||
packageId: number;
|
||||
/** 过期时间 */
|
||||
expireTime?: Date;
|
||||
expireTime: Date;
|
||||
/** 用户数量(-1不限制) */
|
||||
accountCount?: number;
|
||||
accountCount: number;
|
||||
/** 租户状态(0正常 1停用) */
|
||||
status?: string;
|
||||
status: string;
|
||||
/** 删除标志(0代表存在 2代表删除) */
|
||||
delFlag: string;
|
||||
}
|
||||
@ -159,39 +178,39 @@ declare namespace Api {
|
||||
|
||||
type Menu = Common.CommonRecord<{
|
||||
/** 菜单 ID */
|
||||
menuId?: CommonType.IdType;
|
||||
menuId: CommonType.IdType;
|
||||
/** 父菜单 ID */
|
||||
parentId?: CommonType.IdType;
|
||||
parentId: CommonType.IdType;
|
||||
/** 菜单名称 */
|
||||
menuName?: string;
|
||||
menuName: string;
|
||||
/** 显示顺序 */
|
||||
orderNum?: number;
|
||||
orderNum: number;
|
||||
/** 路由地址 */
|
||||
path?: string;
|
||||
path: string;
|
||||
/** 组件路径 */
|
||||
component?: string;
|
||||
component: string;
|
||||
/** 路由参数 */
|
||||
queryParam?: string;
|
||||
queryParam: string;
|
||||
/** 是否为外链(0是 1否 2iframe) */
|
||||
isFrame?: IsMenuFrame;
|
||||
isFrame: IsMenuFrame;
|
||||
/** 是否缓存(0缓存 1不缓存) */
|
||||
isCache?: Common.YesOrNoStatus;
|
||||
isCache: Common.YesOrNoStatus;
|
||||
/** 菜单类型(M目录 C菜单 F按钮) */
|
||||
menuType?: MenuType;
|
||||
menuType: MenuType;
|
||||
/** 显示状态(0显示 1隐藏) */
|
||||
visible?: Common.VisibleStatus;
|
||||
visible: Common.VisibleStatus;
|
||||
/** 菜单状态(0正常 1停用) */
|
||||
status?: Common.EnableStatus;
|
||||
status: Common.EnableStatus;
|
||||
/** 权限标识 */
|
||||
perms?: string;
|
||||
perms: string;
|
||||
/** 菜单图标 */
|
||||
icon?: string;
|
||||
icon: string;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 父菜单名称 */
|
||||
parentName?: string;
|
||||
parentName: string;
|
||||
/** 子菜单 */
|
||||
children?: MenuList;
|
||||
children: MenuList;
|
||||
}>;
|
||||
|
||||
/** menu list */
|
||||
@ -201,57 +220,59 @@ declare namespace Api {
|
||||
type MenuSearchParams = CommonType.RecordNullable<Pick<Menu, 'menuName' | 'status' | 'menuType' | 'parentId'>>;
|
||||
|
||||
/** menu operate params */
|
||||
type MenuOperateParams = Pick<
|
||||
Menu,
|
||||
| 'menuId'
|
||||
| 'menuName'
|
||||
| 'parentId'
|
||||
| 'orderNum'
|
||||
| 'path'
|
||||
| 'component'
|
||||
| 'queryParam'
|
||||
| 'isFrame'
|
||||
| 'isCache'
|
||||
| 'menuType'
|
||||
| 'visible'
|
||||
| 'status'
|
||||
| 'perms'
|
||||
| 'icon'
|
||||
| 'remark'
|
||||
type MenuOperateParams = CommonType.RecordNullable<
|
||||
Pick<
|
||||
Menu,
|
||||
| 'menuId'
|
||||
| 'menuName'
|
||||
| 'parentId'
|
||||
| 'orderNum'
|
||||
| 'path'
|
||||
| 'component'
|
||||
| 'queryParam'
|
||||
| 'isFrame'
|
||||
| 'isCache'
|
||||
| 'menuType'
|
||||
| 'visible'
|
||||
| 'status'
|
||||
| 'perms'
|
||||
| 'icon'
|
||||
| 'remark'
|
||||
>
|
||||
>;
|
||||
|
||||
/** 字典类型 */
|
||||
type DictType = Common.CommonRecord<{
|
||||
/** 字典主键 */
|
||||
dictId?: number;
|
||||
dictId: number;
|
||||
/** 字典名称 */
|
||||
dictName?: string;
|
||||
dictName: string;
|
||||
/** 字典类型 */
|
||||
dictType?: string;
|
||||
dictType: string;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
remark: string;
|
||||
}>;
|
||||
|
||||
/** 字典数据 */
|
||||
type DictData = Common.CommonRecord<{
|
||||
/** 样式属性(其他样式扩展) */
|
||||
cssClass?: string;
|
||||
cssClass: string;
|
||||
/** 字典编码 */
|
||||
dictCode?: number;
|
||||
dictCode: number;
|
||||
/** 字典标签 */
|
||||
dictLabel?: string;
|
||||
dictLabel: string;
|
||||
/** 字典排序 */
|
||||
dictSort?: number;
|
||||
dictSort: number;
|
||||
/** 字典类型 */
|
||||
dictType?: string;
|
||||
dictType: string;
|
||||
/** 字典键值 */
|
||||
dictValue?: string;
|
||||
dictValue: string;
|
||||
/** 是否默认(Y是 N否) */
|
||||
isDefault?: string;
|
||||
isDefault: string;
|
||||
/** 表格回显样式 */
|
||||
listClass?: string;
|
||||
listClass: string;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
remark: string;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
|
2
src/typings/components.d.ts
vendored
2
src/typings/components.d.ts
vendored
@ -11,8 +11,10 @@ declare module 'vue' {
|
||||
BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default']
|
||||
BooleanTag: typeof import('./../components/custom/boolean-tag.vue')['default']
|
||||
ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default']
|
||||
copy: typeof import('./../components/custom/dict-select copy.vue')['default']
|
||||
CountTo: typeof import('./../components/custom/count-to.vue')['default']
|
||||
DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
|
||||
DictRadio: typeof import('./../components/custom/dict-radio.vue')['default']
|
||||
DictSelect: typeof import('./../components/custom/dict-select.vue')['default']
|
||||
ExceptionBase: typeof import('./../components/common/exception-base.vue')['default']
|
||||
FullScreen: typeof import('./../components/common/full-screen.vue')['default']
|
||||
|
2
src/typings/elegant-router.d.ts
vendored
2
src/typings/elegant-router.d.ts
vendored
@ -25,6 +25,7 @@ declare module "@elegant-router/types" {
|
||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
|
||||
"system": "/system";
|
||||
"system_menu": "/system/menu";
|
||||
"system_user": "/system/user";
|
||||
"tool": "/tool";
|
||||
"tool_gen": "/tool/gen";
|
||||
};
|
||||
@ -89,6 +90,7 @@ declare module "@elegant-router/types" {
|
||||
| "login"
|
||||
| "home"
|
||||
| "system_menu"
|
||||
| "system_user"
|
||||
| "tool_gen"
|
||||
>;
|
||||
|
||||
|
@ -31,7 +31,7 @@ interface Props {
|
||||
const props = defineProps<Props>();
|
||||
|
||||
interface Emits {
|
||||
(e: 'submitted', menuType?: Api.System.MenuType): void;
|
||||
(e: 'submitted', menuType: Api.System.MenuType): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
@ -45,7 +45,7 @@ const { options: enableStatusOptions } = useDict('sys_normal_disable');
|
||||
|
||||
const iconType = ref<Api.System.IconType>('1');
|
||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
const { defaultRequiredRule } = useFormRules();
|
||||
const { createRequiredRule } = useFormRules();
|
||||
const queryList = ref<{ key: string; value: string }[]>([]);
|
||||
|
||||
const drawerTitle = computed(() => {
|
||||
@ -82,10 +82,10 @@ function createDefaultModel(): Model {
|
||||
type RuleKey = Extract<keyof Model, 'menuName' | 'orderNum' | 'path' | 'component'>;
|
||||
|
||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
menuName: { ...defaultRequiredRule, message: '菜单名称不能为空' },
|
||||
orderNum: { ...defaultRequiredRule, type: 'number', message: '菜单排序不能为空' },
|
||||
path: { ...defaultRequiredRule, message: '路由地址不能为空' },
|
||||
component: { ...defaultRequiredRule, message: '组件路径不能为空' }
|
||||
menuName: createRequiredRule('菜单名称不能为空'),
|
||||
orderNum: createRequiredRule('菜单排序不能为空'),
|
||||
path: createRequiredRule('路由地址不能为空'),
|
||||
component: createRequiredRule('组件路径不能为空')
|
||||
};
|
||||
|
||||
const isBtn = computed(() => model.menuType === 'F');
|
||||
@ -210,7 +210,7 @@ async function handleSubmit() {
|
||||
}
|
||||
|
||||
closeDrawer();
|
||||
emit('submitted', menuType);
|
||||
emit('submitted', menuType!);
|
||||
}
|
||||
|
||||
watch(visible, () => {
|
||||
@ -344,7 +344,7 @@ const FormTipComponent = defineComponent({
|
||||
ignore-path-change
|
||||
:show-label="false"
|
||||
:path="`query[${index}].key`"
|
||||
:rule="{ ...defaultRequiredRule, validator: value => isNotNull(value) }"
|
||||
:rule="{ ...createRequiredRule('请输入 Key'), validator: value => isNotNull(value) }"
|
||||
>
|
||||
<NInput v-model:value="queryList[index].key" placeholder="Key" @keydown.enter.prevent />
|
||||
</NFormItem>
|
||||
@ -354,7 +354,7 @@ const FormTipComponent = defineComponent({
|
||||
ignore-path-change
|
||||
:show-label="false"
|
||||
:path="`query[${index}].value`"
|
||||
:rule="{ ...defaultRequiredRule, validator: value => isNotNull(value) }"
|
||||
:rule="{ ...createRequiredRule('请输入 Value'), validator: value => isNotNull(value) }"
|
||||
>
|
||||
<NInput v-model:value="queryList[index].value" placeholder="Value" @keydown.enter.prevent />
|
||||
</NFormItem>
|
||||
|
179
src/views/system/user/index.vue
Normal file
179
src/views/system/user/index.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<script setup lang="tsx">
|
||||
import { NButton, NPopconfirm } from 'naive-ui';
|
||||
import { fetchBatchDeleteUser, fetchGetUserList } from '@/service/api/system';
|
||||
import { $t } from '@/locales';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import UserOperateDrawer from './modules/user-operate-drawer.vue';
|
||||
import UserSearch from './modules/user-search.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'UserList'
|
||||
});
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const {
|
||||
columns,
|
||||
columnChecks,
|
||||
data,
|
||||
getData,
|
||||
getDataByPage,
|
||||
loading,
|
||||
mobilePagination,
|
||||
searchParams,
|
||||
resetSearchParams
|
||||
} = useTable({
|
||||
apiFn: fetchGetUserList,
|
||||
apiParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 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
|
||||
deptId: null,
|
||||
userName: null,
|
||||
nickName: null,
|
||||
phonenumber: null,
|
||||
status: null,
|
||||
params: {}
|
||||
},
|
||||
columns: () => [
|
||||
{
|
||||
type: 'selection',
|
||||
align: 'center',
|
||||
width: 48
|
||||
},
|
||||
{
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 64
|
||||
},
|
||||
{
|
||||
key: 'deptId',
|
||||
title: '部门',
|
||||
align: 'center',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
key: 'userName',
|
||||
title: '用户名称',
|
||||
align: 'center',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
key: 'nickName',
|
||||
title: '用户昵称',
|
||||
align: 'center',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
key: 'phonenumber',
|
||||
title: '手机号码',
|
||||
align: 'center',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
title: '帐号状态',
|
||||
align: 'center',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
key: 'createTime',
|
||||
title: '创建时间',
|
||||
align: 'center',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
key: 'remark',
|
||||
title: '备注',
|
||||
align: 'center',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
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.userId!)}>
|
||||
{$t('common.edit')}
|
||||
</NButton>
|
||||
<NPopconfirm onPositiveClick={() => handleDelete(row.userId!)}>
|
||||
{{
|
||||
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 } =
|
||||
useTableOperate(data, getData);
|
||||
|
||||
async function handleBatchDelete() {
|
||||
// request
|
||||
const { error } = await fetchBatchDeleteUser(checkedRowKeys.value);
|
||||
if (error) return;
|
||||
onBatchDeleted();
|
||||
}
|
||||
|
||||
async function handleDelete(userId: CommonType.IdType) {
|
||||
// request
|
||||
const { error } = await fetchBatchDeleteUser([userId]);
|
||||
if (error) return;
|
||||
onDeleted();
|
||||
}
|
||||
|
||||
async function edit(userId: CommonType.IdType) {
|
||||
handleEdit('userId', userId);
|
||||
}
|
||||
</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="用户信息列表" :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.userId"
|
||||
: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>
|
175
src/views/system/user/modules/user-operate-drawer.vue
Normal file
175
src/views/system/user/modules/user-operate-drawer.vue
Normal file
@ -0,0 +1,175 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
import { fetchCreateUser, fetchUpdateUser } from '@/service/api/system';
|
||||
|
||||
defineOptions({
|
||||
name: 'UserOperateDrawer'
|
||||
});
|
||||
|
||||
interface Props {
|
||||
/** the type of operation */
|
||||
operateType: NaiveUI.TableOperateType;
|
||||
/** the edit row data */
|
||||
rowData?: Api.System.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 { createRequiredRule } = useFormRules();
|
||||
|
||||
const title = computed(() => {
|
||||
const titles: Record<NaiveUI.TableOperateType, string> = {
|
||||
add: '新增用户信息',
|
||||
edit: '编辑用户信息'
|
||||
};
|
||||
return titles[props.operateType];
|
||||
});
|
||||
|
||||
type Model = Api.System.UserOperateParams;
|
||||
|
||||
const model: Model = reactive(createDefaultModel());
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
return {
|
||||
deptId: null,
|
||||
userName: '',
|
||||
nickName: '',
|
||||
email: '',
|
||||
phonenumber: '',
|
||||
sex: '',
|
||||
password: '',
|
||||
status: '',
|
||||
remark: ''
|
||||
};
|
||||
}
|
||||
|
||||
type RuleKey = Extract<keyof Model, 'userName' | 'nickName' | 'password' | 'status'>;
|
||||
|
||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
userName: createRequiredRule('用户名称不能为空'),
|
||||
nickName: createRequiredRule('用户昵称不能为空'),
|
||||
password: createRequiredRule('密码不能为空'),
|
||||
status: createRequiredRule('帐号状态不能为空')
|
||||
};
|
||||
|
||||
function handleUpdateModelWhenEdit() {
|
||||
if (props.operateType === 'add') {
|
||||
Object.assign(model, createDefaultModel());
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.operateType === 'edit' && props.rowData) {
|
||||
Object.assign(model, props.rowData);
|
||||
}
|
||||
}
|
||||
|
||||
function closeDrawer() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
|
||||
// request
|
||||
if (props.operateType === 'add') {
|
||||
const { deptId, userName, nickName, email, phonenumber, sex, password, status, remark } = model;
|
||||
const { error } = await fetchCreateUser({
|
||||
deptId,
|
||||
userName,
|
||||
nickName,
|
||||
email,
|
||||
phonenumber,
|
||||
sex,
|
||||
password,
|
||||
status,
|
||||
remark
|
||||
});
|
||||
if (error) return;
|
||||
}
|
||||
|
||||
if (props.operateType === 'edit') {
|
||||
const { userId, deptId, userName, nickName, email, phonenumber, sex, password, status, remark } = model;
|
||||
const { error } = await fetchUpdateUser({
|
||||
userId,
|
||||
deptId,
|
||||
userName,
|
||||
nickName,
|
||||
email,
|
||||
phonenumber,
|
||||
sex,
|
||||
password,
|
||||
status,
|
||||
remark
|
||||
});
|
||||
if (error) return;
|
||||
}
|
||||
|
||||
window.$message?.success($t('common.updateSuccess'));
|
||||
closeDrawer();
|
||||
emit('submitted');
|
||||
}
|
||||
|
||||
watch(visible, () => {
|
||||
if (visible.value) {
|
||||
handleUpdateModelWhenEdit();
|
||||
restoreValidation();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
|
||||
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
||||
<NForm ref="formRef" :model="model" :rules="rules">
|
||||
<NFormItem label="部门" path="deptId">
|
||||
<!-- <NInput v-model:value="model.deptId" placeholder="请输入部门" /> -->
|
||||
</NFormItem>
|
||||
<NFormItem label="用户名称" path="userName">
|
||||
<NInput v-model:value="model.userName" placeholder="请输入用户名称" />
|
||||
</NFormItem>
|
||||
<NFormItem label="用户昵称" path="nickName">
|
||||
<NInput v-model:value="model.nickName" placeholder="请输入用户昵称" />
|
||||
</NFormItem>
|
||||
<NFormItem label="用户邮箱" path="email">
|
||||
<NInput v-model:value="model.email" placeholder="请输入用户邮箱" />
|
||||
</NFormItem>
|
||||
<NFormItem label="手机号码" path="phonenumber">
|
||||
<NInput v-model:value="model.phonenumber" placeholder="请输入手机号码" />
|
||||
</NFormItem>
|
||||
<NFormItem label="用户性别" path="sex">
|
||||
<DictRadio v-model:value="model.sex" dict-code="sys_user_sex" />
|
||||
</NFormItem>
|
||||
<NFormItem label="密码" path="password">
|
||||
<NInput v-model:value="model.password" placeholder="请输入密码" />
|
||||
</NFormItem>
|
||||
<NFormItem label="帐号状态" path="status">
|
||||
<NInput v-model:value="model.status" placeholder="请输入帐号状态" />
|
||||
</NFormItem>
|
||||
<NFormItem label="备注" path="remark">
|
||||
<NInput v-model:value="model.remark" placeholder="请输入备注" />
|
||||
</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>
|
87
src/views/system/user/modules/user-search.vue
Normal file
87
src/views/system/user/modules/user-search.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { useNaiveForm } from '@/hooks/common/form';
|
||||
defineOptions({
|
||||
name: 'UserSearch'
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'reset'): void;
|
||||
(e: 'search'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
|
||||
const dateRangeCreateTime = ref<[string, string]>();
|
||||
|
||||
const model = defineModel<Api.System.UserSearchParams>('model', { required: true });
|
||||
|
||||
async function reset() {
|
||||
dateRangeCreateTime.value = undefined;
|
||||
await restoreValidation();
|
||||
emit('reset');
|
||||
}
|
||||
|
||||
async function search() {
|
||||
await validate();
|
||||
if (dateRangeCreateTime.value?.length) {
|
||||
model.value.params!.beginCreateTime = dateRangeCreateTime.value[0];
|
||||
model.value.params!.endCreateTime = dateRangeCreateTime.value[0];
|
||||
}
|
||||
emit('search');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NCard :bordered="false" size="small" class="card-wrapper">
|
||||
<NCollapse>
|
||||
<NCollapseItem :title="$t('common.search')" name="user-search">
|
||||
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
|
||||
<NGrid responsive="screen" item-responsive>
|
||||
<NFormItemGi span="24 s:12 m:6" label="用户名称" path="userName" class="pr-24px">
|
||||
<NInput v-model:value="model.userName" placeholder="请输入用户名称" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="用户昵称" path="nickName" class="pr-24px">
|
||||
<NInput v-model:value="model.nickName" placeholder="请输入用户昵称" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="手机号码" path="phonenumber" class="pr-24px">
|
||||
<NInput v-model:value="model.phonenumber" placeholder="请输入手机号码" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="帐号状态" path="status" class="pr-24px">
|
||||
<NSelect v-model:value="model.status" placeholder="请选择帐号状态" :options="[]" clearable />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="创建时间" path="createTime" class="pr-24px">
|
||||
<NDatePicker
|
||||
v-model:formatted-value="dateRangeCreateTime"
|
||||
type="datetimerange"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
clearable
|
||||
/>
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24" 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>
|
||||
</NCollapseItem>
|
||||
</NCollapse>
|
||||
</NCard>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -218,7 +218,7 @@ async function handleGenCode(row?: Api.Tool.GenTable) {
|
||||
if (error) return;
|
||||
window.$message?.success('生成成功');
|
||||
} else {
|
||||
zip(`/tool/gen/batchGenCode?tableIdStr=${tableIds}`, `ruoyi-${new Date().getTime()}.zip`);
|
||||
zip(`/tool/gen/batchGenCode?tableIdStr=${tableIds}`, `RuoYi-${row?.tableId ? `${row.className}` : Date.now()}.zip`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,6 +269,7 @@ const columns: NaiveUI.TableColumn<Api.Tool.GenTableColumn>[] = [
|
||||
consistent-menu-width={false}
|
||||
render-label={renderLabel}
|
||||
render-tag={renderTag}
|
||||
clearable
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user