weaver-work-cli 0.1.21 → 0.1.23

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.
Files changed (31) hide show
  1. package/dist/shortcuts/invoice/host.js +5 -4
  2. package/dist/shortcuts/meeting/operations/change.js +7 -4
  3. package/dist/shortcuts/meeting/operations/create.js +5 -3
  4. package/dist/shortcuts/meeting/operations/eb/association.js +151 -0
  5. package/dist/shortcuts/meeting/operations/eb/attendance-summary.js +153 -0
  6. package/dist/shortcuts/meeting/operations/eb/catalog.js +185 -13
  7. package/dist/shortcuts/meeting/operations/eb/conflict.js +17 -11
  8. package/dist/shortcuts/meeting/operations/eb/decision.js +405 -0
  9. package/dist/shortcuts/meeting/operations/eb/factory.js +222 -35
  10. package/dist/shortcuts/meeting/operations/eb/index.js +18 -1
  11. package/dist/shortcuts/meeting/operations/eb/link.js +212 -0
  12. package/dist/shortcuts/meeting/operations/eb/task-progress.js +123 -0
  13. package/dist/shortcuts/meeting/operations/env.js +78 -61
  14. package/dist/shortcuts/meeting/operations/lifecycle.js +8 -6
  15. package/dist/shortcuts/meeting/operations/link.js +125 -0
  16. package/dist/shortcuts/meeting/operations/receipts.js +54 -21
  17. package/dist/shortcuts/meeting/operations/registry.js +2 -0
  18. package/dist/shortcuts/meeting/operations/shared.js +41 -0
  19. package/dist/shortcuts/meeting/operations/signs.js +14 -4
  20. package/dist/shortcuts/project/operations/read.js +7 -6
  21. package/docs/e10-auth.md +4 -0
  22. package/docs/invoice.md +3 -0
  23. package/package.json +1 -1
  24. package/skills/weaver-e10-meeting/SKILL.md +28 -11
  25. package/skills/weaver-e10-meeting/references/meeting-eb.md +172 -7
  26. package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +7 -2
  27. package/skills/weaver-e10-meeting/references/meeting-verification.md +271 -0
  28. package/skills/weaver-e10-meeting.zip +0 -0
  29. package/skills/weaver-e10-shijingran/SKILL.md +68 -3
  30. package/skills/weaver-e10-shijingran/references/disabled-capabilities.md +22 -0
  31. package/skills/weaver-e10-shijingran/references/source-manifest.json +12 -4
@@ -13,6 +13,8 @@
13
13
  * - 详情 / 写:只用 body(详情 body 顶层 mainTable;写操作 body 用 datas 数组包裹 mainTable)。
14
14
  * - 写操作日期字段统一 `yyyy-MM-dd HH:mm`(不带秒);create 不传 id,update/delete 必传 id。
15
15
  */
16
+ import { summarizeReceiptRows, summarizeSignRows } from './attendance-summary.js';
17
+ import { summarizeTaskProgress } from './task-progress.js';
16
18
  const MEETING_FIELDS_CREATE = [
17
19
  'mt_creator', 'mt_name', 'begin_datetime', 'end_datetime', 'mt_status', 'operate_type',
18
20
  'is_decision', 'mt_type', 'caller', 'contacter', 'mt_format', 'mt_desc', 'mt_hours',
@@ -27,6 +29,20 @@ const MEETING_FIELDS_CHANGE = [
27
29
  'next_occur_date', 'repeat_status', 'repeat_id', 'request_id', 'mt_status',
28
30
  'attend_user', 'reporting_user',
29
31
  ];
32
+ /**
33
+ * 签到字段(2026-09-21 按最新接口文档 `RestfulDocumentation (6)` 补全)。
34
+ * 原清单缺 `map_typeback` / `signback_longitude` / `signback_latitude` / `external_*` 7 个字段,
35
+ * 会导致签退经纬度与外部人员信息写不进去。
36
+ */
37
+ const SIGN_FIELDS_CREATE = [
38
+ 'mt_id', 'hylx', 'site', 'sign_flag', 'user_id', 'attend_type', 'sign_time', 'sign_reson',
39
+ 'is_sign', 'longitude', 'latitude', 'sign_remark', 'signback_time', 'backsite', 'map_type', 'map_typeback',
40
+ 'signback_longitude', 'signback_latitude', 'allow_late_time', 'sign_out_status',
41
+ 'external_flag', 'external_name', 'external_email', 'external_phone', 'external_remark',
42
+ 'sub_dept', 'department',
43
+ ];
44
+ /** 更新签到:在 create 字段基础上加 id(必填)。 */
45
+ const SIGN_FIELDS_UPDATE = ['id', ...SIGN_FIELDS_CREATE];
30
46
  const ROOM_FIELDS = [
31
47
  'id', 'room_name', 'hrm_ids', 'org_id', 'status', 'mr_type', 'place', 'room_attr',
32
48
  'allow_minnum', 'allow_maxnum', 'rs_style', 'room_desc', 'equipments', 'dsporder', 'images',
@@ -82,6 +98,8 @@ export const EB_ENDPOINTS = [
82
98
  fields: MEETING_FIELDS_CHANGE,
83
99
  requiredFields: ['id', 'operate_type'],
84
100
  dateFields: ['begin_datetime', 'end_datetime', 'next_occur_date'],
101
+ // 主键必须走 URL(updateFormData 端点统一要求,2026-09-21 真机实测)
102
+ pkQueryParam: 'id',
85
103
  summary: 'EB 版变更会议(change_meeting):必传 id + operate_type;取消会议也用本接口',
86
104
  notes: ['变更用 CHANGE;取消用 CANCEL 并置 mt_status=4。'],
87
105
  },
@@ -126,6 +144,8 @@ export const EB_ENDPOINTS = [
126
144
  interfacePk: 'update_room',
127
145
  fields: ROOM_FIELDS,
128
146
  requiredFields: ['id'],
147
+ // 主键必须走 URL(updateFormData 端点统一要求)
148
+ pkQueryParam: 'id',
129
149
  summary: 'EB 版更新会议室(update_room):仅 id 必填',
130
150
  },
131
151
  {
@@ -176,6 +196,8 @@ export const EB_ENDPOINTS = [
176
196
  countPk: 'query_meeting_sign_count',
177
197
  queryParams: ['mt_id', 'signMember', 'sign_status', 'sign_back_status'],
178
198
  summary: 'EB 版签到列表(query_meeting_sign_list + count)',
199
+ // 附带出席汇总(data.progress):各状态人数 / 已签退 / 出席率;原始 rows 原样保留。
200
+ summarizeRows: summarizeSignRows,
179
201
  notes: [
180
202
  'sign_status:0缺席/1正常/2请假/3迟到/4早退/5未签退/6迟到未签退/7迟到早退;sign_back_status:0已签退/1未签退/2早退。',
181
203
  '未签到判断:sign_time 为空或查不到记录。',
@@ -194,28 +216,33 @@ export const EB_ENDPOINTS = [
194
216
  operation: 'meeting.eb.sign.create',
195
217
  kind: 'create',
196
218
  interfacePk: 'create_meeting_sign',
197
- fields: [
198
- 'mt_id', 'hylx', 'site', 'sign_flag', 'user_id', 'attend_type', 'sign_time', 'sign_reson',
199
- 'is_sign', 'longitude', 'latitude', 'sign_remark', 'signback_time', 'backsite', 'map_type',
200
- 'allow_late_time', 'external_flag', 'sub_dept', 'department', 'sign_out_status',
201
- ],
219
+ fields: SIGN_FIELDS_CREATE,
202
220
  requiredFields: ['mt_id'],
203
- dateFields: ['sign_time', 'signback_time', 'allow_late_time'],
221
+ // 签到表时间字段**必须带秒**(真机实测:传 yyyy-MM-dd HH:mm 被拒,要求 yyyy-MM-dd HH:mm:ss)
222
+ secondDateFields: ['sign_time', 'signback_time', 'allow_late_time'],
204
223
  summary: 'EB 版新建签到记录(create_meeting_sign):必填 mt_id',
224
+ notes: [
225
+ '仅用于「建会后初始化签到记录」等**该会议尚无签到记录**的场景。',
226
+ '⚠️ **补签不是本接口**:已有记录再 create 会产生重复签到数据,补签请用 meeting.eb.sign.mark。',
227
+ ],
205
228
  },
206
229
  {
207
230
  domain: 'sign',
208
231
  operation: 'meeting.eb.sign.update',
209
232
  kind: 'update',
210
233
  interfacePk: 'update_meeting_sign_info',
211
- fields: [
212
- 'id', 'mt_id', 'hylx', 'site', 'sign_flag', 'user_id', 'attend_type', 'sign_time', 'sign_reson',
213
- 'is_sign', 'longitude', 'latitude', 'sign_remark', 'signback_time', 'backsite', 'map_type',
214
- 'allow_late_time', 'external_flag', 'sub_dept', 'department', 'sign_out_status',
215
- ],
234
+ fields: SIGN_FIELDS_UPDATE,
216
235
  requiredFields: ['id', 'mt_id'],
217
- dateFields: ['sign_time', 'signback_time', 'allow_late_time'],
236
+ // 同 create:签到时间字段必须带秒(yyyy-MM-dd HH:mm:ss)
237
+ secondDateFields: ['sign_time', 'signback_time', 'allow_late_time'],
238
+ // 主键必须走 URL(真机实测:只在 body 里传 id 会报「主键传入不能为空」)
239
+ pkQueryParam: 'id',
218
240
  summary: 'EB 版更新签到记录(update_meeting_sign_info):必传 id + mt_id',
241
+ notes: [
242
+ '**补签 / 补签退的正确入口**(`meeting.eb.sign.mark` 即封装本接口)。',
243
+ '必传 id = **签到记录 id**(从 meeting.eb.sign.list 的 rows[].mainTable.id 取),不是会议 id;mt_id 也要带。',
244
+ 'is_sign:0缺席/1正常/2请假/3迟到/4早退/5未签退/6迟到未签退/7迟到早退;sign_out_status 对应签退状态。',
245
+ ],
219
246
  },
220
247
  {
221
248
  domain: 'receipt',
@@ -225,7 +252,9 @@ export const EB_ENDPOINTS = [
225
252
  countPk: 'query_meeting_receipt_count',
226
253
  queryParams: ['mt_id', 'hrmmember', 'is_attend'],
227
254
  summary: 'EB 版回执列表(query_meeting_receipt_list + count)',
228
- notes: ['is_attend:0否/1是。'],
255
+ // 附带出席汇总(data.progress):参加 / 不参加 / 未回执、回执率、人员类型分布;原始 rows 原样保留。
256
+ summarizeRows: summarizeReceiptRows,
257
+ notes: ['is_attend:0否/1是(URL query 筛选);`attend_status` 空 = 未回执,`0` = 不参加、`1` = 参加。'],
229
258
  },
230
259
  {
231
260
  domain: 'receipt',
@@ -263,6 +292,8 @@ export const EB_ENDPOINTS = [
263
292
  ],
264
293
  requiredFields: ['id', 'mt_id', 'member_id', 'attend_status'],
265
294
  dateFields: ['arrive_date_time', 'return_date_time'],
295
+ // 主键必须走 URL(updateFormData 端点统一要求)
296
+ pkQueryParam: 'id',
266
297
  summary: 'EB 版更新回执(update_meeting_receipt):attend_status 0否/1是',
267
298
  },
268
299
  {
@@ -324,6 +355,8 @@ export const EB_ENDPOINTS = [
324
355
  interfacePk: 'update_mt_topicType_info',
325
356
  fields: ['id', 'name', 'topic_type_num', 'topic_type_name', 'data_status'],
326
357
  requiredFields: ['id'],
358
+ // 主键必须走 URL(updateFormData 端点统一要求)
359
+ pkQueryParam: 'id',
327
360
  summary: 'EB 版更新议题类型(update_mt_topicType_info):必传 id',
328
361
  },
329
362
  {
@@ -362,6 +395,8 @@ export const EB_ENDPOINTS = [
362
395
  ],
363
396
  requiredFields: ['id'],
364
397
  dateFields: ['start_time', 'end_time'],
398
+ // 主键必须走 URL(updateFormData 端点统一要求)
399
+ pkQueryParam: 'id',
365
400
  summary: 'EB 版更新会议议题(update_mt_topic_info):必传 id',
366
401
  notes: ['topic_status:0待开始/1进行中/2已结束。'],
367
402
  },
@@ -383,6 +418,143 @@ export const EB_ENDPOINTS = [
383
418
  '据此判断 EB 版建会是否需走流程(审批开启 → 走 workflow,不由 CLI 直接建会)。',
384
419
  ],
385
420
  },
421
+ // ---------------------------------------------------------------------------
422
+ // 会议决议(决议概述表 + 决议任务表)—— 2026-09-21 新增
423
+ // 链路:create_mt_decision 写「概述 + 明细」→ 用户配置的 ESB 联动按明细生成决议任务
424
+ // → update_mt_isdecision 把会议标记为已决议(is_decision=2 + decision_Id + mt_status)
425
+ // → 后续用 decisionTask.* 查进度、更新完成状态
426
+ // ---------------------------------------------------------------------------
427
+ {
428
+ domain: 'decision',
429
+ operation: 'meeting.eb.decision.list',
430
+ kind: 'list',
431
+ interfacePk: 'query_mt_decision_list',
432
+ countPk: 'query_mt_decision_count',
433
+ queryParams: ['mt_id', 'name', 'creator', 'data_status'],
434
+ summary: 'EB 版会议决议列表(query_mt_decision_list + count)',
435
+ notes: [
436
+ '一个会议**只有一个**决议概述(按 mt_id 查即可)。',
437
+ '主表为概述(mt_content 为决议概述文本),detail1 为决议明细。',
438
+ ],
439
+ },
440
+ {
441
+ domain: 'decision',
442
+ operation: 'meeting.eb.decision.detail',
443
+ kind: 'detail',
444
+ interfacePk: 'query_mt_decision_info',
445
+ summary: 'EB 版会议决议详情(query_mt_decision_info):含 detail1 决议明细',
446
+ },
447
+ {
448
+ domain: 'decision',
449
+ operation: 'meeting.eb.decision.create',
450
+ kind: 'create',
451
+ interfacePk: 'create_mt_decision',
452
+ // ⚠️ data_status **不在**写入字段内:2026-09-21 真机实测该接口拒绝它
453
+ // (DataError:dataKey:data_status,该字段不存在);提交状态由系统自动置为 1(回查列表 data_status=1)。
454
+ fields: ['mt_id', 'mt_content'],
455
+ requiredFields: ['mt_id', 'mt_content'],
456
+ summary: 'EB 版创建会议决议(create_mt_decision):主表概述 + detail1 决议明细',
457
+ notes: [
458
+ 'mt_id 关联会议;mt_content 为概述文本(由调用方结合议题 / 纪要 / 材料汇总后传入)。',
459
+ '**不要传 data_status**:该接口不接受该字段(真机报 DataError:该字段不存在),提交状态由系统自动置 1。',
460
+ 'detail1 至少 1 条:ESB 按明细逐条生成决议任务;`rummager`(检查人)已改为非必填。',
461
+ 'decision_status 默认 0(未完成)、related_type 默认 0(未关联);executors 必须是**员工 id**。',
462
+ ],
463
+ details: [
464
+ {
465
+ node: 'detail1',
466
+ fields: [
467
+ 'sort_number', 'decision_title', 'executors', 'rummager', 'begin_datetime', 'end_datetime',
468
+ 'related_type', 'relate_agenda', 'decision_status', 'relate_task',
469
+ ],
470
+ requiredFields: ['decision_title', 'executors', 'begin_datetime', 'end_datetime', 'decision_status'],
471
+ dateFields: ['begin_datetime', 'end_datetime'],
472
+ // 0未完成 / 1已完成 / 2已延期(非法值 EB 常静默忽略,故入口拦下)
473
+ enumFields: { decision_status: ['0', '1', '2'] },
474
+ minRows: 1,
475
+ purpose: '决议明细:每条 = 一项待办任务',
476
+ },
477
+ ],
478
+ },
479
+ {
480
+ domain: 'decision',
481
+ operation: 'meeting.eb.decision.delete',
482
+ kind: 'delete',
483
+ interfacePk: 'delete_mt_decision',
484
+ summary: 'EB 版删除会议决议(delete_mt_decision):仅传 id(概述 id)',
485
+ notes: ['删除概述**不会**自动回收已生成的决议任务,需要时另行处理。'],
486
+ },
487
+ {
488
+ domain: 'decisionTask',
489
+ operation: 'meeting.eb.decisionTask.list',
490
+ kind: 'list',
491
+ interfacePk: 'query_mt_decision_task_list',
492
+ countPk: 'query_mt_decision_task_count',
493
+ queryParams: ['mt_id', 'relate_decision', 'decision_status', 'executors', 'decision_title'],
494
+ summary: 'EB 版决议任务列表(query_mt_decision_task_list + count):一条任务 = 一条决议明细',
495
+ // 声明式进度汇总:结果进 `data.progress`(原始 rows 原样保留),实现见 task-progress.ts。
496
+ summarizeRows: summarizeTaskProgress,
497
+ notes: [
498
+ '★ **`data.progress` 已直接给出进度与延误**,不需要自己解析 detail1:`progress.summary` 是整页汇总(total/done/overdue/inProgress/pending);`progress.items[]` 逐任务给出 `progress.status`(done 全员完成 / overdue 有人延期 / inProgress 部分完成 / pending 尚未开始)与 `members[]`(每人 executorId / executorName / status / finishDate)。',
499
+ '任务由用户配置的 **ESB 联动**生成:一条**决议明细**生成**一个任务**;明细里写多个执行人 ⇒ 该任务**多人共同跟进**(真机实测:1 明细 + 2 执行人 → 仅 1 个任务)。',
500
+ '看某会议的全部任务 → 传 mt_id;看某人的任务 → 传 executors(员工 id);分页用 pageNo/pageSize(分页必须走 body.pageInfo,CLI 已处理)。',
501
+ '★ **读进度请看 `detail1`**:每条 = 一个执行人的跟进记录,含 `finish_status`(未完成/已完成/已延期)、`finish_date`、`executor`;**同一执行人重复更新会覆盖其记录,不同执行人是追加**(真机实测互不覆盖)。',
502
+ '⚠️ **`mainTable.decision_status` 不能作为进度依据**:真机实测它**始终为「未完成」**,既不随 detail1 变化,也无法经 `update_mt_decision_task` 写入(该接口只映射 detail1),故 catalog 未暴露该字段。',
503
+ '任务由明细带出 `begin_datetime`/`end_datetime`/`decision_title`,可用于展示计划周期。',
504
+ ],
505
+ },
506
+ {
507
+ domain: 'decisionTask',
508
+ operation: 'meeting.eb.decisionTask.update',
509
+ kind: 'update',
510
+ interfacePk: 'update_mt_decision_task',
511
+ // ⚠️ 只开放 id:真机实测即使传主表 `decision_status`,接口返回成功但**值不生效**
512
+ // (该接口只映射 detail1 明细),故不暴露它以免误导。
513
+ fields: ['id'],
514
+ requiredFields: ['id'],
515
+ // 主键必须走 URL(updateFormData 端点统一要求)
516
+ pkQueryParam: 'id',
517
+ summary: 'EB 版更新决议任务完成状态(update_mt_decision_task):按执行人更新 detail1',
518
+ notes: [
519
+ 'id = **任务 id**(decisionTask.list 的 rows[].mainTable.id),不是会议 id、不是决议 id。',
520
+ 'detail1 传 executor(员工 id)+ finish_status(0未完成/1已完成/2已延期)+ finish_date(**带秒**:yyyy-MM-dd HH:mm:ss)。',
521
+ '⚠️ **finish_date 是服务端必填**(真机:不传报「存为未填写的必填字段: finish_date」);把任务改回「未完成」时传一个**空格**即可显式清空(CLI 会落库为空串,与页面生成的未完成记录一致)。',
522
+ '不传 operationinfo.operateType 时为「更新追加」,不会覆盖其他执行人的记录 —— 真机实测:同一任务上两人分别跟进后,detail1 保留**两条**记录。',
523
+ '⚠️ **任务主表的 decision_status 不随 detail1 变化**(真机实测始终为「未完成」);查任务进度请看 detail1 的 finish_status。',
524
+ '写入后建议回查 decisionTask.list 确认;EB 写接口报错**不代表没有写入**。',
525
+ ],
526
+ details: [
527
+ {
528
+ node: 'detail1',
529
+ fields: ['executor', 'finish_status', 'finish_date'],
530
+ // finish_date 服务端也是必填;「未完成」时传空格显式清空(见 factory 的 normalizeDetailRow)。
531
+ requiredFields: ['executor', 'finish_status', 'finish_date'],
532
+ // 0未完成 / 1已完成 / 2已延期(非法值 EB 常静默忽略,故入口拦下并提示可选值)
533
+ enumFields: { finish_status: ['0', '1', '2'] },
534
+ // finish_date 必须**带秒**:真机实测传 "2026-09-21 18:30" 被拒(要求 yyyy-MM-dd HH:mm:ss)。
535
+ secondDateFields: ['finish_date'],
536
+ minRows: 1,
537
+ purpose: '执行人跟进:同一任务的每个执行人分别记录完成状态',
538
+ },
539
+ ],
540
+ },
541
+ {
542
+ domain: 'meeting',
543
+ operation: 'meeting.eb.meeting.markDecided',
544
+ kind: 'update',
545
+ interfacePk: 'update_mt_isdecision',
546
+ fields: ['id', 'decision_Id', 'is_decision', 'mt_status'],
547
+ requiredFields: ['id', 'is_decision'],
548
+ // 主键必须走 URL(updateFormData 端点统一要求)
549
+ pkQueryParam: 'id',
550
+ summary: 'EB 版把会议标记为已决议(update_mt_isdecision):写回关联决议 + 决议状态 + 会议状态',
551
+ notes: [
552
+ 'is_decision:0未决议 / 1决议临时保存 / **2决议提交完成**。',
553
+ 'decision_Id:关联的决议概述 id(decision.create 的 dataIds[0])。',
554
+ 'mt_status:**8结束**(产生决议即视为会议结束),也可按需传 9进行中 等。',
555
+ 'detail1(汇报人)/ detail2(服务项目)已由接口配置清空,**无需传**。',
556
+ ],
557
+ },
386
558
  ];
387
559
  /** 写操作(create/update/delete)需要确认链。 */
388
560
  export function isWriteKind(kind) {
@@ -20,8 +20,8 @@ import { EB_BASE, ebBusinessSuccess, extractEbRows, queryBody } from './factory.
20
20
  * 占用视图与回执只对有效状态生成,故无需再额外过滤;
21
21
  * - 命中后**严格按应用设置**处理,CLI 不额外加码:
22
22
  * - `1` = **禁止提交** → 抛 `conflict_rejected`,怎么都不允许提交(不询问、不新建);
23
- * - `0` = **仅提醒** → 只写入 warnings(如实告知冲突、建议换时间/换地点),
24
- * **不阻止提交**:用户了解冲突后仍要求新建时,可继续 prepare → apply 完成建会。
23
+ * - `0` = **仅提醒** → 只写入 warnings(如实告知冲突、建议换时间/换地点、决定权交用户);
24
+ * 服务端与 CLI 都不阻止提交,但 CLI **不主动建议忽略冲突**、不替用户做决定。
25
25
  *
26
26
  * 失败语义与标准版(create.ts 的 runMandatoryConflictChecks)对齐:
27
27
  * - 应用设置读取失败:非致命,按「开启检测 + 仅提醒」继续,并在 warnings 中如实说明;
@@ -41,12 +41,16 @@ function errorText(error) {
41
41
  /** 单页 EB 列表查询(list,不计数;筛选走 URL query,body 带 datajson)。 */
42
42
  async function requestEbList(env, interfacePk, query, operation) {
43
43
  const session = await env.host.getSession();
44
+ // ⚠️ 分页必须进 body.pageInfo(EB 只认 body):仅放 URL query 时 EB 恒定返回首页 10 条,
45
+ // 于是 listAllEbRows 会在第一页误判「末页」⇒ 冲突检测只比对前 10 条(漏检,2026-09-21 修复)。
46
+ const pageNo = typeof query.pageNo === 'number' ? query.pageNo : 1;
47
+ const pageSize = typeof query.pageSize === 'number' ? query.pageSize : PAGE_SIZE;
44
48
  const response = await env.host.request({
45
49
  method: 'POST',
46
50
  path: `${EB_BASE}/getFormDataList/${interfacePk}`,
47
51
  operation,
48
52
  query,
49
- body: queryBody(session.userId),
53
+ body: queryBody(session.userId, { pageNo, pageSize }),
50
54
  acceptBusiness: ebBusinessSuccess,
51
55
  });
52
56
  // 行数据可能是 { mainTable: {...} } 包裹,统一摊平(与 member-conflict.mjs 同口径)。
@@ -184,7 +188,7 @@ export async function runEbConflictCheck(input, env, operation, options = {}) {
184
188
  * 命中冲突的处置(**fail-fast**):
185
189
  * - 禁止提交 → **立即抛错并结束**,**不再继续后续检测** —— 结论已定局为拒绝,
186
190
  * 继续检测只会多花请求,也不会改变结果;
187
- * - 仅提醒 → 记入 warnings,**不阻止提交**(用户了解冲突后坚持新建即可继续)。
191
+ * - 仅提醒 → 记入 warnings,**不阻止提交**(如实告知 + 建议改期改址,是否继续由用户决定)。
188
192
  * `throwOnReject=false`(只查不建的 operation)时,禁止项改为写入 warnings 而不抛错。
189
193
  */
190
194
  const handleHit = (action, message, details) => {
@@ -195,8 +199,8 @@ export async function runEbConflictCheck(input, env, operation, options = {}) {
195
199
  warnings.push(text);
196
200
  return;
197
201
  }
198
- warnings.push(`${message};应用设置仅提醒(action=0):请先把冲突如实告知用户,并建议更换时间或地点;`
199
- + '若用户了解冲突后仍要求新建,可以继续提交完成建会(仅提醒不阻止提交)');
202
+ warnings.push(`${message};应用设置仅提醒(action=0):本次不阻止提交,请如实告知用户该冲突并建议更换时间或地点,`
203
+ + '由用户决定是否继续(不要主动建议忽略冲突,也不要替用户做决定)');
200
204
  };
201
205
  // ---- 1) 会议室冲突 ----
202
206
  if (input.address) {
@@ -270,12 +274,14 @@ export async function runEbConflictCheck(input, env, operation, options = {}) {
270
274
  export const ebMeetingWritePreflight = async ({ endpoint, payload, args, env }) => {
271
275
  if (endpoint.interfacePk !== 'create_meeting' && endpoint.interfacePk !== 'change_meeting')
272
276
  return [];
273
- const begin = payload.begin_datetime;
274
- const end = payload.end_datetime;
277
+ // 载荷自 2026-09-21 起为结构化(mainTable + details),冲突检测只关心主表字段。
278
+ const main = payload.mainTable;
279
+ const begin = main.begin_datetime;
280
+ const end = main.end_datetime;
275
281
  if (typeof begin !== 'string' || typeof end !== 'string' || !begin || !end)
276
282
  return [];
277
- const address = typeof payload.address === 'string' && payload.address ? payload.address : undefined;
278
- const hrmMembers = typeof payload.hrm_members === 'string' && payload.hrm_members ? payload.hrm_members : undefined;
283
+ const address = typeof main.address === 'string' && main.address ? main.address : undefined;
284
+ const hrmMembers = typeof main.hrm_members === 'string' && main.hrm_members ? main.hrm_members : undefined;
279
285
  if (!address && !hrmMembers)
280
286
  return [];
281
287
  const outcome = await runEbConflictCheck({
@@ -283,7 +289,7 @@ export const ebMeetingWritePreflight = async ({ endpoint, payload, args, env })
283
289
  endDatetime: end,
284
290
  ...(address ? { address } : {}),
285
291
  ...(hrmMembers ? { hrmMembers } : {}),
286
- ...(typeof payload.org_members === 'string' && payload.org_members ? { orgMembers: payload.org_members } : {}),
292
+ ...(typeof main.org_members === 'string' && main.org_members ? { orgMembers: main.org_members } : {}),
287
293
  ...(typeof args.id === 'string' || typeof args.id === 'number' ? { excludeMtId: String(args.id) } : {}),
288
294
  }, env, endpoint.operation === 'meeting.eb.meeting.change' ? 'meeting.eb.meeting.change.prepare' : 'meeting.eb.meeting.create.prepare');
289
295
  return outcome.warnings;