Files
smart_grid_iot/server/src/service/dispatch_price.service.ts
T
andyesfly f4454ad014 feat: 新增电工APP端与定时任务管理功能
- 新增电工APP独立鉴权中间件与登录注册接口
- 新增定时任务管理模块,支持任务配置、执行日志与手动触发
- 新增运维费定价与电工派单成本价目管理
- 新增电工资质证照管理与到期提醒定时任务
- 完善数据库实体与DTO校验,优化权限控制
2026-10-02 16:08:00 +08:00

135 lines
5.3 KiB
TypeScript

import { Provide } from "@midwayjs/core";
import { InjectRepository } from "@midwayjs/sequelize";
import { Repository } from "sequelize-typescript";
import { Op, UniqueConstraintError } from "sequelize";
import { Context } from "@midwayjs/koa";
import DispatchPrice from "../entity/dispatch_price.entity";
// 创建/更新可写入字段白名单(priceCode 只读,服务端生成)
const WRITABLE_FIELDS = ["dispatchType", "priceType", "priceMode", "unitPrice", "unit", "status", "remark"];
// 计价方式 → 默认单位兜底
const MODE_UNIT: Record<number, string> = { 1: "次", 2: "小时" };
@Provide()
export class DispatchPriceService {
@InjectRepository(DispatchPrice)
dispatchPriceModel!: Repository<DispatchPrice>;
// 价格编码规则:DG + 东八区 yyyymmdd + 3 位序号(当日已有记录数 +1),唯一冲突时递增重试 1 次
private async generatePriceCode(): Promise<string> {
const now = new Date();
const d = new Date(now.getTime() + 8 * 60 * 60 * 1000);
const yyyymmdd = `${d.getUTCFullYear()}${String(d.getUTCMonth() + 1).padStart(2, "0")}${String(d.getUTCDate()).padStart(2, "0")}`;
const prefix = `DG${yyyymmdd}`;
const count = await this.dispatchPriceModel.count({ where: { priceCode: { [Op.like]: `${prefix}%` } } });
let seq = count + 1;
for (let i = 0; i <= 1; i++) {
const code = `${prefix}${String(seq).padStart(3, "0")}`;
const exists = await this.dispatchPriceModel.findOne({ where: { priceCode: code } });
if (!exists) return code;
seq++;
}
throw new Error("价格编码生成冲突,请重试");
}
// 仅保留白名单字段
private pickWritable(data: any): any {
const payload: any = {};
for (const key of WRITABLE_FIELDS) {
if (data[key] !== undefined) payload[key] = data[key];
}
return payload;
}
async list(query: any, ctx: Context): Promise<any> {
const page = Number(query.page) || 1;
const pageSize = Math.min(Number(query.pageSize) || 10, 200);
const where: any = {};
if (query.keyword) {
where.priceCode = { [Op.like]: `%${query.keyword}%` };
}
if (query.dispatchType !== undefined && query.dispatchType !== "") where.dispatchType = query.dispatchType;
if (query.priceMode !== undefined && query.priceMode !== "") where.priceMode = Number(query.priceMode);
if (query.status !== undefined && query.status !== "") where.status = Number(query.status);
const { count, rows } = await this.dispatchPriceModel.findAndCountAll({
where,
limit: pageSize,
offset: (page - 1) * pageSize,
order: [["id", "DESC"]]
});
return {
code: 200,
message: "获取派单成本价目列表成功",
data: { list: rows.map((r) => r.toJSON()), total: count, page: Number(page), pageSize: Number(pageSize) }
};
}
async detail(id: number): Promise<any> {
const record = await this.dispatchPriceModel.findByPk(id);
if (!record) return { code: 404, message: "价目不存在", data: null };
return { code: 200, message: "获取派单成本价目详情成功", data: record.toJSON() };
}
async create(data: any, ctx: Context): Promise<any> {
if (!data.dispatchType) return { code: 400, message: "派单类型不能为空", data: null };
if (data.unitPrice === undefined || data.unitPrice === null || data.unitPrice === "") {
return { code: 400, message: "单价不能为空", data: null };
}
const payload = this.pickWritable(data);
if (payload.priceMode === undefined || payload.priceMode === null) payload.priceMode = 1;
if (payload.status === undefined || payload.status === null) payload.status = 1;
if (!payload.unit) payload.unit = MODE_UNIT[Number(payload.priceMode)] || "次";
try {
payload.priceCode = await this.generatePriceCode();
const created = await this.dispatchPriceModel.create(payload);
return { code: 200, message: "创建派单成本价目成功", data: created.toJSON() };
} catch (err: any) {
// 唯一冲突:重新生成编码后重试 1 次
if (err instanceof UniqueConstraintError) {
try {
payload.priceCode = await this.generatePriceCode();
const created = await this.dispatchPriceModel.create(payload);
return { code: 200, message: "创建派单成本价目成功", data: created.toJSON() };
} catch (_e) {
return { code: 400, message: "价格编码已存在", data: null };
}
}
throw err;
}
}
async update(id: number, data: any, ctx: Context): Promise<any> {
const record = await this.dispatchPriceModel.findByPk(id);
if (!record) return { code: 404, message: "价目不存在", data: null };
const payload = this.pickWritable(data);
await record.update(payload);
return { code: 200, message: "更新派单成本价目成功", data: record.toJSON() };
}
async delete(id: number, ctx: Context): Promise<any> {
const record = await this.dispatchPriceModel.findByPk(id);
if (!record) return { code: 404, message: "价目不存在", data: null };
await record.destroy();
return { code: 200, message: "删除派单成本价目成功", data: null };
}
async updateStatus(id: number, status: number, ctx: Context): Promise<any> {
if (status !== 0 && status !== 1) return { code: 400, message: "状态值非法", data: null };
const record = await this.dispatchPriceModel.findByPk(id);
if (!record) return { code: 404, message: "价目不存在", data: null };
await record.update({ status });
return { code: 200, message: "更新派单成本价目状态成功", data: null };
}
}