字典
This commit is contained in:
parent
81953dd44c
commit
7b4dffecac
@ -1,11 +1,11 @@
|
||||
import { mysqlTable, mysqlSchema, AnyMySqlColumn, primaryKey, unique, bigint, int, tinyint, varchar, datetime } from "drizzle-orm/mysql-core"
|
||||
import { mysqlTable, mysqlSchema, AnyMySqlColumn, primaryKey, unique, int, varchar, bigint, datetime, tinyint } from "drizzle-orm/mysql-core"
|
||||
import { sql } from "drizzle-orm"
|
||||
|
||||
export const sysDict = mysqlTable("sys_dict", {
|
||||
id: bigint({ mode: "number" }).notNull(),
|
||||
id: int().autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
module: tinyint(),
|
||||
pid: int().notNull(),
|
||||
moduleId: int("module_Id"),
|
||||
dictKey: varchar("dict_key", { length: 255 }),
|
||||
value: varchar({ length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
@ -36,7 +36,6 @@ export const sysModule = mysqlTable("sys_module", {
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_module_id"}),
|
||||
unique("uniq_name").on(table.name),
|
||||
unique("uniq_module_key").on(table.moduleKey),
|
||||
]);
|
||||
|
||||
@ -98,8 +97,8 @@ export const sysPermission = mysqlTable("sys_permission", {
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.permId], name: "sys_permission_perm_id"}),
|
||||
unique("uniq_pid_name").on(table.permName, table.pid),
|
||||
unique("uniq_perm_key").on(table.permKey),
|
||||
unique("uniq_pid_name").on(table.permName, table.pid),
|
||||
]);
|
||||
|
||||
export const sysProfile = mysqlTable("sys_profile", {
|
||||
@ -184,6 +183,7 @@ export const sysRole = mysqlTable("sys_role", {
|
||||
export const sysUser = mysqlTable("sys_user", {
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
nickname: varchar({ length: 255 }).notNull(),
|
||||
username: varchar({ length: 255 }).notNull(),
|
||||
email: varchar({ length: 255 }).notNull(),
|
||||
phone: varchar({ length: 255 }),
|
||||
@ -197,8 +197,8 @@ export const sysUser = mysqlTable("sys_user", {
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.userId], name: "sys_user_user_id"}),
|
||||
unique("uniq_username").on(table.username),
|
||||
unique("uniq_email").on(table.email),
|
||||
unique("uniq_username").on(table.username),
|
||||
]);
|
||||
|
||||
export const sysUserAuth = mysqlTable("sys_user_auth", {
|
||||
@ -212,7 +212,7 @@ export const sysUserAuth = mysqlTable("sys_user_auth", {
|
||||
]);
|
||||
|
||||
export const sysUserAuthHistory = mysqlTable("sys_user_auth_history", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
id: bigint({ mode: "number" }).notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
passwordHash: varchar("password_hash", { length: 255 }).notNull(),
|
||||
modifiedAt: datetime("modified_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
@ -242,12 +242,12 @@ export const sysUserFieldDefinition = mysqlTable("sys_user_field_definition", {
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.fieldId], name: "sys_user_field_definition_field_id"}),
|
||||
unique("uniq_field_name").on(table.fieldName),
|
||||
unique("uniq_field_key").on(table.fieldKey),
|
||||
unique("uniq_field_name").on(table.fieldName),
|
||||
]);
|
||||
|
||||
export const sysUserFieldValue = mysqlTable("sys_user_field_value", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
id: bigint({ mode: "number" }).notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
fieldId: int("field_id").notNull(),
|
||||
value: varchar({ length: 4096 }),
|
||||
|
@ -5,10 +5,10 @@ import { mysqlTable, primaryKey, unique, int, tinyint, varchar, datetime } from
|
||||
import { sql } from "drizzle-orm"
|
||||
|
||||
export const sysDict = mysqlTable("sys_dict", {
|
||||
id: bigint({ mode: "number" }).notNull(),
|
||||
id: int().autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
module: tinyint(),
|
||||
pid: int().notNull(),
|
||||
moduleId: int('module_id', { mode: "number" }).notNull(),
|
||||
dictKey: varchar("dict_key", { length: 255 }),
|
||||
value: varchar({ length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
@ -39,7 +39,6 @@ export const sysModule = mysqlTable("sys_module", {
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_module_id"}),
|
||||
unique("uniq_name").on(table.name),
|
||||
unique("uniq_module_key").on(table.moduleKey),
|
||||
]);
|
||||
|
||||
@ -187,6 +186,7 @@ export const sysRole = mysqlTable("sys_role", {
|
||||
export const sysUser = mysqlTable("sys_user", {
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
nickname: varchar({ length: 255 }).notNull(),
|
||||
username: varchar({ length: 255 }).notNull(),
|
||||
email: varchar({ length: 255 }).notNull(),
|
||||
phone: varchar({ length: 255 }),
|
||||
|
@ -14,6 +14,8 @@ async function constData(fastify, options) {
|
||||
CREATE_MODULE: 'CREATE_MODULE:',
|
||||
// 编辑模块
|
||||
UPDATE_MODULE: 'UPDATE_MODULE:',
|
||||
// 新增字典
|
||||
CREATE_DICT: 'CREATE_DICT:',
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,13 @@ async function database(fastify, options) {
|
||||
// }
|
||||
});
|
||||
// 暴露数据库
|
||||
const db = drizzle(pool);
|
||||
const db = drizzle(pool, {
|
||||
logger: {
|
||||
logQuery: (query, params) => {
|
||||
fastify.log.info(`SQL: ${query} - Params: ${JSON.stringify(params)}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
// 新增获取所有表名方法
|
||||
const [result] = await db.execute(sql`SHOW TABLES`);
|
||||
const tableList = result.map(row => Object.values(row)[0]);
|
||||
|
22
src/routes/dict.route.js
Normal file
22
src/routes/dict.route.js
Normal file
@ -0,0 +1,22 @@
|
||||
import { dictListSchema, dictInfoSchema, dictTreeSchema, dictCreateSchema, dictUpdateSchema, dictDeleteSchema } from "#schema/dict.schema";
|
||||
import { dictListService, dictInfoService, dictTreeService, dictCreateService, dictUpdateService, dictDeleteService } from "#services/dict/dict.service";
|
||||
export default async function moduleRoute(fastify, options) {
|
||||
// 1. 通过PID获取字典列表 25-03/27
|
||||
fastify.get('/', { schema: dictListSchema }, dictListService);
|
||||
|
||||
// 2. 获取字典详情 25-03/27
|
||||
fastify.get('/:id', { schema: dictInfoSchema }, dictInfoService);
|
||||
|
||||
// 3. 获取字典树 25-03/27
|
||||
fastify.get('/tree/:id', dictTreeService);
|
||||
|
||||
// 4. 添加字典 25-03/27
|
||||
fastify.post('/', { schema: dictCreateSchema }, dictCreateService);
|
||||
|
||||
// 5. 修改字典 25-03/27
|
||||
fastify.patch('/:id', { schema: dictUpdateSchema }, dictUpdateService);
|
||||
|
||||
// 6. 删除字典 25-03/27
|
||||
fastify.delete('/:id', { schema: dictDeleteSchema }, dictDeleteService);
|
||||
|
||||
}
|
@ -2,6 +2,7 @@ import { testSchema } from '#src/schema/test.schema';
|
||||
import { testService } from '#src/services/test.service';
|
||||
import userRoute from '#routes/user.route';
|
||||
import moduleRoute from '#routes/module.route';
|
||||
import dictRoute from '#routes/dict.route';
|
||||
|
||||
export default async function routes(fastify, options) {
|
||||
// 定义一个GET请求的路由,路径为根路径
|
||||
@ -19,45 +20,8 @@ export default async function routes(fastify, options) {
|
||||
|
||||
// 注册子路由 -------- 角色
|
||||
|
||||
fastify.route({
|
||||
method: 'POST',
|
||||
url: '/login',
|
||||
schema: {
|
||||
tags: ['认证体系'], // 接口分组
|
||||
summary: '用户登录',
|
||||
description: '使用用户名密码进行身份认证',
|
||||
security: [{}],
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['username', 'password'],
|
||||
properties: {
|
||||
username: { type: 'string', default: 'user1' },
|
||||
password: { type: 'string', default: '123456' },
|
||||
},
|
||||
},
|
||||
response: {
|
||||
200: {
|
||||
description: '登录成功',
|
||||
type: 'object',
|
||||
properties: {
|
||||
token: { type: 'string' },
|
||||
expire: { type: 'number' },
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: '认证失败',
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [401] },
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
handler: async (req, reply) => {
|
||||
// ...业务逻辑...
|
||||
},
|
||||
});
|
||||
// 注册子路由 -------- 字典
|
||||
fastify.register(dictRoute, { prefix: '/dict' });
|
||||
|
||||
// 输出路由树
|
||||
fastify.ready(() => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { moduleListSchema, moduleCreateSchema, moduleUpdateSchema } from '#schema/module.schema';
|
||||
import { moduleListService, moduleCreateService, moduleUpdateService } from '#services/module/module.service';
|
||||
export default async function moduleRoute(fastify, options) {
|
||||
// 1. 获取系统模块列表 23-04/23
|
||||
// 1. 获取系统模块列表 25-03/26
|
||||
fastify.get('/', { schema: moduleListSchema }, moduleListService);
|
||||
|
||||
// 2. 新增系统模块
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { userDefaultSchema, userRegisterSchema, userLoginSchema, userRefreshTokenSchema } from '#src/schema/user.schema';
|
||||
import { userRegisterService, userLoginService, refreshTokenService } from '#src/services/user/user.service';
|
||||
import { userDefaultSchema, userRegisterSchema, userLoginSchema, userRefreshTokenSchema } from '#schema/user.schema';
|
||||
import { userRegisterService, userLoginService, refreshTokenService } from '#services/user/user.service';
|
||||
|
||||
export default async function userRoute(fastify, options) {
|
||||
// 1. 新用户注册 25-03/25
|
||||
fastify.post('/register', { schema: userRegisterSchema }, userRegisterService);
|
||||
// 2. 用户登录 25-03/26
|
||||
fastify.post('/login', { schema: userLoginSchema }, userLoginService);
|
||||
// 3. 刷新token 25-03/27
|
||||
// 3. 刷新token 25-03/26
|
||||
fastify.post('/refreshToken', { schema: userRefreshTokenSchema }, refreshTokenService);
|
||||
}
|
||||
|
@ -40,6 +40,17 @@ export const password = {
|
||||
pattern: '必须包含至少一个小写字母、一个大写字母、一个数字和一个特殊字符',
|
||||
},
|
||||
};
|
||||
export const nickname = {
|
||||
type: 'string',
|
||||
minLength: 1,
|
||||
maxLength: 32,
|
||||
isTrim: true,
|
||||
description: '昵称',
|
||||
errorMessage: {
|
||||
minLength: '昵称至少需要1个字符',
|
||||
maxLength: '昵称不能超过32个字符',
|
||||
},
|
||||
};
|
||||
|
||||
export const page = {
|
||||
type: 'integer',
|
||||
@ -99,6 +110,15 @@ export const description = {
|
||||
default: null,
|
||||
description: '描述信息'
|
||||
}
|
||||
export const pid = {
|
||||
type: 'integer',
|
||||
default: 0,
|
||||
description: '上级ID(0表示根节点)',
|
||||
errorMessage: {
|
||||
type: '上级ID必须是整数',
|
||||
}
|
||||
}
|
||||
|
||||
export const module = {
|
||||
name: {
|
||||
type: 'string',
|
||||
@ -118,7 +138,7 @@ export const module = {
|
||||
pattern: '^[a-z][a-z0-9_]*$',
|
||||
description: '模块唯一标识Key(英文小写)',
|
||||
errorMessage: {
|
||||
maxLength: '模块名称不能超过255个字符',
|
||||
maxLength: '模块标识不能超过255个字符',
|
||||
pattern: '必须小写字母开头,只能包含字母、数字和下划线'
|
||||
}
|
||||
},
|
||||
@ -131,4 +151,64 @@ export const module = {
|
||||
enum: '状态值只能是0(正常)或1(禁用)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const dict = {
|
||||
dictKey: {
|
||||
type:'string',
|
||||
maxLength: 255,
|
||||
isLowerCase: true,
|
||||
isTrim: true,
|
||||
pattern: '^[a-z][a-z0-9_]*$',
|
||||
description: '字典唯一标识Key(英文小写)',
|
||||
errorMessage: {
|
||||
maxLength: '模块标识不能超过255个字符',
|
||||
pattern: '必须小写字母开头,只能包含字母、数字和下划线'
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type:'string',
|
||||
maxLength: 255,
|
||||
description: '字典值/名',
|
||||
}
|
||||
}
|
||||
|
||||
export const edit = {
|
||||
|
||||
pid: {
|
||||
type: 'integer',
|
||||
description: '上级ID(0表示根节点)',
|
||||
errorMessage: {
|
||||
type: '上级ID必须是整数',
|
||||
},
|
||||
nullable: true
|
||||
},
|
||||
moduleId: {
|
||||
type: 'integer', examples: [0], default: 0, description: '模块',
|
||||
errorMessage: {
|
||||
type: '模块必须是整数',
|
||||
}
|
||||
},
|
||||
description: {
|
||||
type: ['string', 'null'],
|
||||
maxLength: 255,
|
||||
description: '描述信息', nullable: true
|
||||
},
|
||||
sort: {
|
||||
|
||||
type: 'integer',
|
||||
minimum: 0,
|
||||
maximum: 9999,
|
||||
errorMessage: '排序值范围0-9999',
|
||||
nullable: true
|
||||
},
|
||||
status: {
|
||||
type: 'integer',
|
||||
enum: [0, 1, null],
|
||||
nullable: true,
|
||||
errorMessage: {
|
||||
type: '状态值必须是整数',
|
||||
enum: '状态值只能是0(正常)或1(禁用)'
|
||||
},
|
||||
}
|
||||
}
|
213
src/schema/dict.schema.js
Normal file
213
src/schema/dict.schema.js
Normal file
@ -0,0 +1,213 @@
|
||||
import { sortOrder, module, sortBy, description, sort, pid, dict, edit } from "#schema/atomSchema";
|
||||
import errorAtomSchema from "#schema/error.atomSchema";
|
||||
|
||||
const dictProperties = {
|
||||
id: { type: 'integer', examples: [1] },
|
||||
pid: { type: 'integer', examples: [0] },
|
||||
dictKey: { type: 'string', examples: ['gender'] },
|
||||
value: { type: 'string', examples: ['男'] },
|
||||
description: { type: ['string', 'null'] },
|
||||
sort: { type: 'integer', examples: [10] },
|
||||
status: { type: 'integer', enum: [0, 1] },
|
||||
moduleKey: { type: 'string', examples: [''] },
|
||||
moduleName: { type: 'string', examples: [''] },
|
||||
createdUser: { type: 'string', examples: [1001] },
|
||||
updatedUser: { type: 'string', examples: [1001] },
|
||||
createdBy: { type: 'string', examples: [1001] },
|
||||
updatedBy: { type: ['string', 'null'], examples: [1002] },
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
examples: ['2023-07-15T08:23:45.000Z']
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
examples: ['2023-07-16T09:34:12.000Z']
|
||||
}
|
||||
}
|
||||
// 通过PID获取字典列表
|
||||
export const dictListSchema = {
|
||||
tags: ['系统管理'],
|
||||
summary: '获取字典列表',
|
||||
description: '通过PID获取字典列表(非分页)',
|
||||
querystring: {
|
||||
type: 'object',
|
||||
required: ['pid'],
|
||||
properties: {
|
||||
pid: {
|
||||
...pid,
|
||||
nullable: true,
|
||||
},
|
||||
moduleKey: {
|
||||
type: 'string',
|
||||
maxLength: 255,
|
||||
default: null,
|
||||
description: '模块过滤',
|
||||
toNull: true,
|
||||
isLowerCase: true,
|
||||
isTrim: true,
|
||||
errorMessage: {
|
||||
maxLength: '模块标识不能超过255个字符',
|
||||
},
|
||||
},
|
||||
sortBy: {
|
||||
...sortBy,
|
||||
default: 'sort'
|
||||
},
|
||||
sortOrder
|
||||
}
|
||||
},
|
||||
response: {
|
||||
200: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [200] },
|
||||
data: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: dictProperties
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
400: errorAtomSchema['400']
|
||||
},
|
||||
security: [{ apiKey: [] }]
|
||||
};
|
||||
|
||||
// 字典详情
|
||||
export const dictInfoSchema = {
|
||||
tags: ['系统管理'],
|
||||
summary: '获取字典详情',
|
||||
response: {
|
||||
200: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [200] },
|
||||
data: {
|
||||
type: 'object',
|
||||
properties: dictProperties
|
||||
},
|
||||
message: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
security: [{ apiKey: [] }]
|
||||
};
|
||||
|
||||
// 字典树schema
|
||||
export const dictTreeSchema = {
|
||||
tags: ['系统管理'],
|
||||
summary: '获取字典树',
|
||||
response: {
|
||||
200: {
|
||||
...dictListSchema.response[200],
|
||||
properties: {
|
||||
code: { type: 'number', enum: [200] },
|
||||
data: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...dictProperties,
|
||||
children: {
|
||||
type: 'array',
|
||||
items: { $ref: '#' }
|
||||
}
|
||||
}
|
||||
},
|
||||
message: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
security: [{ apiKey: [] }]
|
||||
};
|
||||
|
||||
// 添加字典
|
||||
export const dictCreateSchema = {
|
||||
tags: ['系统管理'],
|
||||
summary: '创建字典项',
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['pid', 'moduleId', 'dictKey', 'value'],
|
||||
properties: {
|
||||
pid: {
|
||||
type: 'integer', examples: [0], default: 0, description: '上级字典ID(0表示根节点)',
|
||||
errorMessage: {
|
||||
type: '上级ID必须是整数',
|
||||
}
|
||||
},
|
||||
moduleId: {
|
||||
type: 'integer', examples: [0], default: 0, description: '模块',
|
||||
errorMessage: {
|
||||
type: '模块必须是整数',
|
||||
}
|
||||
},
|
||||
dictKey: { ...dict.dictKey },
|
||||
value: { ...dict.value },
|
||||
description,
|
||||
sort,
|
||||
status: { ...module.status }
|
||||
}
|
||||
},
|
||||
response: {
|
||||
201: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [201] },
|
||||
data: {
|
||||
type: 'object',
|
||||
properties: dictProperties
|
||||
},
|
||||
message: { type: 'string' }
|
||||
},
|
||||
},
|
||||
409: errorAtomSchema['409']
|
||||
},
|
||||
security: [{ apiKey: [] }]
|
||||
};
|
||||
|
||||
// 修改字典
|
||||
export const dictUpdateSchema = {
|
||||
tags: ['系统管理'],
|
||||
summary: '修改字典项',
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
dictKey: { ...dict.dictKey, nullable: true },
|
||||
value: { ...dict.value, nullable: true },
|
||||
moduleId: edit.moduleId,
|
||||
description: edit.description,
|
||||
sort: edit.sort,
|
||||
status: edit.status,
|
||||
},
|
||||
anyOf: [
|
||||
{ required: ['dictKey'] },
|
||||
{ required: ['value'] },
|
||||
{ required: ['moduleId'] },
|
||||
{ required: ['description'] },
|
||||
{ required: ['sort'] },
|
||||
{ required: ['status'] }
|
||||
],
|
||||
additionalProperties: false
|
||||
},
|
||||
// response: dictCreateSchema.response,
|
||||
security: [{ apiKey: [] }]
|
||||
};
|
||||
|
||||
// 删除字典
|
||||
export const dictDeleteSchema = {
|
||||
tags: ['系统管理'],
|
||||
summary: '删除字典项',
|
||||
response: {
|
||||
204: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [204] },
|
||||
message: { type: 'string' }
|
||||
}
|
||||
},
|
||||
404: errorAtomSchema['404']
|
||||
},
|
||||
security: [{ apiKey: [] }]
|
||||
};
|
@ -75,6 +75,8 @@ export const moduleListSchema = {
|
||||
description: { type: ['string', 'null'], examples: ['用户权限管理模块'] },
|
||||
sort: { type: 'integer', examples: [10] },
|
||||
status: { type: 'integer', enum: [0, 1] },
|
||||
createdUser: { type: 'string', examples: [1001] },
|
||||
updatedUser: { type: 'string', examples: [1001] },
|
||||
createdBy: { type: 'string', examples: [1001] },
|
||||
updatedBy: { type: ['string', 'null'], examples: [1002] },
|
||||
createdAt: {
|
||||
@ -209,6 +211,8 @@ export const moduleUpdateSchema = {
|
||||
description: { type: ['string', 'null'], examples: ['用户权限管理模块'] },
|
||||
sort: { type: 'integer', examples: [10] },
|
||||
status: { type: 'integer', enum: [0, 1] },
|
||||
createdUser: { type: 'string', examples: [1001] },
|
||||
updatedUser: { type: 'string', examples: [1001] },
|
||||
createdBy: { type: 'string', examples: [1001] },
|
||||
updatedBy: { type: ['string', 'null'], examples: [1002] },
|
||||
createdAt: {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { email, username, password } from '#schema/atomSchema';
|
||||
import { email, username, password, nickname } from '#schema/atomSchema';
|
||||
import errorAtomSchema from '#schema/error.atomSchema';
|
||||
// 默认schema
|
||||
export const userDefaultSchema = {};
|
||||
@ -10,12 +10,13 @@ export const userRegisterSchema = {
|
||||
description: '创建新用户账号(需验证手机/邮箱)',
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['username', 'email', 'password'],
|
||||
required: ['username', 'email', 'password', 'nickname'],
|
||||
errorMessage: {
|
||||
required: {
|
||||
username: '缺少用户名',
|
||||
email: '缺少邮箱',
|
||||
password: '缺少密码',
|
||||
nickname: '缺少昵称',
|
||||
},
|
||||
},
|
||||
properties: {
|
||||
@ -33,6 +34,7 @@ export const userRegisterSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
username: { type: 'string' },
|
||||
nickname: { type: 'string' },
|
||||
email: { type: 'string' },
|
||||
userId: {
|
||||
type: 'string',
|
||||
|
249
src/services/dict/dict.db.js
Normal file
249
src/services/dict/dict.db.js
Normal file
@ -0,0 +1,249 @@
|
||||
import { sysUser, sysUserAuth, sysUserAuthHistory, sysModule, sysDict } from '#entity';
|
||||
import { or, eq, and, asc, desc, count, like, ne, sql } from 'drizzle-orm';
|
||||
import { alias, QueryBuilder } from 'drizzle-orm/mysql-core';
|
||||
|
||||
// 获取字典列表
|
||||
export async function getDictList(queryData) {
|
||||
const { pid = 0, moduleKey, sortBy = 'sort', sortOrder = 'asc' } = queryData;
|
||||
|
||||
// 联表查询构造器
|
||||
const sysCreatedUser = alias(sysUser, 'sysCreatedUser');
|
||||
const sysUpdatedUser = alias(sysUser, 'sysUpdatedUser');
|
||||
const query = this.db
|
||||
.select({
|
||||
id: sysDict.id,
|
||||
pid: sysDict.pid,
|
||||
dictKey: sysDict.dictKey,
|
||||
value: sysDict.value,
|
||||
description: sysDict.description,
|
||||
sort: sysDict.sort,
|
||||
status: sysDict.status,
|
||||
moduleKey: sysModule.moduleKey, // 新增模块Key字段
|
||||
moduledName: sysModule.name, // 新增模块名称字段
|
||||
createdUser: sysCreatedUser.nickname,
|
||||
updatedUser: sysUpdatedUser.nickname,
|
||||
createdBy: sysModule.createdBy,
|
||||
updatedBy: sysModule.updatedBy,
|
||||
createdAt: sysModule.createdAt,
|
||||
updatedAt: sysModule.updatedAt
|
||||
})
|
||||
.from(sysDict)
|
||||
.leftJoin(sysModule, eq(sysDict.moduleId, sysModule.id)) // 通过moduleKey关联模块表
|
||||
.leftJoin(sysCreatedUser, eq(sysCreatedUser.userId, sysModule.createdBy))
|
||||
.leftJoin(sysUpdatedUser, eq(sysUpdatedUser.userId, sysModule.updatedBy))
|
||||
.$dynamic();
|
||||
|
||||
// 构建过滤条件
|
||||
const conditions = [eq(sysDict.pid, pid === null ? 0 : pid)];
|
||||
if (moduleKey) {
|
||||
conditions.push(eq(sysModule.moduleKey, moduleKey)); // 根据模块Key过滤
|
||||
}
|
||||
|
||||
// 应用排序规则
|
||||
const orderBy = sortOrder === 'desc'
|
||||
? desc(sysDict[sortBy])
|
||||
: asc(sysDict[sortBy]);
|
||||
|
||||
return await query
|
||||
.where(and(...conditions))
|
||||
.orderBy(orderBy);
|
||||
}
|
||||
|
||||
// 新增字典详情查询方法
|
||||
export async function getDictDetail(dictId) {
|
||||
const sysCreatedUser = alias(sysUser, 'sysCreatedUser');
|
||||
const sysUpdatedUser = alias(sysUser, 'sysUpdatedUser');
|
||||
|
||||
const result = await this.db
|
||||
.select({
|
||||
id: sysDict.id,
|
||||
pid: sysDict.pid,
|
||||
dictKey: sysDict.dictKey,
|
||||
value: sysDict.value,
|
||||
description: sysDict.description,
|
||||
sort: sysDict.sort,
|
||||
status: sysDict.status,
|
||||
moduleKey: sysModule.moduleKey,
|
||||
moduleName: sysModule.name,
|
||||
createdUser: sysCreatedUser.nickname,
|
||||
updatedUser: sysUpdatedUser.nickname,
|
||||
createdAt: sysDict.createdAt, // 修正为字典表字段
|
||||
updatedAt: sysDict.updatedAt // 修正为字典表字段
|
||||
})
|
||||
.from(sysDict)
|
||||
.leftJoin(sysModule, eq(sysDict.moduleId, sysModule.id))
|
||||
.leftJoin(sysCreatedUser, eq(sysCreatedUser.userId, sysDict.createdBy))
|
||||
.leftJoin(sysUpdatedUser, eq(sysUpdatedUser.userId, sysDict.updatedBy))
|
||||
.where(eq(sysDict.id, dictId))
|
||||
.limit(1);
|
||||
|
||||
return result[0] || null;
|
||||
}
|
||||
|
||||
// 检查字典Key冲突
|
||||
export async function checkDictKeyConflict(pid, dictKey) {
|
||||
const result = await this.db
|
||||
.select({ count: count() })
|
||||
.from(sysDict)
|
||||
.where(and(
|
||||
eq(sysDict.pid, pid),
|
||||
eq(sysDict.dictKey, dictKey)
|
||||
));
|
||||
|
||||
return result[0].count > 0;
|
||||
}
|
||||
// 检查字典Key冲突(排除当前记录)
|
||||
export async function checkDictKeyConflictNotMe(pid, dictKey, excludeId) {
|
||||
const [result] = await this.db.select({ id: sysDict.id })
|
||||
.from(sysDict)
|
||||
.where(and(
|
||||
eq(sysDict.pid, pid),
|
||||
eq(sysDict.dictKey, dictKey),
|
||||
ne(sysDict.id, excludeId)
|
||||
));
|
||||
return !!result;
|
||||
}
|
||||
|
||||
// 通过pid和dictKey获取字典详情
|
||||
export async function getDictByPidAndDictKey(pid, dictKey) {
|
||||
const sysCreatedUser = alias(sysUser, 'sysCreatedUser');
|
||||
const sysUpdatedUser = alias(sysUser, 'sysUpdatedUser');
|
||||
|
||||
const result = await this.db
|
||||
.select({
|
||||
id: sysDict.id,
|
||||
pid: sysDict.pid,
|
||||
dictKey: sysDict.dictKey,
|
||||
value: sysDict.value,
|
||||
description: sysDict.description,
|
||||
sort: sysDict.sort,
|
||||
status: sysDict.status,
|
||||
moduleKey: sysModule.moduleKey,
|
||||
moduleName: sysModule.name,
|
||||
createdUser: sysCreatedUser.nickname,
|
||||
updatedUser: sysUpdatedUser.nickname,
|
||||
createdAt: sysDict.createdAt, // 修正为字典表字段
|
||||
updatedAt: sysDict.updatedAt // 修正为字典表字段
|
||||
})
|
||||
.from(sysDict)
|
||||
.leftJoin(sysModule, eq(sysDict.moduleId, sysModule.id))
|
||||
.leftJoin(sysCreatedUser, eq(sysCreatedUser.userId, sysDict.createdBy))
|
||||
.leftJoin(sysUpdatedUser, eq(sysUpdatedUser.userId, sysDict.updatedBy))
|
||||
.where(and(eq(sysDict.pid, pid), eq(sysDict.dictKey, dictKey)))
|
||||
.limit(1);
|
||||
|
||||
return result[0] || null;
|
||||
}
|
||||
|
||||
// 新增字典
|
||||
export async function createDict(dictData) {
|
||||
await this.db.insert(sysDict).values({
|
||||
pid: dictData.pid,
|
||||
moduleId: dictData.moduleId, // 关联模块ID
|
||||
dictKey: dictData.dictKey,
|
||||
value: dictData.value,
|
||||
description: dictData.description,
|
||||
sort: dictData.sort || 0,
|
||||
status: dictData.status || 0,
|
||||
createdBy: dictData.createdBy,
|
||||
}).execute();
|
||||
return await getDictByPidAndDictKey.call(this, dictData.pid, dictData.dictKey);
|
||||
}
|
||||
|
||||
// 更新字典数据
|
||||
export async function updateDict(id, updateData) {
|
||||
await this.db.update(sysDict)
|
||||
.set({
|
||||
...Object.entries(updateData).reduce((acc, [key, value]) => {
|
||||
if (value !== null && value !== undefined) {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {}),
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(and(
|
||||
eq(sysDict.id, id),
|
||||
));
|
||||
|
||||
return await getDictDetail.call(this, id);
|
||||
}
|
||||
|
||||
|
||||
// 删除字典项
|
||||
export async function deleteDict(id) {
|
||||
const [result] = await this.db.delete(sysDict)
|
||||
.where(eq(sysDict.id, id))
|
||||
.execute();
|
||||
return result.affectedRows;
|
||||
}
|
||||
|
||||
// 获取字典树
|
||||
export async function getDictTree(dictId) {
|
||||
console.log(dictId);
|
||||
const sysCreatedUser = alias(sysUser, 'sysCreatedUser');
|
||||
const sysUpdatedUser = alias(sysUser, 'sysUpdatedUser');
|
||||
const dictList = {
|
||||
id: sysDict.id,
|
||||
pid: sysDict.pid,
|
||||
dictKey: sysDict.dictKey,
|
||||
value: sysDict.value,
|
||||
description: sysDict.description,
|
||||
sort: sysDict.sort,
|
||||
status: sysDict.status,
|
||||
moduleKey: sysModule.moduleKey,
|
||||
moduleName: sysModule.name,
|
||||
createdUser: sysCreatedUser.nickname,
|
||||
updatedUser: sysUpdatedUser.nickname,
|
||||
createdAt: sysDict.createdAt, // 修正为字典表字段
|
||||
updatedAt: sysDict.updatedAt // 修正为字典表字段
|
||||
}
|
||||
// ! 基础层级
|
||||
const baseQueryBuilder = new QueryBuilder();
|
||||
const baseQuery = baseQueryBuilder
|
||||
.select({
|
||||
...dictList,
|
||||
level: sql`0`.as('level'),
|
||||
})
|
||||
.from(sysDict)
|
||||
.leftJoin(sysModule, eq(sysDict.moduleId, sysModule.id))
|
||||
.leftJoin(sysCreatedUser, eq(sysCreatedUser.userId, sysDict.createdBy))
|
||||
.leftJoin(sysUpdatedUser, eq(sysUpdatedUser.userId, sysDict.updatedBy))
|
||||
.where(eq(sysDict.id, dictId));
|
||||
|
||||
// ! 递归层级
|
||||
const recursiveQueryBuilder = new QueryBuilder();
|
||||
const recursiveQuery = recursiveQueryBuilder
|
||||
.select({
|
||||
...dictList,
|
||||
level: sql`dictHierarchy.level + 1`.as('level'),
|
||||
})
|
||||
.from(sysDict)
|
||||
.leftJoin(sysModule, eq(sysDict.moduleId, sysModule.id))
|
||||
.leftJoin(sysCreatedUser, eq(sysCreatedUser.userId, sysDict.createdBy))
|
||||
.leftJoin(sysUpdatedUser, eq(sysUpdatedUser.userId, sysDict.updatedBy))
|
||||
.innerJoin(sql`dictHierarchy`, sql`dictHierarchy.id = ${sysDict.pid}`);
|
||||
|
||||
const rowName = customDrizzleRowWithRecursive(dictList);
|
||||
|
||||
// ! 执行原始SQL查询
|
||||
return this.db.execute(
|
||||
sql`WITH RECURSIVE dictHierarchy(${rowName}) AS(${baseQuery} UNION ALL ${recursiveQuery}) SELECT * FROM dictHierarchy`,
|
||||
);
|
||||
}
|
||||
|
||||
export function customDrizzleRowWithRecursive(obj) {
|
||||
// ! 获取所有的列别名
|
||||
const rowNameList = [...Object.keys(obj), 'level'];
|
||||
|
||||
// ! 制造drizzle专属的列名称
|
||||
const rowName = sql.empty();
|
||||
rowNameList.forEach((i, index) => {
|
||||
rowName.append(sql`${sql.raw(i)}`);
|
||||
if (index < rowNameList.length - 1) {
|
||||
rowName.append(sql`, `);
|
||||
}
|
||||
});
|
||||
|
||||
return rowName;
|
||||
}
|
162
src/services/dict/dict.service.js
Normal file
162
src/services/dict/dict.service.js
Normal file
@ -0,0 +1,162 @@
|
||||
import {
|
||||
getDictList,
|
||||
getDictDetail,
|
||||
checkDictKeyConflict,
|
||||
createDict,
|
||||
deleteDict,
|
||||
checkDictKeyConflictNotMe,
|
||||
updateDict,
|
||||
getDictTree
|
||||
} from './dict.db.js';
|
||||
|
||||
// 字典列表服务
|
||||
export async function dictListService(request) {
|
||||
const data = await getDictList.call(this, request.query);
|
||||
console.log('查询结果:', data); // 打印查询结果,用于调试和验证查询逻辑是否正确
|
||||
return { code: 200, data, message: '查询成功' };
|
||||
}
|
||||
|
||||
// 字典详情服务
|
||||
export async function dictInfoService(request) {
|
||||
const { id } = request.params;
|
||||
const data = await getDictDetail.call(this, id);
|
||||
|
||||
if (!data) {
|
||||
return { code: 404, error: '字典不存在' };
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: data,
|
||||
message: '查询成功'
|
||||
};
|
||||
}
|
||||
|
||||
// 字典树服务
|
||||
export async function dictTreeService(request) {
|
||||
const data = await getDictTree.call(this, request.params.id);
|
||||
return { code: 200, data: data[0], message: '查询成功' };
|
||||
}
|
||||
|
||||
// 创建字典服务(带分布式锁)
|
||||
export async function dictCreateService(request, reply) {
|
||||
const { pid, moduleId, dictKey, value, description, sort, status } = request.body;
|
||||
const userId = request.user.userId; // 从JWT获取用户ID
|
||||
const lockKey = `${this.const.DISTRIBUTED_LOCK_PREFIX.CREATE_DICT}_${pid}_${dictKey}`;
|
||||
const lockIdentifier = this.snowflake();
|
||||
let renewInterval;
|
||||
|
||||
try {
|
||||
// 获取分布式锁
|
||||
const locked = await this.redis.SET(lockKey, lockIdentifier, { NX: true, EX: 5 });
|
||||
if (!locked) throw this.httpErrors.tooManyRequests('操作正在进行,请稍后重试');
|
||||
|
||||
// 启动锁续期
|
||||
renewInterval = setInterval(async () => {
|
||||
if (await this.redis.GET(lockKey) === lockIdentifier) {
|
||||
await this.redis.EXPIRE(lockKey, 5);
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
// 检查字典Key冲突
|
||||
const exists = await checkDictKeyConflict.call(this, pid, dictKey);
|
||||
if (exists) throw this.httpErrors.conflict('当前集合下字典标识已存在');
|
||||
|
||||
// 创建新字典项
|
||||
const newDict = await createDict.call(this, { pid, moduleId, dictKey, value, description, sort, status, createdBy: userId }); // 确保 userId 正确传递给 createDict 方法;
|
||||
|
||||
reply.code(201).send({
|
||||
code: 201,
|
||||
data: newDict,
|
||||
message: '字典创建成功'
|
||||
});
|
||||
} catch (err) {
|
||||
if (err.statusCode === 409) {
|
||||
throw this.httpErrors.conflict(err.message);
|
||||
}
|
||||
throw err;
|
||||
} finally {
|
||||
clearInterval(renewInterval);
|
||||
if (await this.redis.GET(lockKey) === lockIdentifier) {
|
||||
await this.redis.DEL(lockKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 更新字典服务
|
||||
export async function dictUpdateService(request) {
|
||||
const { id } = request.params;
|
||||
const updateData = request.body;
|
||||
const userId = request.user.userId;
|
||||
console.log('updateData:', updateData); // 打印更新数据,用于调试和验证更新逻辑是否正确
|
||||
|
||||
let lockKey = `${this.const.DISTRIBUTED_LOCK_PREFIX.UPDATE_DICT}${id}`;
|
||||
// 检查字典是否存在
|
||||
const existing = await getDictDetail.call(this, id);
|
||||
if (!existing) throw this.httpErrors.notFound('字典不存在');
|
||||
// 如果更新了字典标识,需要改变锁key
|
||||
if (updateData.dictKey) {
|
||||
lockKey = `${this.const.DISTRIBUTED_LOCK_PREFIX.CREATE_DICT}_${existing.pid}_${updateData.dictKey}`;
|
||||
}
|
||||
|
||||
const lockIdentifier = this.snowflake();
|
||||
let renewInterval;
|
||||
|
||||
try {
|
||||
// 获取分布式锁
|
||||
const locked = await this.redis.SET(lockKey, lockIdentifier, { NX: true, EX: 5 });
|
||||
if (!locked) throw this.httpErrors.tooManyRequests('操作正在进行,请稍后重试');
|
||||
|
||||
// 启动锁续期
|
||||
renewInterval = setInterval(async () => {
|
||||
if (await this.redis.GET(lockKey) === lockIdentifier) {
|
||||
await this.redis.EXPIRE(lockKey, 5);
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
// 检查字典Key冲突(如果更新了dictKey)
|
||||
if (updateData.dictKey && updateData.dictKey !== existing.dictKey) {
|
||||
const keyExists = await checkDictKeyConflictNotMe.call(
|
||||
this,
|
||||
existing.pid,
|
||||
updateData.dictKey,
|
||||
id
|
||||
);
|
||||
if (keyExists) throw this.httpErrors.conflict('字典标识已被占用');
|
||||
}
|
||||
|
||||
// 执行更新
|
||||
const updated = await updateDict.call(this, id, {
|
||||
...updateData,
|
||||
updatedBy: userId,
|
||||
});
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: updated,
|
||||
message: '字典更新成功'
|
||||
};
|
||||
} catch (err) {
|
||||
if (err.statusCode === 409) {
|
||||
throw this.httpErrors.conflict(err.message);
|
||||
}
|
||||
throw err;
|
||||
} finally {
|
||||
clearInterval(renewInterval);
|
||||
if (await this.redis.GET(lockKey) === lockIdentifier) {
|
||||
await this.redis.DEL(lockKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除字典服务
|
||||
export async function dictDeleteService(request) {
|
||||
const { id } = request.params;
|
||||
const data = await deleteDict.call(this, id);
|
||||
if(data === 0){
|
||||
return { code: 404, error: '字典不存在' };
|
||||
}else{
|
||||
return { code: 200, message: '删除成功' };
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { sysUser, sysUserAuth, sysUserAuthHistory, sysModule } from '#entity';
|
||||
import { or, eq, and, asc, desc, count, like, ne } from 'drizzle-orm';
|
||||
import { alias } from 'drizzle-orm/mysql-core';
|
||||
|
||||
// 获取模块列表和分页
|
||||
export async function getModuleList(queryData) {
|
||||
@ -13,6 +14,8 @@ export async function getModuleList(queryData) {
|
||||
sortOrder = 'desc'
|
||||
} = queryData;
|
||||
this.log.info(queryData);
|
||||
const sysCreatedUser = alias(sysUser, 'sysCreatedUser');
|
||||
const sysUpdatedUser = alias(sysUser, 'sysUpdatedUser');
|
||||
const isGetPage = page && pageSize;
|
||||
const listSelect = {
|
||||
id: sysModule.id,
|
||||
@ -25,6 +28,8 @@ export async function getModuleList(queryData) {
|
||||
version: sysModule.version,
|
||||
sort: sysModule.sort,
|
||||
status: sysModule.status,
|
||||
createdUser: sysCreatedUser.nickname,
|
||||
updatedUser: sysUpdatedUser.nickname,
|
||||
createdBy: sysModule.createdBy,
|
||||
updatedBy: sysModule.updatedBy,
|
||||
createdAt: sysModule.createdAt,
|
||||
@ -35,6 +40,8 @@ export async function getModuleList(queryData) {
|
||||
let query = db
|
||||
.select(isGetPage ? pageSelect : listSelect)
|
||||
.from(sysModule)
|
||||
.leftJoin(sysCreatedUser, eq(sysCreatedUser.userId, sysModule.createdBy))
|
||||
.leftJoin(sysUpdatedUser, eq(sysUpdatedUser.userId, sysModule.updatedBy))
|
||||
.$dynamic();
|
||||
// 应用过滤条件
|
||||
const conditions = [];
|
||||
@ -100,8 +107,6 @@ export async function insertModule(data) {
|
||||
description: data.description,
|
||||
sort: data.sort || 0,
|
||||
status: data.status || 0,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
createdBy: data.createdBy,
|
||||
}).execute();
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ export async function moduleCreateService(request, reply) {
|
||||
if (exists) throw this.httpErrors.conflict('模块标识已存在');
|
||||
|
||||
// 创建模块
|
||||
const newModule = await insertModule.call(this, {
|
||||
await insertModule.call(this, {
|
||||
...request.body,
|
||||
createdBy: request.user?.userId || 0 // 从JWT获取用户ID
|
||||
});
|
||||
@ -48,7 +48,6 @@ export async function moduleCreateService(request, reply) {
|
||||
reply.code(201).send({
|
||||
code: 201,
|
||||
data: {
|
||||
id: newModule.insertId,
|
||||
moduleKey,
|
||||
name
|
||||
},
|
||||
@ -67,7 +66,7 @@ export async function moduleCreateService(request, reply) {
|
||||
}
|
||||
}
|
||||
|
||||
// 新增模块修改服务
|
||||
// 模块修改服务
|
||||
export async function moduleUpdateService(request, reply) {
|
||||
const { id } = request.params;
|
||||
const updateData = request.body;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import ajvErrors from 'ajv-errors';
|
||||
import { isLowerCase, isTrim } from '#utils/ajv/method';
|
||||
import { isLowerCase, isTrim, toNull } from '#utils/ajv/method';
|
||||
export const ajvConfig = {
|
||||
customOptions: {
|
||||
removeAdditional: true, // 自动删除schema未定义的额外属性
|
||||
@ -12,5 +12,6 @@ export const ajvConfig = {
|
||||
ajvErrors, // 支持自定义错误消息
|
||||
isLowerCase, // 自定义验证:强制小写(如用户名)
|
||||
isTrim, // 自定义验证:自动trim字符串
|
||||
toNull, // 自定义验证:如果为空字符串将其设置为null
|
||||
],
|
||||
};
|
||||
|
@ -22,7 +22,11 @@ export function isLowerCase(ajv){
|
||||
errors: true,
|
||||
modifying: true,
|
||||
validate: function validateIsEven(schema, data, parentSchema, dataCxt) {
|
||||
if(typeof data == 'string'){
|
||||
if(typeof data == 'string' || data == null){
|
||||
if(data == null){
|
||||
dataCxt.parentData[dataCxt.parentDataProperty] = null;
|
||||
return true;
|
||||
}
|
||||
dataCxt.parentData[dataCxt.parentDataProperty] = dataCxt.parentData[dataCxt.parentDataProperty].trim().toLowerCase();
|
||||
return true;
|
||||
}else{
|
||||
@ -44,7 +48,11 @@ export function isTrim(ajv){
|
||||
errors: true,
|
||||
modifying: true,
|
||||
validate: function validateIsEven(schema, data, parentSchema, dataCxt) {
|
||||
if(typeof data == 'string'){
|
||||
if(typeof data == 'string' || data == null){
|
||||
if(data == null){
|
||||
dataCxt.parentData[dataCxt.parentDataProperty] = null;
|
||||
return true;
|
||||
}
|
||||
dataCxt.parentData[dataCxt.parentDataProperty] = dataCxt.parentData[dataCxt.parentDataProperty].trim();
|
||||
return true;
|
||||
}else{
|
||||
@ -56,6 +64,29 @@ export function isTrim(ajv){
|
||||
}
|
||||
});
|
||||
}
|
||||
// 如果为空字符串将其设置为null
|
||||
export function toNull(ajv){
|
||||
ajv.addKeyword({
|
||||
keyword: 'toNull',
|
||||
type: 'string',
|
||||
errors: true,
|
||||
modifying: true,
|
||||
validate: function validateIsEven(schema, data, parentSchema, dataCxt) {
|
||||
if(typeof data == 'string' || data == null){
|
||||
if(data.trim() ==''){
|
||||
dataCxt.parentData[dataCxt.parentDataProperty] = null;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}else{
|
||||
validateIsEven.errors = [ {
|
||||
message: '参数不是字符串格式'
|
||||
} ];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 给fastify添加自定义的参数校验规则
|
||||
|
@ -1,8 +1,8 @@
|
||||
CREATE TABLE `sys_dict` (
|
||||
`id` BIGINT NOT NULL COMMENT 'ID',
|
||||
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`version` INT NOT NULL DEFAULT 0,
|
||||
`pid` BIGINT NOT NULL COMMENT '上级ID',
|
||||
`module` tinyint NULL COMMENT '模块',
|
||||
`pid` INT NOT NULL COMMENT '上级ID',
|
||||
`module_id` tinyint NULL COMMENT '模块',
|
||||
`dict_key` varchar(255) NULL COMMENT '字典标识',
|
||||
`value` varchar(255) NULL COMMENT '字典值',
|
||||
`description` varchar(255) NULL COMMENT '描述',
|
||||
@ -129,6 +129,7 @@ CREATE TABLE `sys_user` (
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`pid` bigint NOT NULL COMMENT '上级ID',
|
||||
`username` varchar(255) NOT NULL COMMENT '用户名,全小写',
|
||||
`nickname` varchar(255) NOT NULL COMMENT '用户昵称',
|
||||
`email` varchar(255) NOT NULL COMMENT '邮箱',
|
||||
`phone` varchar(255) NULL COMMENT '手机号',
|
||||
`avatar_url` varchar(255) NULL COMMENT '图标',
|
||||
|
Loading…
Reference in New Issue
Block a user