73 lines
4.6 KiB
JavaScript
73 lines
4.6 KiB
JavaScript
(function (root, factory) {
|
||
const api = factory();
|
||
if (typeof module === 'object' && module.exports) module.exports = api;
|
||
root.LTJTHotelBatch = api;
|
||
})(typeof self !== 'undefined' ? self : globalThis, function () {
|
||
'use strict';
|
||
const object = value => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
||
const group = value => String(value || '').normalize('NFKC').replace(/\s+/gu, '').toUpperCase();
|
||
function verified(result, identifier) {
|
||
const report = object(result?.report), refs = object(report.resolved_refs);
|
||
return result?.status === 'completed' && report.status === 'lifecycle_completed' && report.server_response?.completed === true
|
||
&& report.requery?.matched === true && report.requery?.skipped !== true
|
||
&& !result.uncertain && !result.manual_review_required && !report.manual_review_required
|
||
&& ![result.blockers, report.blockers].some(value => Array.isArray(value) && value.length)
|
||
&& refs.kind !== 'shared_child_order' && group(refs.identifier || refs.group_no) === group(identifier);
|
||
}
|
||
function inspect(value) {
|
||
const batch = object(value), items = batch.items;
|
||
if (batch.version !== 1 || !group(batch.group_number) || !Array.isArray(items)
|
||
|| items.length < 2 || items.length > 10) return null;
|
||
let stopped = false, pending = false, completed = 0, failed = 0, uncertain = 0;
|
||
const rowIds = new Set();
|
||
for (let index = 0; index < items.length; index++) {
|
||
const item = object(items[index]);
|
||
if (item.index !== index || item.arrangement?.mode !== 'create') return null;
|
||
if (item.status === 'completed') {
|
||
if (stopped || pending || !verified(item.result, batch.group_number)) return null;
|
||
const subpage = object(item.result.report.requery.subpage), target = object(subpage.arrangement_target);
|
||
const rowId = String(target.row_id || '');
|
||
if (!rowId || rowId === '0' || rowIds.has(rowId)) return null;
|
||
rowIds.add(rowId);
|
||
const normalizeDate = value => String(value || '').replace(/^(\d{4})-(\d{1,2})-(\d{1,2})$/, (_, y, m, d) => `${y}-${m.padStart(2, '0')}-${d.padStart(2, '0')}`);
|
||
const checks = Array.isArray(subpage.checks) ? subpage.checks : [];
|
||
const actual = pattern => checks.filter(check => check.matched === true && pattern.test(check.field));
|
||
for (const [pattern, expected] of [[/^riqi\d+$/, item.arrangement.start_date], [/^riqis\d+$/, item.arrangement.end_date]]) {
|
||
const matches = actual(pattern);
|
||
if (matches.length !== 1 || normalizeDate(matches[0].actual) !== expected) return null;
|
||
}
|
||
if (Number(target.quantity_value) !== item.arrangement.room_count) return null;
|
||
completed++;
|
||
} else if (item.status === 'failed') {
|
||
if (stopped || pending || item.result?.no_erp_write !== true || item.result?.write_attempted === true) return null;
|
||
stopped = true; failed++;
|
||
} else if (item.status === 'uncertain') {
|
||
if (stopped || pending) return null;
|
||
stopped = true; uncertain++;
|
||
} else if (item.status === 'running') {
|
||
if (stopped || pending) return null;
|
||
pending = true;
|
||
} else if (item.status === 'not_started') pending = true;
|
||
else return null;
|
||
}
|
||
return { completed, failed, uncertain, total: items.length,
|
||
not_started: items.filter(item => item.status === 'not_started').length,
|
||
allCompleted: completed === items.length, knownStopped: (failed === 1 || (batch.stopped === true && completed > 0 && !items.some(item => item.status === 'running'))) && uncertain === 0 };
|
||
}
|
||
function resultText(batch) {
|
||
const stats = inspect(batch);
|
||
if (!stats) return '';
|
||
const lines = [`共 ${stats.total} 条:成功 ${stats.completed} 条,失败 ${stats.failed} 条,待核验 ${stats.uncertain} 条,未执行 ${stats.not_started} 条`];
|
||
const labels = { completed: '已完成', failed: '失败', uncertain: '结果不确定,待只读回查', not_started: '未执行', running: '处理中' };
|
||
batch.items.forEach(item => {
|
||
const a = item.arrangement;
|
||
lines.push('', `${item.index + 1}. ${String(a.start_date).replaceAll('-', '/')}—${String(a.end_date).replaceAll('-', '/')}`,
|
||
` 酒店搜索:${a.resource?.keyword || a.resource?.name || ''};${a.room_count} 间`, ` ${labels[item.status]}`);
|
||
if (item.status === 'failed') lines.push(` 原因:${String(item.result?.failure_message || item.result?.message || '执行阻断').slice(0, 250)}`);
|
||
});
|
||
if (!stats.allCompleted) lines.push('', '已完成的安排已保留,请勿整批重复提交。');
|
||
return lines.join('\n');
|
||
}
|
||
return { verified, inspect, resultText };
|
||
});
|