- 新增电工APP独立鉴权中间件与登录注册接口 - 新增定时任务管理模块,支持任务配置、执行日志与手动触发 - 新增运维费定价与电工派单成本价目管理 - 新增电工资质证照管理与到期提醒定时任务 - 完善数据库实体与DTO校验,优化权限控制
135 lines
5.3 KiB
TypeScript
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 };
|
|
}
|
|
} |