import type { RowDataPacket } from 'mysql2'; import pool from '../../db.js'; import { mapFault, type RawFault } from './model.js'; // OneOS fault ledger: latest delivery first; do not reuse the active-asset WHERE clause. export const FAULT_SQL = `SELECT f.fault_level, f.fault_categories, f.solve_process, f.report_method, CAST(f.source_work_order_id AS CHAR) source_work_order_id, CAST(f.id AS CHAR) id, f.fault_code, f.plate_number, f.fault_desc, f.handling_status, DATE_FORMAT(f.fault_report_time, '%Y-%m-%d %H:%i:%s') reported_at, DATE_FORMAT(f.archived_at, '%Y-%m-%d %H:%i:%s') archived_at, DATE_FORMAT(f.deadline_at, '%Y-%m-%d %H:%i:%s') deadline_at, DATE_FORMAT(receipt.received_at, '%Y-%m-%d %H:%i:%s') received_at, CAST(vi.id AS CHAR) matched_vehicle_id, vi.operation_city, COALESCE(city.NAME, district.NAME) city_name, vi.registered_ownership subject, COALESCE(province.NAME, vi.province_name) province_name, vm.brand, vm.model model_name, vm.vehicle_type model_type, vi.body_color, vi.vehicle_source, vi.actual_ownership, vi.rental_company, vs.operation_status, vs.vehicle_status, lease.customer_name, lease.business_dept, lease.business_manager, CAST(COALESCE(contract.business_manager_id, vi.business_id) AS CHAR) manager_id, CAST(f.inspection_operator_id AS CHAR) handler_id, f.inspection_operator_name handler_name, f.inspection_operator_ids_json handler_ids, f.inspection_operator_names_json handler_names, CAST(wo.current_executor_user_id AS CHAR) work_id, wo.current_executor_name work_name, CAST(wo.current_executor_user_ids_json AS CHAR) work_ids, CAST(wo.current_executor_names_json AS CHAR) work_names FROM vehicle_fault_manage f LEFT JOIN ( SELECT fault_id, MIN(create_time) received_at FROM vehicle_fault_operation_log WHERE del_flag='0' AND action_code='SAVE_PROGRESS' AND COALESCE(TRIM(before_status), '') IN ('', '待处理', '待处置', '未处理') AND TRIM(after_status) IN ('处理中', '处置中', '处理') GROUP BY fault_id ) receipt ON receipt.fault_id=f.id LEFT JOIN vehicle_info vi ON vi.id=f.vehicle_id AND vi.del_flag='0' LEFT JOIN vehicle_model vm ON vm.id=vi.vehicle_model_id AND vm.del_flag='0' LEFT JOIN common_district province ON province.CODE=CONCAT(LEFT(vi.operation_city,2),'0000') COLLATE utf8mb4_unicode_ci AND province.STATUS='VALID' LEFT JOIN vehicle_status vs ON vs.id=( SELECT s.id FROM vehicle_status s WHERE s.vehicle_id=vi.id AND s.del_flag=0 ORDER BY s.update_time DESC, s.id DESC LIMIT 1 ) LEFT JOIN vehicle_lease_order_record lease ON lease.id=( SELECT r.id FROM vehicle_lease_order_record r WHERE r.vehicle_id=vi.id AND r.del_flag='0' ORDER BY r.last_delivery_time DESC, r.id DESC LIMIT 1 ) LEFT JOIN vehicle_lease_contract_info contract ON contract.id=lease.contract_id AND contract.del_flag='0' LEFT JOIN common_district district ON district.CODE=vi.operation_city COLLATE utf8mb4_unicode_ci AND district.STATUS='VALID' LEFT JOIN common_district city ON city.CODE=(CASE WHEN LEFT(vi.operation_city,2) IN ('11','12','31','50') THEN CONCAT(LEFT(vi.operation_city,2),'0000') ELSE CONCAT(LEFT(vi.operation_city,4),'00') END) COLLATE utf8mb4_unicode_ci AND city.STATUS='VALID' LEFT JOIN task_work_order wo ON wo.id=f.source_work_order_id AND wo.del_flag='0' WHERE f.del_flag='0' AND f.is_submit IN (0,1)`; export async function loadFaults() { const connection = await pool.getConnection(); try { await connection.query('START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY'); const [raw] = await connection.query({ sql: FAULT_SQL, timeout: 20000 }); const [users] = await connection.query({ sql: `SELECT CAST(user_id AS CHAR) id, nick_name name FROM \`ry-cloud\`.sys_user WHERE del_flag='0' AND status='0' AND (user_type IS NULL OR user_type='sys_user')`, timeout: 10000 }); const directory = new Map(users.map(row => [String(row.id), String(row.name || '').trim()])); // Defensive ID de-duplication keeps imperfect lookup tables from multiplying tickets. const rows = [...new Map(raw.map(row => [String(row.id), mapFault(row as RawFault, directory)])).values()]; return { rows, updatedAt: new Date().toISOString() }; } finally { try { await connection.rollback(); } finally { connection.release(); } } }