cloudcc-cli 2.3.9 → 2.4.1

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 (53) hide show
  1. package/README.md +48 -0
  2. package/bin/cc.js +2 -1
  3. package/bin/index.js +1 -0
  4. package/cloudcc-dev-skill/SKILL.md +31 -8
  5. package/cloudcc-dev-skill/cloudcc-dev-html.md +42 -0
  6. package/cloudcc-dev-skill/config.json +2 -2
  7. package/mcp/index.js +10 -4
  8. package/mcp/tools/JSP Migrator/handler.js +51 -866
  9. package/mcp/tools/Object Creator/handler.js +14 -4
  10. package/mcp/tools/Trigger List Retriever/handler.js +24 -8
  11. package/package.json +1 -1
  12. package/src/classes/docs/devguide.md +863 -356
  13. package/src/classes/docs/introduction.md +279 -143
  14. package/src/jsp/analyze.js +17 -0
  15. package/src/jsp/doc.js +18 -0
  16. package/src/jsp/docs/devguide.md +111 -0
  17. package/src/jsp/docs/introduction.md +50 -0
  18. package/src/jsp/docs.js +21 -0
  19. package/src/jsp/index.js +14 -0
  20. package/src/jsp/migration.js +871 -0
  21. package/src/jsp/split.js +17 -0
  22. package/src/object/create.js +36 -10
  23. package/src/object/docs/devguide.md +6 -3
  24. package/src/project/docs/devguide.md +1 -1
  25. package/src/script/docs/devguide.md +22 -2
  26. package/src/timer/docs/devguide.md +1038 -400
  27. package/src/timer/docs/introduction.md +343 -231
  28. package/src/triggers/docs/devguide.md +1027 -329
  29. package/src/triggers/docs/introduction.md +640 -369
  30. package/src/triggers/get.js +8 -0
  31. package/src/version/listModuleCommands.js +6 -0
  32. package/target/classes/com/cloudcc/core/BaseException.class +0 -0
  33. package/target/classes/com/cloudcc/core/BusiException.class +0 -0
  34. package/target/classes/com/cloudcc/core/CCObject.class +0 -0
  35. package/target/classes/com/cloudcc/core/CCSchedule.class +0 -0
  36. package/target/classes/com/cloudcc/core/CCService.class +0 -0
  37. package/target/classes/com/cloudcc/core/CCTrigger.class +0 -0
  38. package/target/classes/com/cloudcc/core/CCTriggerHandler.class +0 -0
  39. package/target/classes/com/cloudcc/core/DevLogger.class +0 -0
  40. package/target/classes/com/cloudcc/core/OperatationEnum.class +0 -0
  41. package/target/classes/com/cloudcc/core/PeakInterf.class +0 -0
  42. package/target/classes/com/cloudcc/core/SendEmail.class +0 -0
  43. package/target/classes/com/cloudcc/core/ServiceResult.class +0 -0
  44. package/target/classes/com/cloudcc/core/StringUtils.class +0 -0
  45. package/target/classes/com/cloudcc/core/TimeUtil.class +0 -0
  46. package/target/classes/com/cloudcc/core/Tool$1.class +0 -0
  47. package/target/classes/com/cloudcc/core/Tool.class +0 -0
  48. package/target/classes/com/cloudcc/core/TriggerInvoker.class +0 -0
  49. package/target/classes/com/cloudcc/core/TriggerMethod.class +0 -0
  50. package/target/classes/com/cloudcc/core/TriggerTimeEnum.class +0 -0
  51. package/target/classes/com/cloudcc/core/UserInfo.class +0 -0
  52. package/test/jsp.cli.test.js +70 -0
  53. package/test/object.cli.test.js +9 -1
@@ -1,554 +1,1192 @@
1
- # CloudCC 定时作业完全指南
1
+ # CloudCC 定时器类 AI 开发规范
2
2
 
3
- > 定时作业(Scheduled Jobs)是 CloudCC CRM 系统中的后台任务调度机制,用于在指定时间自动执行业务逻辑。
3
+ ## 1. 文档目的
4
4
 
5
- ---
5
+ 本文用于约束 AI 在当前 CloudCC 项目中编写定时器类时的分析方式、实现方式、SDK 选型和输出要求。
6
+
7
+ 目标不是让 AI “能写出代码”即可,而是让 AI 写出的定时器类:
8
+
9
+ - 适合放在定时器而不是触发器或页面脚本中
10
+ - 符合 CloudCC 官方 SDK 用法
11
+ - 符合 `cloudcc-cli` 的目录和发布约束
12
+ - 符合当前项目的主流实现模式
13
+ - 具备幂等性、可观测性、批量处理意识和时区安全意识
14
+
15
+ ## 2. 依据来源
16
+
17
+ - 官方 SDK 文档提供 `CCObject`、`CCService`、`SendEmail`、`DevLogger`、`TimeUtil` 等核心 API 依据
18
+ - `2-timer-classes-analysis.md` 提供当前项目定时器使用场景和共性模式
19
+ - `timer devguide` 提供本地目录、CLI、发布和 SOURCE 区域约束
20
+
21
+ ## 3. 与 introduction 的分工(避免重复)
22
+
23
+ 为避免与 `timer introduction` 内容重复,本 `devguide` 只保留“开发落地规范”:
24
+
25
+ - 命令与入参(可直接执行)
26
+ - 目录与文件约束(可直接检查)
27
+ - SDK 用法与边界(可直接编码)
28
+ - 代码模板与禁止事项(可直接评审)
29
+
30
+ “定时器是什么、能解决什么、与触发器差异、适用/不适用场景”等概念说明,统一以 `cloudcc doc timer introduction` 为准。
31
+
32
+ ## 4. 文件与交付规范
33
+
34
+ 这是 AI 必须遵守的第一层约束。
6
35
 
7
- ## CLI 与本地文件(必读)
36
+ ### 4.1 目录与文件来源
8
37
 
9
- 本仓库中的**定时类**(与定时作业绑定的 Java 类)通过 **cloudcc-cli** 与平台同步,本地目录为 **`schedule/<类名>/`**(内含 `*.java` 与 `config.json`),源码中的 `// @SOURCE_CONTENT_START` … `// @SOURCE_CONTENT_END` 与发布、拉取逻辑一致。**必须通过下列命令** 完成新建目录、发布、拉取与删除;不要手工新建 `schedule/` 子目录、不要整包复制其他项目的定时类、不要私自篡改 `config.json` 中的 `id` 或版本字段。
38
+ - 定时器目录必须位于 `schedule/<类名>/`
39
+ - 每个定时器目录包含主类 `*.java` 和 `config.json`
40
+ - 定时器目录必须通过 `cloudcc create timer <name>` 创建
10
41
 
11
- **允许的做法**:在 CLI 已生成的主类中,仅在上述 SOURCE 标记之间编写业务逻辑;与云端列表、详情、拉取、删除、发布相关的操作一律走命令。
42
+ ### 4.2 AI 不得做的事情
12
43
 
13
- 执行命令前请确认:已完成 `cloudcc doc project devguide` 中的环境初始化,项目根目录配置可用且包含 `accessToken`。
44
+ - 不要手工新建 `schedule/` 子目录
45
+ - 不要整包复制其他项目的定时器目录
46
+ - 不要手工修改 `config.json` 中的 `id` 或版本字段
47
+ - 不要在 `// @SOURCE_CONTENT_START` 与 `// @SOURCE_CONTENT_END` 之外写业务逻辑
14
48
 
15
- ### 命令总览(以代码实现为准)
49
+ ### 4.3 AI 允许做的事情
50
+
51
+ - 只在 CLI 生成的主类 SOURCE 区域内实现业务逻辑
52
+ - 保持 `package schedule.<类名>;` 与目录名一致
53
+ - 让类继承 `CCSchedule`
54
+ - 构造方法名与类名一致
55
+
56
+ ### 4.4 timer 模块支持的 CLI 命令总览(重点:入参)
57
+
58
+ 说明:
59
+
60
+ - 下文命令中的资源名使用 `timer`,也可使用别名 `schedule`(两者路由到同一模块)。
61
+ - `projectPath` 未传时,默认使用当前工作目录。
62
+
63
+ #### 1) 创建定时类
64
+
65
+ 命令:
16
66
 
17
67
  ```bash
18
68
  cloudcc create timer <name>
69
+ ```
70
+
71
+ 参数:
72
+
73
+ | 参数 | 必填 | 类型 | 说明 |
74
+ | --- | --- | --- | --- |
75
+ | `name` | 是 | `string` | 定时类名称(同时作为目录名、Java 类名) |
76
+
77
+ 示例:
78
+
79
+ ```bash
80
+ cloudcc create timer DailySyncJob
81
+ ```
82
+
83
+ ---
84
+
85
+ #### 2) 发布定时类
86
+
87
+ 命令:
88
+
89
+ ```bash
19
90
  cloudcc publish timer <name>
91
+ ```
92
+
93
+ 参数:
94
+
95
+ | 参数 | 必填 | 类型 | 说明 |
96
+ | --- | --- | --- | --- |
97
+ | `name` | 是 | `string` | 本地 `schedule/<name>/` 目录名 |
98
+
99
+ 示例:
100
+
101
+ ```bash
102
+ cloudcc publish timer DailySyncJob
103
+ ```
104
+
105
+ ---
106
+
107
+ #### 3) 拉取定时类(按本地名称)
108
+
109
+ 命令:
110
+
111
+ ```bash
20
112
  cloudcc pull timer <name>
113
+ ```
114
+
115
+ 参数:
116
+
117
+ | 参数 | 必填 | 类型 | 说明 |
118
+ | --- | --- | --- | --- |
119
+ | `name` | 是 | `string` | 本地 `schedule/<name>/` 目录名;会读取该目录 `config.json` 中的 `id` 到线上拉取 |
120
+
121
+ 示例:
122
+
123
+ ```bash
124
+ cloudcc pull timer DailySyncJob
125
+ ```
126
+
127
+ ---
128
+
129
+ #### 4) 查询定时类列表(支持条件查询)
130
+
131
+ 命令:
132
+
133
+ ```bash
21
134
  cloudcc get timer [listQueryJson] [projectPath]
22
- cloudcc detail timer <name>
23
- cloudcc detail timer "" <id>
135
+ ```
136
+
137
+ `listQueryJson` 推荐结构:
138
+
139
+ ```json
140
+ {
141
+ "shownum": 2000,
142
+ "showpage": 1,
143
+ "sname": "",
144
+ }
145
+ ```
146
+
147
+ 字段说明:
148
+
149
+ | 字段 | 类型 | 必填 | 说明 |
150
+ | --- | --- | --- | --- |
151
+ | `shownum` | `number|string` | 否 | 每页条数,默认 `2000` |
152
+ | `showpage` | `number|string` | 否 | 页码,默认 `1` |
153
+ | `sname` | `string` | 否 | 名称筛选关键字,模糊查询 |
154
+
155
+ 示例:
156
+
157
+ ```bash
158
+ cloudcc get timer "$(node -e 'console.log(encodeURI(JSON.stringify({shownum:2000,showpage:1,fid:\"\",sname:\"Daily\",rptcond:\"\",rptorder:\"\"})))')"
159
+ ```
160
+
161
+ ---
162
+
163
+ #### 5) 查看定时类详情
164
+
165
+ 命令:
166
+
167
+ ```bash
168
+ cloudcc detail timer <name> <id>
169
+ ```
170
+
171
+ 参数规则(实现口径):
172
+
173
+ | 参数 | 必填 | 类型 | 说明 |
174
+ | --- | --- | --- | --- |
175
+ | `name` | 条件必填 | `string` | 传 `name` 时优先查本地;本地不完整时再走线上 |
176
+ | `id` | 条件必填 | `string` | 当 `name` 为空时,必须传 `id` 走线上查询 |
177
+
178
+ 等价理解:`name` 与 `id` 至少传一个,优先使用 `name` 路径。
179
+
180
+ 示例(按本地名):
181
+
182
+ ```bash
183
+ cloudcc detail timer DailySyncJob
184
+ ```
185
+
186
+ 示例(按线上 id):
187
+
188
+ ```bash
189
+ cloudcc detail timer "" a0Bxxxxxxxxxxxx
190
+ ```
191
+
192
+ ---
193
+
194
+ #### 6) 按 ID 拉取并落地到本地目录
195
+
196
+ 命令:
197
+
198
+ ```bash
24
199
  cloudcc pullList timer <id> <projectPath>
25
- cloudcc delete timer <nameOrId> [projectPath]
26
- cloudcc doc timer <introduction|devguide>
27
200
  ```
28
201
 
29
- 参数约定:
202
+ 参数:
203
+
204
+ | 参数 | 必填 | 类型 | 说明 |
205
+ | --- | --- | --- | --- |
206
+ | `id` | 是 | `string` | 线上定时类 ID |
207
+ | `projectPath` | 是 | `string` | 项目根目录;会写入到 `<projectPath>/schedule/<name>/` |
208
+
209
+ 示例:
210
+
211
+ ```bash
212
+ cloudcc pullList timer a0Bxxxxxxxxxxxx /path/to/project
213
+ ```
214
+
215
+ ---
216
+
217
+ #### 7) 删除定时类
218
+
219
+ 命令:
30
220
 
31
- - `name`:定时类名,与 `schedule/<name>/` 目录名一致。
32
- - `listQueryJson`:可选;列表查询 JSON `encodeURI(JSON.stringify(...))` 编码后传入;不传则使用默认分页参数。
33
- - `projectPath`:项目根路径,可选。
34
- - `id`:线上定时类 ID。`detail` 仅查服务器时:`cloudcc detail timer "" <id>`。`pullList` 必填。
35
- - `nameOrId`:本地目录名或类 ID;若本地 `config.json` 含 `id`,删除时优先使用该 ID。
221
+ ```bash
222
+ cloudcc delete timer <nameOrId> [projectPath]
223
+ ```
36
224
 
37
- ### 命令作用摘要
225
+ 参数规则:
38
226
 
39
- | 命令 | 作用 |
40
- |------|------|
41
- | `create` | `schedule/<name>/` 生成继承 `CCSchedule` Java 模板与 `config.json` |
42
- | `publish` | SOURCE 区域提交到服务器;首次成功后可写回 `config.json` `id` |
43
- | `pull` | 按本地 `id` 拉取远端源码,覆盖主类中 SOURCE 区域(需已发布) |
44
- | `get` | 查询线上定时类列表(JSON 输出) |
45
- | `detail` | 按类名优先读本地;或仅按 `id` 读服务器 |
46
- | `pullList` | 按类 `id` 将线上定时类落到指定项目的 `schedule/<类名>/` |
47
- | `delete` | 删除服务器上的定时类 |
48
- | `doc` | 输出模块文档;`devguide` 含附录后端 Java SDK 速查 |
227
+ | 参数 | 必填 | 类型 | 说明 |
228
+ | --- | --- | --- | --- |
229
+ | `nameOrId` | | `string` | 可传本地目录名或线上 ID;若本地 `schedule/<nameOrId>/config.json` 存在且带 `id`,优先使用其中 `id` 删除 |
230
+ | `projectPath` | | `string` | 项目根目录,默认当前目录 |
49
231
 
50
- ### 推荐操作顺序
232
+ 示例(按名称):
51
233
 
52
234
  ```bash
53
- # 1) 查看线上已有定时类(可选)
54
- cloudcc get timer
235
+ cloudcc delete timer DailySyncJob
236
+ ```
55
237
 
56
- # 2) 新建定时类(仅通过 create 生成目录与模板)
57
- cloudcc create timer MySchedule
238
+ 示例(按 id):
58
239
 
59
- # 3) 编辑 schedule/MySchedule/MySchedule.java 中 SOURCE 区域后发布
60
- cloudcc publish timer MySchedule
240
+ ```bash
241
+ cloudcc delete timer a0Bxxxxxxxxxxxx
242
+ ```
243
+
244
+ ---
61
245
 
62
- # 4) 与服务器对齐时拉取
63
- cloudcc pull timer MySchedule
246
+ #### 8) 文档命令
64
247
 
65
- # 5) 按已知线上 ID 拉到指定项目
66
- cloudcc pullList timer <线上类ID> <projectPath>
248
+ 命令:
67
249
 
68
- # 6) 删除
69
- cloudcc delete timer MySchedule
250
+ ```bash
251
+ cloudcc doc timer <introduction|devguide>
70
252
  ```
71
253
 
72
- ### 文档子命令
254
+ 参数:
255
+
256
+ | 参数 | 必填 | 类型 | 说明 |
257
+ | --- | --- | --- | --- |
258
+ | `introduction|devguide` | 是 | `string` | `introduction` 返回概念文档;`devguide` 返回开发规范(并附 SDK 速查) |
259
+
260
+ 示例:
73
261
 
74
262
  ```bash
75
263
  cloudcc doc timer introduction
76
264
  cloudcc doc timer devguide
77
265
  ```
78
266
 
79
- 仅支持 `introduction` `devguide`。
267
+ ## 5. AI 编写定时器类的核心原则
80
268
 
81
- ---
269
+ ### 5.1 先分析,再编码
82
270
 
83
- ## 📌 什么是定时作业?
271
+ AI 在写代码前,至少应明确以下内容:
84
272
 
85
- 定时作业是一种**自动化任务调度系统**,允许你:
273
+ - 主对象是什么
274
+ - 关联对象是什么
275
+ - 触发频率是什么
276
+ - 筛选条件是什么
277
+ - 执行动作是什么
278
+ - 是否存在重复执行风险
279
+ - 是否需要批量处理
280
+ - 是否需要通知
281
+ - 是否需要日志
282
+ - 是否需要失败补偿
86
283
 
87
- - 设定任务的执行时间(如每天上午 8 点、每周一、每月 1 号)
88
- - 关联自定义的业务逻辑代码(定时类)
89
- - 系统自动在指定时间触发执行,无需人工干预
284
+ ### 5.2 优先配置化,不要硬编码
90
285
 
91
- **类比理解:** 就像手机的闹钟功能,但触发的是业务代码而不是铃声。
286
+ 以下信息如果未来可能变化,优先配置化,不要直接写死在代码里:
92
287
 
93
- ---
288
+ - 提醒天数
289
+ - 阈值条件
290
+ - 模版 ID
291
+ - 收件人范围
292
+ - 开关标记
293
+ - 外部接口地址或行为参数
94
294
 
95
- ## 🎯 定时作业的主要作用
295
+ 如果必须读取配置,优先使用官方 SDK 的自定义设置能力。
96
296
 
97
- ### 1. 自动化重复性任务
297
+ ### 5.3 必须考虑幂等性
98
298
 
99
- 将人工需要定期执行的操作自动化,例如:
299
+ 定时器会重复执行,因此 AI 生成代码时必须避免“重复跑一次就重复造数据”。
100
300
 
101
- - 每天发送收款提醒邮件
102
- - 每周生成销售报表
103
- - 每月清理过期数据
301
+ 常见幂等策略包括:
104
302
 
105
- ### 2. 时间敏感的业务逻辑
303
+ - 先判断是否已处理,再执行
304
+ - 通过状态位、标记位、执行日期控制重复执行
305
+ - 通过业务唯一键判断是否已存在目标记录
306
+ - 通过补偿表或日志表判断是否已成功处理
106
307
 
107
- 在特定时间点必须执行的操作:
308
+ ### 5.4 必须考虑批量处理
108
309
 
109
- - 合同到期前 30 天提醒续约
110
- - 客户生日当天发送祝福
111
- - 季度末自动生成业绩报告
310
+ 定时器天然面向批量数据。AI 不能默认按“单笔页面逻辑”写法来写。
112
311
 
113
- ### 3. 后台批处理
312
+ 应优先考虑:
114
313
 
115
- 处理大量数据的离线任务:
314
+ - 分页查询
315
+ - 分批写入
316
+ - 减少循环内查询
317
+ - 减少循环内单条更新
116
318
 
117
- - 夜间同步外部系统数据
118
- - 批量更新客户状态
119
- - 计算佣金和业绩
319
+ ### 5.5 必须考虑可观测性
120
320
 
121
- ### 4. 监控与预警
321
+ AI 生成的定时器类至少要做到:
122
322
 
123
- 持续监控系统状态并触发告警:
323
+ - 关键路径有日志
324
+ - 异常可定位
325
+ - 批处理数量可观察
326
+ - 失败信息可追踪
124
327
 
125
- - 客户超过 15 天未联系 → 提醒销售跟进
126
- - 收款计划逾期 → 通知财务人员
127
- - 资产即将失效 → 自动生成业务机会
328
+ ### 5.6 必须考虑时区安全
128
329
 
129
- ---
330
+ 涉及日期比较、日期格式化、写库时间时,不能默认依赖本地时区。
331
+
332
+ 应优先使用 `TimeUtil`。
333
+
334
+ ## 6. 官方 SDK 详细速查
130
335
 
131
- ## 💡 为什么要用定时作业?
336
+ - 本节优先给出方法签名、入参、返回值和使用场景
337
+ - 表中“必填”信息来源于官方文档
338
+ - 如果某个批量方法在当前项目里很常见,但官方页面没有展开签名,会单独标注“项目约定”
339
+ - 当前项目大量定时器直接调用 `this.cquery(...)`、`this.cqlQuery(...)`、`this.insert(...)` 等 inherited 方法;AI 在理解参数语义时,应以官方 `CCService` 版本为准
132
340
 
133
- ### 对比人工操作
341
+ ### 6.1 `CCObject`
134
342
 
135
- | 维度 | 人工操作 | 定时作业 |
136
- |------|----------|----------|
137
- | **准确性** | 可能遗忘、出错 | 100% 准时执行 |
138
- | **效率** | 耗时耗力 | 自动执行,零人力成本 |
139
- | **一致性** | 不同人操作可能有差异 | 每次执行逻辑一致 |
140
- | **可扩展性** | 任务多了忙不过来 | 可同时运行多个任务 |
141
- | **可追溯** | 难以追踪谁什么时候做的 | 完整执行日志 |
343
+ 类定位:
142
344
 
143
- ### 核心价值
345
+ - CloudCC 对象封装类
346
+ - 用于承载新增、更新、删除、共享等对象数据
144
347
 
348
+ #### 构造方法 1
349
+
350
+ ```java
351
+ public CCObject()
145
352
  ```
146
- 定时作业 = 自动化 + 准时性 + 可追溯
353
+
354
+ 说明:
355
+
356
+ - 官方提供默认构造
357
+ - 在当前项目定时器中较少单独使用
358
+
359
+ #### 构造方法 2
360
+
361
+ ```java
362
+ public CCObject(String ccobj)
147
363
  ```
148
364
 
149
- ---
365
+ 参数说明:
366
+
367
+ | 参数 | 类型 | 必填 | 说明 |
368
+ | --- | --- | --- | --- |
369
+ | `ccobj` | `String` | 是 | 对象 API 名 |
370
+
371
+ 返回:
150
372
 
151
- ## 🔧 定时作业能解决哪些问题?
373
+ - `CCObject` 实例
152
374
 
153
- ### 问题 1:遗忘和延误
375
+ AI 使用要求:
154
376
 
155
- **场景:** 销售忘记跟进客户,导致商机流失
377
+ - 新增普通记录时优先用这个构造器
378
+ - `ccobj` 必须写对象 API 名,不要写对象标签名
156
379
 
157
- **解决:** 设置定时作业检测客户最后联系时间,超过 15 天自动提醒
380
+ #### 构造方法 3
158
381
 
382
+ ```java
383
+ public CCObject(String ccobj, String isShared)
159
384
  ```
160
- ┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐
161
- │ 客户最后联系时间 │ → │ 定时作业检测 │ → │ 创建跟进活动 │
162
- │ > 15 天 │ │ (每天 8:00) │ │ 并通知销售 │
163
- └─────────────────┘ └──────────────┘ └─────────────────┘
385
+
386
+ 参数说明:
387
+
388
+ | 参数 | 类型 | 必填 | 说明 |
389
+ | --- | --- | --- | --- |
390
+ | `ccobj` | `String` | 是 | 对象 API 名 |
391
+ | `isShared` | `String` | 是 | 共享标识,官方建议使用 `CCObject.IS_SHARED` |
392
+
393
+ 返回:
394
+
395
+ - `CCObject` 实例
396
+
397
+ AI 使用要求:
398
+
399
+ - 仅在共享表对象场景使用
400
+ - 不要自己发明共享标识字符串,优先使用 `CCObject.IS_SHARED`
401
+
402
+ #### 常用对象方法
403
+
404
+ 官方文档列出:
405
+
406
+ - `getUserId()`
407
+ - `getOrgId()`
408
+ - `getRoleId()`
409
+
410
+ AI 使用要求:
411
+
412
+ - 如果需要读取当前对象上下文中的用户、组织、角色信息,可使用这些方法
413
+ - 定时器的主要业务数据写入仍以 `put` 为主
414
+
415
+ ### 6.2 `CCService`
416
+
417
+ 类定位:
418
+
419
+ - CloudCC 核心对象服务类
420
+ - 提供对象增删改查、自定义设置、共享删除等能力
421
+
422
+ #### 构造函数
423
+
424
+ ```java
425
+ public CCService(UserInfo userInfo)
426
+ ```
427
+
428
+ 参数说明:
429
+
430
+ | 参数 | 类型 | 必填 | 说明 |
431
+ | --- | --- | --- | --- |
432
+ | `userInfo` | `UserInfo` | 是 | 当前用户对象 |
433
+
434
+ 返回:
435
+
436
+ - `CCService` 实例
437
+
438
+ AI 使用要求:
439
+
440
+ - 定时器中默认先初始化 `CCService cs = new CCService(userInfo);`
441
+ - 除非使用 `CCSchedule` 已提供的同语义快捷方法,否则统一从 `cs` 调用 SDK
442
+
443
+ ### 6.3 `insert`
444
+
445
+ 方法签名:
446
+
447
+ ```java
448
+ public ServiceResult insert(CCObject ccobj) throws BusiException
449
+ ```
450
+
451
+ 参数说明:
452
+
453
+ | 参数 | 类型 | 必填 | 说明 |
454
+ | --- | --- | --- | --- |
455
+ | `ccobj` | `CCObject` | 是 | 待新增的 CloudCC 对象 |
456
+
457
+ 返回:
458
+
459
+ - `ServiceResult`
460
+
461
+ 适用场景:
462
+
463
+ - 新增单条记录
464
+ - 新增任务、提醒、日志类单条对象
465
+
466
+ AI 使用要求:
467
+
468
+ - 先构造 `CCObject`,再 `put` 字段,最后 `insert`
469
+ - 不要在大批量循环里无脑逐条 `insert`
470
+ - 如果需要创建大量记录,优先考虑项目已有的批量写法
471
+
472
+ ### 6.4 `cquery`
473
+
474
+ #### 查询普通数据
475
+
476
+ 方法签名:
477
+
478
+ ```java
479
+ public List<CCObject> cquery(String apiName, String condition, String order) throws Exception
480
+ ```
481
+
482
+ 参数说明:
483
+
484
+ | 参数 | 类型 | 必填 | 说明 |
485
+ | --- | --- | --- | --- |
486
+ | `apiName` | `String` | 是 | 对象 API 名 |
487
+ | `condition` | `String` | 否 | 查询条件;自定义字段 API 名要带 `__c` |
488
+ | `order` | `String` | 否 | 排序条件 |
489
+
490
+ 返回:
491
+
492
+ - `List<CCObject>`
493
+
494
+ 适用场景:
495
+
496
+ - 单对象简单条件查询
497
+ - 条件和排序较直接的巡检类定时器
498
+
499
+ AI 使用要求:
500
+
501
+ - 优先用于简单查询
502
+ - 不要把页面字段标签名写进条件
503
+ - 自定义字段必须用 API 名并带 `__c`
504
+
505
+ #### 查询共享数据
506
+
507
+ 方法签名:
508
+
509
+ ```java
510
+ public List<CCObject> cquery(String apiName, String condition, boolean isDataObject) throws Exception
164
511
  ```
165
512
 
166
- ### 问题 2:重复劳动效率低
513
+ 参数说明:
514
+
515
+ | 参数 | 类型 | 必填 | 说明 |
516
+ | --- | --- | --- | --- |
517
+ | `apiName` | `String` | 是 | 对象 API 名 |
518
+ | `condition` | `String` | 否 | 查询条件 |
519
+ | `isDataObject` | `boolean` | 是 | 是否查询业务对象;共享数据场景按项目现有写法传入对应布尔值 |
520
+
521
+ 返回:
522
+
523
+ - `List<CCObject>`
167
524
 
168
- **场景:** 财务人员每天手动发送收款提醒,耗时 2 小时
525
+ 适用场景:
169
526
 
170
- **解决:** 定时作业自动扫描逾期收款计划,批量发送邮件
527
+ - 共享关系查询
528
+ - 权限治理类定时器
171
529
 
530
+ AI 使用要求:
531
+
532
+ - 涉及共享表查询时使用该重载
533
+ - 布尔参数不要凭空猜测语义,优先参考现有仓库同类写法
534
+
535
+ ### 6.5 `cqlQuery`
536
+
537
+ 方法签名:
538
+
539
+ ```java
540
+ public List<CCObject> cqlQuery(String apiName, String cql) throws Exception
172
541
  ```
173
- 人工方式:每天 2 小时 × 250 工作日 = 500 小时/年
174
- 定时作业:配置 1 次,自动执行,0 小时/年
175
- 节省:500 小时/年 ≈ 62 个工作日
542
+
543
+ 参数说明:
544
+
545
+ | 参数 | 类型 | 必填 | 说明 |
546
+ | --- | --- | --- | --- |
547
+ | `apiName` | `String` | 是 | 对象 API 名 |
548
+ | `cql` | `String` | 否 | SQL/CQL 查询语句,支持常见 `where` 条件 |
549
+
550
+ 返回:
551
+
552
+ - `List<CCObject>`
553
+
554
+ 适用场景:
555
+
556
+ - 联表查询
557
+ - 聚合查询
558
+ - 分组统计
559
+ - 报表底表查询
560
+ - 复杂分页场景
561
+
562
+ AI 使用要求:
563
+
564
+ - 复杂查询优先 `cqlQuery`
565
+ - 默认把它当“查询接口”使用
566
+ - 除非有充分依据,不要把它写成更新或删除通道
567
+ - 报表、底表、汇总类定时器优先考虑 `cqlQuery`
568
+
569
+ ### 6.6 `update`
570
+
571
+ 方法签名:
572
+
573
+ ```java
574
+ public ServiceResult update(CCObject ccobj) throws Exception
176
575
  ```
177
576
 
178
- ### 问题 3:跨系统数据同步
577
+ 参数说明:
578
+
579
+ | 参数 | 类型 | 必填 | 说明 |
580
+ | --- | --- | --- | --- |
581
+ | `ccobj` | `CCObject` | 是 | 待更新对象,必须含 `id` |
179
582
 
180
- **场景:** CRM 和 ERP 系统数据需要保持一致
583
+ 返回:
181
584
 
182
- **解决:** 定时作业每晚同步两个系统的数据
585
+ - `ServiceResult`
183
586
 
587
+ 适用场景:
588
+
589
+ - 修改单条记录
590
+ - 回填单条标记、状态、编号
591
+
592
+ AI 使用要求:
593
+
594
+ - 更新前必须 `put("id", ...)`
595
+ - 仅回写必要字段,不要把无关字段全量覆盖
596
+ - 如果数据量大,优先改用批量更新策略
597
+
598
+ ### 6.7 `delete`
599
+
600
+ 方法签名:
601
+
602
+ ```java
603
+ public ServiceResult delete(CCObject ccobj) throws Exception
184
604
  ```
185
- ┌──────────┐ ┌──────────────┐ ┌──────────┐
186
- │ CRM │ ←─────→ │ 定时作业同步 │ ←─────→ │ ERP │
187
- │ 客户数据 │ 2:00 │ (每日凌晨) │ 2:30 │ 客户数据 │
188
- └──────────┘ └──────────────┘ └──────────┘
605
+
606
+ 参数说明:
607
+
608
+ | 参数 | 类型 | 必填 | 说明 |
609
+ | --- | --- | --- | --- |
610
+ | `ccobj` | `CCObject` | 是 | 待删除对象,通常至少包含 `id` |
611
+
612
+ 返回:
613
+
614
+ - `ServiceResult`
615
+
616
+ 适用场景:
617
+
618
+ - 删除普通业务记录
619
+
620
+ AI 使用要求:
621
+
622
+ - 删除前必须确认这是业务允许的动作
623
+ - 默认不要在定时器中做大批量物理/逻辑删除,除非需求明确
624
+
625
+ ### 6.8 `deleteShareObjectBySql`
626
+
627
+ 方法签名:
628
+
629
+ ```java
630
+ public void deleteShareObjectBySql(String objectApiName, String expression) throws Exception
189
631
  ```
190
632
 
191
- ### 问题 4:报表生成和分发
633
+ 参数说明:
634
+
635
+ | 参数 | 类型 | 必填 | 说明 |
636
+ | --- | --- | --- | --- |
637
+ | `objectApiName` | `String` | 是 | 共享对象 API 名 |
638
+ | `expression` | `String` | 是 | SQL 表达式;官方说明字段名不需要加 `__c` |
639
+
640
+ 返回:
641
+
642
+ - `void`
643
+
644
+ 适用场景:
645
+
646
+ - 共享关系清理
647
+ - 权限治理类定时器
192
648
 
193
- **场景:** 管理层需要定期查看各类报表
649
+ AI 使用要求:
194
650
 
195
- **解决:** 定时作业自动生成报表并邮件发送给相关人员
651
+ - 优先用于共享对象删除,不要拿它删除普通业务对象
652
+ - 条件一定要收敛,避免误删共享关系
196
653
 
654
+ ### 6.9 自定义设置 `getListCustomSetting`
655
+
656
+ #### 读取列表类型全部记录
657
+
658
+ 方法签名:
659
+
660
+ ```java
661
+ public Map getListCustomSetting(String objectApiName)
197
662
  ```
198
- 定时触发 → 查询数据 → 生成报表 → 发送邮件 → 完成
199
-
200
- 每周一 9:00
663
+
664
+ 参数说明:
665
+
666
+ | 参数 | 类型 | 必填 | 说明 |
667
+ | --- | --- | --- | --- |
668
+ | `objectApiName` | `String` | 是 | 自定义设置 API 名 |
669
+
670
+ 返回:
671
+
672
+ - `Map`
673
+
674
+ 适用场景:
675
+
676
+ - 读取一整套配置项
677
+ - 读取阈值表、邮件配置表、组织映射配置
678
+
679
+ #### 读取列表类型单条记录
680
+
681
+ 方法签名:
682
+
683
+ ```java
684
+ Map map = cs.getListCustomSetting(String apiName, String name);
201
685
  ```
202
686
 
203
- ---
687
+ 参数说明:
688
+
689
+ | 参数 | 类型 | 必填 | 说明 |
690
+ | --- | --- | --- | --- |
691
+ | `apiName` | `String` | 是 | 自定义设置 API 名 |
692
+ | `name` | `String` | 是 | 自定义设置记录名称 |
204
693
 
205
- ## 📚 典型业务场景
694
+ 返回:
206
695
 
207
- ### 场景 1:销售管理
696
+ - `Map`
208
697
 
209
- | 场景 | 触发条件 | 执行动作 |
210
- |------|----------|----------|
211
- | 线索分配 | 新线索创建后 24 小时未分配 | 自动分配给销售主管 |
212
- | 客户跟进提醒 | 客户最后联系时间 > 15 天 | 创建跟进活动并通知销售 |
213
- | 商机推进提醒 | 商机停留当前阶段 > 30 天 | 提醒销售经理介入 |
214
- | 业绩统计 | 每日 23:00 | 计算当日业绩并更新报表 |
698
+ AI 使用要求:
215
699
 
216
- ### 场景 2:客户服务
700
+ - 可配置项优先放自定义设置,不要硬编码
701
+ - 提醒阈值、开关、模板 ID、收件人规则都应优先配置化
217
702
 
218
- | 场景 | 触发条件 | 执行动作 |
219
- |------|----------|----------|
220
- | 服务到期提醒 | 服务合同到期前 30 天 | 发送续约提醒邮件 |
221
- | 客户满意度调查 | 服务完成后 7 天 | 发送满意度调查问卷 |
222
- | 生日祝福 | 客户生日当天 | 发送祝福短信/邮件 |
223
- | 投诉升级 | 投诉 48 小时未处理 | 自动升级至上级主管 |
703
+ ### 6.10 `getCustomSetting`
224
704
 
225
- ### 场景 3:财务管理
705
+ 方法签名:
226
706
 
227
- | 场景 | 触发条件 | 执行动作 |
228
- |------|----------|----------|
229
- | 收款提醒 | 收款计划日期前 7 天 | 邮件通知客户和财务 |
230
- | 逾期通知 | 收款计划逾期 1 天 | 发送逾期通知并标记 |
231
- | 发票生成 | 确认收款后 | 自动生成并发送发票 |
232
- | 佣金计算 | 每月 1 日 | 计算销售佣金并生成报表 |
707
+ ```java
708
+ public Map getCustomSetting(String objectApiName, String id)
709
+ ```
233
710
 
234
- ### 场景 4:数据维护
711
+ 参数说明:
235
712
 
236
- | 场景 | 触发条件 | 执行动作 |
237
- |------|----------|----------|
238
- | 数据清理 | 每周日 3:00 | 清理临时表和过期日志 |
239
- | 数据备份 | 每日 1:00 | 备份关键数据到指定位置 |
240
- | 数据同步 | 每日 2:00 | 同步 CRM 与外部系统数据 |
241
- | 索引优化 | 每月 1 日 4:00 | 重建数据库索引提升性能 |
713
+ | 参数 | 类型 | 必填 | 说明 |
714
+ | --- | --- | --- | --- |
715
+ | `objectApiName` | `String` | | 自定义设置 API 名 |
716
+ | `id` | `String` | | 简档 ID 或用户 ID |
242
717
 
243
- ### 场景 5:营销自动化
718
+ 返回:
244
719
 
245
- | 场景 | 触发条件 | 执行动作 |
246
- |------|----------|----------|
247
- | 营销活动提醒 | 活动开始前 3 天 | 通知参与人员准备 |
248
- | 线索培育 | 线索创建后第 3/7/14 天 | 发送培育邮件 |
249
- | 活动效果分析 | 活动结束后 1 天 | 生成效果分析报告 |
250
- | 客户分群更新 | 每日 5:00 | 根据行为更新客户分群 |
720
+ - `Map`
251
721
 
252
- ---
722
+ 适用场景:
253
723
 
254
- ## ⚙️ 技术实现
255
-
256
- ### 定时作业结构
257
-
258
- ```
259
- ┌─────────────────────────────────────────────────────────┐
260
- │ 定时作业 (Schedule Job) │
261
- ├─────────────────────────────────────────────────────────┤
262
- │ 基本信息 │
263
- │ ├── 名称 (name) │
264
- │ ├── ID (id) │
265
- │ └── 描述 (description) │
266
- ├─────────────────────────────────────────────────────────┤
267
- │ 调度配置 │
268
- │ ├── 频率类型 (frequency): daily/weekly/monthly │
269
- │ ├── 执行时间 (executetime): 08:00 │
270
- │ ├── 星期 (weeks): Mon,Tues,Wed,Thur,Fri │
271
- │ ├── 开始日期 (startdate): 2024-01-01 │
272
- │ └── 结束日期 (enddate): 2024-12-31 │
273
- ├─────────────────────────────────────────────────────────┤
274
- │ 关联程序 │
275
- │ ├── 程序 ID (prgid) │
276
- │ └── 定时类 (className): com.xxx.scheduler.MyJob │
277
- └─────────────────────────────────────────────────────────┘
278
- ```
279
-
280
- ### 执行流程
281
-
282
- ```
283
- ┌─────────────┐
284
- │ 系统时钟 │
285
- └──────┬──────┘
286
- │ 到达触发时间
287
-
288
- ┌─────────────┐
289
- │ 调度器检查 │ ──→ 是否在有效期内?
290
- └──────┬──────┘ ──→ 状态是否激活?
291
- │ 是
292
-
293
- ┌─────────────┐
294
- │ 加载定时类 │
295
- └──────┬──────┘
296
-
297
-
298
- ┌─────────────┐
299
- │ 执行 main() │
300
- └──────┬──────┘
301
-
302
-
303
- ┌─────────────┐
304
- │ 记录执行日志 │
305
- └─────────────┘
306
- ```
307
-
308
- ### 定时类示例
309
-
310
- ```javascript
311
- /**
312
- * 定时类:客户长时间未联系自动新建活动
313
- * 程序 ID: ccp20213DC20298RebnS
314
- */
315
- function main($CCDK, obj) {
316
- // 1. 查询超过 15 天未联系的客户
317
- const fifteenDaysAgo = new Date();
318
- fifteenDaysAgo.setDate(fifteenDaysAgo.getDate() - 15);
319
-
320
- const customers = $CCDK.query(`
321
- SELECT Id, Name, OwnerId
322
- FROM Account
323
- WHERE LastActivityDate < '${fifteenDaysAgo.toISOString()}'
324
- `);
325
-
326
- // 2. 为每个客户创建跟进活动
327
- customers.forEach(customer => {
328
- $CCDK.create('Activity', {
329
- Subject: `跟进客户:${customer.Name}`,
330
- Type: 'Call',
331
- Status: 'Not Started',
332
- OwnerId: customer.OwnerId,
333
- RelatedToId: customer.Id
334
- });
335
- });
336
-
337
- return `已为 ${customers.length} 个客户创建跟进活动`;
338
- }
724
+ - 分用户、分角色、分权限读取配置
725
+ - 不同组织或角色使用不同阈值/模版
726
+
727
+ ### 6.11 `SendEmail`
728
+
729
+ 类定位:
730
+
731
+ - 官方邮件发送服务
732
+
733
+ #### 构造函数
734
+
735
+ ```java
736
+ public SendEmail(UserInfo userInfo)
339
737
  ```
340
738
 
341
- ---
739
+ 参数说明:
740
+
741
+ | 参数 | 类型 | 必填 | 说明 |
742
+ | --- | --- | --- | --- |
743
+ | `userInfo` | `UserInfo` | 是 | 当前用户对象 |
744
+
745
+ #### `sendMailFromSystem`
342
746
 
343
- ## 📊 实际案例(来自你的系统)
344
-
345
- ### 案例 1:客户长时间未联系新建活动
346
-
347
- ```
348
- ┌─────────────────────────────────────────────────────┐
349
- 作业名称:客户长时间未联系新建活动 │
350
- ├─────────────────────────────────────────────────────┤
351
- 执行时间:每天 上午 8:00 │
352
- 有效期:2021-12-04 ~ 2033-12-21 │
353
- │ 状态:✅ 运行中 │
354
- │ │
355
- │ 业务逻辑: │
356
- │ 1. 扫描所有客户,找出最后联系时间 > 15 天的 │
357
- │ 2. 为每个客户自动创建"跟进"活动 │
358
- │ 3. 活动分配给对应的销售负责人 │
359
- │ │
360
- │ 价值:防止销售遗忘客户跟进,提升客户满意度 │
361
- └─────────────────────────────────────────────────────┘
362
- ```
363
-
364
- ### 案例 2:计划收款日期 7 天后发送邮件
365
-
366
- ```
367
- ┌─────────────────────────────────────────────────────┐
368
- │ 作业名称:计划收款日期 7 天后发送邮件 │
369
- ├─────────────────────────────────────────────────────┤
370
- │ 执行时间:每天 上午 8:00 │
371
- │ 有效期:2021-12-10 ~ 2034-12-31 │
372
- │ 状态:✅ 运行中 │
373
- │ │
374
- │ 业务逻辑: │
375
- │ 1. 查询收款计划日期 = 今天 + 7 天的记录 │
376
- │ 2. 发送邮件给客户提醒付款 │
377
- │ 3. 抄送财务人员和对应销售 │
378
- │ │
379
- │ 价值:提前提醒客户付款,降低逾期率,改善现金流 │
380
- └─────────────────────────────────────────────────────┘
381
- ```
382
-
383
- ### 案例 3:资产失效三个月自动生成业务机会
384
-
385
- ```
386
- ┌─────────────────────────────────────────────────────┐
387
- │ 作业名称:资产失效三个月自动生成业务机会 │
388
- ├─────────────────────────────────────────────────────┤
389
- │ 执行时间:每天 凌晨 1:00 │
390
- │ 有效期:2021-12-10 ~ 2033-12-31 │
391
- │ 状态:✅ 运行中 │
392
- │ │
393
- │ 业务逻辑: │
394
- │ 1. 查询资产失效时间 = 今天 - 3 个月的记录 │
395
- │ 2. 自动创建新的业务机会(续费/升级) │
396
- │ 3. 分配给原销售或客户经理 │
397
- │ │
398
- │ 价值:抓住续费时机,提升客户生命周期价值 │
399
- └─────────────────────────────────────────────────────┘
400
- ```
401
-
402
- ### 案例 4:报表订阅(已过期)
403
-
404
- ```
405
- ┌─────────────────────────────────────────────────────┐
406
- │ 作业名称:报表订阅 - 销售部收款统计报表 │
407
- ├─────────────────────────────────────────────────────┤
408
- │ 执行时间:每月 10 日 下午 4:00 │
409
- │ 有效期:2025-01-01 ~ 2025-02-28 ⚠️ 已过期 │
410
- │ 状态:⚠️ 需要续期或停用 │
411
- │ │
412
- │ 业务逻辑: │
413
- │ 1. 生成销售部收款统计报表 │
414
- │ 2. 发送邮件给销售总监和财务经理 │
415
- │ │
416
- │ 建议:如仍需此报表,需更新有效期 │
417
- └─────────────────────────────────────────────────────┘
747
+ 方法签名:
748
+
749
+ ```java
750
+ public boolean sendMailFromSystem(
751
+ String[] toAddress,
752
+ String[] ccAddress,
753
+ String[] bccAddress,
754
+ String subject,
755
+ String content,
756
+ boolean isText
757
+ )
418
758
  ```
419
759
 
420
- ---
760
+ 参数说明:
761
+
762
+ | 参数 | 类型 | 必填 | 说明 |
763
+ | --- | --- | --- | --- |
764
+ | `toAddress` | `String[]` | 是 | 收件人数组 |
765
+ | `ccAddress` | `String[]` | 是 | 抄送人数组,可传空数组 |
766
+ | `bccAddress` | `String[]` | 是 | 密送人数组,可传空数组 |
767
+ | `subject` | `String` | 是 | 邮件主题 |
768
+ | `content` | `String` | 是 | 邮件正文,支持 HTML |
769
+ | `isText` | `boolean` | 是 | `true` 为纯文本,`false` 为 HTML |
770
+
771
+ 返回:
772
+
773
+ - `boolean`
774
+
775
+ 适用场景:
776
+
777
+ - 简单通知
778
+ - 汇总提醒
779
+ - 失败告警
780
+
781
+ AI 使用要求:
421
782
 
422
- ## 🎓 最佳实践
783
+ - 优先聚合后发送,避免一条记录一封邮件
784
+ - HTML 邮件时 `isText` 应传 `false`
785
+ - 收件人为空时不要发
423
786
 
424
- ### 1. 合理设置执行时间
787
+ #### `sendEmailNew`
425
788
 
789
+ 方法签名:
790
+
791
+ ```java
792
+ public ServiceResult sendEmailNew(
793
+ String emailtemplateid,
794
+ String[] toaddress,
795
+ String[] ccaddress,
796
+ String[] bcaddress,
797
+ String id
798
+ ) throws Exception
426
799
  ```
427
- ✅ 推荐:
428
- - 报表生成:非工作时间(如 23:00 或凌晨)
429
- - 邮件通知:工作时间开始前(如 8:00)
430
- - 数据同步:系统负载低时(如 2:00-4:00)
431
800
 
432
- ❌ 避免:
433
- - 业务高峰期执行大量数据处理
434
- - 多个重任务同时执行
801
+ 参数说明:
802
+
803
+ | 参数 | 类型 | 必填 | 说明 |
804
+ | --- | --- | --- | --- |
805
+ | `emailtemplateid` | `String` | 是 | 邮件模板 ID |
806
+ | `toaddress` | `String[]` | 是 | 收件人数组 |
807
+ | `ccaddress` | `String[]` | 是 | 抄送人数组 |
808
+ | `bcaddress` | `String[]` | 是 | 密送人数组 |
809
+ | `id` | `String` | 是 | 关联记录 ID |
810
+
811
+ 返回:
812
+
813
+ - `ServiceResult`
814
+
815
+ 适用场景:
816
+
817
+ - 已存在标准模版的业务提醒
818
+ - 需要统一邮件样式的场景
819
+
820
+ AI 使用要求:
821
+
822
+ - 模板 ID 应优先配置化
823
+ - 关联记录 ID 应传实际业务记录,不要随意填空字符串
824
+
825
+ ### 6.12 `DevLogger`
826
+
827
+ 类定位:
828
+
829
+ - 官方运行日志采集工具
830
+
831
+ #### 构造函数
832
+
833
+ ```java
834
+ public DevLogger(UserInfo userInfo)
435
835
  ```
436
836
 
437
- ### 2. 设置合理的有效期
837
+ 参数说明:
838
+
839
+ | 参数 | 类型 | 必填 | 说明 |
840
+ | --- | --- | --- | --- |
841
+ | `userInfo` | `UserInfo` | 是 | 当前用户对象 |
438
842
 
843
+ #### `devLogInfo`
844
+
845
+ 方法签名:
846
+
847
+ ```java
848
+ public void devLogInfo(String info)
439
849
  ```
440
- ✅ 推荐:
441
- - 长期任务:设置 5-10 年有效期
442
- - 临时任务:设置明确结束日期
443
- - 定期审查:每季度检查过期任务
444
850
 
445
- ❌ 避免:
446
- - 不设置结束日期(永久运行)
447
- - 过期任务不处理(占用系统资源)
851
+ 参数说明:
852
+
853
+ | 参数 | 类型 | 必填 | 说明 |
854
+ | --- | --- | --- | --- |
855
+ | `info` | `String` | 是 | info 级别日志内容 |
856
+
857
+ 返回:
858
+
859
+ - `void`
860
+
861
+ #### `devLogError`
862
+
863
+ 方法签名:
864
+
865
+ ```java
866
+ public void devLogError(String error, Throwable throwable)
448
867
  ```
449
868
 
450
- ### 3. 错误处理和日志
869
+ 参数说明:
451
870
 
452
- ```javascript
453
- function main($CCDK, obj) {
454
- try {
455
- // 业务逻辑
456
- const result = doSomething();
457
- return `成功:${result}`;
458
- } catch (error) {
459
- // 记录错误日志
460
- $CCDK.log(`定时作业执行失败:${error.message}`);
461
- // 发送告警通知
462
- sendAlertToAdmin(error);
463
- throw error; // 让系统记录失败状态
464
- }
465
- }
871
+ | 参数 | 类型 | 必填 | 说明 |
872
+ | --- | --- | --- | --- |
873
+ | `error` | `String` | 是 | 错误日志内容 |
874
+ | `throwable` | `Throwable` | 否 | 异常对象 |
875
+
876
+ 返回:
877
+
878
+ - `void`
879
+
880
+ AI 使用要求:
881
+
882
+ - 批处理开始、结束、数量、关键分支打 `info`
883
+ - 异常路径打 `error`
884
+ - 日志至少带业务主键、批次标识或关键条件
885
+
886
+ ### 6.13 `TimeUtil`
887
+
888
+ 类定位:
889
+
890
+ - 多时区安全时间工具
891
+
892
+ 官方说明重点:
893
+
894
+ - `Date` 和 `Calendar` 基于本地时区
895
+ - 跨时区场景下应优先通过 `TimeUtil` 获取当前时间、时区和格式化工具
896
+
897
+ #### `getNowDate`
898
+
899
+ 官方示例写法:
900
+
901
+ ```java
902
+ TpSysTask task = new TpSysTask();
903
+ task.setBeginTime(TimeUtil.getNowDate(userInfo));
466
904
  ```
467
905
 
468
- ### 4. 性能优化
906
+ 参数说明:
907
+
908
+ | 参数 | 类型 | 必填 | 说明 |
909
+ | --- | --- | --- | --- |
910
+ | `userInfo` | `UserInfo` | 是 | 当前用户对象 |
911
+
912
+ 返回:
913
+
914
+ - 当前用户时区下的当前时间
915
+
916
+ #### `getUserTimeZone`
469
917
 
918
+ 方法签名式写法:
919
+
920
+ ```java
921
+ TimeZone tz = TimeUtil.getUserTimeZone(userInfo);
470
922
  ```
471
- ✅ 推荐:
472
- - 批量操作代替循环单条处理
473
- - 使用分页查询避免内存溢出
474
- - 异步处理非关键逻辑
475
923
 
476
- ❌ 避免:
477
- - 单次查询大量数据(>10000 条)
478
- - 在定时作业中调用外部 API(无超时控制)
479
- - 长时间运行的任务(>30 分钟)
924
+ 参数说明:
925
+
926
+ | 参数 | 类型 | 必填 | 说明 |
927
+ | --- | --- | --- | --- |
928
+ | `userInfo` | `UserInfo` | 是 | 当前用户对象 |
929
+
930
+ 返回:
931
+
932
+ - `TimeZone`
933
+
934
+ #### `getSimpleDateFormat`
935
+
936
+ 官方示例写法:
937
+
938
+ ```java
939
+ SimpleDateFormat myDateFormat =
940
+ TimeUtil.getSimpleDateFormat("yyyy-MM-dd", userInfo);
480
941
  ```
481
942
 
482
- ### 5. 监控和告警
943
+ 参数说明:
944
+
945
+ | 参数 | 类型 | 必填 | 说明 |
946
+ | --- | --- | --- | --- |
947
+ | `format` | `String` | 是 | 日期格式;官方默认示例为 `yyyy-MM-dd` |
948
+ | `userInfo` | `UserInfo` | 是 | 当前用户对象 |
949
+
950
+ 返回:
951
+
952
+ - 已绑定用户时区的 `SimpleDateFormat`
953
+
954
+ #### `getCalendar`
483
955
 
956
+ 官方示例写法:
957
+
958
+ ```java
959
+ Calendar cal = Calendar.getInstance(TimeUtil.getUserTimeZone(userInfo));
960
+ // 或
961
+ Calendar cal2 = TimeUtil.getCalendar(userInfo);
484
962
  ```
485
- 建议配置:
486
- - 执行失败时发送邮件/短信告警
487
- - 定期检查执行日志
488
- - 监控任务执行时长变化
963
+
964
+ 返回:
965
+
966
+ - 带用户时区的 `Calendar`
967
+
968
+ AI 使用要求:
969
+
970
+ - 涉及比较、格式化、写入时间时,优先使用 `TimeUtil`
971
+ - 不要默认直接使用裸 `new Date()`、裸 `SimpleDateFormat`、裸 `Calendar`
972
+
973
+ ### 6.14 项目常见批量写法:`insertLt` / `updateLt`
974
+
975
+ 说明:
976
+
977
+ - 这两个方法在当前项目定时器和 `cloudcc doc timer devguide` 示例中非常常见
978
+ - 官方链接页未在本次抓取结果中展开它们的详细签名表
979
+ - 因此,AI 不能“脑补重载签名”,必须沿用仓库已有写法
980
+
981
+ 当前项目与文档中已出现的典型用法:
982
+
983
+ ```java
984
+ cs.insertLt(batch);
985
+ cs.updateLt(batch);
489
986
  ```
490
987
 
491
- ---
988
+ AI 使用要求:
492
989
 
493
- ## 📋 管理操作
990
+ - 只在已有项目先例清晰时使用
991
+ - 参数形态优先沿用本仓库同类定时器
992
+ - 如果需求需要新的批量调用方式,而仓库中没有先例,应先说明依据不足,不要编造 API
494
993
 
495
- ### 定时类:使用 CLI 管理本地 `schedule/`(推荐)
994
+ ### 6.15 本节给 AI 的结论
496
995
 
497
- 与**定时类源码**的创建、同步、删除,请优先使用上文「CLI 与本地文件(必读)」中的命令,避免绕过 CLI 直接改目录或 `config.json`。
996
+ AI 编写定时器时,对 SDK 的使用顺序应默认如下:
498
997
 
499
- 以下接口面向**定时作业配置**(调度时间、启用状态等在设置中的作业),与 `schedule/` 下定时类源码管理是不同层面;具体以你环境的管理后台与 OpenAPI 为准。
998
+ 1. `CCService` 作为主入口
999
+ 2. 用 `CCObject` 承载新增/更新对象
1000
+ 3. 简单查询优先 `cquery`
1001
+ 4. 联表和聚合优先 `cqlQuery`
1002
+ 5. 单条写入用 `insert` / `update` / `delete`
1003
+ 6. 通知用 `SendEmail`
1004
+ 7. 观测用 `DevLogger`
1005
+ 8. 时间统一走 `TimeUtil`
1006
+ 9. 配置优先走 `getListCustomSetting` / `getCustomSetting`
1007
+ 10. 批量方法只复用项目已验证写法,不凭空猜
500
1008
 
501
- ### 查询定时作业(平台接口示例)
1009
+ ## 7. 当前项目的定时器代码风格要求
502
1010
 
503
- ```bash
504
- # 获取列表
505
- POST /ccsetup/api/schedulAbleprg/list
1011
+ ### 7.1 当前项目更偏向这几类任务
1012
+
1013
+ - 提醒催办
1014
+ - 数据同步
1015
+ - 数据刷新与修正
1016
+ - 报表底表构建
1017
+ - 自动生成下游对象
1018
+ - 权限治理
1019
+
1020
+ 因此,AI 生成方案时应优先往这些成熟模式靠拢,而不是引入与现有仓库明显脱节的实现风格。
1021
+
1022
+ ### 7.2 当前项目中常见模式
1023
+
1024
+ - 先查数据,再按条件处理
1025
+ - 按责任人聚合后通知
1026
+ - 批量更新字段、状态、台账、底表
1027
+ - 在满足条件时自动生成任务或派生对象
1028
+ - 对接口失败记录做补偿和邮件告警
506
1029
 
507
- # 获取详细信息
508
- POST /ccsetup/api/schedulAbleprg/edit
509
- Body: { "id": "作业 ID" }
1030
+ ### 7.3 当前项目中 AI 应优先保留的工程意识
1031
+
1032
+ - 业务逻辑尽量清晰直白
1033
+ - 关键分支有日志
1034
+ - 批量处理避免深层嵌套查询
1035
+ - 数据写回前先判断是否真的需要写
1036
+ - 可能重复执行的逻辑必须考虑去重或状态控制
1037
+
1038
+ ## 8. AI 实现模板
1039
+
1040
+ 下面是推荐给 AI 的定时器实现骨架。
1041
+
1042
+ ```java
1043
+ package schedule.示例定时器;
1044
+
1045
+ import com.cloudcc.core.*;
1046
+
1047
+ public class 示例定时器 extends CCSchedule {
1048
+ public 示例定时器() {
1049
+ // @SOURCE_CONTENT_START
1050
+ CCService cs = new CCService(userInfo);
1051
+ DevLogger log = new DevLogger(userInfo);
1052
+ try {
1053
+ java.util.Date now = TimeUtil.getNowDate(userInfo);
1054
+ java.text.SimpleDateFormat sdf =
1055
+ TimeUtil.getSimpleDateFormat("yyyy-MM-dd HH:mm:ss", userInfo);
1056
+
1057
+ log.devLogInfo("示例定时器 start, now=" + sdf.format(now));
1058
+
1059
+ // 1. 查询目标数据
1060
+ // 2. 判断是否满足执行条件
1061
+ // 3. 批量生成/更新/通知
1062
+ // 4. 记录处理数量与结果
1063
+
1064
+ log.devLogInfo("示例定时器 finish");
1065
+ } catch (Exception e) {
1066
+ log.devLogError("示例定时器 error", e);
1067
+ throw new RuntimeException(e.getMessage(), e);
1068
+ }
1069
+ // @SOURCE_CONTENT_END
1070
+ }
1071
+ }
510
1072
  ```
511
1073
 
512
- ### 常见管理需求
1074
+ AI 可以在此基础上扩展,但不得破坏以下结构:
513
1075
 
514
- | 需求 | 操作 |
515
- |------|------|
516
- | 查看有哪些定时作业 | 调用 list 接口 |
517
- | 查看作业详细配置 | 调用 edit 接口 |
518
- | 启用/禁用作业 | 修改作业状态(需管理权限) |
519
- | 修改执行时间 | 编辑作业的 executetime 和 frequency |
520
- | 延长有效期 | 更新 enddate 字段 |
521
- | 创建新作业 | 使用 cloudcc-cli 创建定时类并配置调度 |
1076
+ - `package schedule.<类名>;`
1077
+ - `extends CCSchedule`
1078
+ - 构造方法同名
1079
+ - SOURCE 边界完整
522
1080
 
523
- ---
1081
+ ## 9. AI 生成定时器类时的必填设计项
524
1082
 
525
- ## 🚨 常见问题
1083
+ AI 在输出实现前,应先在思路中覆盖以下设计项。
526
1084
 
527
- ### Q1: 定时作业不执行怎么办?
1085
+ ### 9.1 业务定义
528
1086
 
529
- **检查清单:**
530
- 1. 当前日期是否在有效期内?
531
- 2. 作业状态是否为激活?
532
- 3. 定时类代码是否有错误?
533
- 4. 系统日志是否有报错?
1087
+ - 这个定时器服务什么业务目标
1088
+ - 为什么它应该是定时器,而不是触发器
534
1089
 
535
- ### Q2: 如何调试定时作业?
1090
+ ### 9.2 数据范围
536
1091
 
537
- **方法:**
538
- 1. 在代码中添加日志输出
539
- 2. 手动执行定时类测试逻辑
540
- 3. 查看系统执行日志
541
- 4. 设置测试环境验证
1092
+ - 主对象
1093
+ - 关联对象
1094
+ - 查询条件
1095
+ - 是否全量
1096
+ - 是否增量
1097
+ - 是否分页
542
1098
 
543
- ### Q3: 定时作业可以传递参数吗?
1099
+ ### 9.3 执行动作
544
1100
 
545
- **答案:** 可以。在配置定时作业时设置参数,在定时类中通过 `obj` 参数接收。
1101
+ - 是提醒、同步、修正、汇总、生成,还是权限治理
1102
+ - 动作顺序是什么
1103
+ - 失败后是否继续处理后续数据
546
1104
 
547
- ### Q4: 定时作业执行失败会重试吗?
1105
+ ### 9.4 幂等设计
548
1106
 
549
- **答案:** 默认不自动重试。建议在代码中实现重试逻辑或配置告警通知人工处理。
1107
+ - 如何防止重复新增
1108
+ - 如何防止重复通知
1109
+ - 如何防止重复推进状态
550
1110
 
551
- ---
1111
+ ### 9.5 性能设计
1112
+
1113
+ - 是否存在循环内查询
1114
+ - 是否存在大量单条写入
1115
+ - 是否需要分批提交
1116
+
1117
+ ### 9.6 观测与异常
1118
+
1119
+ - 哪些日志必须打
1120
+ - 哪些异常要抛出
1121
+ - 哪些异常要告警
1122
+
1123
+ ### 9.7 配置化设计
1124
+
1125
+ - 阈值是否应该来自自定义设置
1126
+ - 邮件模版、收件人、开关是否应该配置化
1127
+
1128
+ ## 10. AI 禁止事项
1129
+
1130
+ 以下是 AI 在当前项目中编写定时器类时应明确避免的行为。
1131
+
1132
+ - 不要手工创建 `schedule/<name>/` 目录
1133
+ - 不要修改 `config.json` 的 `id`、版本字段
1134
+ - 不要在 SOURCE 区域之外写业务代码
1135
+ - 不要把明显实时场景错误地写成定时器
1136
+ - 不要在大循环里频繁嵌套查询,造成 N+1 问题
1137
+ - 不要在大批量处理中逐条单次写入而不考虑 `insertLt` / `updateLt`
1138
+ - 不要默认使用 `new Date()`、裸 `Calendar`、裸 `SimpleDateFormat` 处理业务时间
1139
+ - 不要吞掉异常而不打日志
1140
+ - 不要默认把邮箱、模版 ID、阈值、组织 ID 全部硬编码
1141
+ - 不要在没有明确理由时用 SQL 风格语句替代官方 CRUD
1142
+ - 不要无条件全表扫描并直接修改全量数据
1143
+ - 不要让定时器重复执行后反复创建相同记录、任务或邮件
1144
+
1145
+ ## 11. AI 输出结果要求
1146
+
1147
+ AI 在完成定时器类开发时,输出说明至少应包含:
1148
+
1149
+ - 为什么选择定时器类
1150
+ - 主对象与处理范围
1151
+ - 执行条件
1152
+ - 核心动作
1153
+ - 幂等策略
1154
+ - 批量策略
1155
+ - 日志与异常策略
1156
+ - 是否使用通知
1157
+ - 是否使用配置化
1158
+
1159
+ 如果未能做到其中某一项,AI 应显式说明原因,而不是默认省略。
1160
+
1161
+ ## 12. 推荐给 AI 的任务描述模板
1162
+
1163
+ 下面这个模板适合作为给 AI 下达定时器开发任务时的标准输入。
1164
+
1165
+ ```text
1166
+ 请为 CloudCC 编写一个定时器类,要求如下:
1167
+
1168
+ 1. 定时器名称:
1169
+ 2. 业务目标:
1170
+ 3. 为什么需要定时执行:
1171
+ 4. 主对象与关联对象:
1172
+ 5. 查询范围(全量/增量/按日期/按状态):
1173
+ 6. 满足什么条件后执行:
1174
+ 7. 执行动作(提醒/同步/更新/生成/汇总/权限处理):
1175
+ 8. 是否需要邮件或任务:
1176
+ 9. 是否需要读取自定义设置:
1177
+ 10. 幂等要求:
1178
+ 11. 批量要求:
1179
+ 12. 异常和日志要求:
1180
+
1181
+ 请按当前项目的 CloudCC 定时器规范实现,并只在 SOURCE_CONTENT 区域内编写业务代码。
1182
+ ```
1183
+
1184
+ ## 13. 最终结论
1185
+
1186
+ 对 AI 而言,CloudCC 定时器类不是“会写 Java 就能写”,而是要同时满足三层约束:
552
1187
 
1188
+ - 第一层:必须符合 CloudCC 官方 SDK 的能力边界和推荐用法
1189
+ - 第二层:必须符合 `cloudcc-cli` 的目录、发布和 SOURCE 区域约束
1190
+ - 第三层:必须符合当前项目中定时器类的主流业务模式和工程风格
553
1191
 
554
- *最后更新:2026-03-25*
1192
+ 只有同时满足这三层要求,AI 生成的定时器类才能真正可落地、可维护、可发布。