apaas-oapi-client 0.1.35 → 0.1.37

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.
@@ -0,0 +1,867 @@
1
+ /**
2
+ * aPaaS 数据对象 Schema 管理完整规范
3
+ *
4
+ * 本文档包含:
5
+ * 1. Schema 接口规范(创建、更新对象)
6
+ * 2. 字段类型完整定义(20+ 字段类型)
7
+ * 3. 系统字段说明(6 个自动创建字段)
8
+ * 4. 最佳实践和注意事项
9
+ */
10
+
11
+ // ============================================================
12
+ // Schema 接口规范
13
+ // ============================================================
14
+
15
+ /**
16
+ * 多语文本结构
17
+ */
18
+ export interface MultilingualText {
19
+ zh_cn: string;
20
+ en_us: string;
21
+ }
22
+
23
+ /**
24
+ * 对象设置
25
+ */
26
+ export interface ObjectSettings {
27
+ /** 可搜索字段列表 - 注意:不要包含 _name,会报错 */
28
+ allow_search_fields?: string[];
29
+ /** 展示名称字段 - 注意:不要使用 _name,应使用自定义字段 */
30
+ display_name?: string;
31
+ /** 搜索布局字段列表 */
32
+ search_layout?: string[];
33
+ }
34
+
35
+ /**
36
+ * 字段类型定义
37
+ */
38
+ export interface FieldTypeDefinition {
39
+ /** 字段类型名称 */
40
+ name: string;
41
+ /** 字段类型设置(根据不同类型有不同的结构) */
42
+ settings?: any;
43
+ }
44
+
45
+ /**
46
+ * 加密类型枚举
47
+ */
48
+ export type EncryptType = 'none' | 'rand' | 'fix' | 'ope';
49
+
50
+ /**
51
+ * 字段操作类型(用于 update 接口)
52
+ */
53
+ export type FieldOperator = 'add' | 'replace' | 'remove';
54
+
55
+ /**
56
+ * 创建对象时的字段定义
57
+ */
58
+ export interface CreateFieldDefinition {
59
+ /** 字段 API 名称(必填) */
60
+ api_name: string;
61
+ /** 字段标签(必填) */
62
+ label: MultilingualText;
63
+ /** 字段类型(必填) */
64
+ type: FieldTypeDefinition;
65
+ /** 加密类型(建议显式指定,默认 'none') */
66
+ encrypt_type?: EncryptType | null;
67
+ }
68
+
69
+ /**
70
+ * 更新对象时的字段定义
71
+ */
72
+ export interface UpdateFieldDefinition {
73
+ /** 操作类型(必填):add=添加字段, replace=修改字段, remove=删除字段 */
74
+ operator: FieldOperator;
75
+ /** 字段 API 名称(必填) */
76
+ api_name: string;
77
+ /** 字段标签(operator=add/replace 时需要) */
78
+ label?: MultilingualText;
79
+ /** 字段类型(operator=add/replace 时需要) */
80
+ type?: FieldTypeDefinition;
81
+ /** 加密类型(可选) */
82
+ encrypt_type?: EncryptType | null;
83
+ }
84
+
85
+ /**
86
+ * 创建对象的定义
87
+ */
88
+ export interface CreateObjectDefinition {
89
+ /** 对象 API 名称(必填) */
90
+ api_name: string;
91
+ /** 对象标签(必填) */
92
+ label: MultilingualText;
93
+ /** 对象设置(可选) */
94
+ settings?: ObjectSettings;
95
+ /** 字段列表(必填,至少包含一个自定义字段) */
96
+ fields: CreateFieldDefinition[];
97
+ }
98
+
99
+ /**
100
+ * 更新对象的定义
101
+ */
102
+ export interface UpdateObjectDefinition {
103
+ /** 对象 API 名称(必填) */
104
+ api_name: string;
105
+ /** 对象标签(可选,不传则不修改) */
106
+ label?: MultilingualText;
107
+ /** 对象设置(可选,不传则不修改) */
108
+ settings?: ObjectSettings;
109
+ /** 字段列表(可选,不传则不修改字段) */
110
+ fields?: UpdateFieldDefinition[];
111
+ }
112
+
113
+ /**
114
+ * Schema 接口最佳实践和限制说明
115
+ */
116
+ export const SCHEMA_GUIDELINES = {
117
+ /** 批量操作限制 */
118
+ limits: {
119
+ batch_size: 10, // 单次请求最多 10 个对象
120
+ },
121
+
122
+ /** 系统字段说明 */
123
+ system_fields: {
124
+ description: '系统字段会自动创建,不需要在 fields 数组中定义',
125
+ fields: ['_id', '_name', '_createdBy', '_createdAt', '_updatedBy', '_updatedAt'],
126
+ },
127
+
128
+ /** display_name 限制 */
129
+ display_name: {
130
+ restriction: '不能使用 _name 作为 display_name',
131
+ reason: '系统会误认为是包含 NOW/TODAY 函数的公式',
132
+ solution: '使用自定义字段(如 code、name 等)',
133
+ example: 'display_name: "code"',
134
+ },
135
+
136
+ /** allow_search_fields 限制 */
137
+ allow_search_fields: {
138
+ restriction: '不能包含 _name 字段',
139
+ reason: '系统不允许在可搜索字段中使用包含公式的字段',
140
+ solution: '只包含 _id 和其他自定义字段',
141
+ example: 'allow_search_fields: ["_id", "code", "name"]',
142
+ },
143
+
144
+ /** encrypt_type 说明 */
145
+ encrypt_type: {
146
+ required: true,
147
+ description: '建议每个字段都显式指定 encrypt_type',
148
+ options: {
149
+ none: '不加密(默认)',
150
+ rand: '非确定性加密',
151
+ fix: '固定加密',
152
+ ope: '保序加密',
153
+ },
154
+ },
155
+
156
+ /** operator 说明(用于 update) */
157
+ operator: {
158
+ required: true,
159
+ description: '更新字段时必须指定操作类型',
160
+ options: {
161
+ add: { description: '添加新字段', required_fields: ['api_name', 'label', 'type'] },
162
+ replace: { description: '修改现有字段', required_fields: ['api_name'], note: '只传需要修改的属性' },
163
+ remove: { description: '删除字段', required_fields: ['api_name'], note: '只需要 api_name' },
164
+ },
165
+ },
166
+
167
+ /** 关联字段说明 */
168
+ reference_fields: {
169
+ description: '关联字段用于在对象之间建立关联关系',
170
+ types: {
171
+ lookup: {
172
+ description: '关联对象(单值)- 关联另一个对象的单条记录',
173
+ settings: {
174
+ objectAPIName: '目标对象的 API 名称(必填)',
175
+ required: '是否必填(可选)',
176
+ displayStyle: '显示样式(可选)'
177
+ },
178
+ example: 'type: { name: "lookup", settings: { objectAPIName: "supplier" } }',
179
+ write_format: '写入时只需要 _id:{ supplier: { _id: 123456 } }'
180
+ },
181
+ lookup_multi: {
182
+ description: '关联对象(多值)- 关联另一个对象的多条记录',
183
+ settings: {
184
+ objectAPIName: '目标对象的 API 名称(必填)',
185
+ multiple: 'true(多选)'
186
+ },
187
+ limit: '最多可以关联 200 条记录',
188
+ example: 'type: { name: "lookup_multi", settings: { objectAPIName: "category", multiple: true } }',
189
+ write_format: '写入时提供多个 _id:{ categories: [{ _id: 111 }, { _id: 222 }] }'
190
+ },
191
+ referenceField: {
192
+ description: '引用字段 - 引用关联对象中的字段值(系统自动维护,不可直接写入)',
193
+ settings: {
194
+ guideFieldAPIName: '引导字段(lookup 字段)',
195
+ fieldAPIName: '引用的目标字段',
196
+ referenceObjectApiName: '引用的对象'
197
+ },
198
+ example: 'type: { name: "referenceField", settings: { guideFieldAPIName: "supplier", fieldAPIName: "name", referenceObjectApiName: "supplier" } }',
199
+ note: '系统根据 lookup 字段自动计算,不能直接写入数据'
200
+ },
201
+ rollup: {
202
+ description: '汇总字段 - 对关联对象的数据进行聚合计算(系统自动维护,不可直接写入)',
203
+ settings: {
204
+ objectAPIName: '被汇总的对象',
205
+ lookupFieldAPIName: '关联字段(当前对象中的 lookup 字段)',
206
+ fieldAPIName: '要汇总的字段',
207
+ functionType: '汇总函数:sum/avg/count/max/min/countDistinct',
208
+ rangeFilter: '过滤条件(可选)'
209
+ },
210
+ example: 'type: { name: "rollup", settings: { objectAPIName: "order_item", lookupFieldAPIName: "order", fieldAPIName: "amount", functionType: "sum" } }',
211
+ note: '系统根据关联数据自动汇总,不能直接写入数据'
212
+ }
213
+ },
214
+ prerequisites: {
215
+ description: '创建关联字段的前置条件',
216
+ rules: [
217
+ '目标对象必须已存在',
218
+ 'objectAPIName 必须准确(区分大小写)',
219
+ 'referenceField 和 rollup 依赖的 lookup 字段必须先创建',
220
+ '删除 lookup 字段前,需要先删除依赖它的 referenceField 和 rollup 字段'
221
+ ]
222
+ },
223
+ system_maintained: {
224
+ description: '系统自动维护的字段不能直接写入数据',
225
+ fields: ['referenceField', 'rollup', 'formula'],
226
+ reason: '这些字段的值由系统根据其他字段或公式自动计算'
227
+ }
228
+ },
229
+
230
+ /** 响应结构说明 */
231
+ response: {
232
+ structure: '双层响应结构',
233
+ top_level: {
234
+ code: '0 表示请求格式正确',
235
+ msg: 'success',
236
+ data: '包含 items 数组',
237
+ },
238
+ item_level: {
239
+ description: '每个对象的实际创建/更新状态',
240
+ location: 'data.items[].status',
241
+ check: '需要检查 status.code 判断是否真正成功',
242
+ },
243
+ },
244
+ } as const;
245
+
246
+ /**
247
+ * 创建对象示例
248
+ */
249
+ export const CREATE_OBJECT_EXAMPLE: CreateObjectDefinition = {
250
+ api_name: 'product',
251
+ label: {
252
+ zh_cn: '产品',
253
+ en_us: 'Product',
254
+ },
255
+ settings: {
256
+ display_name: 'code', // ✅ 使用自定义字段
257
+ allow_search_fields: ['_id', 'code', 'name'], // ✅ 不包含 _name
258
+ search_layout: ['code', 'name'],
259
+ },
260
+ fields: [
261
+ {
262
+ api_name: 'code',
263
+ label: { zh_cn: '产品编号', en_us: 'Product Code' },
264
+ type: {
265
+ name: 'text',
266
+ settings: {
267
+ required: true,
268
+ unique: true,
269
+ case_sensitive: false,
270
+ multiline: false,
271
+ max_length: 50,
272
+ },
273
+ },
274
+ encrypt_type: 'none', // ✅ 显式指定
275
+ },
276
+ {
277
+ api_name: 'name',
278
+ label: { zh_cn: '产品名称', en_us: 'Product Name' },
279
+ type: {
280
+ name: 'text',
281
+ settings: {
282
+ required: true,
283
+ unique: false,
284
+ case_sensitive: false,
285
+ multiline: false,
286
+ max_length: 200,
287
+ },
288
+ },
289
+ encrypt_type: 'none',
290
+ },
291
+ {
292
+ api_name: 'price',
293
+ label: { zh_cn: '价格', en_us: 'Price' },
294
+ type: {
295
+ name: 'decimal',
296
+ settings: {
297
+ required: true,
298
+ unique: false,
299
+ display_as_percentage: false,
300
+ decimal_places: 2,
301
+ },
302
+ },
303
+ encrypt_type: 'none',
304
+ },
305
+ ],
306
+ };
307
+
308
+ /**
309
+ * 更新对象示例(添加字段)
310
+ */
311
+ export const UPDATE_OBJECT_ADD_FIELD_EXAMPLE: UpdateObjectDefinition = {
312
+ api_name: 'product',
313
+ fields: [
314
+ {
315
+ operator: 'add', // 添加新字段
316
+ api_name: 'description',
317
+ label: { zh_cn: '产品描述', en_us: 'Description' },
318
+ type: {
319
+ name: 'text',
320
+ settings: {
321
+ required: false,
322
+ unique: false,
323
+ case_sensitive: false,
324
+ multiline: true,
325
+ max_length: 1000,
326
+ },
327
+ },
328
+ encrypt_type: 'none',
329
+ },
330
+ ],
331
+ };
332
+
333
+ /**
334
+ * 更新对象示例(修改字段)
335
+ */
336
+ export const UPDATE_OBJECT_REPLACE_FIELD_EXAMPLE: UpdateObjectDefinition = {
337
+ api_name: 'product',
338
+ fields: [
339
+ {
340
+ operator: 'replace', // 修改现有字段
341
+ api_name: 'price',
342
+ label: { zh_cn: '销售价格', en_us: 'Sale Price' }, // 修改标签
343
+ // 可以只传需要修改的属性
344
+ },
345
+ ],
346
+ };
347
+
348
+ /**
349
+ * 更新对象示例(删除字段)
350
+ */
351
+ export const UPDATE_OBJECT_REMOVE_FIELD_EXAMPLE: UpdateObjectDefinition = {
352
+ api_name: 'product',
353
+ fields: [
354
+ {
355
+ operator: 'remove', // 删除字段
356
+ api_name: 'description', // 只需要 api_name
357
+ },
358
+ ],
359
+ };
360
+
361
+ /**
362
+ * 更新对象示例(只修改标签和设置)
363
+ */
364
+ export const UPDATE_OBJECT_SETTINGS_EXAMPLE: UpdateObjectDefinition = {
365
+ api_name: 'product',
366
+ label: {
367
+ zh_cn: '产品信息', // 修改标签
368
+ en_us: 'Product Information',
369
+ },
370
+ settings: {
371
+ display_name: 'name', // 修改展示名称字段
372
+ allow_search_fields: ['_id', 'code', 'name', 'description'],
373
+ search_layout: ['code', 'name', 'description'],
374
+ },
375
+ // 不传 fields,表示不修改字段
376
+ };
377
+
378
+ // ============================================================
379
+ // 字段类型定义
380
+ // ============================================================
381
+
382
+ /**
383
+ * 字段类型元数据接口
384
+ */
385
+ export interface FieldTypeMetadata {
386
+ /** API 名称 */
387
+ api_name: string;
388
+ /** 字段类型中文名称 */
389
+ label: string;
390
+ /** 存储数据类型 */
391
+ storage_type: 'String' | 'Number' | 'Boolean' | 'Object' | 'Array';
392
+ /** 是否为系统字段 */
393
+ is_system: boolean;
394
+ /** 字段描述 */
395
+ description: string;
396
+ /** 存储示例 */
397
+ example: any;
398
+ /** 特殊说明 */
399
+ notes?: string;
400
+ }
401
+
402
+ /**
403
+ * aPaaS 平台所有字段类型定义
404
+ */
405
+ export const FIELD_TYPES: Record<string, FieldTypeMetadata> = {
406
+ // ==================== 系统默认字段(6个,不可修改)====================
407
+ _id: {
408
+ api_name: '_id',
409
+ label: 'ID',
410
+ storage_type: 'Number',
411
+ is_system: true,
412
+ description: '系统默认字段,数据的关键 ID,唯一键,可被其他对象引用为外键',
413
+ example: 1766662402370564,
414
+ notes: '16位数字,注意该 ID 并不会随着记录的增多而递增生成'
415
+ },
416
+
417
+ _name: {
418
+ api_name: '_name',
419
+ label: '展示名称',
420
+ storage_type: 'Array',
421
+ is_system: true,
422
+ description: '系统默认字段,记录的展示名称',
423
+ example: [
424
+ {
425
+ language_code: 2052,
426
+ text: '1766662402370564'
427
+ }
428
+ ],
429
+ notes: '以多语本形式存储,language_code: 2052=中文, 1033=英文'
430
+ },
431
+
432
+ _createdBy: {
433
+ api_name: '_createdBy',
434
+ label: '创建人',
435
+ storage_type: 'Object',
436
+ is_system: true,
437
+ description: '系统默认字段,记录创建人信息',
438
+ example: {
439
+ _id: 1766661610377271,
440
+ _name: [
441
+ { language_code: 1033, text: 'San Zhang' },
442
+ { language_code: 2052, text: '张三' }
443
+ ],
444
+ avatar: {
445
+ color: null,
446
+ color_id: '',
447
+ content: null,
448
+ image: {
449
+ large: 'https://s1-imfile.feishucdn.com/static-resource/v1/52a9a370-1967-42b2-9c30-730fed90d81g~?image_size=noop&cut_type=&quality=&format=png&sticker_format=.webp'
450
+ },
451
+ source: 'image'
452
+ },
453
+ i18n_name: [
454
+ { language_code: 1033, text: 'San Zhang' },
455
+ { language_code: 2052, text: '张三' }
456
+ ],
457
+ id: 1766661610377271,
458
+ is_deleted: false,
459
+ name: '张三'
460
+ },
461
+ notes: '以关联对象的形式存储,关联系统的用户对象。包含 _id、_name(多语数组)、id、name(中文字符串)、avatar 头像信息'
462
+ },
463
+
464
+ _createdAt: {
465
+ api_name: '_createdAt',
466
+ label: '创建时间',
467
+ storage_type: 'Number',
468
+ is_system: true,
469
+ description: '系统默认字段,记录创建时间',
470
+ example: 1684823950061,
471
+ notes: '属于日期时间字段,以 13 位毫秒时间戳存储'
472
+ },
473
+
474
+ _updatedBy: {
475
+ api_name: '_updatedBy',
476
+ label: '更新人',
477
+ storage_type: 'Object',
478
+ is_system: true,
479
+ description: '系统默认字段,记录最后更新人信息',
480
+ example: {
481
+ _id: 1766661610377271,
482
+ _name: [
483
+ { language_code: 1033, text: 'San Zhang' },
484
+ { language_code: 2052, text: '张三' }
485
+ ],
486
+ avatar: {
487
+ color: null,
488
+ color_id: '',
489
+ content: null,
490
+ image: {
491
+ large: 'https://s1-imfile.feishucdn.com/static-resource/v1/52a9a370-1967-42b2-9c30-730fed90d81g~?image_size=noop&cut_type=&quality=&format=png&sticker_format=.webp'
492
+ },
493
+ source: 'image'
494
+ },
495
+ i18n_name: [
496
+ { language_code: 1033, text: 'San Zhang' },
497
+ { language_code: 2052, text: '张三' }
498
+ ],
499
+ id: 1766661610377271,
500
+ is_deleted: false,
501
+ name: '张三'
502
+ },
503
+ notes: '以关联对象的形式存储,关联系统的用户对象'
504
+ },
505
+
506
+ _updatedAt: {
507
+ api_name: '_updatedAt',
508
+ label: '更新时间',
509
+ storage_type: 'Number',
510
+ is_system: true,
511
+ description: '系统默认字段,记录最后更新时间',
512
+ example: 1688610057236,
513
+ notes: '属于日期时间字段,以 13 位毫秒时间戳存储'
514
+ },
515
+
516
+ // ==================== 基础字段类型 ====================
517
+ text: {
518
+ api_name: 'text',
519
+ label: '文本',
520
+ storage_type: 'String',
521
+ is_system: false,
522
+ description: '单行文本字段',
523
+ example: '文本'
524
+ },
525
+
526
+ bigint: {
527
+ api_name: 'bigint',
528
+ label: '整数',
529
+ storage_type: 'String',
530
+ is_system: false,
531
+ description: '整数字段',
532
+ example: '10',
533
+ notes: '存储为字符串格式'
534
+ },
535
+
536
+ number: {
537
+ api_name: 'number',
538
+ label: '浮点数',
539
+ storage_type: 'Number',
540
+ is_system: false,
541
+ description: '数字字段,可带小数点',
542
+ example: 99.991
543
+ },
544
+
545
+ date: {
546
+ api_name: 'date',
547
+ label: '日期',
548
+ storage_type: 'String',
549
+ is_system: false,
550
+ description: '日期字段',
551
+ example: '2023-05-10',
552
+ notes: '格式固定为 "YYYY-MM-DD",读取和写入都需要按照此格式'
553
+ },
554
+
555
+ datetime: {
556
+ api_name: 'datetime',
557
+ label: '日期时间',
558
+ storage_type: 'Number',
559
+ is_system: false,
560
+ description: '日期时间字段',
561
+ example: 1683698580000,
562
+ notes: '以 13 位毫秒时间戳存储'
563
+ },
564
+
565
+ phone: {
566
+ api_name: 'phone',
567
+ label: '手机号码',
568
+ storage_type: 'Object',
569
+ is_system: false,
570
+ description: '手机号码字段',
571
+ example: {
572
+ code: '+86',
573
+ key: '+86(CN)',
574
+ number: '17624863925'
575
+ },
576
+ notes: '包含国家/地区 code 和手机号'
577
+ },
578
+
579
+ email: {
580
+ api_name: 'email',
581
+ label: '邮箱',
582
+ storage_type: 'String',
583
+ is_system: false,
584
+ description: '邮箱字段',
585
+ example: 'zhaoyizhe@bytedance.com'
586
+ },
587
+
588
+ option: {
589
+ api_name: 'option',
590
+ label: '选项',
591
+ storage_type: 'String',
592
+ is_system: false,
593
+ description: '单选字段',
594
+ example: 'enable',
595
+ notes: '字符串内的内容为选项的 API 名称。可通过 context.metadata.object("objectApiName").getField("optionApiName") 获取选项的元数据信息'
596
+ },
597
+
598
+ boolean: {
599
+ api_name: 'boolean',
600
+ label: '布尔',
601
+ storage_type: 'Boolean',
602
+ is_system: false,
603
+ description: '布尔值字段',
604
+ example: true
605
+ },
606
+
607
+ avatar: {
608
+ api_name: 'avatar',
609
+ label: '头像/标识',
610
+ storage_type: 'Object',
611
+ is_system: false,
612
+ description: '头像或标识字段',
613
+ example: {
614
+ color: null,
615
+ color_id: '',
616
+ content: null,
617
+ image: {
618
+ large: 'https://s1-imfile.feishucdn.com/static-resource/v1/52a9a370-1967-42b2-9c30-730fed90d81g~?image_size=noop&cut_type=&quality=&format=png&sticker_format=.webp'
619
+ },
620
+ source: 'image'
621
+ }
622
+ },
623
+
624
+ multilingual: {
625
+ api_name: 'multilingual',
626
+ label: '多语文本',
627
+ storage_type: 'Array',
628
+ is_system: false,
629
+ description: '多语言文本字段',
630
+ example: [
631
+ {
632
+ language_code: 1033,
633
+ text: 'Multilingual-English'
634
+ },
635
+ {
636
+ language_code: 2052,
637
+ text: '多语言-中文'
638
+ }
639
+ ],
640
+ notes: '包含两个对象,中文文本的 language_code 为 2052,英文文本的 language_code 为 1033'
641
+ },
642
+
643
+ richText: {
644
+ api_name: 'richText',
645
+ label: '富文本',
646
+ storage_type: 'Object',
647
+ is_system: false,
648
+ description: '富文本字段',
649
+ example: {
650
+ config: [
651
+ {
652
+ resourceId: 'BIZ_74da2122261247e6bda16834222c8f74',
653
+ resourceType: 'img',
654
+ token: '022a7279add24dcca7c5e2ae62afcc5c'
655
+ }
656
+ ],
657
+ preview: '',
658
+ raw: '<div style="white-space: pre;"><span style="color: rgb(245, 74, 69);">红色文本</span>\n</div><div style="white-space: pre;"><span style="text-decoration: underline;"><i><span style="font-weight: bold;">加粗文本</span></i></span>\n</div><div style="white-space: pre;">下面是图片\n</div><div style="white-space: pre;"><img src="/ui/attachment?token=f02efe6d990846eba6d2b6aafe053a6c&amp;preview=true&amp;imgId=BIZ_74da2122261247e6bda16834222c8f74" alt="20230523-143736.jpeg">\n</div>'
659
+ },
660
+ notes: '包含了文件的 token 信息和原始的 html 信息'
661
+ },
662
+
663
+ attachment: {
664
+ api_name: 'attachment',
665
+ label: '文件',
666
+ storage_type: 'Array',
667
+ is_system: false,
668
+ description: '文件附件字段',
669
+ example: [
670
+ {
671
+ id: 'BIZ_b38406e0f3a048c2a245ffeb9a14e42a',
672
+ mime_type: 'mp4',
673
+ name: 'test.mp4',
674
+ size: 14216083,
675
+ token: '6a4cb16d29bb43f5bed9735b8c980793'
676
+ }
677
+ ],
678
+ notes: '注意文件的存储只能是数组的形式,即使是设置了最多可上传数量为1,仍然为数组。下载文件:域名前缀 + /ae/api/v1/assets/attachment/download?token=token'
679
+ },
680
+
681
+ autoid: {
682
+ api_name: 'autoid',
683
+ label: '自动编号',
684
+ storage_type: 'String',
685
+ is_system: false,
686
+ description: '自动编号字段',
687
+ example: '5'
688
+ },
689
+
690
+ decimal: {
691
+ api_name: 'decimal',
692
+ label: '定点数',
693
+ storage_type: 'String',
694
+ is_system: false,
695
+ description: '定点数字段,高精度数字',
696
+ example: '123456789.987654321',
697
+ notes: '存储为字符串格式,保证精度'
698
+ },
699
+
700
+ // ==================== 高级字段类型 ====================
701
+ formula: {
702
+ api_name: 'formula',
703
+ label: '公式',
704
+ storage_type: 'String',
705
+ is_system: false,
706
+ description: '公式字段',
707
+ example: '文本',
708
+ notes: '公式字段的返回值取决于选择的返回类型,各个类型的存储请参考文档其他部分'
709
+ },
710
+
711
+ rollup: {
712
+ api_name: 'rollup',
713
+ label: '汇总',
714
+ storage_type: 'Number',
715
+ is_system: false,
716
+ description: '汇总字段',
717
+ example: 0,
718
+ notes: '可带有小数点'
719
+ },
720
+
721
+ lookup: {
722
+ api_name: 'lookup',
723
+ label: '关联对象',
724
+ storage_type: 'Object',
725
+ is_system: false,
726
+ description: '关联对象字段(单值)',
727
+ example: {
728
+ _id: 1767211281913907,
729
+ _name: '关联其他表的一条记录',
730
+ id: 1767211281913907,
731
+ is_deleted: false,
732
+ name: '关联其他表的一条记录'
733
+ },
734
+ notes: '与关联的用户对象一致,包含 _id 和 _name 之外,也包含了 id 和 name。此处的 _name 并不是多语文本,因为在这个数据对象下的展示名称就为普通文本。向关联对象字段写入数据时,仅写入 _id 属性即可,示例:lookup: { _id: 1767211281913907 }'
735
+ },
736
+
737
+ lookup_multi: {
738
+ api_name: 'lookup_multi',
739
+ label: '关联对象-多值',
740
+ storage_type: 'Array',
741
+ is_system: false,
742
+ description: '关联对象字段(多值)',
743
+ example: [
744
+ {
745
+ _id: 1767211281913907,
746
+ _name: '关联其他表的一条记录',
747
+ id: 1767211281913907,
748
+ is_deleted: false,
749
+ name: '关联其他表的一条记录'
750
+ },
751
+ {
752
+ _id: 1767211039388715,
753
+ _name: '关联其他表的另一条记录',
754
+ id: 1767211039388715,
755
+ is_deleted: false,
756
+ name: '关联其他表的另一条记录'
757
+ }
758
+ ],
759
+ notes: '数组里的内容和单条的关联对象字段一致。注意对于多条记录的关联对象,最多可以关联 200 条'
760
+ },
761
+
762
+ referenceField: {
763
+ api_name: 'referenceField',
764
+ label: '引用字段',
765
+ storage_type: 'Array',
766
+ is_system: false,
767
+ description: '引用字段',
768
+ example: [
769
+ {
770
+ language_code: 1033,
771
+ text: 'San Zhang'
772
+ },
773
+ {
774
+ language_code: 2052,
775
+ text: '张三'
776
+ }
777
+ ],
778
+ notes: '与公式类似。引用字段的返回值取决于选择的返回类型,各个类型的存储请参考文档其他部分'
779
+ },
780
+
781
+ region: {
782
+ api_name: 'region',
783
+ label: '行政区划',
784
+ storage_type: 'Object',
785
+ is_system: false,
786
+ description: '行政区划字段',
787
+ example: {
788
+ _isDeleted: false,
789
+ fullPath: [
790
+ {
791
+ language_code: 1033,
792
+ text: 'Xihu / Hangzhou / Zhejiang / Chinese mainland'
793
+ },
794
+ {
795
+ language_code: 2052,
796
+ text: '中国大陆 / 浙江 / 杭州市 / 西湖区'
797
+ }
798
+ ],
799
+ id: 1747012778430564,
800
+ level: 4,
801
+ regionCode: '330106'
802
+ },
803
+ notes: '行政区域字段对象内包含了 fullPath 多语文本,以及 id 和 level 层级。行政区划对象中,以 regionCode 作为唯一值。如果想获取某一行政区划的详细记录,可以通过 context.db.object("_region").select("_id", "_cityLevel").where({ _name: application.operator.contain("北京") }).findOne() 获取'
804
+ }
805
+ };
806
+
807
+ /**
808
+ * 系统默认字段列表(每个对象都会自动创建)
809
+ */
810
+ export const SYSTEM_FIELDS = ['_id', '_name', '_createdBy', '_createdAt', '_updatedBy', '_updatedAt'] as const;
811
+
812
+ /**
813
+ * 获取系统字段
814
+ */
815
+ export function getSystemFields(): FieldTypeMetadata[] {
816
+ return SYSTEM_FIELDS.map(fieldName => FIELD_TYPES[fieldName]);
817
+ }
818
+
819
+ /**
820
+ * 获取自定义字段类型
821
+ */
822
+ export function getCustomFieldTypes(): FieldTypeMetadata[] {
823
+ return Object.values(FIELD_TYPES).filter(field => !field.is_system);
824
+ }
825
+
826
+ /**
827
+ * 根据 API 名称获取字段类型信息
828
+ */
829
+ export function getFieldType(apiName: string): FieldTypeMetadata | undefined {
830
+ return FIELD_TYPES[apiName];
831
+ }
832
+
833
+ /**
834
+ * 判断是否为系统字段
835
+ */
836
+ export function isSystemField(apiName: string): boolean {
837
+ return SYSTEM_FIELDS.includes(apiName as any);
838
+ }
839
+
840
+ /**
841
+ * 语言代码常量
842
+ */
843
+ export const LANGUAGE_CODES = {
844
+ EN_US: 1033,
845
+ ZH_CN: 2052
846
+ } as const;
847
+
848
+ /**
849
+ * 多语文本辅助函数:创建多语文本对象
850
+ */
851
+ export function createMultilingualText(zhCn: string, enUs?: string): Array<{ language_code: number; text: string }> {
852
+ return [
853
+ { language_code: LANGUAGE_CODES.ZH_CN, text: zhCn },
854
+ { language_code: LANGUAGE_CODES.EN_US, text: enUs || zhCn }
855
+ ];
856
+ }
857
+
858
+ /**
859
+ * 多语文本辅助函数:从多语文本对象中提取文本
860
+ */
861
+ export function extractMultilingualText(
862
+ multilingualText: Array<{ language_code: number; text: string }>,
863
+ languageCode: number = LANGUAGE_CODES.ZH_CN
864
+ ): string {
865
+ const found = multilingualText.find(item => item.language_code === languageCode);
866
+ return found ? found.text : multilingualText[0]?.text || '';
867
+ }