feat: 添加Redis支持、雪花ID生成器及集群模式
- 新增Redis插件,支持分布式锁及缓存功能 - 引入雪花ID生成器,用于生成唯一用户ID - 实现集群模式,支持多线程运行 - 优化用户注册逻辑,增加分布式锁机制 - 更新配置文件,添加Redis及雪花ID相关配置 - 修复部分代码格式及数据库字段类型
This commit is contained in:
parent
3d4af91569
commit
fdc4d67092
14
.env
14
.env
@ -1,5 +1,5 @@
|
||||
# 服务器配置
|
||||
PORT=9000
|
||||
PORT=19000
|
||||
HOST=0.0.0.0
|
||||
BACKLOG=511
|
||||
|
||||
@ -17,3 +17,15 @@ DB_USER=nie
|
||||
DB_PASSWORD=Hxl1314521
|
||||
DB_NAME=yuheng
|
||||
DB_PORT=3306
|
||||
|
||||
# redis
|
||||
REDIS_HOST=172.16.1.10
|
||||
REDIS_PORT=16379
|
||||
REDIS_PASSWORD=Hxl1314521
|
||||
REDIS_DB=9
|
||||
|
||||
# 数据中心ID
|
||||
DATACENTER_ID=1
|
||||
|
||||
# 机器ID
|
||||
MACHINE_ID=1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,13 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "mysql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "5",
|
||||
"when": 1742546365192,
|
||||
"tag": "0000_skinny_bloodaxe",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
"version": "7",
|
||||
"dialect": "mysql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "5",
|
||||
"when": 1742546365192,
|
||||
"tag": "0000_skinny_bloodaxe",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,3 +1,2 @@
|
||||
import { relations } from "drizzle-orm/relations";
|
||||
import { } from "./schema";
|
||||
|
||||
import { relations } from 'drizzle-orm/relations';
|
||||
import {} from './schema';
|
||||
|
553
SQL/schema.ts
553
SQL/schema.ts
@ -1,242 +1,339 @@
|
||||
import { mysqlTable, mysqlSchema, AnyMySqlColumn, primaryKey, unique, bigint, int, tinyint, varchar, datetime } from "drizzle-orm/mysql-core"
|
||||
import { sql } from "drizzle-orm"
|
||||
import {
|
||||
mysqlTable,
|
||||
mysqlSchema,
|
||||
AnyMySqlColumn,
|
||||
primaryKey,
|
||||
unique,
|
||||
bigint,
|
||||
int,
|
||||
tinyint,
|
||||
varchar,
|
||||
datetime,
|
||||
} from 'drizzle-orm/mysql-core';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
export const sysDict = mysqlTable("sys_dict", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
module: tinyint(),
|
||||
dictKey: varchar("dict_key", { length: 255 }),
|
||||
value: varchar({ length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_dict_id"}),
|
||||
unique("uniq_dict_key").on(table.dictKey, table.pid),
|
||||
]);
|
||||
export const sysDict = mysqlTable(
|
||||
'sys_dict',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
module: tinyint(),
|
||||
dictKey: varchar('dict_key', { length: 255 }),
|
||||
value: varchar({ length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_dict_id' }),
|
||||
unique('uniq_dict_key').on(table.dictKey, table.pid),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysOrganization = mysqlTable("sys_organization", {
|
||||
orgId: bigint("org_id", { mode: "number" }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
orgName: varchar("org_name", { length: 255 }),
|
||||
orgCode: varchar("org_code", { length: 128 }),
|
||||
orgType: int("org_type").notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.orgId], name: "sys_organization_org_id"}),
|
||||
unique("uniq_org_code").on(table.orgCode, table.pid),
|
||||
unique("uniq_org_name").on(table.orgName, table.pid),
|
||||
]);
|
||||
export const sysOrganization = mysqlTable(
|
||||
'sys_organization',
|
||||
{
|
||||
orgId: bigint('org_id', { mode: 'number' }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
orgName: varchar('org_name', { length: 255 }),
|
||||
orgCode: varchar('org_code', { length: 128 }),
|
||||
orgType: int('org_type').notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.orgId], name: 'sys_organization_org_id' }),
|
||||
unique('uniq_org_code').on(table.orgCode, table.pid),
|
||||
unique('uniq_org_name').on(table.orgName, table.pid),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysOrganizationManager = mysqlTable("sys_organization_manager", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
orgId: bigint("org_id", { mode: "number" }).notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
rank: int().notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_organization_manager_id"}),
|
||||
unique("uniq_org_user").on(table.orgId, table.userId),
|
||||
]);
|
||||
export const sysOrganizationManager = mysqlTable(
|
||||
'sys_organization_manager',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
orgId: bigint('org_id', { mode: 'number' }).notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
rank: int().notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_organization_manager_id' }),
|
||||
unique('uniq_org_user').on(table.orgId, table.userId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysPermission = mysqlTable("sys_permission", {
|
||||
permId: bigint("perm_id", { mode: "number" }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
permName: varchar("perm_name", { length: 255 }).notNull(),
|
||||
permKey: varchar("perm_key", { length: 255 }).notNull(),
|
||||
url: varchar({ length: 255 }),
|
||||
avatarUrl: varchar("avatar_url", { length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
permType: int("perm_type").notNull(),
|
||||
isVisible: int("is_visible").default(0).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(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),
|
||||
]);
|
||||
export const sysPermission = mysqlTable(
|
||||
'sys_permission',
|
||||
{
|
||||
permId: bigint('perm_id', { mode: 'number' }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
permName: varchar('perm_name', { length: 255 }).notNull(),
|
||||
permKey: varchar('perm_key', { length: 255 }).notNull(),
|
||||
url: varchar({ length: 255 }),
|
||||
avatarUrl: varchar('avatar_url', { length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
permType: int('perm_type').notNull(),
|
||||
isVisible: int('is_visible').default(0).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
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),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysReRolePermission = mysqlTable("sys_re_role_permission", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
roleId: bigint("role_id", { mode: "number" }).notNull(),
|
||||
permId: bigint("perm_id", { mode: "number" }).notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_re_role_permission_id"}),
|
||||
unique("uniq_perm_role").on(table.roleId, table.permId),
|
||||
]);
|
||||
export const sysReRolePermission = mysqlTable(
|
||||
'sys_re_role_permission',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).autoincrement().notNull(),
|
||||
roleId: bigint('role_id', { mode: 'number' }).notNull(),
|
||||
permId: bigint('perm_id', { mode: 'number' }).notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_re_role_permission_id' }),
|
||||
unique('uniq_perm_role').on(table.roleId, table.permId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysReUserOrganization = mysqlTable("sys_re_user_organization", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
orgId: bigint("org_id", { mode: "number" }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_re_user_organization_id"}),
|
||||
unique("uniq_user_org").on(table.userId, table.orgId),
|
||||
]);
|
||||
export const sysReUserOrganization = mysqlTable(
|
||||
'sys_re_user_organization',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).autoincrement().notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
orgId: bigint('org_id', { mode: 'number' }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_re_user_organization_id' }),
|
||||
unique('uniq_user_org').on(table.userId, table.orgId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysReUserRole = mysqlTable("sys_re_user_role", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
roleId: bigint("role_id", { mode: "number" }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_re_user_role_id"}),
|
||||
unique("uniq_user_role").on(table.userId, table.roleId),
|
||||
]);
|
||||
export const sysReUserRole = mysqlTable(
|
||||
'sys_re_user_role',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).autoincrement().notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
roleId: bigint('role_id', { mode: 'number' }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_re_user_role_id' }),
|
||||
unique('uniq_user_role').on(table.userId, table.roleId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysRole = mysqlTable("sys_role", {
|
||||
roleId: bigint("role_id", { mode: "number" }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
roleName: varchar("role_name", { length: 255 }).notNull(),
|
||||
roleKey: varchar("role_key", { length: 255 }).notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.roleId], name: "sys_role_role_id"}),
|
||||
unique("uniq_role_pid").on(table.roleName, table.pid),
|
||||
]);
|
||||
export const sysRole = mysqlTable(
|
||||
'sys_role',
|
||||
{
|
||||
roleId: bigint('role_id', { mode: 'number' }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
roleName: varchar('role_name', { length: 255 }).notNull(),
|
||||
roleKey: varchar('role_key', { length: 255 }).notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.roleId], name: 'sys_role_role_id' }),
|
||||
unique('uniq_role_pid').on(table.roleName, table.pid),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUser = mysqlTable("sys_user", {
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
username: varchar({ length: 255 }).notNull(),
|
||||
email: varchar({ length: 255 }).notNull(),
|
||||
phone: varchar({ length: 255 }),
|
||||
avatarUrl: varchar("avatar_url", { length: 255 }),
|
||||
userType: tinyint("user_type"),
|
||||
status: tinyint().default(0).notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.userId], name: "sys_user_user_id"}),
|
||||
unique("uniq_username").on(table.username),
|
||||
unique("uniq_email").on(table.email),
|
||||
]);
|
||||
export const sysUser = mysqlTable(
|
||||
'sys_user',
|
||||
{
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
username: varchar({ length: 255 }).notNull(),
|
||||
email: varchar({ length: 255 }).notNull(),
|
||||
phone: varchar({ length: 255 }),
|
||||
avatarUrl: varchar('avatar_url', { length: 255 }),
|
||||
userType: tinyint('user_type'),
|
||||
status: tinyint().default(0).notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.userId], name: 'sys_user_user_id' }),
|
||||
unique('uniq_username').on(table.username),
|
||||
unique('uniq_email').on(table.email),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUserAuth = mysqlTable("sys_user_auth", {
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
passwordHash: varchar("password_hash", { length: 255 }).notNull(),
|
||||
passwordModified: datetime("password_modified", { mode: 'string'}).notNull(),
|
||||
passwordExpire: datetime("password_expire", { mode: 'string'}),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.userId], name: "sys_user_auth_user_id"}),
|
||||
]);
|
||||
export const sysUserAuth = mysqlTable(
|
||||
'sys_user_auth',
|
||||
{
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
passwordHash: varchar('password_hash', { length: 255 }).notNull(),
|
||||
passwordModified: datetime('password_modified', { mode: 'string' }).notNull(),
|
||||
passwordExpire: datetime('password_expire', { mode: 'string' }),
|
||||
},
|
||||
table => [primaryKey({ columns: [table.userId], name: 'sys_user_auth_user_id' })],
|
||||
);
|
||||
|
||||
export const sysUserAuthHistory = mysqlTable("sys_user_auth_history", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
passwordHash: varchar("password_hash", { length: 255 }).notNull(),
|
||||
modifiedAt: varchar("modified_at", { length: 255 }).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_user_auth_history_id"}),
|
||||
]);
|
||||
export const sysUserAuthHistory = mysqlTable(
|
||||
'sys_user_auth_history',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).autoincrement().notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
passwordHash: varchar('password_hash', { length: 255 }).notNull(),
|
||||
modifiedAt: varchar('modified_at', { length: 255 }).notNull(),
|
||||
},
|
||||
table => [primaryKey({ columns: [table.id], name: 'sys_user_auth_history_id' })],
|
||||
);
|
||||
|
||||
export const sysUserFieldDefinition = mysqlTable("sys_user_field_definition", {
|
||||
fieldId: bigint("field_id", { mode: "number" }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
fieldName: varchar("field_name", { length: 255 }).notNull(),
|
||||
fieldKey: varchar("field_key", { length: 255 }).notNull(),
|
||||
fieldType: tinyint("field_type").notNull(),
|
||||
dictModule: int("dict_module"),
|
||||
isRequired: tinyint("is_required").default(0).notNull(),
|
||||
limit: int(),
|
||||
description: varchar({ length: 255 }),
|
||||
defaultValue: varchar("default_value", { length: 255 }),
|
||||
defaultOptions: varchar("default_options", { length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(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),
|
||||
]);
|
||||
export const sysUserFieldDefinition = mysqlTable(
|
||||
'sys_user_field_definition',
|
||||
{
|
||||
fieldId: bigint('field_id', { mode: 'number' }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
fieldName: varchar('field_name', { length: 255 }).notNull(),
|
||||
fieldKey: varchar('field_key', { length: 255 }).notNull(),
|
||||
fieldType: tinyint('field_type').notNull(),
|
||||
dictModule: int('dict_module'),
|
||||
isRequired: tinyint('is_required').default(0).notNull(),
|
||||
limit: int(),
|
||||
description: varchar({ length: 255 }),
|
||||
defaultValue: varchar('default_value', { length: 255 }),
|
||||
defaultOptions: varchar('default_options', { length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
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),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUserFieldValue = mysqlTable("sys_user_field_value", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
fieldId: int("field_id").notNull(),
|
||||
value: varchar({ length: 4096 }),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_user_field_value_id"}),
|
||||
unique("uniq_user_field").on(table.userId, table.fieldId),
|
||||
]);
|
||||
export const sysUserFieldValue = mysqlTable(
|
||||
'sys_user_field_value',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).autoincrement().notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
fieldId: int('field_id').notNull(),
|
||||
value: varchar({ length: 4096 }),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_user_field_value_id' }),
|
||||
unique('uniq_user_field').on(table.userId, table.fieldId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUserProfile = mysqlTable("sys_user_profile", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
name: varchar({ length: 32 }).notNull(),
|
||||
profileKey: varchar("profile_key", { length: 255 }).notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
content: varchar({ length: 255 }),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_user_profile_id"}),
|
||||
unique("uniq_name").on(table.name),
|
||||
unique("uniq_profile_key").on(table.profileKey),
|
||||
]);
|
||||
export const sysUserProfile = mysqlTable(
|
||||
'sys_user_profile',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
name: varchar({ length: 32 }).notNull(),
|
||||
profileKey: varchar('profile_key', { length: 255 }).notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
content: varchar({ length: 255 }),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_user_profile_id' }),
|
||||
unique('uniq_name').on(table.name),
|
||||
unique('uniq_profile_key').on(table.profileKey),
|
||||
],
|
||||
);
|
||||
|
@ -4,7 +4,7 @@ import path from 'path';
|
||||
|
||||
// 加载环境变量
|
||||
config({ path: path.resolve(process.cwd(), '.env') });
|
||||
console.log('[NODE_ENV]:', process.env.NODE_ENV);
|
||||
// console.log('[NODE_ENV]:', process.env.NODE_ENV);
|
||||
|
||||
// 基础配置
|
||||
const baseConfig = {
|
||||
@ -13,6 +13,11 @@ const baseConfig = {
|
||||
serviceName: 'YuHeng',
|
||||
description: 'User System',
|
||||
version: '1.0.0',
|
||||
deviceInfo: {
|
||||
dataCenterId: process.env.DATACENTER_ID,
|
||||
machineId: process.env.MACHINE_ID,
|
||||
pid: process.pid,
|
||||
},
|
||||
server: {
|
||||
port: process.env.PORT || 9000,
|
||||
host: process.env.HOST || 'localhost',
|
||||
@ -21,7 +26,7 @@ const baseConfig = {
|
||||
profile: {
|
||||
swagger: {
|
||||
basePath: '/swagger',
|
||||
}
|
||||
},
|
||||
},
|
||||
logger: {
|
||||
level: process.env.LOG_LEVEL || 'trace',
|
||||
@ -38,11 +43,22 @@ const baseConfig = {
|
||||
user: process.env.DB_USER || 'root',
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME || 'yuheng',
|
||||
ssl: process.env.NODE_ENV === 'production' ? {
|
||||
rejectUnauthorized: false,
|
||||
servername: '' // 明确置空servername参数
|
||||
} : null,
|
||||
ssl:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? {
|
||||
rejectUnauthorized: false,
|
||||
servername: '', // 明确置空servername参数
|
||||
}
|
||||
: null,
|
||||
},
|
||||
redis: {
|
||||
host: process.env.REDIS_HOST || '127.0.0.1',
|
||||
port: process.env.REDIS_PORT || 6379,
|
||||
connectName: 'yuheng',
|
||||
database: process.env.REDIS_DB || 9,
|
||||
username: 'default',
|
||||
password: process.env.REDIS_PASSWORD || 'Hxl1314521',
|
||||
}
|
||||
};
|
||||
|
||||
// 环境特定配置
|
||||
@ -72,5 +88,6 @@ function deepMerge(target, source) {
|
||||
}
|
||||
return Object.assign({}, target, source);
|
||||
}
|
||||
const configInfo = deepMerge(baseConfig, envConfig[process.env.NODE_ENV] || envConfig.development);
|
||||
|
||||
export default deepMerge(baseConfig, envConfig[process.env.NODE_ENV] || envConfig.development);
|
||||
export default configInfo;
|
||||
|
97
package-lock.json
generated
97
package-lock.json
generated
@ -22,7 +22,8 @@
|
||||
"mysql2": "^3.13.0",
|
||||
"pino": "^9.6.0",
|
||||
"pino-multi-stream": "^6.0.0",
|
||||
"pino-pretty": "^13.0.0"
|
||||
"pino-pretty": "^13.0.0",
|
||||
"redis": "^4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
@ -1307,6 +1308,65 @@
|
||||
"integrity": "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@redis/bloom": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz",
|
||||
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/client": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/client/-/client-1.6.0.tgz",
|
||||
"integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cluster-key-slot": "1.1.2",
|
||||
"generic-pool": "3.9.0",
|
||||
"yallist": "4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/graph": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/graph/-/graph-1.1.1.tgz",
|
||||
"integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/json": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/json/-/json-1.0.7.tgz",
|
||||
"integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/search": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/search/-/search-1.2.0.tgz",
|
||||
"integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/time-series": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.1.0.tgz",
|
||||
"integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rtsao/scc": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/@rtsao/scc/-/scc-1.1.0.tgz",
|
||||
@ -1862,6 +1922,15 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cluster-key-slot": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@ -3368,6 +3437,15 @@
|
||||
"is-property": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/generic-pool": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmmirror.com/generic-pool/-/generic-pool-3.9.0.tgz",
|
||||
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
@ -5241,6 +5319,23 @@
|
||||
"node": ">= 12.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redis": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmmirror.com/redis/-/redis-4.7.0.tgz",
|
||||
"integrity": "sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"./packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@redis/bloom": "1.2.0",
|
||||
"@redis/client": "1.6.0",
|
||||
"@redis/graph": "1.1.1",
|
||||
"@redis/json": "1.0.7",
|
||||
"@redis/search": "1.2.0",
|
||||
"@redis/time-series": "1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect.getprototypeof": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
||||
|
@ -21,8 +21,8 @@
|
||||
"node": ">=22"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env NODE_ENV=production node src/application.js",
|
||||
"dev": "cross-env NODE_ENV=development nodemon src/application.js",
|
||||
"start": "cross-env NODE_ENV=production node src/cluster.js",
|
||||
"dev": "cross-env NODE_ENV=development nodemon src/cluster.js",
|
||||
"lint": "eslint src --ext .js",
|
||||
"format": "prettier --write . --config ./.prettier.config.cjs --ignore-path .prettierignore",
|
||||
"lint:format": "prettier --check . --config ./.prettier.config.cjs --ignore-path .prettierignore",
|
||||
@ -48,7 +48,8 @@
|
||||
"mysql2": "^3.13.0",
|
||||
"pino": "^9.6.0",
|
||||
"pino-multi-stream": "^6.0.0",
|
||||
"pino-pretty": "^13.0.0"
|
||||
"pino-pretty": "^13.0.0",
|
||||
"redis": "^4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
|
@ -1,17 +1,17 @@
|
||||
// ESM
|
||||
import '#start';
|
||||
import Fastify from 'fastify';
|
||||
import config from '#config/index';
|
||||
import plugin from '#src/plugins/index';
|
||||
import routes from '#src/routes/index';
|
||||
import logger from '#src/utils/logger';
|
||||
import loggerConfig from '#src/utils/logger';
|
||||
import { ajvConfig } from '#utils/ajv/index';
|
||||
|
||||
async function start() {
|
||||
export default async function Application(machineId = 1) {
|
||||
config.deviceInfo.machineId = machineId;
|
||||
// 创建Fastify实例
|
||||
const fastify = new Fastify({
|
||||
logger,
|
||||
ajv: ajvConfig
|
||||
logger: loggerConfig(config),
|
||||
ajv: ajvConfig,
|
||||
});
|
||||
// 加载插件
|
||||
await fastify.register(plugin, { config });
|
||||
@ -20,4 +20,3 @@ async function start() {
|
||||
// 启动服务器
|
||||
await fastify.listen(config.server); // 使用配置中的服务器参数
|
||||
}
|
||||
start();
|
||||
|
63
src/cluster.js
Normal file
63
src/cluster.js
Normal file
@ -0,0 +1,63 @@
|
||||
import echo from '#start';
|
||||
import cluster from 'cluster';
|
||||
import os from 'os';
|
||||
import Application from './application.js';
|
||||
|
||||
// 获取 CPU 核心数
|
||||
const numCPUs = os.cpus().length;
|
||||
|
||||
function sleep(time = 1000) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
}
|
||||
|
||||
// 启动集群
|
||||
async function clusterStart() {
|
||||
// 检查是否为主进程
|
||||
if (cluster.isPrimary) {
|
||||
echo();
|
||||
// 设置负载均衡策略
|
||||
cluster.schedulingPolicy = cluster.SCHED_RR;
|
||||
console.log(`Primary ${process.pid} is running`);
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
console.log('>>>>>>>>>>>>>>多线程模式');
|
||||
// 为每个 CPU 核心创建一个工作进程
|
||||
for (let i = 0; i < /*numCPUs*/ 2; i++) {
|
||||
const worker = cluster.fork();
|
||||
worker.on('message', async message => {
|
||||
if (message.type === 'workerStarted') {
|
||||
worker.send({ type: 'workerId', id: i + 1 });
|
||||
}
|
||||
});
|
||||
await sleep(100);
|
||||
}
|
||||
// 监听工作进程退出事件
|
||||
cluster.on('exit', (worker, code, signal) => {
|
||||
console.log(`Worker ${worker.process.pid} died`);
|
||||
});
|
||||
} else {
|
||||
console.log('==============单线程模式');
|
||||
Application();
|
||||
}
|
||||
} else {
|
||||
// 工作进程
|
||||
// 告诉主进程工作进程已启动
|
||||
process.send({ type: 'workerStarted', pid: process.pid });
|
||||
// 监听主进程发送的消息
|
||||
process.on('message', message => {
|
||||
if (message.type === 'workerId') {
|
||||
const workerId = message.id;
|
||||
console.log(
|
||||
`Worker (ID ${workerId.toString().padStart(2, 0)}) ${process.pid.toString().padEnd(8, ' ')} started`,
|
||||
);
|
||||
// 启动服务器
|
||||
Application(workerId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
clusterStart();
|
27
src/entities/customType.js
Normal file
27
src/entities/customType.js
Normal file
@ -0,0 +1,27 @@
|
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-x7129】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: customType.ts -
|
||||
// | @创建时间: 2024-06-04 16:27
|
||||
// | @更新时间: 2024-06-04 16:27
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
// 定义自定义类型
|
||||
import { customType } from 'drizzle-orm/mysql-core';
|
||||
|
||||
// 写入读取是将bigint转化为string
|
||||
export const bigintString = customType({
|
||||
dataType() {
|
||||
return 'bigint';
|
||||
},
|
||||
fromDriver(value) { // 数据库 -> JS
|
||||
return value?.toString(); // 处理 null 值
|
||||
},
|
||||
toDriver(value) { // JS -> 数据库
|
||||
return BigInt(value); // 确保写入时为数字类型
|
||||
}
|
||||
});
|
@ -1,242 +1,341 @@
|
||||
import { mysqlTable, mysqlSchema, primaryKey, unique, bigint, int, tinyint, varchar, datetime } from "drizzle-orm/mysql-core"
|
||||
import { sql } from "drizzle-orm"
|
||||
import {
|
||||
mysqlTable,
|
||||
mysqlSchema,
|
||||
primaryKey,
|
||||
unique,
|
||||
int,
|
||||
tinyint,
|
||||
varchar,
|
||||
datetime,
|
||||
} from 'drizzle-orm/mysql-core';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
export const sysDict = mysqlTable("sys_dict", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
module: tinyint(),
|
||||
dictKey: varchar("dict_key", { length: 255 }),
|
||||
value: varchar({ length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_dict_id"}),
|
||||
unique("uniq_dict_key").on(table.dictKey, table.pid),
|
||||
]);
|
||||
|
||||
export const sysOrganization = mysqlTable("sys_organization", {
|
||||
orgId: bigint("org_id", { mode: "number" }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
orgName: varchar("org_name", { length: 255 }),
|
||||
orgCode: varchar("org_code", { length: 128 }),
|
||||
orgType: int("org_type").notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.orgId], name: "sys_organization_org_id"}),
|
||||
unique("uniq_org_code").on(table.orgCode, table.pid),
|
||||
unique("uniq_org_name").on(table.orgName, table.pid),
|
||||
]);
|
||||
import { bigintString } from './customType.js';
|
||||
const bigint = bigintString;
|
||||
|
||||
export const sysOrganizationManager = mysqlTable("sys_organization_manager", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
orgId: bigint("org_id", { mode: "number" }).notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
rank: int().notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_organization_manager_id"}),
|
||||
unique("uniq_org_user").on(table.orgId, table.userId),
|
||||
]);
|
||||
export const sysDict = mysqlTable(
|
||||
'sys_dict',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
module: tinyint(),
|
||||
dictKey: varchar('dict_key', { length: 255 }),
|
||||
value: varchar({ length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_dict_id' }),
|
||||
unique('uniq_dict_key').on(table.dictKey, table.pid),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysPermission = mysqlTable("sys_permission", {
|
||||
permId: bigint("perm_id", { mode: "number" }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
permName: varchar("perm_name", { length: 255 }).notNull(),
|
||||
permKey: varchar("perm_key", { length: 255 }).notNull(),
|
||||
url: varchar({ length: 255 }),
|
||||
avatarUrl: varchar("avatar_url", { length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
permType: int("perm_type").notNull(),
|
||||
isVisible: int("is_visible").default(0).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(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),
|
||||
]);
|
||||
export const sysOrganization = mysqlTable(
|
||||
'sys_organization',
|
||||
{
|
||||
orgId: bigint('org_id', { mode: 'number' }).notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
orgName: varchar('org_name', { length: 255 }),
|
||||
orgCode: varchar('org_code', { length: 128 }),
|
||||
orgType: int('org_type').notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.orgId], name: 'sys_organization_org_id' }),
|
||||
unique('uniq_org_code').on(table.orgCode, table.pid),
|
||||
unique('uniq_org_name').on(table.orgName, table.pid),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysReRolePermission = mysqlTable("sys_re_role_permission", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
roleId: bigint("role_id", { mode: "number" }).notNull(),
|
||||
permId: bigint("perm_id", { mode: "number" }).notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_re_role_permission_id"}),
|
||||
unique("uniq_perm_role").on(table.roleId, table.permId),
|
||||
]);
|
||||
export const sysOrganizationManager = mysqlTable(
|
||||
'sys_organization_manager',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
orgId: bigint('org_id', { mode: 'number' }).notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
rank: int().notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_organization_manager_id' }),
|
||||
unique('uniq_org_user').on(table.orgId, table.userId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysReUserOrganization = mysqlTable("sys_re_user_organization", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
orgId: bigint("org_id", { mode: "number" }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_re_user_organization_id"}),
|
||||
unique("uniq_user_org").on(table.userId, table.orgId),
|
||||
]);
|
||||
export const sysPermission = mysqlTable(
|
||||
'sys_permission',
|
||||
{
|
||||
permId: bigint('perm_id', { mode: 'number' }).notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
permName: varchar('perm_name', { length: 255 }).notNull(),
|
||||
permKey: varchar('perm_key', { length: 255 }).notNull(),
|
||||
url: varchar({ length: 255 }),
|
||||
avatarUrl: varchar('avatar_url', { length: 255 }),
|
||||
description: varchar({ length: 255 }),
|
||||
permType: int('perm_type').notNull(),
|
||||
isVisible: int('is_visible').default(0).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
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),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysReUserRole = mysqlTable("sys_re_user_role", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
roleId: bigint("role_id", { mode: "number" }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_re_user_role_id"}),
|
||||
unique("uniq_user_role").on(table.userId, table.roleId),
|
||||
]);
|
||||
export const sysReRolePermission = mysqlTable(
|
||||
'sys_re_role_permission',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).notNull(),
|
||||
roleId: bigint('role_id', { mode: 'number' }).notNull(),
|
||||
permId: bigint('perm_id', { mode: 'number' }).notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_re_role_permission_id' }),
|
||||
unique('uniq_perm_role').on(table.roleId, table.permId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysRole = mysqlTable("sys_role", {
|
||||
roleId: bigint("role_id", { mode: "number" }).autoincrement().notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
roleName: varchar("role_name", { length: 255 }).notNull(),
|
||||
roleKey: varchar("role_key", { length: 255 }).notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.roleId], name: "sys_role_role_id"}),
|
||||
unique("uniq_role_pid").on(table.roleName, table.pid),
|
||||
]);
|
||||
export const sysReUserOrganization = mysqlTable(
|
||||
'sys_re_user_organization',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
orgId: bigint('org_id', { mode: 'number' }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_re_user_organization_id' }),
|
||||
unique('uniq_user_org').on(table.userId, table.orgId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUser = mysqlTable("sys_user", {
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
pid: bigint({ mode: "number" }).notNull(),
|
||||
username: varchar({ length: 255 }).notNull(),
|
||||
email: varchar({ length: 255 }).notNull(),
|
||||
phone: varchar({ length: 255 }),
|
||||
avatarUrl: varchar("avatar_url", { length: 255 }),
|
||||
userType: tinyint("user_type"),
|
||||
status: tinyint().default(0).notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.userId], name: "sys_user_user_id"}),
|
||||
unique("uniq_username").on(table.username),
|
||||
unique("uniq_email").on(table.email),
|
||||
]);
|
||||
export const sysReUserRole = mysqlTable(
|
||||
'sys_re_user_role',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
roleId: bigint('role_id', { mode: 'number' }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_re_user_role_id' }),
|
||||
unique('uniq_user_role').on(table.userId, table.roleId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUserAuth = mysqlTable("sys_user_auth", {
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
passwordHash: varchar("password_hash", { length: 255 }).notNull(),
|
||||
passwordModified: datetime("password_modified", { mode: 'string'}).notNull(),
|
||||
passwordExpire: datetime("password_expire", { mode: 'string'}),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.userId], name: "sys_user_auth_user_id"}),
|
||||
]);
|
||||
export const sysRole = mysqlTable(
|
||||
'sys_role',
|
||||
{
|
||||
roleId: bigint('role_id', { mode: 'number' }).notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
roleName: varchar('role_name', { length: 255 }).notNull(),
|
||||
roleKey: varchar('role_key', { length: 255 }).notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.roleId], name: 'sys_role_role_id' }),
|
||||
unique('uniq_role_pid').on(table.roleName, table.pid),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUserAuthHistory = mysqlTable("sys_user_auth_history", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
passwordHash: varchar("password_hash", { length: 255 }).notNull(),
|
||||
modifiedAt: varchar("modified_at", { length: 255 }).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_user_auth_history_id"}),
|
||||
]);
|
||||
export const sysUser = mysqlTable(
|
||||
'sys_user',
|
||||
{
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
pid: bigint({ mode: 'number' }).notNull(),
|
||||
username: varchar({ length: 255 }).notNull(),
|
||||
email: varchar({ length: 255 }).notNull(),
|
||||
phone: varchar({ length: 255 }),
|
||||
avatarUrl: varchar('avatar_url', { length: 255 }),
|
||||
userType: tinyint('user_type'),
|
||||
status: tinyint().default(0).notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.userId], name: 'sys_user_user_id' }),
|
||||
unique('uniq_username').on(table.username),
|
||||
unique('uniq_email').on(table.email),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUserFieldDefinition = mysqlTable("sys_user_field_definition", {
|
||||
fieldId: bigint("field_id", { mode: "number" }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
fieldName: varchar("field_name", { length: 255 }).notNull(),
|
||||
fieldKey: varchar("field_key", { length: 255 }).notNull(),
|
||||
fieldType: tinyint("field_type").notNull(),
|
||||
dictModule: int("dict_module"),
|
||||
isRequired: tinyint("is_required").default(0).notNull(),
|
||||
limit: int(),
|
||||
description: varchar({ length: 255 }),
|
||||
defaultValue: varchar("default_value", { length: 255 }),
|
||||
defaultOptions: varchar("default_options", { length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(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),
|
||||
]);
|
||||
export const sysUserAuth = mysqlTable(
|
||||
'sys_user_auth',
|
||||
{
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
passwordHash: varchar('password_hash', { length: 255 }).notNull(),
|
||||
passwordModified: datetime('password_modified', { mode: 'string' }).notNull(),
|
||||
passwordExpire: datetime('password_expire', { mode: 'string' }),
|
||||
},
|
||||
table => [primaryKey({ columns: [table.userId], name: 'sys_user_auth_user_id' })],
|
||||
);
|
||||
|
||||
export const sysUserFieldValue = mysqlTable("sys_user_field_value", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
fieldId: int("field_id").notNull(),
|
||||
value: varchar({ length: 4096 }),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_user_field_value_id"}),
|
||||
unique("uniq_user_field").on(table.userId, table.fieldId),
|
||||
]);
|
||||
export const sysUserAuthHistory = mysqlTable(
|
||||
'sys_user_auth_history',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
passwordHash: varchar('password_hash', { length: 255 }).notNull(),
|
||||
modifiedAt: varchar('modified_at', { length: 255 }).notNull(),
|
||||
},
|
||||
table => [primaryKey({ columns: [table.id], name: 'sys_user_auth_history_id' })],
|
||||
);
|
||||
|
||||
export const sysUserProfile = mysqlTable("sys_user_profile", {
|
||||
id: bigint({ mode: "number" }).autoincrement().notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
name: varchar({ length: 32 }).notNull(),
|
||||
profileKey: varchar("profile_key", { length: 255 }).notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
content: varchar({ length: 255 }),
|
||||
createdBy: bigint("created_by", { mode: "number" }).notNull(),
|
||||
updatedBy: bigint("updated_by", { mode: "number" }).notNull(),
|
||||
createdAt: datetime("created_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
updatedAt: datetime("updated_at", { mode: 'string'}).default(sql`(CURRENT_TIMESTAMP)`).notNull(),
|
||||
},
|
||||
(table) => [
|
||||
primaryKey({ columns: [table.id], name: "sys_user_profile_id"}),
|
||||
unique("uniq_name").on(table.name),
|
||||
unique("uniq_profile_key").on(table.profileKey),
|
||||
]);
|
||||
export const sysUserFieldDefinition = mysqlTable(
|
||||
'sys_user_field_definition',
|
||||
{
|
||||
fieldId: bigint('field_id', { mode: 'number' }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
fieldName: varchar('field_name', { length: 255 }).notNull(),
|
||||
fieldKey: varchar('field_key', { length: 255 }).notNull(),
|
||||
fieldType: tinyint('field_type').notNull(),
|
||||
dictModule: int('dict_module'),
|
||||
isRequired: tinyint('is_required').default(0).notNull(),
|
||||
limit: int(),
|
||||
description: varchar({ length: 255 }),
|
||||
defaultValue: varchar('default_value', { length: 255 }),
|
||||
defaultOptions: varchar('default_options', { length: 255 }),
|
||||
sort: int().default(0).notNull(),
|
||||
status: int().notNull(),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
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),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUserFieldValue = mysqlTable(
|
||||
'sys_user_field_value',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).notNull(),
|
||||
userId: bigint('user_id', { mode: 'number' }).notNull(),
|
||||
fieldId: int('field_id').notNull(),
|
||||
value: varchar({ length: 4096 }),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_user_field_value_id' }),
|
||||
unique('uniq_user_field').on(table.userId, table.fieldId),
|
||||
],
|
||||
);
|
||||
|
||||
export const sysUserProfile = mysqlTable(
|
||||
'sys_user_profile',
|
||||
{
|
||||
id: bigint({ mode: 'number' }).notNull(),
|
||||
version: int().default(0).notNull(),
|
||||
name: varchar({ length: 32 }).notNull(),
|
||||
profileKey: varchar('profile_key', { length: 255 }).notNull(),
|
||||
description: varchar({ length: 255 }),
|
||||
content: varchar({ length: 255 }),
|
||||
createdBy: bigint('created_by', { mode: 'number' }).notNull(),
|
||||
updatedBy: bigint('updated_by', { mode: 'number' }).notNull(),
|
||||
createdAt: datetime('created_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
updatedAt: datetime('updated_at', { mode: 'string' })
|
||||
.default(sql`(CURRENT_TIMESTAMP)`)
|
||||
.notNull(),
|
||||
},
|
||||
table => [
|
||||
primaryKey({ columns: [table.id], name: 'sys_user_profile_id' }),
|
||||
unique('uniq_name').on(table.name),
|
||||
unique('uniq_profile_key').on(table.profileKey),
|
||||
],
|
||||
);
|
||||
|
22
src/plugins/const/index.js
Normal file
22
src/plugins/const/index.js
Normal file
@ -0,0 +1,22 @@
|
||||
import fastifyPlugin from 'fastify-plugin';
|
||||
async function constData(fastify, options) {
|
||||
fastify.log.warn('Register CONSTDATA Plugin!');
|
||||
|
||||
const CONST = {
|
||||
// 系统名称
|
||||
SYSTEM_NAME: 'Fastify',
|
||||
|
||||
// 分布式锁前缀
|
||||
DISTRIBUTED_LOCK_PREFIX: {
|
||||
// 注册用户
|
||||
REGISTER_USER: 'REGISTER_USER:',
|
||||
}
|
||||
}
|
||||
|
||||
fastify.decorate('const', CONST);
|
||||
|
||||
// 读取数据库基本信息
|
||||
fastify.log.warn('Register CONSTDATA Complete!');
|
||||
|
||||
}
|
||||
export default fastifyPlugin(constData);
|
@ -23,6 +23,13 @@ async function database(fastify, options) {
|
||||
// 启用此选项后,MySQL驱动程序将在接收 bigint 或其他大数值时,将其作为字符串返回,而不是作为JavaScript数字。
|
||||
// 这种处理方式可以避免JavaScript本身的数值精度限制问题,确保大数值在应用程序中保持精确。
|
||||
bigNumberStrings: true,
|
||||
|
||||
// typeCast: function (field, next) {
|
||||
// if (field.type === 'LONGLONG') { // 处理 BIGINT 类型
|
||||
// return field.string(); // 强制转换为字符串
|
||||
// }
|
||||
// return next();
|
||||
// }
|
||||
});
|
||||
// 暴露数据库
|
||||
const db = drizzle(pool);
|
||||
@ -33,6 +40,8 @@ async function database(fastify, options) {
|
||||
fastify.decorate('db', db);
|
||||
|
||||
// 读取数据库基本信息
|
||||
fastify.log.warn('Register Database Complete! => DATABASE TABLES: ' + fastify.db.tableList.length);
|
||||
fastify.log.warn(
|
||||
'Register Database Complete! => DATABASE TABLES: ' + fastify.db.tableList.length,
|
||||
);
|
||||
}
|
||||
export default fastifyPlugin(database);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { hash } from 'bcrypt';
|
||||
import fastifyPlugin from "fastify-plugin";
|
||||
import fastifyPlugin from 'fastify-plugin';
|
||||
// 加密
|
||||
async function encryption(fastify, options) {
|
||||
// 注册swagger插件(新版配置方式)
|
||||
fastify.log.warn('Register Encryption Plugin!');
|
||||
// 初始化时注册插件
|
||||
fastify.decorate('hash', (str, salt = 10) => hash(str,salt));
|
||||
fastify.decorate('hash', (str, salt = 10) => hash(str, salt));
|
||||
fastify.log.warn('Register Encryption complete!');
|
||||
}
|
||||
|
||||
export default fastifyPlugin(encryption);
|
||||
export default fastifyPlugin(encryption);
|
||||
|
@ -1,52 +1,65 @@
|
||||
import fastifyPlugin from 'fastify-plugin';
|
||||
function errorHandler(fastify) {
|
||||
// 添加 404 处理器 (关键修改)
|
||||
fastify.setNotFoundHandler((request, reply) => {
|
||||
const error = new Error(`路由 ${request.url} 不存在`);
|
||||
error.code = 'ROUTE_NOT_FOUND';
|
||||
error.statusCode = 404;
|
||||
return reply.code(404).send(error);
|
||||
});
|
||||
|
||||
fastify.setErrorHandler((error, request, reply) => {
|
||||
// 记录原始错误
|
||||
fastify.log.error(`[ErrorHandler] ${error.message}`, error);
|
||||
// fastify.log.error(`[ErrorHandler] ${error.message}`, error);
|
||||
|
||||
console.log('AAAA1validation', error.validation);
|
||||
console.log('AAAA2statusCode', error.statusCode);
|
||||
console.log('AAAA3code', error.code);
|
||||
console.log('AAAA4message', error.message);
|
||||
|
||||
// 保留AJV验证错误处理
|
||||
if (error.validation) {
|
||||
console.log(error)
|
||||
const bodyError = error.validation.find(e =>
|
||||
e.keyword === 'type' ||
|
||||
e.keyword === 'required' && e.validationContext == 'body'
|
||||
// 没有请求体
|
||||
const bodyError = error.validation.find(
|
||||
e =>
|
||||
e.keyword === 'type' ||
|
||||
(e.keyword === 'required' && e.validationContext == 'body'),
|
||||
);
|
||||
|
||||
|
||||
if (bodyError) {
|
||||
return reply.code(400).send({
|
||||
error: '请求体不能为空,请提供有效的JSON数据',
|
||||
details: error.validation
|
||||
code: error.statusCode,
|
||||
codeString: error.code,
|
||||
error: `请求体不能为空,请提供有效的JSON数据!`,
|
||||
details: error.validation,
|
||||
});
|
||||
}else{
|
||||
return reply.code(400).send({
|
||||
code: error.statusCode,
|
||||
codeString: error.code,
|
||||
error: error.message,
|
||||
details: error.validation,
|
||||
});
|
||||
}
|
||||
return reply.code(400).send({
|
||||
error: error.message,
|
||||
details: error.validation
|
||||
});
|
||||
}
|
||||
|
||||
// 使用sensible的HTTP错误处理
|
||||
if (error.statusCode && error.statusCode >= 400) {
|
||||
return reply
|
||||
.code(error.statusCode)
|
||||
.send({
|
||||
code: error.code || 'HTTP_ERROR',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
|
||||
// 处理Fastify自动生成的404错误
|
||||
if (error.code === 'FST_ERR_NOT_FOUND') {
|
||||
return reply.code(404).send({
|
||||
code: 'ROUTE_NOT_FOUND',
|
||||
error: `路由 ${request.url} 不存在`
|
||||
return reply.code(error.statusCode).send({
|
||||
code: error.statusCode,
|
||||
codeString: error.code,
|
||||
error: error.message,
|
||||
...(error.details && { details: error.details }),
|
||||
});
|
||||
}
|
||||
|
||||
// 最终未处理错误(生产环境隐藏细节)
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
reply.code(500).send({
|
||||
code: 'SERVER_ERROR',
|
||||
code: '500',
|
||||
error: isProduction ? '服务器内部错误' : error.message,
|
||||
...(!isProduction && { stack: error.stack })
|
||||
...(!isProduction && { stack: error.stack }),
|
||||
});
|
||||
});
|
||||
}
|
||||
export default fastifyPlugin(errorHandler);
|
||||
export default fastifyPlugin(errorHandler);
|
||||
|
@ -3,6 +3,9 @@ import database from '#plugins/database/index';
|
||||
import swagger from '#plugins/swagger/index';
|
||||
import errorHandler from '#plugins/error/errorHandler';
|
||||
import encryption from '#plugins/encryption/index';
|
||||
import snowflake from '#plugins/snowflake/index';
|
||||
import redis from '#plugins/redis/index';
|
||||
import conseData from '#plugins/const/index';
|
||||
|
||||
async function plugin(fastify, opts) {
|
||||
fastify.log.warn('Register Global Plugin!');
|
||||
@ -10,16 +13,19 @@ async function plugin(fastify, opts) {
|
||||
fastify.decorate('config', opts.config);
|
||||
// 注册数据库
|
||||
await fastify.register(database);
|
||||
// 注册redis
|
||||
await fastify.register(redis);
|
||||
// 注册swagger
|
||||
fastify.config.env === 'development' && await fastify.register(swagger);
|
||||
fastify.config.env === 'development' && (await fastify.register(swagger));
|
||||
// 注册加密工具
|
||||
await fastify.register(encryption);
|
||||
|
||||
|
||||
|
||||
// 注册雪花ID
|
||||
await fastify.register(snowflake);
|
||||
// 注册常量
|
||||
await fastify.register(conseData);
|
||||
// 注册错误处理工具
|
||||
await fastify.register(import('@fastify/sensible'));
|
||||
fastify.register(errorHandler)
|
||||
fastify.register(errorHandler);
|
||||
|
||||
fastify.log.warn('Register Global Plugin complete!');
|
||||
}
|
||||
|
31
src/plugins/redis/index.js
Normal file
31
src/plugins/redis/index.js
Normal file
@ -0,0 +1,31 @@
|
||||
import fastifyPlugin from 'fastify-plugin';
|
||||
import { createClient } from 'redis';
|
||||
async function redis(fastify, options) {
|
||||
fastify.log.warn('Register Redis Plugin!');
|
||||
const config = fastify.config.redis;
|
||||
const redisConnect = createClient({
|
||||
name: config.connectName,
|
||||
username: config.username,
|
||||
password: config.password,
|
||||
database: config.database,
|
||||
url: `redis://${config.username}:${config.password}@${config.host}:${config.port}/${config.database}`,
|
||||
});
|
||||
redisConnect.on('connect', async () => {
|
||||
fastify.log.info(await redisConnect.set('SI HI', 'YuHeng'));
|
||||
});
|
||||
|
||||
redisConnect.on('error', (err) => {
|
||||
console.log(err)
|
||||
fastify.log.error('Redis error: ', err);
|
||||
});
|
||||
|
||||
// 连接到 Redis
|
||||
await redisConnect.connect();
|
||||
|
||||
fastify.decorate('redis', redisConnect);
|
||||
|
||||
// 读取数据库基本信息
|
||||
fastify.log.warn('Register Redis Complete! => REDIS SI HI: ' + await redisConnect.get('SI HI'));
|
||||
|
||||
}
|
||||
export default fastifyPlugin(redis);
|
73
src/plugins/snowflake/index.js
Normal file
73
src/plugins/snowflake/index.js
Normal file
@ -0,0 +1,73 @@
|
||||
import fastifyPlugin from 'fastify-plugin';
|
||||
// 雪花ID
|
||||
class Snowflake {
|
||||
constructor({ workerId = 0n, dataCenterId = 0n, sequence = 0n } = {}) {
|
||||
this.workerIdBits = 3n; // 工作节点ID位数
|
||||
this.dataCenterIdBits = 6n; // 数据中心ID位数
|
||||
this.sequenceBits = 12n; // 序列号位数
|
||||
|
||||
this.maxWorkerId = -1n ^ (-1n << this.workerIdBits);
|
||||
this.maxDataCenterId = -1n ^ (-1n << this.dataCenterIdBits);
|
||||
|
||||
this.workerIdShift = this.sequenceBits;
|
||||
this.dataCenterIdShift = this.sequenceBits + this.workerIdBits;
|
||||
this.timestampShift = this.sequenceBits + this.workerIdBits + this.dataCenterIdBits;
|
||||
this.sequenceMask = -1n ^ (-1n << this.sequenceBits);
|
||||
|
||||
this.epoch = 1577836800000n; // 2020-01-01 00:00:00 UTC
|
||||
|
||||
this.lastTimestamp = -1n;
|
||||
this.sequence = sequence;
|
||||
this.workerId = BigInt(workerId);
|
||||
this.dataCenterId = BigInt(dataCenterId);
|
||||
|
||||
if (this.workerId > this.maxWorkerId || this.workerId < 0n) {
|
||||
throw new Error(`Worker ID must be between 0 and ${this.maxWorkerId}`);
|
||||
}
|
||||
if (this.dataCenterId > this.maxDataCenterId || this.dataCenterId < 0n) {
|
||||
throw new Error(`Data Center ID must be between 0 and ${this.maxDataCenterId}`);
|
||||
}
|
||||
}
|
||||
|
||||
nextId() {
|
||||
let timestamp = BigInt(Date.now());
|
||||
|
||||
if (timestamp < this.lastTimestamp) {
|
||||
throw new Error('Clock moved backwards!');
|
||||
}
|
||||
|
||||
if (this.lastTimestamp === timestamp) {
|
||||
this.sequence = (this.sequence + 1n) & this.sequenceMask;
|
||||
if (this.sequence === 0n) {
|
||||
while (timestamp <= this.lastTimestamp) {
|
||||
timestamp = BigInt(Date.now());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.sequence = 0n;
|
||||
}
|
||||
|
||||
this.lastTimestamp = timestamp;
|
||||
|
||||
return (
|
||||
((timestamp - this.epoch) << this.timestampShift) |
|
||||
(this.dataCenterId << this.dataCenterIdShift) |
|
||||
(this.workerId << this.workerIdShift) |
|
||||
this.sequence
|
||||
);
|
||||
}
|
||||
}
|
||||
async function snowflake(fastify, options) {
|
||||
// 注册swagger插件(新版配置方式)
|
||||
fastify.log.warn('Register Snowflake Plugin!');
|
||||
// 初始化生成器(工作节点ID范围 0-31)
|
||||
const generator = new Snowflake({
|
||||
workerId: BigInt(fastify.config.deviceInfo.machineId), // 工作节点ID
|
||||
dataCenterId: BigInt(fastify.config.deviceInfo.dataCenterId), // 数据中心ID
|
||||
});
|
||||
// 初始化时注册插件
|
||||
fastify.decorate('snowflake', () => generator.nextId().toString());
|
||||
fastify.log.warn('Register Snowflake complete!');
|
||||
}
|
||||
|
||||
export default fastifyPlugin(snowflake);
|
@ -1,6 +1,6 @@
|
||||
import fastifyPlugin from "fastify-plugin";
|
||||
import fastifySwagger from "@fastify/swagger";
|
||||
import fastifySwaggerUI from "@fastify/swagger-ui";
|
||||
import fastifyPlugin from 'fastify-plugin';
|
||||
import fastifySwagger from '@fastify/swagger';
|
||||
import fastifySwaggerUI from '@fastify/swagger-ui';
|
||||
async function swagger(fastify, options) {
|
||||
// 注册swagger插件(新版配置方式)
|
||||
fastify.log.warn('Register Swagger Plugin!');
|
||||
@ -9,18 +9,20 @@ async function swagger(fastify, options) {
|
||||
info: {
|
||||
title: `${fastify.config.serviceName} API`,
|
||||
version: fastify.config.version,
|
||||
description: fastify.config.description
|
||||
description: fastify.config.description,
|
||||
},
|
||||
},
|
||||
// staticCSP: true, // 启用安全策略
|
||||
exposeRoute: true // 自动暴露路由
|
||||
exposeRoute: true, // 自动暴露路由
|
||||
});
|
||||
// 注册swagger-ui界面 (新增部分)
|
||||
await fastify.register(fastifySwaggerUI, {
|
||||
routePrefix: '/docs',
|
||||
});
|
||||
fastify.log.warn('Register Swagger complete!');
|
||||
fastify.log.info(`Swagger documentation available at http://127.0.0.1:${fastify.config.server.port}/docs`);
|
||||
fastify.log.info(
|
||||
`Swagger documentation available at http://127.0.0.1:${fastify.config.server.port}/docs`,
|
||||
);
|
||||
}
|
||||
|
||||
export default fastifyPlugin(swagger);
|
||||
export default fastifyPlugin(swagger);
|
||||
|
@ -1,29 +1,18 @@
|
||||
import { testSchema } from "#src/schema/test.schema";
|
||||
import { testService } from "#src/services/test.service";
|
||||
import userRoute from "#routes/user.route";
|
||||
import { testSchema } from '#src/schema/test.schema';
|
||||
import { testService } from '#src/services/test.service';
|
||||
import userRoute from '#routes/user.route';
|
||||
|
||||
export default async function routes(fastify, options) {
|
||||
// 定义一个GET请求的路由,路径为根路径
|
||||
fastify.get('/', async (request, reply) => {
|
||||
fastify.log.info(fastify.config);
|
||||
return fastify.config;
|
||||
return fastify.config.deviceInfo;
|
||||
});
|
||||
fastify.get('/test', testSchema , testService);
|
||||
|
||||
fastify.get('/test', testSchema, testService);
|
||||
|
||||
// 注册子路由
|
||||
fastify.register(userRoute, { prefix: '/user' });
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
fastify.route({
|
||||
method: 'POST',
|
||||
url: '/login',
|
||||
@ -31,15 +20,14 @@ export default async function routes(fastify, options) {
|
||||
tags: ['认证体系'], // 接口分组
|
||||
summary: '用户登录',
|
||||
description: '使用用户名密码进行身份认证',
|
||||
security: [{
|
||||
}],
|
||||
security: [{}],
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['username', 'password'],
|
||||
properties: {
|
||||
username: { type: 'string', default: 'user1' },
|
||||
password: { type: 'string', default: '123456' }
|
||||
}
|
||||
password: { type: 'string', default: '123456' },
|
||||
},
|
||||
},
|
||||
response: {
|
||||
200: {
|
||||
@ -47,22 +35,22 @@ export default async function routes(fastify, options) {
|
||||
type: 'object',
|
||||
properties: {
|
||||
token: { type: 'string' },
|
||||
expire: { type: 'number' }
|
||||
}
|
||||
expire: { type: 'number' },
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: '认证失败',
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [401] },
|
||||
error: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
handler: async (req, reply) => {
|
||||
// ...业务逻辑...
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// 输出路由树
|
||||
|
@ -1,27 +1,17 @@
|
||||
import { userDefaultSchema, userRegisterSchema } from "#src/schema/user.schema";
|
||||
import { userDefaultService, } from "#src/services/user.service";
|
||||
import {userRegisterService} from "#src/services/user/user.service"
|
||||
import { userDefaultSchema, userRegisterSchema } from '#src/schema/user.schema';
|
||||
import { userDefaultService } from '#src/services/user.service';
|
||||
import { userRegisterService } from '#src/services/user/user.service';
|
||||
|
||||
export default async function userRoute(fastify, options) {
|
||||
|
||||
// 新用户注册
|
||||
fastify.post('/register', {
|
||||
schema: userRegisterSchema,
|
||||
}, userRegisterService);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
fastify.post('/register', { schema: userRegisterSchema }, userRegisterService);
|
||||
|
||||
fastify.get('/', userDefaultSchema, userDefaultService);
|
||||
/**
|
||||
*
|
||||
* 个人接口
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* 个人接口
|
||||
*
|
||||
*/
|
||||
// 注册
|
||||
// 登录
|
||||
fastify.post('/login', userDefaultSchema, userDefaultService);
|
||||
@ -33,11 +23,11 @@ export default async function userRoute(fastify, options) {
|
||||
fastify.get('/getUserInfo', userDefaultSchema, userDefaultService);
|
||||
// 修改当前用户信息
|
||||
fastify.post('/updateUserInfo', userDefaultSchema, userDefaultService);
|
||||
/**
|
||||
*
|
||||
* 管理接口
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* 管理接口
|
||||
*
|
||||
*/
|
||||
|
||||
// 获取用户列表
|
||||
|
||||
@ -48,20 +38,18 @@ export default async function userRoute(fastify, options) {
|
||||
// 更新用户信息
|
||||
|
||||
// 批量删除用户
|
||||
|
||||
|
||||
// 批量重置用户密码
|
||||
|
||||
// 批量启用用户
|
||||
|
||||
// 批量禁用用户
|
||||
|
||||
/**
|
||||
*
|
||||
* 拓展字段
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* 拓展字段
|
||||
*
|
||||
*/
|
||||
|
||||
// 获取拓展字段列表
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { isTrim } from "#utils/ajv/method";
|
||||
import { is } from "drizzle-orm";
|
||||
import { isTrim } from '#utils/ajv/method';
|
||||
import { is } from 'drizzle-orm';
|
||||
|
||||
// 原子schema定义
|
||||
export const username = {
|
||||
@ -12,8 +12,8 @@ export const username = {
|
||||
errorMessage: {
|
||||
minLength: '用户名至少需要4个字符',
|
||||
maxLength: '用户名不能超过20个字符',
|
||||
pattern: '必须全部小写,且只能包含字母、数字和下划线,并以字母开头'
|
||||
}
|
||||
pattern: '必须全部小写,且只能包含字母、数字和下划线,并以字母开头',
|
||||
},
|
||||
};
|
||||
|
||||
export const email = {
|
||||
@ -22,8 +22,8 @@ export const email = {
|
||||
maxLength: 128,
|
||||
errorMessage: {
|
||||
format: '邮箱格式不正确',
|
||||
maxLength: '邮箱不能超过128个字符'
|
||||
}
|
||||
maxLength: '邮箱不能超过128个字符',
|
||||
},
|
||||
};
|
||||
|
||||
export const password = {
|
||||
@ -34,6 +34,6 @@ export const password = {
|
||||
errorMessage: {
|
||||
minLength: '密码长度至少8位',
|
||||
maxLength: '密码不能超过128个字符',
|
||||
pattern: '必须包含至少一个小写字母、一个大写字母、一个数字和一个特殊字符'
|
||||
}
|
||||
};
|
||||
pattern: '必须包含至少一个小写字母、一个大写字母、一个数字和一个特殊字符',
|
||||
},
|
||||
};
|
||||
|
@ -6,26 +6,26 @@ export const testSchema = {
|
||||
type: 'object',
|
||||
required: ['username', 'password'],
|
||||
properties: {
|
||||
username: { type:'string', default: 'user1' },
|
||||
password: { type:'string', default: '123456' }
|
||||
}
|
||||
username: { type: 'string', default: 'user1' },
|
||||
password: { type: 'string', default: '123456' },
|
||||
},
|
||||
},
|
||||
response: {
|
||||
200: {
|
||||
description: '登录成功',
|
||||
type: 'object',
|
||||
properties: {
|
||||
token: { type:'string' },
|
||||
expire: { type: 'number' }
|
||||
}
|
||||
token: { type: 'string' },
|
||||
expire: { type: 'number' },
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: '认证失败',
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [401] },
|
||||
error: { type:'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { email, username, password } from "#schema/atomSchema";
|
||||
import { email, username, password } from '#schema/atomSchema';
|
||||
// 默认schema
|
||||
export const userDefaultSchema = {
|
||||
|
||||
}
|
||||
export const userDefaultSchema = {};
|
||||
|
||||
// 新用户注册
|
||||
export const userRegisterSchema = {
|
||||
@ -22,18 +20,67 @@ export const userRegisterSchema = {
|
||||
properties: {
|
||||
username,
|
||||
email,
|
||||
password
|
||||
}
|
||||
password,
|
||||
},
|
||||
},
|
||||
response: {
|
||||
201: {
|
||||
description: '注册成功',
|
||||
type: 'object',
|
||||
properties: {
|
||||
userId: { type: 'number', example: 1001 },
|
||||
username: { type: 'string' },
|
||||
email: { type: 'string' },
|
||||
createdAt: { type: 'string', format: 'date-time' }
|
||||
code: { type: 'number' },
|
||||
data: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
username: { type: 'string' },
|
||||
email: { type: 'string' },
|
||||
userId: {
|
||||
type: 'string',
|
||||
examples: ["692397256422330400"]
|
||||
},
|
||||
pid: {
|
||||
type: 'string',
|
||||
enum: [0] // 固定值
|
||||
},
|
||||
phone: {
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
avatarUrl: {
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
userType: {
|
||||
type: ['number', 'null'],
|
||||
default: null
|
||||
},
|
||||
status: {
|
||||
type: 'number',
|
||||
enum: [0, 1] // 假设 0-正常 1-禁用
|
||||
},
|
||||
createdBy: {
|
||||
type: 'number',
|
||||
enum: [0] // 个人注册固定值
|
||||
},
|
||||
updatedBy: {
|
||||
type: ['number', 'null'],
|
||||
default: null
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'username', 'email', 'userId', 'pid',
|
||||
'status', 'createdBy', 'createdAt', 'updatedAt'
|
||||
],
|
||||
additionalProperties: false // 严格模式
|
||||
},
|
||||
message: { type: 'string' }
|
||||
}
|
||||
},
|
||||
400: {
|
||||
@ -41,17 +88,17 @@ export const userRegisterSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [400] },
|
||||
error: { type: 'string' }
|
||||
}
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
409: {
|
||||
description: '用户名/邮箱已存在',
|
||||
type: 'object',
|
||||
properties: {
|
||||
code: { type: 'number', enum: [409] },
|
||||
error: { type: 'string' }
|
||||
}
|
||||
}
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
security: [{}] // 不需要认证
|
||||
};
|
||||
security: [{}], // 不需要认证
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
export async function testService(request, reply) {
|
||||
this.log.warn('testService');
|
||||
return {
|
||||
test: 'test'
|
||||
}
|
||||
}
|
||||
test: 'test',
|
||||
};
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ export async function userDefaultService() {
|
||||
export async function userRegisterService(request, reply) {
|
||||
// 1. 获取已验证的参数
|
||||
const { username, email, password } = req.body;
|
||||
|
||||
|
||||
// 2. 业务逻辑校验
|
||||
const exists = await fastify.db.users.checkExists({ username, email });
|
||||
if (exists) {
|
||||
@ -25,6 +25,6 @@ export async function userRegisterService(request, reply) {
|
||||
userId: newUser.id,
|
||||
username: newUser.username,
|
||||
email: newUser.email,
|
||||
createdAt: newUser.created_at.toISOString()
|
||||
createdAt: newUser.created_at.toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,32 @@
|
||||
import { sysUser } from "#entity";
|
||||
import { or, eq } from "drizzle-orm";
|
||||
import { sysUser } from '#entity';
|
||||
import { or, eq } from 'drizzle-orm';
|
||||
// 查重用户名和邮箱
|
||||
export async function checkExistsUsernameAndEmail(username, email) {
|
||||
const result = await this.db
|
||||
.select()
|
||||
.from(sysUser)
|
||||
.where(or(
|
||||
eq(sysUser.username, username), // 明确指定字段比较
|
||||
eq(sysUser.email, email)
|
||||
));
|
||||
|
||||
return result.length > 0; // 正确判断结果集是否为空
|
||||
.where(
|
||||
or(
|
||||
eq(sysUser.username, username), // 明确指定字段比较
|
||||
eq(sysUser.email, email),
|
||||
),
|
||||
);
|
||||
|
||||
return result.length > 0; // 正确判断结果集是否为空
|
||||
}
|
||||
// 个人注册账户
|
||||
export async function registerAccountForMyself(userData) {
|
||||
const [newUser] = await this.db.insert(sysUser)
|
||||
.values({
|
||||
username: userData.username,
|
||||
email: userData.email,
|
||||
password: userData.password, // 实际应存储加密后的密码
|
||||
})
|
||||
const result = await this.db.insert(sysUser).values({
|
||||
username: userData.username,
|
||||
email: userData.email,
|
||||
password: userData.password, // 实际应存储加密后的密码
|
||||
userId: userData.userId, // 使用雪花算法生成唯一ID
|
||||
pid: 0, // 个人注册账户父节点ID为0
|
||||
createdBy: 0, // 个人注册账户创建者ID为0
|
||||
})
|
||||
const [newUser] = await this.db
|
||||
.select()
|
||||
.from(sysUser)
|
||||
.where(eq(sysUser.userId, userData.userId));
|
||||
return newUser;
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,59 @@
|
||||
import { checkExistsUsernameAndEmail, registerAccountForMyself } from "#services/user/user.db";
|
||||
import { checkExistsUsernameAndEmail, registerAccountForMyself } from '#services/user/user.db';
|
||||
// 新用户注册
|
||||
export async function userRegisterService(request, reply) {
|
||||
// 1. 获取已验证的参数
|
||||
const { username, email, password } = request.body;
|
||||
|
||||
// 2. 检测用户名和邮箱是否已存在
|
||||
const exists = await checkExistsUsernameAndEmail.call(this,username, email);
|
||||
if (exists) {
|
||||
throw reply.code(409).send({
|
||||
code: 'USER_EXISTS',
|
||||
message: '用户名或邮箱已存在'
|
||||
});
|
||||
// 2. 分布式锁
|
||||
// 生成分布式锁 key
|
||||
const lockKey = `${this.const.DISTRIBUTED_LOCK_PREFIX.REGISTER_USER}${username}:${email}`;
|
||||
|
||||
const userId = this.snowflake();
|
||||
const lockIdentifier = userId;
|
||||
let renewInterval;
|
||||
|
||||
try {
|
||||
// 尝试获取分布式锁(NX: 仅当key不存在时设置,EX: 过期时间5秒)
|
||||
const locked = await this.redis.SET(lockKey, lockIdentifier, { NX: true, EX: 5 });
|
||||
if (!locked) {
|
||||
throw this.httpErrors.tooManyRequests('操作正在进行,请稍后重试');
|
||||
}
|
||||
|
||||
// 启动续锁定时器(每3秒续期一次)
|
||||
renewInterval = setInterval(async () => {
|
||||
const currentVal = await this.redis.GET(lockKey);
|
||||
if (currentVal === lockIdentifier) {
|
||||
await this.redis.EXPIRE(lockKey, 5); // 重置过期时间
|
||||
}
|
||||
}, 3000);
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
// 2. 检测用户名和邮箱是否已存在
|
||||
const exists = await checkExistsUsernameAndEmail.call(this, username, email);
|
||||
if (exists) {
|
||||
throw this.httpErrors.conflict('用户名或邮箱已存在');
|
||||
}
|
||||
|
||||
// 3. 注册用户
|
||||
const newUser = await registerAccountForMyself.call(this, {
|
||||
username,
|
||||
email,
|
||||
password: await this.hash(password),
|
||||
userId
|
||||
});
|
||||
reply.code(201) // <-- 关键修改
|
||||
.send({
|
||||
code: 201,
|
||||
data: newUser,
|
||||
message: '用户创建成功'
|
||||
});
|
||||
} finally {
|
||||
if (renewInterval) clearInterval(renewInterval);
|
||||
// 释放锁逻辑(移除Lua脚本)
|
||||
const currentVal = await this.redis.GET(lockKey);
|
||||
if (currentVal === lockIdentifier) {
|
||||
await this.redis.DEL(lockKey);
|
||||
}
|
||||
}
|
||||
// 3. 注册用户
|
||||
await registerAccountForMyself.call(this,{
|
||||
username,
|
||||
email,
|
||||
password: await this.hash(password)
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
import ajvErrors from "ajv-errors";
|
||||
import { isLowerCase, isTrim } from "#utils/ajv/method";
|
||||
import ajvErrors from 'ajv-errors';
|
||||
import { isLowerCase, isTrim } from '#utils/ajv/method';
|
||||
export const ajvConfig = {
|
||||
customOptions: {
|
||||
removeAdditional: true, // 自动删除schema未定义的额外属性
|
||||
useDefaults: true, // 使用schema中定义的默认值填充缺失字段
|
||||
coerceTypes: true, // 自动转换数据类型(如字符串"123"→数字123)
|
||||
allErrors: true, // 收集所有验证错误(不止第一个错误)
|
||||
allowUnionTypes: true // 允许联合类型(如 type: ["string", "number"])
|
||||
removeAdditional: true, // 自动删除schema未定义的额外属性
|
||||
useDefaults: true, // 使用schema中定义的默认值填充缺失字段
|
||||
coerceTypes: true, // 自动转换数据类型(如字符串"123"→数字123)
|
||||
allErrors: true, // 收集所有验证错误(不止第一个错误)
|
||||
allowUnionTypes: true, // 允许联合类型(如 type: ["string", "number"])
|
||||
},
|
||||
plugins: [
|
||||
ajvErrors, // 支持自定义错误消息
|
||||
isLowerCase, // 自定义验证:强制小写(如用户名)
|
||||
isTrim, // 自定义验证:自动trim字符串
|
||||
]
|
||||
}
|
||||
ajvErrors, // 支持自定义错误消息
|
||||
isLowerCase, // 自定义验证:强制小写(如用户名)
|
||||
isTrim, // 自定义验证:自动trim字符串
|
||||
],
|
||||
};
|
||||
|
@ -14,8 +14,6 @@ import Ajv from 'ajv';
|
||||
// ajv错误消息回应
|
||||
import ajvErrors from 'ajv-errors';
|
||||
|
||||
|
||||
|
||||
// // 将字符串转化为全小写
|
||||
// export function isLowerCase(ajv){
|
||||
// ajv.addKeyword({
|
||||
@ -63,21 +61,19 @@ import ajvErrors from 'ajv-errors';
|
||||
export function isLowerCase(ajv) {
|
||||
ajv.addKeyword({
|
||||
keyword: 'isLowerCase',
|
||||
validate: (schema, data) => typeof data === 'string' && data === data.toLowerCase()
|
||||
validate: (schema, data) => typeof data === 'string' && data === data.toLowerCase(),
|
||||
});
|
||||
}
|
||||
|
||||
export function isTrim(ajv) {
|
||||
ajv.addKeyword({
|
||||
keyword: 'isTrim',
|
||||
validate: (schema, data) => typeof data === 'string' && data === data.trim()
|
||||
validate: (schema, data) => typeof data === 'string' && data === data.trim(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 给fastify添加自定义的参数校验规则
|
||||
function customAjv(fastify, options){
|
||||
function customAjv(fastify, options) {
|
||||
// 创建一个新的 AJV 实例
|
||||
// 创建一个新的 AJV 实例
|
||||
const ajv = new Ajv({
|
||||
@ -85,7 +81,7 @@ function customAjv(fastify, options){
|
||||
useDefaults: true,
|
||||
coerceTypes: true,
|
||||
// jsonPointers: true,
|
||||
allErrors: true
|
||||
allErrors: true,
|
||||
});
|
||||
ajvErrors(ajv);
|
||||
isLowerCase(ajv);
|
||||
@ -94,4 +90,3 @@ function customAjv(fastify, options){
|
||||
return ajv.compile(schema);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,43 +1,45 @@
|
||||
import config from '#config/index';
|
||||
export default {
|
||||
// 日志级别顺序(从高到低):
|
||||
// fatal(致命) > error(错误) > warn(警告) > info(信息) > debug(调试) > trace(追踪)
|
||||
// 高级别日志会包含低级别日志(设置warn会包含error和fatal)
|
||||
level: config.logger.level,
|
||||
transport: {
|
||||
// 修正为独立的多传输配置
|
||||
targets: [
|
||||
config.logger.console && {
|
||||
level: config.logger.level,
|
||||
target: 'pino-pretty',
|
||||
options: {
|
||||
colorize: true,
|
||||
translateTime: 'yyyy-mm-dd HH:MM:ss',
|
||||
ignore: 'pid,hostname,reqId,res,responseTime',
|
||||
// 可用字段列表:
|
||||
// - pid: 进程ID
|
||||
// - hostname: 主机名
|
||||
// - level: 日志级别(不建议忽略)
|
||||
// - time: 时间戳(需配合translateTime使用)
|
||||
// - msg/message: 日志消息(必须保留)
|
||||
// - module: 模块名称(自定义字段)
|
||||
// - name: 日志名称
|
||||
// - v: pino版本号
|
||||
// - reqId: 请求ID
|
||||
// - res: 响应对象
|
||||
// - req: 请求对象
|
||||
// - responseTime: 响应时间
|
||||
// - 支持通配符如 'req*'(忽略所有 req 开头字段)
|
||||
export default function loggerConfig(config) {
|
||||
return {
|
||||
// 日志级别顺序(从高到低):
|
||||
// fatal(致命) > error(错误) > warn(警告) > info(信息) > debug(调试) > trace(追踪)
|
||||
// 高级别日志会包含低级别日志(设置warn会包含error和fatal)
|
||||
level: config.logger.level,
|
||||
base: { machineId: config.deviceInfo.machineId },
|
||||
transport: {
|
||||
// 修正为独立的多传输配置
|
||||
targets: [
|
||||
config.logger.console && {
|
||||
level: config.logger.level,
|
||||
target: 'pino-pretty',
|
||||
options: {
|
||||
colorize: true,
|
||||
translateTime: 'yyyy-mm-dd HH:MM:ss',
|
||||
ignore: 'hostname,reqId,',
|
||||
// 可用字段列表:
|
||||
// - pid: 进程ID
|
||||
// - hostname: 主机名
|
||||
// - level: 日志级别(不建议忽略)
|
||||
// - time: 时间戳(需配合translateTime使用)
|
||||
// - msg/message: 日志消息(必须保留)
|
||||
// - module: 模块名称(自定义字段)
|
||||
// - name: 日志名称
|
||||
// - v: pino版本号
|
||||
// - reqId: 请求ID
|
||||
// - res: 响应对象
|
||||
// - req: 请求对象
|
||||
// - responseTime: 响应时间
|
||||
// - 支持通配符如 'req*'(忽略所有 req 开头字段)
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
target: 'pino/file',
|
||||
options: {
|
||||
destination: config.logger.filePath, // 文件路径从配置读取
|
||||
mkdir: true,
|
||||
ignore: 'pid,hostname',
|
||||
{
|
||||
target: 'pino/file',
|
||||
options: {
|
||||
destination: config.logger.filePath, // 文件路径从配置读取
|
||||
mkdir: true,
|
||||
ignore: 'pid,hostname',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -2,11 +2,14 @@ const text = '> Si Hi <'; // 需要显示的文本
|
||||
const terminalWidth = process.stdout.columns || 100;
|
||||
const padding = Math.max(0, Math.floor((terminalWidth - text.length * 1.5) / 2)); // 中文每个字占2字符宽度
|
||||
/* eslint-disable no-console */
|
||||
console.log(
|
||||
'\x1B[48;5;0m%s\x1B[0m', // 灰色背景
|
||||
'\x1B[32;5;12m\x1B[1m ' + // 白色加粗
|
||||
'-'.repeat(padding) +
|
||||
text +
|
||||
'-'.repeat(padding) +
|
||||
' \x1B[0m', // 重置样式
|
||||
);
|
||||
|
||||
export default function echo() {
|
||||
console.log(
|
||||
'\x1B[48;5;0m%s\x1B[0m', // 灰色背景
|
||||
'\x1B[32;5;12m\x1B[1m ' + // 白色加粗
|
||||
'-'.repeat(padding) +
|
||||
text +
|
||||
'-'.repeat(padding) +
|
||||
' \x1B[0m', // 重置样式
|
||||
);
|
||||
}
|
||||
|
26
yuheng.sql
26
yuheng.sql
@ -9,7 +9,7 @@ CREATE TABLE `sys_dict` (
|
||||
`sort` int NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
`status` int NOT NULL COMMENT '状态 0启用 1禁用',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
@ -26,7 +26,7 @@ CREATE TABLE `sys_organization` (
|
||||
`sort` int NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
`status` int NOT NULL COMMENT '状态',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`org_id`),
|
||||
@ -43,7 +43,7 @@ CREATE TABLE `sys_organization_manager` (
|
||||
`status` int NOT NULL COMMENT '状态',
|
||||
`description` varchar(255) NULL,
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
@ -64,7 +64,7 @@ CREATE TABLE `sys_permission` (
|
||||
`sort` int NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
`status` int NOT NULL COMMENT '状态',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`perm_id`),
|
||||
@ -77,7 +77,7 @@ CREATE TABLE `sys_re_role_permission` (
|
||||
`role_id` BIGINT NOT NULL COMMENT '角色ID',
|
||||
`perm_id` BIGINT NOT NULL COMMENT '权限ID',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
@ -90,7 +90,7 @@ CREATE TABLE `sys_re_user_organization` (
|
||||
`org_id` BIGINT NOT NULL COMMENT '组织ID',
|
||||
`version` INT NOT NULL DEFAULT 0,
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
@ -103,7 +103,7 @@ CREATE TABLE `sys_re_user_role` (
|
||||
`role_id` BIGINT NOT NULL COMMENT '角色ID',
|
||||
`version` INT NOT NULL DEFAULT 0,
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
@ -118,7 +118,7 @@ CREATE TABLE `sys_role` (
|
||||
`description` varchar(255) NULL COMMENT '角色描述',
|
||||
`status` int NOT NULL COMMENT '状态',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`role_id`),
|
||||
@ -135,7 +135,7 @@ CREATE TABLE `sys_user` (
|
||||
`user_type` tinyint NULL DEFAULT NULL COMMENT '用户类型从字典取',
|
||||
`status` tinyint DEFAULT 0 NOT NULL COMMENT '状态',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`user_id`),
|
||||
@ -174,7 +174,7 @@ CREATE TABLE `sys_user_field_definition` (
|
||||
`sort` int NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
`status` int NOT NULL COMMENT '状态',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`field_id`),
|
||||
@ -188,7 +188,7 @@ CREATE TABLE `sys_user_field_value` (
|
||||
`field_id` int NOT NULL COMMENT '字段ID',
|
||||
`value` varchar(4096) NULL COMMENT '用户拓展字段值',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
@ -203,7 +203,7 @@ CREATE TABLE `sys_profile` (
|
||||
`description` varchar(255) NULL COMMENT '系统配置记录描述',
|
||||
`content` varchar(255) NULL COMMENT '系统配置记录值',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
@ -220,7 +220,7 @@ CREATE TABLE `sys_module` (
|
||||
`sort` int NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
`status` int NOT NULL COMMENT '状态',
|
||||
`created_by` bigint NOT NULL COMMENT '创建人',
|
||||
`updated_by` bigint NOT NULL COMMENT '更新人',
|
||||
`updated_by` bigint NULL COMMENT '更新人',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
|
Loading…
Reference in New Issue
Block a user