This commit is contained in:
Sergey Yarkov 2026-03-16 16:25:23 +03:00
parent c4831cd7bd
commit cde03d43a6
7 changed files with 121 additions and 31 deletions

13
models/base.model.js Normal file
View File

@ -0,0 +1,13 @@
/** @import sql from "mssql" */
export class BaseModel {
/**
* @template T
* @this {new (args: any) => T} Model
* @param {sql.IRecordSet<any>} recordset
* @returns {T[]}
*/
static fromRecordset(recordset) {
return recordset.map((row) => new this({ ...row }));
}
}

View File

@ -1,8 +1,10 @@
import { BaseModel } from "./base.model.js";
/** @import { ReportColumns } from "#tables/report.table.js" */ /** @import { ReportColumns } from "#tables/report.table.js" */
export class ReportModel { export class ReportModel extends BaseModel {
/** /**
* @type {ReportColumns['id'] | undefined} * @type {ReportColumns['id']}
*/ */
id; id;
@ -37,9 +39,11 @@ export class ReportModel {
equipment_id; equipment_id;
/** /**
* @param {Omit<ReportColumns, 'id'>} columns * @param {ReportColumns} columns
*/ */
constructor(columns) { constructor(columns) {
super();
this.id = columns.id;
this.date = columns.date; this.date = columns.date;
this.reason_call = columns.reason_call; this.reason_call = columns.reason_call;
this.job_description = columns.job_description; this.job_description = columns.job_description;

View File

@ -1,27 +1,33 @@
import sql from "mssql"; import sql from "mssql";
import db from "#root/db.js"; import db from "#root/db.js";
import { ReportModel } from "#models/index.js"; import { ReportModel } from "#models/index.js";
import { ReportTable } from "#tables/index.js"; import { ReportExecutorTable, ReportTable } from "#tables/index.js";
/** @import { ReportColumns } from "#tables/report.table.js" */ /** @import { ReportColumns } from "#tables/report.table.js" */
export const reportRepository = { export const reportRepository = {
async getAll() { async getAll() {
const request = new sql.Request(db); const request = new sql.Request(db);
console.log(ReportTable.tableName); const result = await request.query(`select * from dbo.${ReportTable.tableName};`);
const reports = ReportModel.fromRecordset(result.recordset);
const reports = await request.query(`select * from dbo.${ReportTable.tableName};`); return reports;
console.log(reports); },
return reports.recordset; async getLast() {
const request = new sql.Request(db);
const result = await request.query(`select top 1 * from ${ReportTable.tableName} order by id desc`);
const report = ReportModel.fromRecordset(result.recordset);
return report[0];
}, },
/** /**
* @param {Omit<ReportColumns, 'id'>} entry * @param {ReportColumns} entry
*/ */
async create(entry) { async create(entry) {
const report = new ReportModel(entry);
const request = new sql.Request(db); const request = new sql.Request(db);
const report = new ReportModel(entry);
request.input("date", ReportTable.getColumn("date"), report.date); request.input("date", ReportTable.getColumn("date"), report.date);
request.input("reasonCall", ReportTable.getColumn("reason_call"), report.reason_call); request.input("reasonCall", ReportTable.getColumn("reason_call"), report.reason_call);
@ -44,18 +50,45 @@ export const reportRepository = {
}, },
/** /**
* @param {Omit<ReportColumns, 'id'>[]} entries * @param {Record<string | number, Array<string | number>>} links
* @param {sql.Transaction} [trx]
*/
async attachExecutors(links, trx) {
const request = trx ? new sql.Request(trx) : new sql.Request(db);
const table = ReportExecutorTable.createInstance();
for (const [rId, executorIds] of Object.entries(links)) {
executorIds.forEach((eId) => table.rows.add(rId, eId));
}
await request.bulk(table);
return table.rows.length;
},
/**
* @param {ReportColumns[]} entries
* @param {sql.Transaction} [trx] * @param {sql.Transaction} [trx]
*/ */
async bulk(entries, trx) { async bulk(entries, trx) {
const request = trx ? new sql.Request(trx) : new sql.Request(db); const request = trx ? new sql.Request(trx) : new sql.Request(db);
const table = ReportTable.createInstance(); const table = ReportTable.createInstance();
const lastReportId = (await this.getLast()).id;
let nextAddId = Number.parseInt(lastReportId, 10);
for (const r of entries) { for (const e of entries) {
table.rows.add(r.date, r.reason_call, r.job_description, r.root_cause, r.applicant_id, r.equipment_id); table.rows.add(
++nextAddId,
e.date,
e.reason_call,
e.job_description,
e.root_cause,
e.applicant_id,
e.equipment_id
);
} }
await request.bulk(table); const res = await request.bulk(table);
return table.rows.length;
return res.rowsAffected;
} }
}; };

View File

@ -3,7 +3,7 @@ import pLimit from "p-limit";
import db from "#root/db.js"; import db from "#root/db.js";
import mssql from "mssql"; import mssql from "mssql";
import { reportRepository } from "#repositories/index.js"; import { reportRepository } from "#repositories/index.js";
// import * as utilsDate from "#utils/date.js"; import * as utilsDate from "#utils/date.js";
/** @import { reportsSchema } from "#schemas/report.schema.js" */ /** @import { reportsSchema } from "#schemas/report.schema.js" */
/** @import { InferType } from "yup" */ /** @import { InferType } from "yup" */
@ -85,7 +85,7 @@ export const reportsService = {
*/ */
async checkReportLinks(report, cancelCondFn) { async checkReportLinks(report, cancelCondFn) {
const executorSurnames = extractSurnamesFromExecutorField(report.executorNames); const executorSurnames = extractSurnamesFromExecutorField(report.executorNames);
if (cancelCondFn()) return Promise.reject(); if (cancelCondFn()) return Promise.reject("Report check rejected");
const equipment = await db.request() const equipment = await db.request()
.query(`select t1.id, t1.name, t1.location_id, t3.name as base_location_name, t2.name as location_name, t2.base_location_id .query(`select t1.id, t1.name, t1.location_id, t3.name as base_location_name, t2.name as location_name, t2.base_location_id
@ -172,31 +172,50 @@ export const reportsService = {
}, },
/** /**
* @param {InferType<typeof reportsSchema>['reports']} reports * @param {InferType<typeof reportsSchema>['reports']} inReports
*/ */
async syncReportsWithDatabase(reports) { async syncReportsWithDatabase(inReports) {
const trx = new mssql.Transaction(db); const trx = new mssql.Transaction(db);
const dbReports = await reportRepository.getAll(); const reports = await reportRepository.getAll();
/** /**
* 1. проверить на существование дубликатов и отфильтровать
* 2. начать транзакцию на множественную вставку отчетов
* 3. установить связь добавленных отчетов с исполнителями и завершить транзакцию * 3. установить связь добавленных отчетов с исполнителями и завершить транзакцию
*/ */
/** Отфильтровывание дубликатов по полям. */
const filteredInReports = inReports.filter((inputR) => {
const isDub = reports.some((dbR) => {
return (
inputR.reason_call === dbR.reason_call &&
inputR.job_description === dbR.job_description &&
inputR.root_cause === dbR.root_cause &&
inputR.equipment?.id == dbR.equipment_id &&
inputR.applicant?.id == dbR.applicant_id
);
});
return !isDub;
});
if (filteredInReports.length === 0) return 0;
try { try {
await trx.begin(); await trx.begin();
const countRows = await reportRepository.bulk( const countRows = await reportRepository.bulk(
reports.map((r) => ({ filteredInReports.map((r) => {
applicant_id: r.applicant?.id || null, const reportDate = new Date(r.date || "");
equipment_id: r.equipment?.id || null, return {
date: new Date("2026"), applicant_id: r.applicant?.id || null,
job_description: r.job_description || "", equipment_id: r.equipment?.id || null,
reason_call: r.reason_call || "", date: utilsDate.isDateValid(reportDate) ? reportDate : new Date("2016-10-24"),
root_cause: r.root_cause || "" job_description: r.job_description || "",
})), reason_call: r.reason_call || "",
root_cause: r.root_cause || ""
};
}),
trx trx
); );
// filteredInReports.map((r) => ({ [r.]: "" }));
// await reportRepository.attachExecutors()
await trx.commit(); await trx.commit();
return countRows; return countRows;
} catch (error) { } catch (error) {

View File

@ -1 +1,2 @@
export * from "./report.table.js"; export * from "./report.table.js";
export * from "./reportExecutor.table.js";

View File

@ -2,7 +2,7 @@ import sql from "mssql";
import { BaseTable } from "./base.table.js"; import { BaseTable } from "./base.table.js";
/** /**
* @typedef {{ id: number; date: Date; reason_call: string; job_description: string; root_cause: string | null; applicant_id: number | null; equipment_id: number | null; }} ReportColumns * @typedef {{ id?: number | string; date: Date; reason_call: string; job_description: string; root_cause: string | null; applicant_id: number | string | null; equipment_id: number | string | null; }} ReportColumns
*/ */
export class ReportTable extends BaseTable { export class ReportTable extends BaseTable {
@ -10,6 +10,7 @@ export class ReportTable extends BaseTable {
static table = new sql.Table(this.tableName); static table = new sql.Table(this.tableName);
static columns = { static columns = {
id: { type: sql.BigInt, nullable: false },
date: { type: sql.Date, nullable: false }, date: { type: sql.Date, nullable: false },
reason_call: { type: sql.NVarChar(sql.MAX), nullable: false }, reason_call: { type: sql.NVarChar(sql.MAX), nullable: false },
job_description: { type: sql.NVarChar(sql.MAX), nullable: false }, job_description: { type: sql.NVarChar(sql.MAX), nullable: false },

View File

@ -0,0 +1,19 @@
import sql from "mssql";
import { BaseTable } from "./base.table.js";
/**
* @typedef {{ id: string | number; report_id: string | number; user_id: string | number; }} ReportExecutorTableCols
*/
export class ReportExecutorTable extends BaseTable {
static tableName = "gpp_report_api_report_executor";
static table = new sql.Table(this.tableName);
static columns = {
report_id: { type: sql.BigInt, nullable: false },
user_id: { type: sql.BigInt, nullable: false }
};
}
ReportExecutorTable.table.create = false;
ReportExecutorTable.init();