Эх сурвалжийг харах

添加系统配置模块,包括控制器、服务、路由和数据传输对象,支持创建、更新、删除和查询系统配置。更新package.json以引入decimal.js库。

wuyi 4 сар өмнө
parent
commit
27a1a3195e

+ 1 - 0
package.json

@@ -22,6 +22,7 @@
     "bcryptjs": "^3.0.2",
     "class-transformer": "^0.5.1",
     "class-validator": "^0.14.1",
+    "decimal.js": "^10.6.0",
     "dotenv": "^16.4.7",
     "fastify": "^5.2.2",
     "mysql2": "^3.14.0",

+ 2 - 0
src/app.ts

@@ -10,6 +10,7 @@ import { schema } from './config/env'
 import { createDataSource } from './config/database'
 import userRoutes from './routes/user.routes'
 import fileRoutes from './routes/file.routes'
+import sysConfigRoutes from './routes/sys-config.routes'
 
 const options: FastifyEnvOptions = {
   schema: schema,
@@ -75,6 +76,7 @@ export const createApp = async () => {
 
   app.register(userRoutes, { prefix: '/api/users' })
   app.register(fileRoutes, { prefix: '/api/files' })
+  app.register(sysConfigRoutes, { prefix: '/api/sys-config' })
 
   const dataSource = createDataSource(app)
   await dataSource.initialize()

+ 70 - 0
src/controllers/sys-config.controller.ts

@@ -0,0 +1,70 @@
+import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify'
+import { SysConfigService } from '../services/sys-config.service'
+import { CreateSysConfigBody } from '../dto/sys-config.dto'
+import { UpdateSysConfigBody } from '../dto/sys-config.dto'
+import { ListSysConfigQuery } from '../dto/sys-config.dto'
+
+export class SysConfigController {
+  private sysConfigService: SysConfigService
+
+  constructor(app: FastifyInstance) {
+    this.sysConfigService = new SysConfigService(app)
+  }
+
+  async create(request: FastifyRequest<{ Body: CreateSysConfigBody }>, reply: FastifyReply) {
+    try {
+      const { name } = request.body
+
+      const config = await this.sysConfigService.create(request.body)
+      return reply.code(201).send(config)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async update(request: FastifyRequest<{ Params: { name: string }, Body: UpdateSysConfigBody }>, reply: FastifyReply) {
+    try {
+      const config = await this.sysConfigService.update(request.params.name, request.body)
+      return reply.send(config)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async delete(request: FastifyRequest<{ Params: { name: string } }>, reply: FastifyReply) {
+    try {
+      await this.sysConfigService.delete(request.params.name)
+      return reply.send({ success: true })
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async getByName(request: FastifyRequest<{ Params: { name: string } }>, reply: FastifyReply) {
+    try {
+      const config = await this.sysConfigService.getSysConfig(request.params.name)
+      return reply.send(config)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async list(request: FastifyRequest<{ Querystring: ListSysConfigQuery }>, reply: FastifyReply) {
+    try {
+      const { page = 0, size = 20, name, type } = request.query
+      const configs = await this.sysConfigService.list(Number(page), Number(size), name, type)
+      return reply.send(configs)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async getConfigTypes(request: FastifyRequest, reply: FastifyReply) {
+    try {
+      const types = await this.sysConfigService.getConfigTypes()
+      return reply.send(types)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+} 

+ 25 - 0
src/dto/sys-config.dto.ts

@@ -0,0 +1,25 @@
+import { ConfigType } from '../entities/sys-config.entity'
+
+export interface CreateSysConfigBody {
+  name: string
+  value: string
+  remark?: string
+  type?: ConfigType
+}
+
+export interface UpdateSysConfigBody {
+  value: string
+  remark?: string
+  type?: ConfigType
+}
+
+export interface ListSysConfigQuery {
+  page?: number
+  size?: number
+  name?: string
+  type?: ConfigType
+}
+
+export interface GetSysConfigParams {
+  name: string
+} 

+ 30 - 0
src/entities/sys-config.entity.ts

@@ -0,0 +1,30 @@
+import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
+
+export enum ConfigType {
+  String = 'string',
+  Date = 'date',
+  Number = 'number',
+  Boolean = 'boolean',
+  Object = 'object',
+  File = 'file',
+  TimeRange = 'time_range',
+  Range = 'range'
+}
+
+@Entity()
+export class SysConfig {
+  @PrimaryGeneratedColumn()
+  id: number
+
+  @Column({ length: 100, unique: true })
+  name: string
+
+  @Column({ type: 'text' })
+  value: string
+
+  @Column({ nullable: true })
+  public remark: string
+
+  @Column({ default: ConfigType.String })
+  public type: ConfigType
+}

+ 39 - 0
src/routes/sys-config.routes.ts

@@ -0,0 +1,39 @@
+import { FastifyInstance } from 'fastify'
+import { authenticate, hasRole } from '../middlewares/auth.middleware'
+import { UserRole } from '../entities/user.entity'
+import { SysConfigController } from '../controllers/sys-config.controller'
+import { CreateSysConfigBody } from '../dto/sys-config.dto'
+import { UpdateSysConfigBody } from '../dto/sys-config.dto'
+import { ListSysConfigQuery } from '../dto/sys-config.dto'
+
+export default async function sysConfigRoutes(fastify: FastifyInstance) {
+  const sysConfigController = new SysConfigController(fastify)
+
+  fastify.post<{ Body: CreateSysConfigBody }>(
+    '/',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    sysConfigController.create.bind(sysConfigController)
+  )
+
+  fastify.post<{ Params: { name: string }; Body: UpdateSysConfigBody }>(
+    '/update/:name',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    sysConfigController.update.bind(sysConfigController)
+  )
+
+  fastify.post<{ Params: { name: string } }>(
+    '/delete/:name',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    sysConfigController.delete.bind(sysConfigController)
+  )
+
+  fastify.get<{ Params: { name: string } }>('/:name', sysConfigController.getByName.bind(sysConfigController))
+
+  fastify.get<{ Querystring: ListSysConfigQuery }>(
+    '/',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    sysConfigController.list.bind(sysConfigController)
+  )
+
+  fastify.get('/types/all', { onRequest: [authenticate] }, sysConfigController.getConfigTypes.bind(sysConfigController))
+}

+ 129 - 0
src/services/sys-config.service.ts

@@ -0,0 +1,129 @@
+import { FastifyInstance } from 'fastify'
+import { Like, Repository, Not } from 'typeorm'
+import Decimal from 'decimal.js'
+import { SysConfig } from '../entities/sys-config.entity'
+import { CreateSysConfigBody } from '../dto/sys-config.dto'
+import { UpdateSysConfigBody } from '../dto/sys-config.dto'
+import { ConfigType } from '../entities/sys-config.entity'
+
+export class SysConfigService {
+  private app: FastifyInstance
+  private sysConfigRepository: Repository<SysConfig>
+
+  constructor(app: FastifyInstance) {
+    this.app = app
+    this.sysConfigRepository = app.dataSource.getRepository(SysConfig)
+  }
+
+  async getSysConfig(name: string) {
+    const sysConfig = await this.sysConfigRepository.findOneOrFail({ where: { name } })
+    return sysConfig
+  }
+
+  async maxTransferAmount(defaultAmount: Decimal) {
+    const sysConfig = await this.sysConfigRepository.findOne({ where: { name: 'max_transfer_amount' } })
+    if (sysConfig) {
+      return new Decimal(sysConfig.value)
+    }
+    await this.sysConfigRepository.save({ name: 'max_transfer_amount', value: defaultAmount.toString() })
+    return defaultAmount
+  }
+
+  async replaceType(defaultValue: number) {
+    try {
+      const sysConfig = await this.sysConfigRepository.findOne({ where: { name: 'replace_type' } })
+      if (sysConfig) {
+        return Number(sysConfig.value)
+      }
+      await this.sysConfigRepository.save({ name: 'replace_type', value: defaultValue.toString() })
+    } catch (e) {
+      this.app.log.error(e, 'get replaceType error')
+    }
+    return defaultValue
+  }
+
+  async getSensitiveWords() {
+    try {
+      const config = await this.sysConfigRepository.findOne({ where: { name: 'sensitive_words' } })
+      if (config) {
+        return { value: config.value }
+      }
+    } catch (e) {
+      this.app.log.error(e, 'get sensitiveWords error')
+    }
+    return null
+  }
+
+  async updateSensitiveWords(words: string) {
+    try {
+      const config = await this.sysConfigRepository.findOne({ where: { name: 'sensitive_words' } })
+      if (config) {
+        config.value = words
+        const sysConfig = await this.sysConfigRepository.save(config)
+        return {
+          value: sysConfig.value
+        }
+      }
+      await this.sysConfigRepository.save({ name: 'sensitive_words', value: words })
+    } catch (e) {
+      this.app.log.error(e, 'update sensitiveWords error')
+    }
+  }
+
+  async create(data: CreateSysConfigBody) {
+    const existingConfig = await this.sysConfigRepository.findOne({ where: { name: data.name } })
+    if (existingConfig) {
+      throw new Error('配置名称已存在')
+    }
+    const config = this.sysConfigRepository.create(data)
+    return await this.sysConfigRepository.save(config)
+  }
+
+  async update(name: string, data: UpdateSysConfigBody) {
+    const config = await this.getSysConfig(name)
+    Object.assign(config, data)
+    return await this.sysConfigRepository.save(config)
+  }
+
+  async delete(name: string) {
+    const config = await this.getSysConfig(name)
+    return await this.sysConfigRepository.remove(config)
+  }
+
+  async list(page: number = 0, size: number = 20, name?: string, type?: ConfigType) {
+    const where: any = {
+      name: Not('sensitive_words')
+    }
+
+    if (name) {
+      where.name = Like(`%${name}%`)
+    }
+
+    if (type) {
+      where.type = type
+    }
+
+    const [data, total] = await this.sysConfigRepository.findAndCount({
+      where,
+      skip: page * size,
+      take: size,
+      order: {
+        id: 'ASC'
+      }
+    })
+
+    return {
+      data,
+      meta: {
+        page,
+        size,
+        total,
+        totalPages: Math.ceil(total / size)
+      }
+    }
+  }
+
+  async getConfigTypes() {
+    return Object.values(ConfigType)
+  }
+}

+ 5 - 0
yarn.lock

@@ -971,6 +971,11 @@ debug@^4.1.1, debug@^4.3.4:
   dependencies:
     ms "^2.1.3"
 
+decimal.js@^10.6.0:
+  version "10.6.0"
+  resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a"
+  integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==
+
 default-user-agent@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmmirror.com/default-user-agent/-/default-user-agent-1.0.0.tgz"