import { Provide, Inject } from "@midwayjs/core"; import { InjectRepository } from "@midwayjs/sequelize"; import { Repository } from "sequelize-typescript"; import { Op, UniqueConstraintError } from "sequelize"; import { Context } from "@midwayjs/koa"; import ProjectPlan from "../entity/project_plan.entity"; import ProjectPlanDetail from "../entity/project_plan_detail.entity"; import Customer from "../entity/customer.entity"; import SysUserRole from "../entity/sysUserRole.entity"; import SysRole from "../entity/sysRole.entity"; import { LogService } from "./log.service"; @Provide() export class ProjectPlanService { @InjectRepository(ProjectPlan) planModel!: Repository; @InjectRepository(ProjectPlanDetail) detailModel!: Repository; @InjectRepository(Customer) customerModel!: Repository; @InjectRepository(SysUserRole) userRoleModel!: Repository; @InjectRepository(SysRole) roleModel!: Repository; @Inject() logService!: LogService; private async isAdmin(userId: number): Promise { const userRoles = await this.userRoleModel.findAll({ where: { userId }, include: [this.roleModel] }); return userRoles.some((ur) => (ur as any).role?.roleCode === "ADMIN"); } private async isCustomerOwner(userId: number, customerId: number): Promise { if (await this.isAdmin(userId)) return true; const customer = await this.customerModel.findByPk(customerId); return !!customer && customer.salesmanId === userId; } private async generatePlanNo(retry: number = 0): Promise { 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 = `FA${yyyymmdd}`; const last = await this.planModel.findOne({ where: { planNo: { [Op.like]: `${prefix}%` } }, order: [["plan_no", "DESC"]] }); let seq = 1; if (last) seq = (parseInt(last.planNo.slice(-3), 10) || 0) + 1; const result = `${prefix}${String(seq).padStart(3, "0")}`; const exists = await this.planModel.findOne({ where: { planNo: result } }); if (exists) { if (retry < 1) return this.generatePlanNo(retry + 1); throw new Error("方案单号生成冲突,请重试"); } return result; } async list(query: any, ctx: Context): Promise { const page = Number(query.page) || 1; const pageSize = Number(query.pageSize) || 10; const userId = ctx.state.user.userId; const where: any = {}; if (query.keyword) { where[Op.or] = [ { planNo: { [Op.like]: `%${query.keyword}%` } }, { registrar: { [Op.like]: `%${query.keyword}%` } }, { planDesc: { [Op.like]: `%${query.keyword}%` } } ]; } if (query.customerId !== undefined) where.customerId = query.customerId; if (query.status !== undefined) where.status = query.status; if (query.registerStartDate || query.registerEndDate) { where.registerTime = {}; if (query.registerStartDate) where.registerTime[Op.gte] = query.registerStartDate; if (query.registerEndDate) where.registerTime[Op.lte] = query.registerEndDate; } if (!(await this.isAdmin(userId))) { const myCustomers = await this.customerModel.findAll({ where: { salesmanId: userId }, attributes: ["id"] }); const ids = myCustomers.map((c) => c.id); if (ids.length === 0) return { code: 200, message: "获取项目方案列表成功", data: { list: [], total: 0, page: Number(page), pageSize: Number(pageSize) } }; if (where.customerId !== undefined) { if (!ids.includes(where.customerId)) return { code: 200, message: "获取项目方案列表成功", data: { list: [], total: 0, page: Number(page), pageSize: Number(pageSize) } }; } else { where.customerId = { [Op.in]: ids }; } } const { count, rows } = await this.planModel.findAndCountAll({ where, limit: pageSize, offset: (page - 1) * pageSize, order: [["created_at", "DESC"]] }); return { code: 200, message: "获取项目方案列表成功", data: { list: rows.map((r) => r.toJSON()), total: count, page: Number(page), pageSize: Number(pageSize) } }; } async detail(id: number, ctx: Context): Promise { const record = await this.planModel.findByPk(id, { include: [this.detailModel] }); if (!record) return { code: 404, message: "项目方案不存在", data: null }; if (!(await this.isCustomerOwner(ctx.state.user.userId, record.customerId))) return { code: 403, message: "无权限访问该方案", data: null }; return { code: 200, message: "获取项目方案详情成功", data: record.toJSON() }; } async create(data: any, ctx: Context): Promise { if (!(await this.isCustomerOwner(ctx.state.user.userId, data.customerId))) return { code: 403, message: "无权限为该客户创建方案", data: null }; const details = data.details || []; delete data.details; try { data.planNo = await this.generatePlanNo(); const created = await this.planModel.create(data); if (details.length > 0) { await this.detailModel.bulkCreate(details.map((d: any) => ({ ...d, planId: created.id, customerId: created.customerId }))); } const result = await this.planModel.findByPk(created.id, { include: [this.detailModel] }); await this.logService.logAction(ctx, "项目方案", "创建", data.planNo, `创建项目方案 ${data.planNo}`); return { code: 200, message: "创建项目方案成功", data: result?.toJSON() }; } catch (err: any) { if (err instanceof UniqueConstraintError) { data.planNo = await this.generatePlanNo(); const created = await this.planModel.create(data); if (details.length > 0) { await this.detailModel.bulkCreate(details.map((d: any) => ({ ...d, planId: created.id, customerId: created.customerId }))); } const result = await this.planModel.findByPk(created.id, { include: [this.detailModel] }); return { code: 200, message: "创建项目方案成功", data: result?.toJSON() }; } throw err; } } async update(id: number, data: any, ctx: Context): Promise { const record = await this.planModel.findByPk(id); if (!record) return { code: 404, message: "项目方案不存在", data: null }; if (!(await this.isAdmin(ctx.state.user.userId))) { if (!(await this.isCustomerOwner(ctx.state.user.userId, record.customerId))) return { code: 403, message: "无权限修改该方案", data: null }; delete data.customerId; } const details = data.details; delete data.details; delete data.planNo; await record.update(data); if (details && Array.isArray(details)) { await this.detailModel.destroy({ where: { planId: id } }); if (details.length > 0) { await this.detailModel.bulkCreate(details.map((d: any) => ({ ...d, planId: id, customerId: record.customerId }))); } } const result = await this.planModel.findByPk(id, { include: [this.detailModel] }); await this.logService.logAction(ctx, "项目方案", "更新", record.planNo, `更新项目方案 ${record.planNo}`); return { code: 200, message: "更新项目方案成功", data: result?.toJSON() }; } async delete(id: number, ctx: Context): Promise { const record = await this.planModel.findByPk(id); if (!record) return { code: 404, message: "项目方案不存在", data: null }; if (!(await this.isCustomerOwner(ctx.state.user.userId, record.customerId))) return { code: 403, message: "无权限删除该方案", data: null }; const planNo = record.planNo; await this.detailModel.destroy({ where: { planId: id } }); await record.destroy(); await this.logService.logAction(ctx, "项目方案", "删除", planNo, `删除项目方案 ${planNo}`); return { code: 200, message: "删除项目方案成功", data: null }; } async findOptions(customerId: number): Promise { const where: any = {}; if (customerId) where.customerId = customerId; const records = await this.planModel.findAll({ where, order: [["created_at", "DESC"]] }); return { code: 200, message: "获取项目方案选项成功", data: records.map((r) => r.toJSON()) }; } }