weaver-work-cli 0.1.28 → 0.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/shortcuts/invoice/host.js +2 -1
- package/dist/shortcuts/invoice/manifest.js +2 -1
- package/dist/shortcuts/invoice/operations/issuing-qys.js +132 -36
- package/dist/shortcuts/workflow/index.js +3 -0
- package/dist/shortcuts/workflow/operations/read.js +13 -6
- package/dist/shortcuts/workflow/operations/registry.js +2 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +331 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +133 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +326 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +113 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +259 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoListRows.js +64 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoOutputPlanner.js +28 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.aggregate.js +70 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +267 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +392 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +165 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +448 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +348 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +222 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +66 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +502 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +540 -0
- package/docs/_catalog.md +1 -0
- package/docs/invoice.md +3 -3
- package/docs/todo-smart-convert/README.md +171 -0
- package/docs/todo-smart-convert/data-contract.md +236 -0
- package/docs/todo-smart-convert/mock/ai-todo-query-target.json +209 -0
- package/docs/todo-smart-convert/subgroup-rules.md +245 -0
- package/package.json +1 -1
- package/scripts/package-skill.mjs +1 -1
- package/skill-template/domains/yepiaotong.md +2 -2
- package/skills/weaver-e10-workflow/SKILL.md +23 -1
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +282 -0
- package/skills/weaver-e10-workflow/scripts/todo-summary.cjs +695 -0
- package/skills/weaver-e10-yepiaotong/SKILL.md +6 -6
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-examples.md +10 -7
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-form-fill-rules.md +41 -14
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-workflow.md +54 -26
- package/skills/weaver-e10-yepiaotong/references/source-manifest.json +2 -2
|
@@ -185,7 +185,7 @@ export function createInvoiceHost(ctx, dependencies = {}) {
|
|
|
185
185
|
throw businessError(value);
|
|
186
186
|
}
|
|
187
187
|
async function invoiceRequest(request, canRetryExpiredToken = true) {
|
|
188
|
-
const { method = 'POST', path, query, body, operation, needsInvoiceToken = true, timeoutMs = 30_000, } = request;
|
|
188
|
+
const { method = 'POST', path, query, headers, body, operation, needsInvoiceToken = true, timeoutMs = 30_000, } = request;
|
|
189
189
|
assertPath(path);
|
|
190
190
|
const token = await ensureContext(needsInvoiceToken, timeoutMs, path);
|
|
191
191
|
const response = await (await runtime()).requestJson({
|
|
@@ -194,6 +194,7 @@ export function createInvoiceHost(ctx, dependencies = {}) {
|
|
|
194
194
|
method,
|
|
195
195
|
path,
|
|
196
196
|
query,
|
|
197
|
+
headers,
|
|
197
198
|
body,
|
|
198
199
|
timeoutMs,
|
|
199
200
|
trustedHeaders: trustedInvoiceHeaders(token),
|
|
@@ -671,6 +671,7 @@ const qysListOutputSchema = objectSchema({
|
|
|
671
671
|
goodsNames: arrayOf({ type: 'string' }),
|
|
672
672
|
taxRates: arrayOf({ type: 'string' }),
|
|
673
673
|
specifications: arrayOf({ type: 'string' }, { description: '可开票行“规格型号”去重(开票流程主表“所售产品版本号”取此值)' }),
|
|
674
|
+
sellerNames: arrayOf({ type: 'string' }, { description: '台账“核算公司”去重,即所属公司(销售方);空名称不计入。用于选择开票流程' }),
|
|
674
675
|
rowCount: { type: 'integer' },
|
|
675
676
|
formDataIds: arrayOf({ type: 'string' }),
|
|
676
677
|
totalAmount: { type: 'string', description: '可开票行“开票金额”合计,按分累加(开票流程按含税金额使用)' },
|
|
@@ -1197,7 +1198,7 @@ export const invoiceOperations = [
|
|
|
1197
1198
|
{
|
|
1198
1199
|
name: 'invoice.issuing.qys.list',
|
|
1199
1200
|
risk: 'read',
|
|
1200
|
-
fixed: { path: '/api/ebuilder/form/
|
|
1201
|
+
fixed: { path: '/api/ebuilder/form/list/getListDatas', ledger: '待开票合同数据' },
|
|
1201
1202
|
inputSchema: {
|
|
1202
1203
|
type: 'object',
|
|
1203
1204
|
additionalProperties: false,
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { InvoiceCliError, invoiceValidationError } from '../errors.js';
|
|
2
3
|
import { asNonEmptyString, assertBusinessSuccess } from './shared.js';
|
|
3
|
-
const LEDGER_PATH = '/api/ebuilder/form/
|
|
4
|
-
const
|
|
4
|
+
const LEDGER_PATH = '/api/ebuilder/form/list/getListDatas';
|
|
5
|
+
const LEDGER_LIST_ID = '1201416963938369627';
|
|
6
|
+
const LEDGER_PASS_ID = '1201416959744065575';
|
|
5
7
|
const LEDGER_APP_ID = '846297243998732291';
|
|
6
|
-
const LEDGER_MENU_ID = '
|
|
7
|
-
|
|
8
|
+
const LEDGER_MENU_ID = '5416292802968839298';
|
|
9
|
+
/** urlPageTitle:合同商品信息 */
|
|
10
|
+
const LEDGER_PAGE_TITLE = '5ZCI5ZCM5ZWG5ZOB5L+h5oGv';
|
|
8
11
|
const LEDGER_PAGE_SIZE = 50;
|
|
9
12
|
const LEDGER_MAX_PAGES = 40;
|
|
10
|
-
/**
|
|
13
|
+
/** 待开票合同数据:数据 key → 可读字段。含契约锁、泛微及其他合同。 */
|
|
11
14
|
export const QYS_LEDGER_FIELDS = [
|
|
12
15
|
{ id: '1314988311673275798', key: 'contractNo', label: '合同号', kind: 'text' },
|
|
13
16
|
{ id: '1314988311673275801', key: 'contractFlow', label: '合同审批流程', kind: 'relation' },
|
|
@@ -106,49 +109,136 @@ export function qysRowBlockers(row) {
|
|
|
106
109
|
blockers.push('已废弃');
|
|
107
110
|
return blockers;
|
|
108
111
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
function parseSpan(value) {
|
|
113
|
+
if (typeof value === 'string' && value.trim().startsWith('[')) {
|
|
114
|
+
try {
|
|
115
|
+
return optionValue(JSON.parse(value));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return optionValue(value);
|
|
122
|
+
}
|
|
123
|
+
function cellText(data, display, key) {
|
|
124
|
+
const raw = data[key] !== undefined && data[key] !== null && data[key] !== '' ? data[key] : display[key];
|
|
125
|
+
return textValue(raw);
|
|
126
|
+
}
|
|
127
|
+
function moneyText(data, display, key) {
|
|
128
|
+
const text = cellText(data, display, key);
|
|
129
|
+
return text === null ? null : text.replace(/,/g, '');
|
|
130
|
+
}
|
|
131
|
+
/** 获取待开票合同数据:getListDatas 的 data / displayData 行,转成与旧列表相同的可读字段。 */
|
|
132
|
+
export function convertPendingLedgerRow(data, display = {}) {
|
|
133
|
+
const formDataId = textValue(data.form_data_id) ?? textValue(data.id);
|
|
134
|
+
if (!formDataId)
|
|
135
|
+
throw invoiceValidationError('ledger_row_invalid', '台账行缺少 form_data_id');
|
|
136
|
+
const statusText = textValue(display.data_status);
|
|
137
|
+
return {
|
|
138
|
+
formDataId,
|
|
139
|
+
title: textValue(data.name) ?? textValue(display.name),
|
|
140
|
+
dataStatus: statusText && !/^\d+$/u.test(statusText) ? statusText : null,
|
|
141
|
+
contractNo: cellText(data, display, 'hth'),
|
|
142
|
+
contractFlow: parseSpan(display.htsplcSpan),
|
|
143
|
+
contractCategory: cellText(data, display, 'htzl'),
|
|
144
|
+
productType: parseSpan(display.cplxSpan),
|
|
145
|
+
productTypeDetail: cellText(data, display, 'cplxmx'),
|
|
146
|
+
accountingCompany: parseSpan(display.hsgs_idSpan),
|
|
147
|
+
invoiceGroupFlag: cellText(data, display, 'kpfzbs'),
|
|
148
|
+
sourceFlag: cellText(data, display, 'lybs'),
|
|
149
|
+
flowDetailId: cellText(data, display, 'lcmxid'),
|
|
150
|
+
invoiceType: parseSpan(display.fplxSpan),
|
|
151
|
+
purchaserName: cellText(data, display, 'gmfmc'),
|
|
152
|
+
purchaserTaxNo: cellText(data, display, 'gmfsh'),
|
|
153
|
+
purchaserAddress: cellText(data, display, 'gmfdz'),
|
|
154
|
+
purchaserTel: cellText(data, display, 'gmfdh'),
|
|
155
|
+
purchaserBankName: cellText(data, display, 'gmfkhx'),
|
|
156
|
+
purchaserBankAccount: cellText(data, display, 'gmfkhxzh'),
|
|
157
|
+
invoiceItemName: cellText(data, display, 'kpmc'),
|
|
158
|
+
goodsName: cellText(data, display, 'spmc'),
|
|
159
|
+
revenueCode: cellText(data, display, 'spshflbm'),
|
|
160
|
+
taxRate: parseSpan(display.spslSpan),
|
|
161
|
+
specification: cellText(data, display, 'ggxh'),
|
|
162
|
+
unit: cellText(data, display, 'dw'),
|
|
163
|
+
quantity: cellText(data, display, 'spslkwk'),
|
|
164
|
+
unitPrice: moneyText(data, display, 'spdjkwk'),
|
|
165
|
+
amount: moneyText(data, display, 'kpje'),
|
|
166
|
+
uninvoicedAmount: moneyText(data, display, 'wkpje'),
|
|
167
|
+
invoicedAmount: moneyText(data, display, 'ykpje'),
|
|
168
|
+
invoicingAmount: moneyText(data, display, 'kpzje'),
|
|
169
|
+
amountDiffers: parseSpan(display.kpjeczcySpan),
|
|
170
|
+
thirdPartyPurchase: parseSpan(display.sfsfcgSpan),
|
|
171
|
+
invoiceNo: cellText(data, display, 'fphm'),
|
|
172
|
+
invoiceFlow: parseSpan(display.kplcidSpan),
|
|
173
|
+
invoiceDate: cellText(data, display, 'kpsj'),
|
|
174
|
+
discarded: parseSpan(display.sfzfSpan),
|
|
175
|
+
discardedDate: cellText(data, display, 'zfsj'),
|
|
176
|
+
contactName: cellText(data, display, 'khlxr'),
|
|
177
|
+
contactPhone: cellText(data, display, 'khlxdh'),
|
|
178
|
+
contactEmail: cellText(data, display, 'khlxyx'),
|
|
115
179
|
};
|
|
116
|
-
|
|
180
|
+
}
|
|
181
|
+
async function fetchLedgerPage(host, pageNo, tableuid, operation) {
|
|
182
|
+
const result = await host.invoiceRequest({
|
|
117
183
|
path: LEDGER_PATH,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
...fieldFilter,
|
|
121
|
-
filter: '[]',
|
|
122
|
-
fieldFilter,
|
|
123
|
-
pageFilter: { filter: {}, filterIsNull: true, esbFilter: [] },
|
|
124
|
-
pageAppId: LEDGER_APP_ID,
|
|
125
|
-
compId: 'e00e8244de584b369417a4fea31d7bed',
|
|
126
|
-
pageId: LEDGER_PAGE_ID,
|
|
127
|
-
pageNo: String(pageNo),
|
|
128
|
-
pageSize: String(LEDGER_PAGE_SIZE),
|
|
129
|
-
tableuid: 'a74d995bddd54a4f831551b468071632',
|
|
130
|
-
refPluginPackageId: '933846626099339271',
|
|
131
|
-
},
|
|
184
|
+
query: { passid: LEDGER_PASS_ID, cid: LEDGER_PASS_ID },
|
|
185
|
+
headers: { ebbusinessid: LEDGER_LIST_ID },
|
|
132
186
|
operation,
|
|
187
|
+
body: {
|
|
188
|
+
current: pageNo,
|
|
189
|
+
pageSize: LEDGER_PAGE_SIZE,
|
|
190
|
+
requiredMatch: 1,
|
|
191
|
+
tableuid,
|
|
192
|
+
mapResult: '1',
|
|
193
|
+
recheckQuery: '1',
|
|
194
|
+
cusMenuId: LEDGER_MENU_ID,
|
|
195
|
+
urlPageTitle: LEDGER_PAGE_TITLE,
|
|
196
|
+
[`appId_${LEDGER_LIST_ID}`]: LEDGER_APP_ID,
|
|
197
|
+
searchParamData: {
|
|
198
|
+
searchType: '3',
|
|
199
|
+
quickSearchFields: {},
|
|
200
|
+
commonSearchFields: {},
|
|
201
|
+
type: 'and',
|
|
202
|
+
groupFields: {},
|
|
203
|
+
},
|
|
204
|
+
listId: LEDGER_LIST_ID,
|
|
205
|
+
isFollow: 0,
|
|
206
|
+
isShareToMe: 0,
|
|
207
|
+
filterCondition: {},
|
|
208
|
+
browser: 'Chrome',
|
|
209
|
+
},
|
|
133
210
|
});
|
|
134
|
-
assertBusinessSuccess(result, 'qys_ledger_query_failed', '
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
211
|
+
assertBusinessSuccess(result, 'qys_ledger_query_failed', '获取待开票合同数据失败');
|
|
212
|
+
const payload = result?.data;
|
|
213
|
+
const dataRows = payload?.data;
|
|
214
|
+
const displayRows = payload?.displayData;
|
|
215
|
+
if (!Array.isArray(dataRows) || !Array.isArray(displayRows)) {
|
|
216
|
+
throw new InvoiceCliError('api', 'qys_ledger_query_failed', '获取待开票合同数据的返回缺少 data.data 或 data.displayData', { exitCode: 1 });
|
|
138
217
|
}
|
|
139
|
-
return
|
|
218
|
+
return dataRows.map((data, index) => ({
|
|
219
|
+
data,
|
|
220
|
+
display: displayRows[index] && typeof displayRows[index] === 'object' ? displayRows[index] : {},
|
|
221
|
+
}));
|
|
140
222
|
}
|
|
141
|
-
/**
|
|
223
|
+
/** total / hasMore 不可靠,按本页未取满或出现重复行结束。 */
|
|
142
224
|
async function scanLedger(host, operation, visit) {
|
|
225
|
+
const tableuid = randomUUID().replace(/-/g, '');
|
|
226
|
+
const seen = new Set();
|
|
143
227
|
let scanned = 0;
|
|
144
228
|
for (let pageNo = 1; pageNo <= LEDGER_MAX_PAGES; pageNo += 1) {
|
|
145
|
-
const page = await fetchLedgerPage(host, pageNo, operation);
|
|
146
|
-
|
|
229
|
+
const page = await fetchLedgerPage(host, pageNo, tableuid, operation);
|
|
230
|
+
let fresh = 0;
|
|
231
|
+
for (const pair of page) {
|
|
232
|
+
const row = convertPendingLedgerRow(pair.data, pair.display);
|
|
233
|
+
if (seen.has(row.formDataId))
|
|
234
|
+
continue;
|
|
235
|
+
seen.add(row.formDataId);
|
|
236
|
+
fresh += 1;
|
|
147
237
|
scanned += 1;
|
|
148
|
-
if (visit(
|
|
238
|
+
if (visit(row))
|
|
149
239
|
return { scanned, complete: true };
|
|
150
240
|
}
|
|
151
|
-
if (page.length < LEDGER_PAGE_SIZE)
|
|
241
|
+
if (page.length < LEDGER_PAGE_SIZE || fresh === 0)
|
|
152
242
|
return { scanned, complete: true };
|
|
153
243
|
}
|
|
154
244
|
return { scanned, complete: false };
|
|
@@ -198,6 +288,7 @@ export class QysLedgerGrouper {
|
|
|
198
288
|
goodsNames: new Set(),
|
|
199
289
|
taxRates: new Set(),
|
|
200
290
|
specifications: new Set(),
|
|
291
|
+
sellerNames: new Set(),
|
|
201
292
|
bankName: null,
|
|
202
293
|
bankAccount: null,
|
|
203
294
|
formDataIds: [],
|
|
@@ -207,6 +298,8 @@ export class QysLedgerGrouper {
|
|
|
207
298
|
};
|
|
208
299
|
this.groups.set(key, group);
|
|
209
300
|
}
|
|
301
|
+
if (row.accountingCompany?.name)
|
|
302
|
+
group.sellerNames.add(row.accountingCompany.name);
|
|
210
303
|
if (blocked) {
|
|
211
304
|
group.blockedRows += 1;
|
|
212
305
|
return;
|
|
@@ -255,6 +348,8 @@ export class QysLedgerGrouper {
|
|
|
255
348
|
}
|
|
256
349
|
if (!group.contractNo)
|
|
257
350
|
warnings.push('台账行缺少合同号,无法按合同号发起开票流程');
|
|
351
|
+
if (group.sellerNames.size > 1)
|
|
352
|
+
warnings.push(`同组销售方(核算公司)不一致:${[...group.sellerNames].join('、')}`);
|
|
258
353
|
if (group.invoiceTypes.size > 1)
|
|
259
354
|
warnings.push(`同组发票类型不一致:${[...group.invoiceTypes].join('、')}`);
|
|
260
355
|
if (group.purchaserTaxNos.size > 1)
|
|
@@ -277,6 +372,7 @@ export class QysLedgerGrouper {
|
|
|
277
372
|
goodsNames: [...group.goodsNames],
|
|
278
373
|
taxRates: [...group.taxRates],
|
|
279
374
|
specifications: [...group.specifications],
|
|
375
|
+
sellerNames: [...group.sellerNames],
|
|
280
376
|
rowCount: group.formDataIds.length,
|
|
281
377
|
formDataIds: group.formDataIds,
|
|
282
378
|
totalAmount: formatCents(group.amountCents),
|
|
@@ -95,6 +95,9 @@ export function printWorkflowResult(ctx, operation, result) {
|
|
|
95
95
|
ctx.output.write(successEnvelope(operation, result), {
|
|
96
96
|
json: true,
|
|
97
97
|
compactPaths: compactStdoutPaths(operation),
|
|
98
|
+
// todoSmartConvert 的业务契约要求直接返回完整 requestDatas/displayItems;
|
|
99
|
+
// 禁止公共输出层按 24KB 预算递归折叠该分支(2026-10-27 用户要求,勿删)。
|
|
100
|
+
persist: operation !== 'workflow.todoSmartConvert',
|
|
98
101
|
});
|
|
99
102
|
}
|
|
100
103
|
async function executeAndPrint(ctx, operation, input) {
|
|
@@ -892,7 +892,7 @@ async function resolveFilterFieldItem(env, raw, fields, workflowLabel, ordinal)
|
|
|
892
892
|
throw workflowValidationError('field_type_unsupported', `字段「${field.fieldName}」的组件类型 ${field.componentKey} 暂不支持作为筛选条件(filterFields 第 ${ordinal} 项),`
|
|
893
893
|
+ '本次查询已停止。请改用文本/数值/日期/选项类字段。');
|
|
894
894
|
}
|
|
895
|
-
async function buildSearchQuery(env, args, mode) {
|
|
895
|
+
export async function buildSearchQuery(env, args, mode) {
|
|
896
896
|
// 1. 原始 JSON 直传(--query-json / --query-file 透传;CLI 侧用 queryJson 字段承载)
|
|
897
897
|
const rawJson = args.queryJson;
|
|
898
898
|
let query;
|
|
@@ -3131,7 +3131,7 @@ const workflowDetail = {
|
|
|
3131
3131
|
});
|
|
3132
3132
|
},
|
|
3133
3133
|
};
|
|
3134
|
-
function normalizeDetailResponse(response) {
|
|
3134
|
+
export function normalizeDetailResponse(response) {
|
|
3135
3135
|
// ★ 层级:`detailDataOf` 负责"`responseData()` 已解一层 `data`"这件事(真机实测响应为
|
|
3136
3136
|
// `{message, data:{workflowBaseInfo, otherInfo, formData}}`、**无内层 `data`**,与 V11.3 同口径)。
|
|
3137
3137
|
// 旧实现在这里又取了一次 `.data` ⇒ 实际拿到 `response.data.data`(不存在)⇒ `workflow.detail` 与
|
|
@@ -4472,14 +4472,14 @@ async function enrichWorkflowCardSummaries(env, normalized, maxItems = 10) {
|
|
|
4472
4472
|
};
|
|
4473
4473
|
return normalized;
|
|
4474
4474
|
}
|
|
4475
|
-
function normalizeDetailSummaryValue(_name, value) {
|
|
4475
|
+
function normalizeDetailSummaryValue(_name, value, maxChars = 180) {
|
|
4476
4476
|
let text = stripHtml(value);
|
|
4477
4477
|
text = text.replace(/https?:\/\/\S+/gi, '').trim();
|
|
4478
4478
|
// 与 V11.3 一致:标点只裁**首尾**(Python `.strip(" ::;;,.,。")`),不删正文里的标点——
|
|
4479
4479
|
// 旧实现用 `/[...]/g` 删掉了「金额:1000」这类值里的冒号,摘要读起来是「金额1000」。
|
|
4480
4480
|
text = text.replace(/\s+/g, ' ').replace(/^[ ::;;,.,。]+|[ ::;;,.,。]+$/g, '');
|
|
4481
4481
|
// 截断同样走 V11.3 的标点边界口径(旧实现是硬 slice,会把词截成半截)
|
|
4482
|
-
return truncateText(text,
|
|
4482
|
+
return truncateText(text, maxChars);
|
|
4483
4483
|
}
|
|
4484
4484
|
function isMeaninglessSummaryValue(value) {
|
|
4485
4485
|
const text = (value || '').trim();
|
|
@@ -4505,13 +4505,20 @@ function looksLikeUrlOrDoc(value) {
|
|
|
4505
4505
|
const stripped = text.replace(/https?:\/\/\S+/gi, '').trim().replace(/[::;;,.,。"'“” \t\r\n]/g, '');
|
|
4506
4506
|
return stripped.length < 20;
|
|
4507
4507
|
}
|
|
4508
|
-
|
|
4508
|
+
/**
|
|
4509
|
+
* 摘要字段筛选(业务字段白名单 + 信息量排序,最多 `limit` 个)。
|
|
4510
|
+
* `maxValueChars` 默认 180(列表卡片口径,既有调用方不受影响)。
|
|
4511
|
+
*
|
|
4512
|
+
* `options.fullValue = true` 时**不做任何值裁剪**(不截断、不切句),原值直接给下游
|
|
4513
|
+
* ——待办汇总喂 AI 用这个口径(用户 2026-10-21:全量给,不做 400 字截断)。
|
|
4514
|
+
*/
|
|
4515
|
+
export function selectSummaryFields(fields, limit = 12, maxValueChars = 180, options = {}) {
|
|
4509
4516
|
const candidates = [];
|
|
4510
4517
|
const seen = new Set();
|
|
4511
4518
|
const collectField = (field) => {
|
|
4512
4519
|
const name = stripHtml(field?.fieldName ?? '');
|
|
4513
4520
|
const rawValue = stripHtml(field?.value ?? '');
|
|
4514
|
-
const value = normalizeDetailSummaryValue(name, rawValue);
|
|
4521
|
+
const value = options.fullValue ? rawValue : normalizeDetailSummaryValue(name, rawValue, maxValueChars);
|
|
4515
4522
|
if (!name || !value)
|
|
4516
4523
|
return false;
|
|
4517
4524
|
if (isMeaninglessSummaryValue(rawValue))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { workflowValidationError } from '../errors.js';
|
|
2
2
|
import { workflowFormOperations } from './form.js';
|
|
3
3
|
import { workflowReadOperations } from './read.js';
|
|
4
|
+
import { workflowTodoSmartConvertOperations } from './todoSmartConvert/todoSmartConvert.js';
|
|
4
5
|
import { workflowWriteOperations } from './write.js';
|
|
5
6
|
function buildRegistry() {
|
|
6
7
|
const registry = new Map();
|
|
@@ -8,6 +9,7 @@ function buildRegistry() {
|
|
|
8
9
|
...workflowReadOperations,
|
|
9
10
|
...workflowFormOperations,
|
|
10
11
|
...workflowWriteOperations,
|
|
12
|
+
...workflowTodoSmartConvertOperations,
|
|
11
13
|
];
|
|
12
14
|
for (const definition of definitions) {
|
|
13
15
|
if (registry.has(definition.name)) {
|