image.png
image.pngimage.png

1-1 用户路由表

src/routes/user.ts

  1. import Router from '@koa/router'
  2. import {
  3. getAllUserController,
  4. updateUserController,
  5. allocUserRoleController,
  6. removeUserController
  7. } from '../controller/user'
  8. const router = new Router({
  9. prefix: '/api/user'
  10. })
  11. /**
  12. * 获取用户列表
  13. * get /api/user
  14. */
  15. router.get('/', async ctx => {
  16. const { pageNum = 0, pageSize = 10, ...query } = ctx.request.query
  17. ctx.body = await getAllUserController({
  18. offset: Number(pageNum),
  19. limit: Number(pageSize),
  20. query
  21. })
  22. })
  23. /**
  24. * 编辑用户
  25. * post /api/user/:id
  26. */
  27. router.put('/:id', async ctx => {
  28. const { id } = ctx.params
  29. ctx.body = await updateUserController(Number(id), ctx.request.body)
  30. })
  31. /**
  32. * 给用户分配角色
  33. * post /api/user/role/:id
  34. */
  35. router.post('/role/:id', async ctx => {
  36. const { id } = ctx.params
  37. const { roles } = ctx.request.body
  38. ctx.body = await allocUserRoleController(Number(id), roles)
  39. })
  40. /**
  41. * 删除用户
  42. * delete /api/user/:id
  43. */
  44. router.delete('/:id', async ctx => {
  45. const { id } = ctx.params
  46. ctx.body = await removeUserController(Number(id))
  47. })
  48. export default router

1-2 用户controller

src/controller/user.ts

  1. import {
  2. getAllUserService,
  3. updateUserService,
  4. allocUserRoleService,
  5. destroyUserRoleByUserID,
  6. removeUserService
  7. } from '../services/user'
  8. import { createErrorResponse, SuccessResponse } from '../utils/Response'
  9. import errorInfo from '../constants/errorInfo'
  10. import { RegisterModel } from '../db/models/user'
  11. import { getUserInfo } from '../services/auth'
  12. import { RegisterPropsWithRoles } from './types'
  13. const {
  14. updateUserExistFailInfo,
  15. getUserListFailInfo,
  16. allocUserRoleFailInfo,
  17. deleteUserInfoFailInfo
  18. } = errorInfo
  19. // 获取全部菜单
  20. export interface WhereQuery {
  21. name: string;
  22. status: number;
  23. mobile: string;
  24. }
  25. export interface UserListParams {
  26. offset: number;
  27. limit: number;
  28. query: Record<string, any>;
  29. }
  30. // 获取全部用户列表
  31. export const getAllUserController = async ({ offset, limit, query }: UserListParams) => {
  32. try {
  33. const result = await getAllUserService(offset, limit, query)
  34. return new SuccessResponse(result)
  35. } catch (error) {
  36. console.error(error.message)
  37. return createErrorResponse(getUserListFailInfo)
  38. }
  39. }
  40. // 更改用户信息
  41. export const updateUserController = async (id: number, data: RegisterPropsWithRoles) => {
  42. const {
  43. username,
  44. email,
  45. mobile,
  46. description,
  47. status,
  48. roleIds,
  49. } = data
  50. console.log('roleIds',roleIds)
  51. // 判断修改后的用户名是否已经存在其他重名用户
  52. const userInfo = await getUserInfo({ username })
  53. if (userInfo && userInfo.id !== id) {
  54. return createErrorResponse(updateUserExistFailInfo)
  55. }
  56. try {
  57. await updateUserService(id, {
  58. username,
  59. email,
  60. mobile,
  61. description,
  62. status
  63. } as RegisterModel)
  64. await allocUserRoleController(id, roleIds)
  65. return new SuccessResponse(null, '用户信息修改成功')
  66. } catch (error) {
  67. console.error(error.message)
  68. return createErrorResponse(getUserListFailInfo)
  69. }
  70. }
  71. // 分配用户角色
  72. export const allocUserRoleController = async (id: number, roles: number[] = []) => {
  73. // 移除之前该用户与角色记录
  74. await destroyUserRoleByUserID(id)
  75. try {
  76. await allocUserRoleService(id, roles)
  77. return new SuccessResponse(null, '用户角色分配成功')
  78. } catch (error) {
  79. console.error(error.message)
  80. return createErrorResponse(allocUserRoleFailInfo)
  81. }
  82. }
  83. // 删除用户
  84. export const removeUserController = async (id: number) => {
  85. try {
  86. await removeUserService(id)
  87. return new SuccessResponse(null, '用户删除成功')
  88. } catch (error) {
  89. console.error(error.message)
  90. return createErrorResponse(deleteUserInfoFailInfo)
  91. }
  92. }

1-3 用户services

src/services/user.ts

  1. import { UserInfo } from './types'
  2. import { RolesModel, UserModel, UserRoleModel } from '../db/models'
  3. import { RegisterModel } from '../db/models/user'
  4. // 获取全部用户
  5. export const getAllUserService = async (offset = 0, limit = 10, query: Record<string, any>) => {
  6. const whereProps = {} as Record<string, any>
  7. // 检索条件处理
  8. if (query.mobile) {
  9. whereProps.mobile = query.mobile
  10. }
  11. if (query.username) {
  12. whereProps.username = query.username
  13. }
  14. if (!isNaN(query.status)) {
  15. whereProps.status = Number(query.status)
  16. }
  17. const { count, rows } = await UserModel.findAndCountAll({
  18. attributes: ['id', 'username', 'email', 'mobile', 'isSuper', 'status', 'avatar', 'description', 'createdAt'],
  19. where: whereProps,
  20. limit,
  21. offset: limit * offset,
  22. // https://blog.csdn.net/Tirst_/article/details/109677451
  23. distinct: true, //去重 解决findAndCountAll联表查询时 count数不准确问题解决
  24. include: [ // 联表查询
  25. {
  26. model: UserRoleModel,
  27. attributes: ['id'],
  28. include: [
  29. {
  30. model: RolesModel,
  31. attributes: ['id', 'name', 'description']
  32. }
  33. ]
  34. }
  35. ]
  36. })
  37. // 数据格式化
  38. const users = rows.map(row => {
  39. const user = row.toJSON() as UserInfo
  40. user.roles = user.UserRoles?.map(item => item.Role)
  41. delete user.UserRoles
  42. return user
  43. })
  44. return {
  45. users,
  46. count
  47. }
  48. }
  49. // 修改用户
  50. export const updateUserService = async (id: number, data: RegisterModel) => {
  51. const result = await UserModel.update(data, {
  52. where: {
  53. id
  54. }
  55. })
  56. return result
  57. }
  58. /**
  59. * 删除与该用户相关联记录
  60. * @param id 角色id
  61. */
  62. export const destroyUserRoleByUserID = async (id: number) => {
  63. const result = await UserRoleModel.destroy({
  64. where: {
  65. user_id: id
  66. }
  67. })
  68. return result
  69. }
  70. // 分配用户角色
  71. export const allocUserRoleService = async (id: number, data: number[]) => {
  72. const roles = data.map(rid => ({
  73. user_id: id,
  74. role_id: rid
  75. }))
  76. const result = await UserRoleModel.bulkCreate(roles)
  77. return result
  78. }
  79. // 根据用户id删除用户
  80. export const removeUserService = async (id: number) => {
  81. const result = await UserModel.destroy({
  82. where: {
  83. id
  84. }
  85. })
  86. return result
  87. }

1-4 auth services

src/services/auth.ts

  1. import UserModel, { RegisterModel, UserModelProps } from '../db/models/user'
  2. import { UserWhereProps } from './types'
  3. import { createMd5 } from '../utils/createMD5'
  4. import { RolesModel, UserRoleModel } from '../db/models'
  5. import { UserInfo } from './types'
  6. /**
  7. * 创建用户
  8. */
  9. export const createUser = async ({ username, password, email, mobile, status, avatar }: RegisterModel): Promise<UserModelProps> => {
  10. const result = await UserModel.create({
  11. username,
  12. password,
  13. email,
  14. mobile,
  15. status
  16. })
  17. return result.toJSON() as UserModelProps
  18. }
  19. /**
  20. * 根据用户名 获取用户信息
  21. * @param username 用户名
  22. * @param password 密码
  23. * @param id 用户id
  24. * @returns 用户信息
  25. */
  26. export const getUserInfo = async ({ username, password, id }: UserWhereProps): Promise<UserModelProps | null> => {
  27. const where: UserWhereProps = {
  28. username
  29. }
  30. if (password) {
  31. where.password = createMd5(password)
  32. }
  33. if (typeof id != 'undefined') {
  34. where.id = id
  35. }
  36. const result = await UserModel.findOne({
  37. attributes: {
  38. exclude: ['password', 'createdAt', 'updatedAt']
  39. },
  40. where,
  41. })
  42. if (result == null) return null
  43. return result.toJSON() as UserModelProps
  44. }
  45. // 获取用户信息 包含 角色信息
  46. export const getUserInfoAndRoles = async (id: number) => {
  47. const result = await UserModel.findOne({
  48. attributes: ['id', 'username', 'email', 'mobile', 'isSuper', 'status', 'avatar', 'description'],
  49. where: {
  50. id
  51. },
  52. include: [ // 联表查询
  53. {
  54. model: UserRoleModel,
  55. attributes: ['id'],
  56. include: [
  57. {
  58. model: RolesModel,
  59. attributes: ['id', 'name', 'description']
  60. }
  61. ]
  62. }
  63. ]
  64. })
  65. if (!result) return null
  66. const user = result.toJSON() as UserInfo
  67. user.roles = user.UserRoles?.map(item => item.Role)
  68. delete user.UserRoles
  69. return user
  70. }

1-5 user model

src/db/models/user.ts

  1. import {
  2. Model,
  3. DataTypes,
  4. Optional
  5. } from 'sequelize'
  6. import seq from '../seq'
  7. // sequelize+typescript 参考文档
  8. // https://sequelize.org/master/manual/typescript.html
  9. // model类型
  10. export interface UserModelProps {
  11. id: number;
  12. username: string;
  13. password: string;
  14. email: string | null;
  15. mobile: string | null;
  16. avatar: string;
  17. description: string;
  18. isSuper: 0 | 1;
  19. status: 0 | 1;
  20. }
  21. // 注册接口params类型 id 和 isSuper创建时候可以不用定义自动分配
  22. export type RegisterModel = Omit<UserModelProps, 'id'|'isSuper'>
  23. // 在“User.build”和“User.create”调用中,有些属性是可选的
  24. interface UserCreationAttributes extends Optional<UserModelProps, "id" | "isSuper" | "status" | "avatar"|"description"> {}
  25. // Model实例接口
  26. interface UserInstance
  27. extends Model<UserModelProps, UserCreationAttributes>,
  28. UserModelProps {}
  29. // 创建User模型 数据表的名字是users
  30. const User = seq.define<UserInstance>('User', {
  31. id: {
  32. primaryKey: true,
  33. type: DataTypes.INTEGER.UNSIGNED,
  34. autoIncrement: true
  35. },
  36. // id会自动创建 并设为主键、自增
  37. username: {
  38. type: DataTypes.STRING,
  39. allowNull: false,
  40. comment: '用户名'
  41. },
  42. password: {
  43. type: DataTypes.STRING,
  44. allowNull: false,
  45. comment: '密码'
  46. },
  47. email: {
  48. type: DataTypes.STRING,
  49. comment: '用户邮箱'
  50. },
  51. mobile: {
  52. type: DataTypes.STRING,
  53. comment: '手机号'
  54. },
  55. avatar: {
  56. type: DataTypes.STRING,
  57. comment: '头像'
  58. },
  59. isSuper: {
  60. type: DataTypes.BOOLEAN, // TINYINT(1)
  61. comment: '超级管理员 1是 0不是',
  62. defaultValue: 0
  63. },
  64. description: {
  65. type: DataTypes.TEXT,
  66. comment: '描述说明'
  67. },
  68. status: {
  69. type: DataTypes.BOOLEAN, // TINYINT(1)
  70. comment: '账户禁用状态 1正常 0禁用',
  71. defaultValue: 1
  72. }
  73. })
  74. export default User

导入models/index
src/db/models/index.ts

  1. import UserModel from './user'
  2. export {
  3. UserModel,
  4. }

同步下model信息

  1. npm run db

1-6 errorinfo

目前最新错误信息

src/constants/errorInfo.ts

  1. /**
  2. * @description 失败信息集合,包括 code 和 message
  3. * @author 拔都
  4. */
  5. export default {
  6. // 用户名已存在
  7. registerUserNameExistInfo: {
  8. code: 10001,
  9. message: '用户名已存在'
  10. },
  11. // 注册失败
  12. registerFailInfo: {
  13. code: 10002,
  14. message: '注册失败,请重试'
  15. },
  16. // 用户名不存在
  17. registerUserNameNotExistInfo: {
  18. code: 10003,
  19. message: '用户名未存在'
  20. },
  21. // 登录失败
  22. loginFailInfo: {
  23. code: 10004,
  24. message: '登录失败,用户名或密码错误'
  25. },
  26. // 未登录
  27. loginCheckFailInfo: {
  28. code: 10005,
  29. message: '您尚未登录'
  30. },
  31. // 修改密码失败
  32. changePasswordFailInfo: {
  33. code: 10006,
  34. message: '修改密码失败,请重试'
  35. },
  36. // 用户信息失败
  37. getUserInfoFailInfo: {
  38. code: 10007,
  39. message: '用户信息获取失败 token验证无效'
  40. },
  41. getUserListFailInfo: {
  42. code: 10008,
  43. message: '用户列表获取失败, 请重试'
  44. },
  45. editUserInfoFailInfo: {
  46. code: 10009,
  47. message: '用户信息修改失败, 请重试'
  48. },
  49. deleteUserInfoFailInfo: {
  50. code: 10010,
  51. message: '用户删除失败, 请重试'
  52. },
  53. updateUserRoleFailInfo: {
  54. code: 10011,
  55. message: '用户角色修改失败,请重试'
  56. },
  57. addAccessFailInfo: {
  58. code: 10012,
  59. message: '菜单添加失败'
  60. },
  61. getAccessAllFailInfo: {
  62. code: 10013,
  63. message: '获取全部菜单失败'
  64. },
  65. removeAccessFailInfo: {
  66. code: 10014,
  67. message: '删除菜单失败'
  68. },
  69. updateAccessFailInfo: {
  70. code: 10015,
  71. message: '编辑菜单失败'
  72. },
  73. addRoleFailInfo: {
  74. code: 10016,
  75. message: '添加角色失败'
  76. },
  77. addRoleNameExistInfo: {
  78. code: 10017,
  79. message: '角色已存在, 不能重复添加'
  80. },
  81. updateRoleFailInfo: {
  82. code: 10018,
  83. message: '编辑角色失败'
  84. },
  85. updateRoleNameExistInfo: {
  86. code: 10019,
  87. message: '编辑失败,已存在同名角色'
  88. },
  89. removeRoleFailInfo: {
  90. code: 10020,
  91. message: '角色删除失败'
  92. },
  93. allocRoleAccessFailInfo: {
  94. code: 10021,
  95. message: '角色分配权限失败'
  96. },
  97. getRoleAccessFailInfo: {
  98. code: 10022,
  99. message: '根据角色获取权限失败'
  100. },
  101. updateUserExistFailInfo: {
  102. code: 10023,
  103. message: '用户信息修改失败,已存在同名用户'
  104. },
  105. allocUserRoleFailInfo: {
  106. code: 10024,
  107. message: '用户角色分配失败'
  108. },
  109. accountForbiddenFailInfo: {
  110. code: 10027,
  111. message: '登录失败,账号已被禁用!'
  112. }
  113. }

目前最新参考源码

https://gitee.com/brolly/vue3-admin-server