fix(extension): wait for ERP entry readiness

This commit is contained in:
inman committed 2026-09-03 14:31:38 +08:00
1 parent 69ea6d2517
commit 500034bb63
16 files changed
+231 -24

No files matched your search

@@ -11,9 +11,11 @@ Chrome Manifest V3 扩展,在用户已登录的 LTJT ERP 页面内执行经过
## 当前版本
当前源码版本为 `0.5.165`。版本化 ZIP、文件哈希和 Skill/DOCX 基线见 [`../../dist/release-manifest.json`](../../dist/release-manifest.json)。旧版本实现流水已冻结在 [`../../archive/project-history/2026-08-16/chrome-extension-README.pre-governance.md`](../../archive/project-history/2026-08-16/chrome-extension-README.pre-governance.md)。
当前源码版本为 `0.5.166`。版本化 ZIP、文件哈希和 Skill/DOCX 基线见 [`../../dist/release-manifest.json`](../../dist/release-manifest.json)。旧版本实现流水已冻结在 [`../../archive/project-history/2026-08-16/chrome-extension-README.pre-governance.md`](../../archive/project-history/2026-08-16/chrome-extension-README.pre-governance.md)。
0.5.165 当前重点:
0.5.166 当前重点:
- 散拼新增计划进入计划表后立即检查“新增计划”按钮;若同路径 iframe 尚在渲染,则每 100ms 重新取得当前 document 并检查按钮是否已连接且可用,出现后立即继续,最长 15 秒后才在写前阻断。快速页面没有固定等待,也不会自动重试任何 ERP 写入。
- 散拼新增计划和独立团批量下单在已加载候选无法唯一匹配时,会真正触发 `S_chanpinming` 的原生非空检索并等待 Ajax 返回,再对产品名/时长做本地唯一匹配。完整产品名原样查询;只有尾部 `10D`、`8天` 等数字时长会先剥离。最后仍保留一次空条件兼容重载,零候选或多候选继续在写前阻断。
@@ -2,6 +2,8 @@
'use strict';
const SPLIT_PARENT_RESPONSE_REQUERY_DELAYS_MS = Object.freeze([0, 750, 2000]);
const SPLIT_PARENT_ENTRY_READY_TIMEOUT_MS = 15000;
const SPLIT_PARENT_ENTRY_READY_INTERVAL_MS = 100;
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
@@ -1351,6 +1353,24 @@
return current;
}
async function waitForSplitParentAddButton(initialListDocument) {
return waitForCondition(() => {
// The ERP can expose the destination path before replacing or finishing
// the iframe document. Reacquire it on every probe so a stale same-path
// document cannot make the first execution fail while the button renders.
const candidate = mainIframe() ? mainIframeDocument() : initialListDocument;
if (!candidate) return null;
try {
if (!/\/system\/business\/plan\.asp$/i.test(candidate.location.pathname)) return null;
const addButton = candidate.querySelector('#NewBuildB, [name="NewBuildB"]');
if (!addButton || addButton.isConnected === false || addButton.disabled === true) return null;
return { document: candidate, addButton };
} catch (error) {
return null;
}
}, SPLIT_PARENT_ENTRY_READY_TIMEOUT_MS, SPLIT_PARENT_ENTRY_READY_INTERVAL_MS);
}
function nativeListRequestMatches(settings = {}, scopeDocument) {
let requestUrl;
try {
@@ -3879,9 +3899,16 @@
S_chufariqi: dateStart,
S_chufarizhi: dateEnd
});
const addButton = listDocument.querySelector('#NewBuildB, [name="NewBuildB"]');
if (!addButton) return { status: 'split_parent_live_blocked', blockers: ['split parent add button not found'], no_erp_write: true };
addButton.click();
const listReady = await waitForSplitParentAddButton(listDocument);
if (!listReady) {
return {
status: 'split_parent_live_blocked',
blockers: ['split parent add button not found after readiness timeout'],
no_erp_write: true
};
}
listDocument = listReady.document;
listReady.addButton.click();
const formDocument = await waitForDocumentPath(/\/system\/business\/plan_add\.asp$/i, 30000);
if (!formDocument) return { status: 'split_parent_live_blocked', blockers: ['split parent form did not load'], no_erp_write: true };
const ready = await waitForCondition(() => {
@@ -6091,7 +6118,7 @@
}
window.LTJTOrderAssistant = {
version: '0.5.165',
version: '0.5.166',
resolveNativeListSearchValues,
lookupKeywordMatchesText,
inspectLifecycleSearchCriteria: lifecycleSearchCriteria,
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "联泰下单助手",
"version": "0.5.165",
"version": "0.5.166",
"description": "在已登录 LTJT ERP 页面内规划并受控执行联泰 ERP 业务操作。",
"permissions": [
"activeTab",
@@ -944,7 +944,7 @@
window.LTJTOrderAssistant = {
...(window.LTJTOrderAssistant || {}),
version: '0.5.165',
version: '0.5.166',
openTeamBatchForm,
pingTeamBatchFrame,
preflightTeamBatchNative,