Merge branch 'main' of http://git.dibox.tech/parttime/smart_grid_iot
This commit is contained in:
commit
3596462eca
34 files changed
+2703
-93
No files matched your search
@@ -23,6 +23,16 @@ export default {
|
||||
port: 7001
|
||||
},
|
||||
|
||||
// 日志输出目录(显式指定到项目内 server/logs,避免写入用户主目录导致 EPERM 权限报错)
|
||||
logger: {
|
||||
dir: join(envDir, "logs"),
|
||||
appLogName: "midway-app.log",
|
||||
coreLogName: "midway-core.log",
|
||||
errorLogName: "common-error.log",
|
||||
enableError: true,
|
||||
maxFiles: "30d"
|
||||
},
|
||||
|
||||
sequelize: {
|
||||
dataSource: {
|
||||
default: {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Controller, Get, Post, Put, Del, Inject, Query, Body, Param } from "@midwayjs/core";
|
||||
import { Context } from "@midwayjs/koa";
|
||||
import { CustomerEquipmentService } from "../service/customer_equipment.service";
|
||||
|
||||
@Controller("/api/customer-equipments")
|
||||
export class CustomerEquipmentController {
|
||||
@Inject() ctx!: Context;
|
||||
@Inject() customerEquipmentService!: CustomerEquipmentService;
|
||||
|
||||
@Get("/") async list(@Query() query: any) { return this.customerEquipmentService.list(query, this.ctx); }
|
||||
@Get("/:id") async detail(@Param("id") id: string) { return this.customerEquipmentService.detail(Number(id), this.ctx); }
|
||||
@Post("/") async create(@Body() body: any) { return this.customerEquipmentService.create(body, this.ctx); }
|
||||
@Put("/:id") async update(@Param("id") id: string, @Body() body: any) { return this.customerEquipmentService.update(Number(id), body, this.ctx); }
|
||||
@Del("/:id") async delete(@Param("id") id: string) { return this.customerEquipmentService.delete(Number(id), this.ctx); }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Controller, Get, Post, Put, Del, Inject, Query, Body, Param } from "@midwayjs/core";
|
||||
import { Context } from "@midwayjs/koa";
|
||||
import { SmartDeviceService } from "../service/smart_device.service";
|
||||
|
||||
@Controller("/api/smart-devices")
|
||||
export class SmartDeviceController {
|
||||
@Inject() ctx!: Context;
|
||||
@Inject() smartDeviceService!: SmartDeviceService;
|
||||
|
||||
@Get("/") async list(@Query() query: any) { return this.smartDeviceService.list(query, this.ctx); }
|
||||
@Get("/:id") async detail(@Param("id") id: string) { return this.smartDeviceService.detail(Number(id), this.ctx); }
|
||||
@Post("/") async create(@Body() body: any) { return this.smartDeviceService.create(body, this.ctx); }
|
||||
@Put("/:id") async update(@Param("id") id: string, @Body() body: any) { return this.smartDeviceService.update(Number(id), body, this.ctx); }
|
||||
@Del("/:id") async delete(@Param("id") id: string) { return this.smartDeviceService.delete(Number(id), this.ctx); }
|
||||
}
|
||||
@@ -13,6 +13,7 @@ export class CustomerBuildingCreateDTO {
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) basicInfo?: string;
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) purpose?: string;
|
||||
@IsOptional() @IsInt() @Min(0) floorCount?: number;
|
||||
@IsOptional() @IsInt() @Min(0) floorDownCount?: number;
|
||||
}
|
||||
|
||||
export class CustomerBuildingUpdateDTO {
|
||||
@@ -21,4 +22,5 @@ export class CustomerBuildingUpdateDTO {
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) basicInfo?: string;
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) purpose?: string;
|
||||
@IsOptional() @IsInt() @Min(0) floorCount?: number;
|
||||
@IsOptional() @IsInt() @Min(0) floorDownCount?: number;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { IsNotEmpty, IsOptional, IsString, IsInt, Matches, Min, Max, MaxLength } from "class-validator";
|
||||
|
||||
export class CustomerEquipmentQueryDTO {
|
||||
@IsOptional() @IsInt() @Min(1) page?: number = 1;
|
||||
@IsOptional() @IsInt() @Min(1) @Max(200) pageSize?: number = 10;
|
||||
@IsOptional() @IsString() @MaxLength(64) keyword?: string;
|
||||
@IsOptional() @IsInt() customerId?: number;
|
||||
@IsOptional() @IsInt() buildingId?: number;
|
||||
@IsOptional() @IsString() @MaxLength(32) equipType?: string;
|
||||
}
|
||||
|
||||
export class CustomerEquipmentCreateDTO {
|
||||
@IsNotEmpty({ message: "所属客户不能为空" }) @IsInt() customerId!: number;
|
||||
@IsNotEmpty({ message: "设备名称不能为空" }) @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) equipName!: string;
|
||||
@IsOptional() @IsString() @MaxLength(32) @Matches(/^[^<>]*$/) equipType?: string;
|
||||
@IsOptional() @IsInt() buildingId?: number;
|
||||
@IsOptional() @IsString() @MaxLength(16) floorNo?: string;
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) location?: string;
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) description?: string;
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) remark?: string;
|
||||
@IsOptional() @IsString() @MaxLength(512) photoUrl?: string;
|
||||
}
|
||||
|
||||
export class CustomerEquipmentUpdateDTO {
|
||||
@IsOptional() @IsInt() customerId?: number;
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) equipName?: string;
|
||||
@IsOptional() @IsString() @MaxLength(32) @Matches(/^[^<>]*$/) equipType?: string;
|
||||
@IsOptional() @IsInt() buildingId?: number;
|
||||
@IsOptional() @IsString() @MaxLength(16) floorNo?: string;
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) location?: string;
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) description?: string;
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) remark?: string;
|
||||
@IsOptional() @IsString() @MaxLength(512) photoUrl?: string;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { IsNotEmpty, IsOptional, IsString, Matches, Min, Max, MaxLength } from "class-validator";
|
||||
|
||||
export class SmartDeviceQueryDTO {
|
||||
@IsOptional() @Min(1) page?: number = 1;
|
||||
@IsOptional() @Min(1) @Max(200) pageSize?: number = 10;
|
||||
@IsOptional() @IsString() @MaxLength(64) keyword?: string;
|
||||
@IsOptional() @IsString() @MaxLength(64) deviceType?: string;
|
||||
}
|
||||
|
||||
export class SmartDeviceCreateDTO {
|
||||
@IsNotEmpty({ message: "设备型号不能为空" }) @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) deviceModel!: string;
|
||||
@IsNotEmpty({ message: "设备名称不能为空" }) @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) deviceName!: string;
|
||||
@IsOptional() @IsString() @MaxLength(256) @Matches(/^[^<>]*$/) deviceSpec?: string;
|
||||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) deviceType?: string;
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) deviceFunction?: string;
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) supplier?: string;
|
||||
}
|
||||
|
||||
export class SmartDeviceUpdateDTO {
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) deviceModel?: string;
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) deviceName?: string;
|
||||
@IsOptional() @IsString() @MaxLength(256) @Matches(/^[^<>]*$/) deviceSpec?: string;
|
||||
@IsOptional() @IsString() @MaxLength(64) @Matches(/^[^<>]*$/) deviceType?: string;
|
||||
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) deviceFunction?: string;
|
||||
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) supplier?: string;
|
||||
}
|
||||
@@ -26,9 +26,12 @@ export default class CustomerBuilding extends Model {
|
||||
@Column({ type: DataType.STRING(128), comment: "用途" })
|
||||
purpose!: string;
|
||||
|
||||
@Column({ type: DataType.INTEGER, field: "floor_count", comment: "层数" })
|
||||
@Column({ type: DataType.INTEGER, field: "floor_count", comment: "地上楼层数" })
|
||||
floorCount!: number;
|
||||
|
||||
@Column({ type: DataType.INTEGER, field: "floordown_count", comment: "地下楼层数", defaultValue: 0 })
|
||||
floorDownCount!: number;
|
||||
|
||||
@BelongsTo(() => Customer)
|
||||
customer!: Customer;
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Column, Model, Table, DataType, CreatedAt, ForeignKey, BelongsTo } from "sequelize-typescript";
|
||||
import CustomerBuilding from "./customer_building.entity";
|
||||
|
||||
@Table({
|
||||
tableName: "customer_equipment",
|
||||
comment: "客户设备台账表",
|
||||
timestamps: false,
|
||||
indexes: [
|
||||
{ name: "idx_equip_customer", fields: ["customer_id"] },
|
||||
{ name: "idx_equip_building", fields: ["building_id"] },
|
||||
{ name: "uk_equip_code", unique: true, fields: ["equip_code"] }
|
||||
]
|
||||
})
|
||||
export default class CustomerEquipment extends Model {
|
||||
@Column({ type: DataType.BIGINT, autoIncrement: true, primaryKey: true })
|
||||
id!: number;
|
||||
|
||||
@Column({ type: DataType.STRING(64), allowNull: false, unique: true, field: "equip_code", comment: "设备编码(EQ+YYYYMMDD+序号)" })
|
||||
equipCode!: string;
|
||||
|
||||
@Column({ type: DataType.BIGINT, allowNull: false, field: "customer_id", comment: "客户ID" })
|
||||
customerId!: number;
|
||||
|
||||
@Column({ type: DataType.STRING(128), allowNull: false, field: "equip_name", comment: "设备名称" })
|
||||
equipName!: string;
|
||||
|
||||
@Column({ type: DataType.STRING(32), field: "equip_type", comment: "设备类型" })
|
||||
equipType!: string;
|
||||
|
||||
@ForeignKey(() => CustomerBuilding)
|
||||
@Column({ type: DataType.BIGINT, field: "building_id", comment: "所属建筑ID" })
|
||||
buildingId!: number;
|
||||
|
||||
@Column({ type: DataType.STRING(16), field: "floor_no", comment: "楼层" })
|
||||
floorNo!: string;
|
||||
|
||||
@Column({ type: DataType.STRING(128), comment: "安装位置" })
|
||||
location!: string;
|
||||
|
||||
@Column({ type: DataType.TEXT, comment: "设备描述" })
|
||||
description!: string;
|
||||
|
||||
@Column({ type: DataType.TEXT, comment: "备注" })
|
||||
remark!: string;
|
||||
|
||||
@Column({ type: DataType.STRING(512), field: "photo_url", comment: "设备照片URL" })
|
||||
photoUrl!: string;
|
||||
|
||||
@BelongsTo(() => CustomerBuilding, { foreignKey: "buildingId", as: "building" })
|
||||
building!: CustomerBuilding;
|
||||
|
||||
@CreatedAt
|
||||
created_at!: Date;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Column, Model, Table, DataType, CreatedAt } from "sequelize-typescript";
|
||||
|
||||
@Table({
|
||||
tableName: "smart_device",
|
||||
comment: "智电设备型号目录表",
|
||||
timestamps: false
|
||||
})
|
||||
export default class SmartDevice extends Model {
|
||||
@Column({ type: DataType.BIGINT, autoIncrement: true, primaryKey: true })
|
||||
id!: number;
|
||||
|
||||
@Column({ type: DataType.STRING(128), allowNull: false, unique: true, field: "device_model", comment: "设备型号" })
|
||||
deviceModel!: string;
|
||||
|
||||
@Column({ type: DataType.STRING(128), allowNull: false, field: "device_name", comment: "设备名称" })
|
||||
deviceName!: string;
|
||||
|
||||
@Column({ type: DataType.STRING(256), field: "device_spec", comment: "设备规格" })
|
||||
deviceSpec!: string;
|
||||
|
||||
@Column({ type: DataType.STRING(64), field: "device_type", comment: "设备类型" })
|
||||
deviceType!: string;
|
||||
|
||||
@Column({ type: DataType.TEXT, field: "device_function", comment: "设备功能说明" })
|
||||
deviceFunction!: string;
|
||||
|
||||
@Column({ type: DataType.STRING(128), comment: "供应商" })
|
||||
supplier!: string;
|
||||
|
||||
@CreatedAt
|
||||
created_at!: Date;
|
||||
}
|
||||
@@ -23,6 +23,8 @@ const PERMISSION_MAP: Record<string, string> = {
|
||||
"/api/upload": "customer:visit",
|
||||
"/api/customer-buildings": "customer:building",
|
||||
"/api/customer-rooms": "customer:room",
|
||||
"/api/customer-equipments": "device:list",
|
||||
"/api/smart-devices": "device:model",
|
||||
"/api/survey-orders": "project:survey",
|
||||
"/api/project-plans": "project:plan",
|
||||
"/api/contracts": "project:contract",
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
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 CustomerEquipment from "../entity/customer_equipment.entity";
|
||||
import Customer from "../entity/customer.entity";
|
||||
import CustomerBuilding from "../entity/customer_building.entity";
|
||||
import SysUserRole from "../entity/sysUserRole.entity";
|
||||
import SysRole from "../entity/sysRole.entity";
|
||||
|
||||
@Provide()
|
||||
export class CustomerEquipmentService {
|
||||
@InjectRepository(CustomerEquipment)
|
||||
equipmentModel!: Repository<CustomerEquipment>;
|
||||
|
||||
@InjectRepository(Customer)
|
||||
customerModel!: Repository<Customer>;
|
||||
|
||||
@InjectRepository(CustomerBuilding)
|
||||
buildingModel!: Repository<CustomerBuilding>;
|
||||
|
||||
@InjectRepository(SysUserRole)
|
||||
userRoleModel!: Repository<SysUserRole>;
|
||||
|
||||
@InjectRepository(SysRole)
|
||||
roleModel!: Repository<SysRole>;
|
||||
|
||||
private async isAdmin(userId: number): Promise<boolean> {
|
||||
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<boolean> {
|
||||
if (await this.isAdmin(userId)) return true;
|
||||
const customer = await this.customerModel.findByPk(customerId);
|
||||
return !!customer && customer.salesmanId === userId;
|
||||
}
|
||||
|
||||
private async generateEquipCode(retry: number = 0): Promise<string> {
|
||||
const now = new Date();
|
||||
const offsetMs = now.getTime() + 8 * 60 * 60 * 1000;
|
||||
const dateLocal = new Date(offsetMs);
|
||||
const yyyy = dateLocal.getUTCFullYear();
|
||||
const mm = String(dateLocal.getUTCMonth() + 1).padStart(2, "0");
|
||||
const dd = String(dateLocal.getUTCDate()).padStart(2, "0");
|
||||
const yyyymmdd = `${yyyy}${mm}${dd}`;
|
||||
|
||||
const lastRecord = await this.equipmentModel.findOne({
|
||||
where: { equipCode: { [Op.like]: `EQ${yyyymmdd}%` } },
|
||||
order: [["equip_code", "DESC"]]
|
||||
});
|
||||
|
||||
let newSeq = 1;
|
||||
if (lastRecord) {
|
||||
const lastNo = lastRecord.equipCode;
|
||||
const seqStr = lastNo.slice(-3);
|
||||
const seq = parseInt(seqStr, 10) || 0;
|
||||
newSeq = seq + 1;
|
||||
}
|
||||
|
||||
const newSeqStr = String(newSeq).padStart(3, "0");
|
||||
const result = `EQ${yyyymmdd}${newSeqStr}`;
|
||||
|
||||
const exists = await this.equipmentModel.findOne({ where: { equipCode: result } });
|
||||
if (exists) {
|
||||
if (retry < 1) {
|
||||
return this.generateEquipCode(retry + 1);
|
||||
}
|
||||
throw new Error("设备编码生成冲突,请重试");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async list(query: any, ctx: Context): Promise<any> {
|
||||
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] = [
|
||||
{ equipCode: { [Op.like]: `%${query.keyword}%` } },
|
||||
{ equipName: { [Op.like]: `%${query.keyword}%` } },
|
||||
{ equipType: { [Op.like]: `%${query.keyword}%` } },
|
||||
{ location: { [Op.like]: `%${query.keyword}%` } }
|
||||
];
|
||||
}
|
||||
if (query.customerId !== undefined) where.customerId = query.customerId;
|
||||
if (query.buildingId !== undefined) where.buildingId = query.buildingId;
|
||||
if (query.equipType) where.equipType = query.equipType;
|
||||
|
||||
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.equipmentModel.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<any> {
|
||||
const record = await this.equipmentModel.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 };
|
||||
return { code: 200, message: "获取客户设备详情成功", data: record.toJSON() };
|
||||
}
|
||||
|
||||
async create(data: any, ctx: Context): Promise<any> {
|
||||
if (!(await this.isCustomerOwner(ctx.state.user.userId, data.customerId))) return { code: 403, message: "无权限为该客户创建设备", data: null };
|
||||
|
||||
try {
|
||||
data.equipCode = await this.generateEquipCode();
|
||||
const created = await this.equipmentModel.create(data);
|
||||
return { code: 200, message: "创建客户设备成功", data: created.toJSON() };
|
||||
} catch (err: any) {
|
||||
if (err instanceof UniqueConstraintError && err.errors?.some((e) => e.path === "equip_code" || e.path === "uk_equip_code")) {
|
||||
try {
|
||||
const equipCode = await this.generateEquipCode();
|
||||
const created = await this.equipmentModel.create({ ...data, equipCode });
|
||||
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.equipmentModel.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;
|
||||
}
|
||||
|
||||
delete data.equipCode;
|
||||
delete data.createdAt;
|
||||
delete data.created_at;
|
||||
|
||||
try {
|
||||
await record.update(data);
|
||||
return { code: 200, message: "更新客户设备成功", data: record.toJSON() };
|
||||
} catch (err: any) {
|
||||
if (err instanceof UniqueConstraintError) {
|
||||
return { code: 400, message: "设备编码已存在", data: null };
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async delete(id: number, ctx: Context): Promise<any> {
|
||||
const record = await this.equipmentModel.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 };
|
||||
await record.destroy();
|
||||
return { code: 200, message: "删除客户设备成功", data: null };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
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 SmartDevice from "../entity/smart_device.entity";
|
||||
|
||||
@Provide()
|
||||
export class SmartDeviceService {
|
||||
@InjectRepository(SmartDevice)
|
||||
smartDeviceModel!: Repository<SmartDevice>;
|
||||
|
||||
async list(query: any, ctx: Context): Promise<any> {
|
||||
const page = Number(query.page) || 1;
|
||||
const pageSize = Number(query.pageSize) || 10;
|
||||
const where: any = {};
|
||||
|
||||
if (query.keyword) {
|
||||
where[Op.or] = [
|
||||
{ deviceModel: { [Op.like]: `%${query.keyword}%` } },
|
||||
{ deviceName: { [Op.like]: `%${query.keyword}%` } },
|
||||
{ supplier: { [Op.like]: `%${query.keyword}%` } }
|
||||
];
|
||||
}
|
||||
if (query.deviceType) where.deviceType = query.deviceType;
|
||||
|
||||
const { count, rows } = await this.smartDeviceModel.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<any> {
|
||||
const record = await this.smartDeviceModel.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> {
|
||||
try {
|
||||
const created = await this.smartDeviceModel.create(data);
|
||||
return { code: 200, message: "创建智电设备型号成功", data: created.toJSON() };
|
||||
} catch (err: any) {
|
||||
if (err instanceof UniqueConstraintError && err.errors?.some((e) => e.path === "device_model")) {
|
||||
return { code: 400, message: "设备型号已存在", data: null };
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async update(id: number, data: any, ctx: Context): Promise<any> {
|
||||
const record = await this.smartDeviceModel.findByPk(id);
|
||||
if (!record) return { code: 404, message: "智电设备型号不存在", data: null };
|
||||
|
||||
delete data.createdAt;
|
||||
delete data.created_at;
|
||||
|
||||
try {
|
||||
await record.update(data);
|
||||
return { code: 200, message: "更新智电设备型号成功", data: record.toJSON() };
|
||||
} catch (err: any) {
|
||||
if (err instanceof UniqueConstraintError && err.errors?.some((e) => e.path === "device_model")) {
|
||||
return { code: 400, message: "设备型号已存在", data: null };
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async delete(id: number, ctx: Context): Promise<any> {
|
||||
const record = await this.smartDeviceModel.findByPk(id);
|
||||
if (!record) return { code: 404, message: "智电设备型号不存在", data: null };
|
||||
await record.destroy();
|
||||
return { code: 200, message: "删除智电设备型号成功", data: null };
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2038,7 +2038,7 @@ create-require@^1.1.0:
|
||||
resolved "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
cron@3.5.0:
|
||||
cron@3.5.0, cron@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.npmmirror.com/cron/-/cron-3.5.0.tgz#e8caa384e998ed275e19598df4dbd0e8578c35d9"
|
||||
integrity sha512-0eYZqCnapmxYcV06uktql93wNWdlTmmBFP2iYz+JPVcQqlyFYcn1lFuIk4R54pkOmE7mcldTAPZv6X5XA4Q46A==
|
||||
|
||||
Reference in new issue
Block a user