完成角色部分

main
expressgy 3 months ago
parent 7488c21ed5
commit dc4391a79f
  1. 2812
      docs/pacAuth_database_0.2.ndm2
  2. 51
      src/application/auth-role/auth-role.controller.ts
  3. 237
      src/application/auth-role/auth-role.service.ts
  4. 1
      src/application/auth-role/dto/create-auth-role.dto.ts
  5. 48
      src/application/auth-role/dto/get-auth-role.dto.ts
  6. 44
      src/application/auth-role/dto/roleLinkUser.dto.ts
  7. 23
      src/entities/schema.ts

File diff suppressed because it is too large Load Diff

@ -6,7 +6,13 @@ import { ApiOperation, ApiProduces, ApiTags } from '@nestjs/swagger';
import { PacInfo } from '@common/decorator/pac-info/pac-info.decorator'; import { PacInfo } from '@common/decorator/pac-info/pac-info.decorator';
import { PacInfoType } from '@utils/myType'; import { PacInfoType } from '@utils/myType';
import { query } from 'express'; import { query } from 'express';
import { GetPacAuthRoleAllDto } from '@app/auth-role/dto/get-auth-role.dto'; import {
GetPacAuthRoleAllDto,
GetUserForRoleDto
} from "@app/auth-role/dto/get-auth-role.dto";
import {
RoleLinkUserDto
} from "@app/auth-role/dto/roleLinkUser.dto";
@ApiTags('角色服务') @ApiTags('角色服务')
@Controller('authRole') @Controller('authRole')
@ -32,6 +38,7 @@ export class AuthRoleController {
findAll(@Query() getPacAuthRoleAllDto: GetPacAuthRoleAllDto) { findAll(@Query() getPacAuthRoleAllDto: GetPacAuthRoleAllDto) {
return this.authRoleService.findAll(getPacAuthRoleAllDto); return this.authRoleService.findAll(getPacAuthRoleAllDto);
} }
@ApiOperation({ @ApiOperation({
summary: '获取角色详细信息', summary: '获取角色详细信息',
description: '查询角色详细信息,目录菜单列表,数据权限范围', description: '查询角色详细信息,目录菜单列表,数据权限范围',
@ -42,6 +49,16 @@ export class AuthRoleController {
return this.authRoleService.findOne(id); return this.authRoleService.findOne(id);
} }
@ApiOperation({
summary: '获取角色树',
description: '查询角色基本信息,树结构',
})
@ApiProduces('application/json')
@Get('/tree/:pid')
findTree(@Param('pid') pid: string) {
return this.authRoleService.findTree(pid);
}
@ApiOperation({ @ApiOperation({
summary: '更新角色信息', summary: '更新角色信息',
description: '更新角色信息', description: '更新角色信息',
@ -51,6 +68,7 @@ export class AuthRoleController {
update(@Param('id') id: string, @Body() updateAuthRoleDto: UpdateAuthRoleDto, @PacInfo() pacInfo: PacInfoType) { update(@Param('id') id: string, @Body() updateAuthRoleDto: UpdateAuthRoleDto, @PacInfo() pacInfo: PacInfoType) {
return this.authRoleService.update(id, updateAuthRoleDto, pacInfo); return this.authRoleService.update(id, updateAuthRoleDto, pacInfo);
} }
@ApiOperation({ @ApiOperation({
summary: '删除目标角色', summary: '删除目标角色',
description: '删除目标角色信息', description: '删除目标角色信息',
@ -60,4 +78,35 @@ export class AuthRoleController {
remove(@Param('id') id: string, @PacInfo() pacInfo: PacInfoType) { remove(@Param('id') id: string, @PacInfo() pacInfo: PacInfoType) {
return this.authRoleService.remove(id, pacInfo); return this.authRoleService.remove(id, pacInfo);
} }
@ApiOperation({
summary: '获取角色下关联的账户',
description: '查询角色保定的用户',
})
@ApiProduces('application/json')
@Get('/user/:roleId')
findUserByRoleId(@Param('roleId') roleId: string, @Query() getUserForRoleDto: GetUserForRoleDto) {
return this.authRoleService.findUserByRoleId(roleId, getUserForRoleDto);
}
@ApiOperation({
summary: '给角色绑定账户',
description: '给角色关联上账户,最大200个',
})
@ApiProduces('application/json')
@Post('/user')
linkUser(@Body() roleLinkUserDto: RoleLinkUserDto, @PacInfo() pacInfo: PacInfoType) {
return this.authRoleService.linkUser(roleLinkUserDto, pacInfo);
}
@ApiOperation({
summary: '给角色解绑账户',
description: '给角色取消关联上账户,最大200个',
})
@ApiProduces('application/json')
@Delete('/user')
unlinkUser(@Body() roleLinkUserDto: RoleLinkUserDto) {
console.log(roleLinkUserDto);
return this.authRoleService.unlinkUser(roleLinkUserDto);
}
} }

@ -8,11 +8,22 @@ import { Snowflake } from '@service/snowflake/snowflake.service';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { PacInfoType } from '@utils/myType'; import { PacInfoType } from '@utils/myType';
import { isExistKey, isTrueEnum } from '@utils/boolean.enum'; import { isExistKey, isTrueEnum } from '@utils/boolean.enum';
import { pacAuthDept, pacAuthLinkRoleDept, pacAuthLinkRoleMenu, pacAuthRole, pacAuthUser, pacCoreDict, pacCoreMenu } from '@entities/schema'; import {
import { and, asc, desc, eq, isNull, like, or, sql } from 'drizzle-orm'; pacAuthDept,
import { GetPacAuthRoleAllDto } from '@app/auth-role/dto/get-auth-role.dto'; pacAuthLinkRoleDept,
pacAuthLinkRoleMenu,
pacAuthLinkUserRole,
pacAuthRole,
pacAuthUser,
pacCoreDict,
pacCoreMenu,
} from '@entities/schema';
import { and, asc, desc, eq, inArray, isNull, like, or, SQL, sql } from 'drizzle-orm';
import { GetPacAuthRoleAllDto, GetUserForRoleDto } from '@app/auth-role/dto/get-auth-role.dto';
import { likeQuery } from '@utils/likeQuery'; import { likeQuery } from '@utils/likeQuery';
import { alias } from 'drizzle-orm/mysql-core'; import { alias, QueryBuilder } from 'drizzle-orm/mysql-core';
import { customDrizzleRowWithRecursive } from '@utils/customDrizzleRowWithRecursive';
import { RoleLinkUserDto } from '@app/auth-role/dto/roleLinkUser.dto';
@Injectable() @Injectable()
export class AuthRoleService { export class AuthRoleService {
@ -38,28 +49,6 @@ export class AuthRoleService {
updatetime: pacAuthRole.updatetime, updatetime: pacAuthRole.updatetime,
}; };
// 角色详细信息
private readonly roleMoreType = {
roleId: pacAuthRole.roleId,
pid: pacAuthRole.pid,
roleName: pacAuthRole.roleName,
roleKey: pacAuthRole.roleKey,
roleDesc: pacAuthRole.roleDesc,
roleType: pacAuthRole.roleType,
roleTypeName: pacCoreDict.dictName,
roleTypeKey: pacCoreDict.dictKey,
deptScope: pacAuthRole.deptScope,
root: pacAuthRole.root,
orderNum: pacAuthRole.orderNum,
status: pacAuthRole.status,
createby: pacAuthRole.createby,
createName: pacAuthUser.nickname,
createtime: pacAuthRole.createtime,
updateby: pacAuthRole.updateby,
updateName: pacAuthUser.nickname,
updatetime: pacAuthRole.updatetime,
};
// 角色列表/数信息 // 角色列表/数信息
private readonly roleListType = { private readonly roleListType = {
roleId: pacAuthRole.roleId, roleId: pacAuthRole.roleId,
@ -163,6 +152,25 @@ export class AuthRoleService {
return this.getRoleMore(id); return this.getRoleMore(id);
} }
/** Service
* NAME: findTree
* DESC: 获取角色树结构信息
* DATE: 2024-06-27 14:23:36 -
* */
public async findTree(pid: string) {
const [result] = await this.getRoleTree(pid);
return result;
}
/** Service
* NAME: findUserByRoleId
* DESC: 获取角色下的关联账户
* DATE: 2024-06-27 14:49:42 -
* */
public async findUserByRoleId(roleId: string, getUserForRoleDto: GetUserForRoleDto) {
return await this.getRoleUser(roleId, getUserForRoleDto);
}
public async update(roleId: string, updateAuthRoleDto: UpdateAuthRoleDto, pacInfo: PacInfoType) { public async update(roleId: string, updateAuthRoleDto: UpdateAuthRoleDto, pacInfo: PacInfoType) {
// ! 查找角色信息 // ! 查找角色信息
const roleData = await this.getRoleForRoleId(roleId); const roleData = await this.getRoleForRoleId(roleId);
@ -232,6 +240,24 @@ export class AuthRoleService {
return await this.deleteRole(roleId, pacInfo.userId as any); return await this.deleteRole(roleId, pacInfo.userId as any);
} }
/** Service
* NAME: linkUser
* DESC: 关联账户给角色
* DATE: 2024-06-27 15:38:50 -
* */
public async linkUser(roleLinkUserDto: RoleLinkUserDto, pacInfo: PacInfoType) {
return this.linkUserForRole(roleLinkUserDto, pacInfo);
}
/** Service
* NAME: unlinkUser
* DESC: 取消关联账户给角色
* DATE: 2024-06-27 15:38:54 -
* */
public async unlinkUser(roleLinkUserDto: RoleLinkUserDto) {
return this.unlinkUserForRole(roleLinkUserDto);
}
// DB 通过roleKey查找角色信息 // DB 通过roleKey查找角色信息
private getRoleForRoleKey(key: string) { private getRoleForRoleKey(key: string) {
return this.mysqlService.db return this.mysqlService.db
@ -387,11 +413,41 @@ export class AuthRoleService {
} }
// DB 查角色树 // DB 查角色树
getRoleTree() {} private getRoleTree(pid: string) {
// ! 基础层级
const baseQueryBuilder = new QueryBuilder();
const baseQuery = baseQueryBuilder
.select({
...this.roleListType,
level: sql`0`.as('level'),
})
.from(pacAuthRole)
.leftJoin(pacCoreDict, eq(pacAuthRole.roleType, pacCoreDict.dictId))
.where(and(isNull(pacAuthRole.deleteby), eq(pacAuthRole.pid, pid)));
// ! 递归层级
const recursiveQueryBuilder = new QueryBuilder();
const recursiveQuery = recursiveQueryBuilder
.select({
...this.roleListType,
level: sql`roleHierarchy.level + 1`.as('level'),
})
.from(pacAuthRole)
.leftJoin(pacCoreDict, eq(pacAuthRole.roleType, pacCoreDict.dictId))
.where(isNull(pacAuthRole.deleteby))
.innerJoin(sql`roleHierarchy`, sql`roleHierarchy.roleId = ${pacAuthRole.pid}`);
const rowName: SQL = customDrizzleRowWithRecursive(this.roleListType);
// ! 执行原始SQL查询
return this.mysqlService.db.execute(
sql`WITH RECURSIVE roleHierarchy(${rowName}) AS(${baseQuery} UNION ALL ${recursiveQuery}) SELECT * FROM roleHierarchy`,
);
}
// DB 查角色详细信息 // DB 查角色详细信息
private async getRoleMore(roleId: string) { private async getRoleMore(roleId: string) {
// ! 定义2次连表查询的用户表 // ! 定义2次连表查询的户表
const userTable1 = alias(pacAuthUser, 'userTable1'); const userTable1 = alias(pacAuthUser, 'userTable1');
// ! 查询目标角色信息 // ! 查询目标角色信息
@ -514,4 +570,129 @@ export class AuthRoleService {
}) })
.where(eq(pacAuthRole.roleId, roleId)); .where(eq(pacAuthRole.roleId, roleId));
} }
// DB 查找角色下的账户查询构建
private getRoleUserQuery(roleId: string, getUserForRoleDto: GetUserForRoleDto, selectData = null) {
const query = this.mysqlService.db
.select(selectData)
.from(pacAuthUser)
.orderBy(isTrueEnum(getUserForRoleDto.isAsc) ? asc(pacAuthUser.userId) : desc(pacAuthUser.userId))
.leftJoin(pacCoreDict, eq(pacAuthUser.userType, pacCoreDict.dictId))
.leftJoin(pacAuthLinkUserRole, eq(pacAuthLinkUserRole.userId, pacAuthUser.userId))
.$dynamic();
const wl = [];
// ? 未删除
wl.push(isNull(pacAuthUser.deleteby));
// ? 模糊查询
wl.push(
or(
like(pacAuthUser.nickname, likeQuery(getUserForRoleDto.userInfo)),
like(pacAuthUser.userDesc, likeQuery(getUserForRoleDto.userInfo)),
like(pacAuthUser.userEmail, likeQuery(getUserForRoleDto.userInfo)),
like(pacAuthUser.userPhone, likeQuery(getUserForRoleDto.userInfo)),
like(pacAuthUser.username, likeQuery(getUserForRoleDto.userInfo)),
).if(isExistKey(getUserForRoleDto, 'userInfo')),
);
// ? 目标roleId
wl.push(eq(pacAuthLinkUserRole.roleId, roleId));
// ? 用户类型
wl.push(eq(pacAuthUser.userType, getUserForRoleDto.userType).if(isExistKey(getUserForRoleDto, 'userType')));
query.where(and(...wl));
return query;
}
// DB 查找角色下的账户
private async getRoleUser(roleId: string, getUserForRoleDto: GetUserForRoleDto) {
const offset = (getUserForRoleDto.pageNumber - 1) * getUserForRoleDto.pageSize;
// ! 使用基础查询构建查询总记录数
const totalCountQuery = this.getRoleData(getUserForRoleDto, {
totalCount: sql`COUNT(*)`,
});
// ! 使用基础查询构建分页查询
// 重命名表
const userTable1 = alias(pacAuthUser, 'userTable1');
const userTable2 = alias(pacAuthUser, 'userTable2');
const paginatedQuery = this.getRoleUserQuery(roleId, getUserForRoleDto, {
userId: pacAuthUser.userId,
username: pacAuthUser.username,
nickname: pacAuthUser.nickname,
userType: pacAuthUser.userType,
userTypeName: pacCoreDict.dictName,
userTypeKey: pacCoreDict.dictKey,
userEmail: pacAuthUser.userEmail,
avatar: pacAuthUser.avatar,
userPhone: pacAuthUser.userPhone,
userDesc: pacAuthUser.userDesc,
haveChildren: pacAuthUser.haveChildren,
createby: pacAuthUser.createby,
createName: userTable2.nickname,
createtime: pacAuthUser.createtime,
updateName: userTable1.nickname,
})
.leftJoin(userTable2, eq(pacAuthUser.createby, userTable2.userId))
.leftJoin(userTable1, eq(pacAuthUser.updateby, userTable1.userId))
.limit(getUserForRoleDto.pageSize)
.offset(offset);
return {
total: (await totalCountQuery)[0].totalCount,
rowData: await paginatedQuery,
searchData: getUserForRoleDto,
};
}
// DB 查找角色账户关联数据
private async getRoleLinkUser(roleId: string, userIdList: string[]) {
return this.mysqlService.db
.select({
id: pacAuthLinkUserRole.userId,
index: pacAuthLinkUserRole.index,
})
.from(pacAuthLinkUserRole)
.where(and(eq(pacAuthLinkUserRole.roleId, roleId), inArray(pacAuthLinkUserRole.userId, userIdList)));
}
// DB 给角色关联上账户
private async linkUserForRole(roleLinkUserDto: RoleLinkUserDto, pacInfo: PacInfoType) {
// ! 去重账户ID
const deduplicateUserId = Array.from(new Set(roleLinkUserDto.userIdList));
// ! 查找角色是否存在这些账户
const existUser = await this.getRoleLinkUser(roleLinkUserDto.roleId, deduplicateUserId);
// ! 获取已存在的账户Id
const existUserIdList = existUser.map((user) => user.id);
// ! 过滤已经存在的账户
const userIdList = roleLinkUserDto.userIdList.filter((i) => !existUserIdList.includes(i));
return await this.mysqlService.db.insert(pacAuthLinkUserRole).values(
userIdList.map((i) => ({
roleId: roleLinkUserDto.roleId,
userId: i,
createby: pacInfo.userId,
createtime: sql`now()` as any,
})),
);
}
// DB 取消角色关联的账户
private async unlinkUserForRole(roleLinkUserDto: RoleLinkUserDto) {
// ! 去重账户ID
const deduplicateUserId = Array.from(new Set(roleLinkUserDto.userIdList));
// ! 查找角色是否存在这些账户
const existUser = await this.getRoleLinkUser(roleLinkUserDto.roleId, deduplicateUserId);
// ! 获取已存在的账户Id
const existUserIndexList = existUser.map((user) => user.index);
return await this.mysqlService.db.delete(pacAuthLinkUserRole).where(inArray(pacAuthLinkUserRole.index, existUserIndexList));
}
} }

@ -118,6 +118,7 @@ export class CreateAuthRoleDto {
@IsString({ each: true, message: '菜单id格式错误' }) @IsString({ each: true, message: '菜单id格式错误' })
@ArrayMinSize(1, { message: '至少需要选择一个菜单作为权限' }) @ArrayMinSize(1, { message: '至少需要选择一个菜单作为权限' })
@Length(19, 19, { each: true, message: '菜单id格式错误' }) @Length(19, 19, { each: true, message: '菜单id格式错误' })
@IsOptional()
readonly menuList?: string[]; readonly menuList?: string[];
@ApiProperty({ @ApiProperty({

@ -29,8 +29,8 @@ export class GetPacAuthRoleAllDto extends GetDto {
maxLength: 128, maxLength: 128,
}) })
@Trim() @Trim()
@IsString({ message: '字典信息应为字符串格式!' }) @IsString({ message: '角色信息应为字符串格式!' })
@Length(0, 128, { message: '请将字典信息长度控制在1到128位之间!' }) @Length(0, 128, { message: '请将角色信息长度控制在1到128位之间!' })
@IsOptional() @IsOptional()
readonly roleInfo?: string; readonly roleInfo?: string;
@ -61,7 +61,7 @@ export class GetPacAuthRoleAllDto extends GetDto {
readonly root: BooleanEnum; readonly root: BooleanEnum;
@ApiProperty({ @ApiProperty({
description: '字典状态', description: '角色状态',
type: Number, type: Number,
example: 0, example: 0,
required: false, required: false,
@ -71,19 +71,19 @@ export class GetPacAuthRoleAllDto extends GetDto {
@Trim() @Trim()
@Int() @Int()
@IsInt({ @IsInt({
message: '字典状态必须是整数!', message: '角色状态必须是整数!',
}) })
@Min(-100, { @Min(-100, {
message: '字典状态需要大于-100!', message: '角色状态需要大于-100!',
}) })
@Max(100, { @Max(100, {
message: '字典状态不能超过100', message: '角色状态不能超过100',
}) })
@IsOptional() @IsOptional()
readonly status?: string; readonly status?: string;
@ApiProperty({ @ApiProperty({
description: '字典层级id', description: '角色层级id',
type: Number, type: Number,
example: 0, example: 0,
required: false, required: false,
@ -91,24 +91,38 @@ export class GetPacAuthRoleAllDto extends GetDto {
maximum: 100, maximum: 100,
}) })
@Trim() @Trim()
@IsString({ message: '字典层级id应为字符串格式!' }) @IsString({ message: '角色层级id应为字符串格式!' })
@Length(1, 20, { message: '字典层级id格式错误!' }) @Length(1, 20, { message: '角色层级id格式错误!' })
@IsOptional() @IsOptional()
readonly hierarchy?: string; readonly hierarchy?: string;
} }
export class PacAuthRoleTargetListDto { export class GetUserForRoleDto extends GetDto {
@ApiProperty({ @ApiProperty({
description: '是否查找树结构', description: '用户信息',
type: BooleanEnum, type: String,
enum: BooleanEnum, example: '哈哈',
example: 0,
required: false, required: false,
minLength: 1,
maxLength: 128,
}) })
@Trim() @Trim()
@IsEnum(BooleanEnum, { @IsString({ message: '用户信息应为字符串格式!' })
message: '查找树结构数据错误', @Length(0, 128, { message: '请将用户信息长度控制在1到128位之间!' })
@IsOptional()
readonly userInfo?: string;
@ApiProperty({
description: '用户类型,来自于字典',
type: String,
example: '0',
required: false,
minLength: 19,
maxLength: 19,
}) })
@Trim()
@IsString({ message: '用户类型格式不正确!' })
@Length(19, 19, { message: '用户类型格式不正确!' })
@IsOptional() @IsOptional()
readonly isTree: BooleanEnum; readonly userType: string;
} }

@ -0,0 +1,44 @@
// | ------------------------------------------------------------
// | @版本: version 0.1
// | @创建人: 【Nie-x7129】
// | @E-mail: x71291@outlook.com
// | @所在项目: pac-auth
// | @文件描述: roleLinkUser.dto.ts -
// | @创建时间: 2024-06-27 15:30
// | @更新时间: 2024-06-27 15:30
// | @修改记录:
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
// | =
// | ------------------------------------------------------------
import { ApiProperty } from '@nestjs/swagger';
import Trim from '@common/decorator/trim/trim.decorator';
import { ArrayMaxSize, ArrayMinSize, IsString, Length } from 'class-validator';
export class RoleLinkUserDto {
@ApiProperty({
description: '角色ID',
type: String,
example: '0',
required: true,
minLength: 19,
maxLength: 19,
})
@Trim()
@IsString({ message: '角色属性格式不正确!' })
@Length(19, 19, { message: '角色属性格式不正确!' })
readonly roleId: string;
@ApiProperty({
description: '账户Id列表',
type: [String],
example: ['a'],
required: true,
minItems: 1,
})
@IsString({ each: true, message: '账户Id格式错误' })
@ArrayMinSize(1, { message: '至少需要选择一个需要绑定的账户' })
@ArrayMaxSize(200, { message: '需要绑定的账户账户超过限制' })
@Length(19, 19, { each: true, message: '账户Id格式错误' })
readonly userIdList?: string[];
}

@ -7,21 +7,22 @@ export const pacAuthDept = mysqlTable(
'pac_auth_dept', 'pac_auth_dept',
{ {
index: int('index').autoincrement().notNull(), index: int('index').autoincrement().notNull(),
deptId: int('dept_id').notNull(), deptId: bigint('dept_id', { mode: 'number' }).notNull(),
pid: int('pid').default(0).notNull(), pid: bigint('pid', { mode: 'number' }).notNull(),
grade: int('grade').notNull(), grade: int('grade').notNull(),
deptName: varchar('dept_name', { length: 255 }), deptName: varchar('dept_name', { length: 255 }).notNull(),
deptDesc: varchar('dept_desc', { length: 255 }), deptDesc: varchar('dept_desc', { length: 255 }),
deptType: int('dept_type').default(0).notNull(), deptType: bigint('dept_type', { mode: 'number' }).notNull(),
deptLeader: int('dept_leader'), deptLeader: bigint('dept_leader', { mode: 'number' }),
defaultRole: int('default_role'), defaultRole: bigint('default_role', { mode: 'number' }),
haveChildren: int('have_children').default(0).notNull(),
orderNum: int('order_num').default(0).notNull(), orderNum: int('order_num').default(0).notNull(),
status: int('status').default(0).notNull(), status: int('status').default(0).notNull(),
createby: int('createby').notNull(), createby: bigint('createby', { mode: 'number' }).notNull(),
createtime: datetime('createtime', { mode: 'string' }).notNull(), createtime: datetime('createtime', { mode: 'string' }).notNull(),
updateby: int('updateby'), updateby: bigint('updateby', { mode: 'number' }),
updatetime: datetime('updatetime', { mode: 'string' }), updatetime: datetime('updatetime', { mode: 'string' }),
deleteby: int('deleteby'), deleteby: bigint('deleteby', { mode: 'number' }),
deletetime: datetime('deletetime', { mode: 'string' }), deletetime: datetime('deletetime', { mode: 'string' }),
}, },
(table) => { (table) => {
@ -179,10 +180,10 @@ export const pacAuthUser = mysqlTable(
username: varchar('username', { length: 255 }).notNull(), username: varchar('username', { length: 255 }).notNull(),
password: varchar('password', { length: 255 }).notNull(), password: varchar('password', { length: 255 }).notNull(),
nickname: varchar('nickname', { length: 255 }).notNull(), nickname: varchar('nickname', { length: 255 }).notNull(),
userType: int('user_type').default(0).notNull(), userType: bigint('user_type', { mode: 'number' }).notNull(),
userEmail: varchar('user_email', { length: 255 }), userEmail: varchar('user_email', { length: 255 }),
pid: bigint('pid', { mode: 'number' }).notNull(), pid: bigint('pid', { mode: 'number' }).notNull(),
wxAppid: int('wx_appid'), wxAppid: varchar('wx_appid', { length: 255 }),
avatar: varchar('avatar', { length: 255 }), avatar: varchar('avatar', { length: 255 }),
userPhone: varchar('user_phone', { length: 255 }), userPhone: varchar('user_phone', { length: 255 }),
userDesc: varchar('user_desc', { length: 255 }), userDesc: varchar('user_desc', { length: 255 }),

Loading…
Cancel
Save