- classifyVehicleType now parses dic_type.dic_name (e.g. "4.5吨冷链车") instead of raw model code - Remove overly strict completionRate >= 0.8 filter for hopeless candidates - Use vehicle's yearTarget as fallback when inventory has no assessment target - Filter out suggestions with no candidates (not actionable) - estimatedGain counts rescue_hopeless suggestions as potential gains Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
61 lines
2.5 KiB
TypeScript
61 lines
2.5 KiB
TypeScript
import mysql from 'mysql2/promise';
|
|
import fs from 'node:fs';
|
|
|
|
const pool = mysql.createPool({
|
|
host: 'rm-uf65w5v2r77n674x2.mysql.rds.aliyuncs.com',
|
|
port: 3306,
|
|
user: 'root',
|
|
password: 'LN#Passw0rd@2026',
|
|
database: 'lingniu_prod',
|
|
connectTimeout: 15000, ssl: { rejectUnauthorized: false },
|
|
});
|
|
|
|
async function main() {
|
|
const excelPlates = new Set(
|
|
fs.readFileSync('/Users/kkfluous/Projects/ai-coding/ln-bi/scripts-tmp/excel_plates.txt', 'utf8').trim().split('\n').map((s) => s.trim())
|
|
);
|
|
console.log('excel plates:', excelPlates.size);
|
|
|
|
// 按 dept-stats 逻辑查金可鹏 18T Operating
|
|
const [rows] = await pool.query<any[]>(`
|
|
SELECT truck.plate_number AS plate,
|
|
dic_type.dic_name AS type_label,
|
|
dic_status.dic_name AS status_label,
|
|
cus.customer_name AS customer,
|
|
org_truck.org_name AS subject_org
|
|
FROM tab_truck truck
|
|
LEFT JOIN tab_dic dic_type ON dic_type.parent_code='dic_truck_type' AND dic_type.dic_code=truck.model AND dic_type.is_deleted=0
|
|
LEFT JOIN tab_dic dic_status ON dic_status.parent_code='dic_truck_rent_status' AND dic_status.dic_code=truck.truck_rent_status AND dic_status.is_deleted=0
|
|
LEFT JOIN tab_truck_status_info si ON si.truck_id=truck.id AND si.is_deleted=0
|
|
LEFT JOIN tab_contract c ON c.id=si.contract_id AND c.is_deleted=0
|
|
LEFT JOIN tab_customer cus ON cus.id=c.customer_id AND cus.is_deleted=0
|
|
LEFT JOIN tab_org org_truck ON org_truck.id=truck.org_id AND org_truck.is_deleted=0
|
|
LEFT JOIN tab_user u ON u.id=c.bd AND u.is_deleted=0
|
|
WHERE truck.is_deleted=0 AND truck.is_operation=1
|
|
AND u.user_name='金可鹏'
|
|
AND dic_type.dic_name LIKE '%18吨%'
|
|
AND dic_status.dic_name IN ('租赁','自营','挂靠')
|
|
ORDER BY truck.plate_number
|
|
`);
|
|
|
|
console.log('DB 金可鹏 18T operating:', rows.length);
|
|
const dbPlates = new Set((rows as any[]).map((r) => (r.plate || '').trim()));
|
|
|
|
const extra = [...dbPlates].filter((p) => !excelPlates.has(p)).sort();
|
|
const missing = [...excelPlates].filter((p) => !dbPlates.has(p)).sort();
|
|
|
|
console.log('\n=== DB 有但 Excel 没有(多出来的) ===');
|
|
console.log('数量:', extra.length);
|
|
for (const p of extra) {
|
|
const r = (rows as any[]).find((x) => x.plate === p);
|
|
console.log(' ', p, '|', r?.type_label, '|', r?.customer, '|', r?.subject_org);
|
|
}
|
|
|
|
console.log('\n=== Excel 有但 DB 没有 ===');
|
|
console.log('数量:', missing.length);
|
|
for (const p of missing) console.log(' ', p);
|
|
|
|
await pool.end();
|
|
}
|
|
main().catch((e) => { console.error(e); process.exit(1); });
|