feat: Enhance packaging and work instruction functionality

- Updated SQL queries in the packaging and work instruction controllers to include additional fields such as `inventory_unit` and `material`, improving data retrieval for packaging items.
- Implemented new columns in the `work_instruction_detail` table for better tracking of item schedules, equipment, and personnel involved in work instructions.
- Enhanced frontend components to utilize the new data structure, including category options for inventory units and materials, improving user experience in the packaging and subcontractor item pages.
- Refactored item inspection display logic to format pass criteria more clearly, enhancing readability for inspection data.
This commit is contained in:
kjs
2026-04-22 14:49:40 +09:00
parent af6c309a46
commit d9ced89a95
30 changed files with 1079 additions and 182 deletions

View File

@@ -175,7 +175,7 @@ export async function getPkgUnitItems(
const pool = getPool();
const result = await pool.query(
`SELECT pui.*, ii.item_name, ii.size AS spec, ii.unit
`SELECT pui.*, ii.item_name, ii.size AS spec, ii.unit, ii.inventory_unit, ii.material
FROM pkg_unit_item pui
LEFT JOIN item_info ii ON pui.item_number = ii.item_number AND pui.company_code = ii.company_code
WHERE pui.pkg_code=$1 AND pui.company_code=$2
@@ -532,7 +532,7 @@ export async function getItemsByDivision(
}
const result = await pool.query(
`SELECT id, item_number, item_name, size, material, unit, division
`SELECT id, item_number, item_name, size, material, unit, inventory_unit, division
FROM item_info
WHERE ${conditions.join(" AND ")}
ORDER BY item_name`,
@@ -585,7 +585,7 @@ export async function getGeneralItems(
}
const result = await pool.query(
`SELECT id, item_number, item_name, size AS spec, material, unit, division
`SELECT id, item_number, item_name, size AS spec, material, unit, inventory_unit, division
FROM item_info
WHERE ${conditions.join(" AND ")}
ORDER BY item_name

View File

@@ -7,13 +7,19 @@ import { getPool } from "../database/db";
import { logger } from "../utils/logger";
import { numberingRuleService } from "../services/numberingRuleService";
// 자동 마이그레이션: work_instruction_detail에 routing_version_id 컬럼 추가
// 자동 마이그레이션: work_instruction_detail에 routing_version_id + 품목별 일정/설비/작업조/작업자 컬럼 추가
let _migrationDone = false;
async function ensureDetailRoutingColumn() {
if (_migrationDone) return;
try {
const pool = getPool();
await pool.query("ALTER TABLE work_instruction_detail ADD COLUMN IF NOT EXISTS routing_version_id VARCHAR(500)");
// 품목별 일정/설비/작업조/작업자 컬럼 (옵션 A — 다중선택 지원)
await pool.query("ALTER TABLE work_instruction_detail ADD COLUMN IF NOT EXISTS start_date VARCHAR(500)");
await pool.query("ALTER TABLE work_instruction_detail ADD COLUMN IF NOT EXISTS end_date VARCHAR(500)");
await pool.query("ALTER TABLE work_instruction_detail ADD COLUMN IF NOT EXISTS equipment_ids VARCHAR(1000)");
await pool.query("ALTER TABLE work_instruction_detail ADD COLUMN IF NOT EXISTS work_teams VARCHAR(200)");
await pool.query("ALTER TABLE work_instruction_detail ADD COLUMN IF NOT EXISTS workers VARCHAR(1000)");
_migrationDone = true;
} catch { /* 이미 존재하거나 권한 문제 시 무시 */ }
}
@@ -130,6 +136,11 @@ export async function getList(req: AuthenticatedRequest, res: Response) {
d.source_table,
d.source_id,
d.routing_version_id AS detail_routing_version_id,
d.start_date AS detail_start_date,
d.end_date AS detail_end_date,
d.equipment_ids AS detail_equipment_ids,
d.work_teams AS detail_work_teams,
d.workers AS detail_workers,
COALESCE(itm.item_name, '') AS item_name,
COALESCE(itm.type, '') AS item_type,
COALESCE(itm.size, '') AS item_spec,
@@ -186,6 +197,11 @@ export async function getList(req: AuthenticatedRequest, res: Response) {
d.source_table,
d.source_id,
d.routing_version_id AS detail_routing_version_id,
d.start_date AS detail_start_date,
d.end_date AS detail_end_date,
d.equipment_ids AS detail_equipment_ids,
d.work_teams AS detail_work_teams,
d.workers AS detail_workers,
COALESCE(itm.item_name, '') AS item_name,
COALESCE(itm.type, '') AS item_type,
COALESCE(itm.size, '') AS item_spec,
@@ -293,8 +309,25 @@ export async function save(req: AuthenticatedRequest, res: Response) {
if (!firstRouting && itemRouting) firstRouting = itemRouting;
totalQty += Number(item.qty || 0);
await client.query(
`INSERT INTO work_instruction_detail (id,company_code,work_instruction_no,work_instruction_id,item_number,qty,remark,source_table,source_id,part_code,routing_version_id,created_date,writer) VALUES (gen_random_uuid()::text,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,NOW(),$11)`,
[companyCode, wiNo, wiId, item.itemNumber||item.itemCode||"", item.qty||"0", item.remark||"", item.sourceTable||"", item.sourceId||"", item.partCode||item.itemNumber||item.itemCode||"", itemRouting, userId]
`INSERT INTO work_instruction_detail (id,company_code,work_instruction_no,work_instruction_id,item_number,qty,remark,source_table,source_id,part_code,routing_version_id,start_date,end_date,equipment_ids,work_teams,workers,created_date,writer) VALUES (gen_random_uuid()::text,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,NOW(),$16)`,
[
companyCode,
wiNo,
wiId,
item.itemNumber||item.itemCode||"",
item.qty||"0",
item.remark||"",
item.sourceTable||"",
item.sourceId||"",
item.partCode||item.itemNumber||item.itemCode||"",
itemRouting,
item.startDate||"",
item.endDate||"",
item.equipmentIds||"",
item.workTeams||"",
item.workers||"",
userId,
]
);
}