neo-cmp-cli 1.13.13 → 1.13.16
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/README.md +1 -1
- package/dist/neo/neoEnvManager.js +1 -1
- package/dist/neo/neoLogin.js +1 -1
- package/dist/neo/neoRequire.js +1 -1
- package/dist/package.json.js +1 -1
- package/docs//351/200/232/347/224/250/344/273/243/347/220/206/346/216/245/345/217/243/forward.zip +0 -0
- package/docs//351/200/232/347/224/250/344/273/243/347/220/206/346/216/245/345/217/243//350/207/252/345/256/232/344/271/211API:/351/200/232/347/224/250/344/273/243/347/220/206/346/216/245/345/217/243/344/275/277/347/224/250/350/257/264/346/230/216.md +13 -0
- package/package.json +1 -1
- package/template/antd-custom-cmp-template/package.json +1 -1
- package/template/asset-manage-template/package.json +1 -1
- package/template/echarts-custom-cmp-template/package.json +1 -1
- package/template/empty-custom-cmp-template/package.json +1 -1
- package/template/map-custom-cmp-template/package.json +1 -1
- package/template/neo-bi-cmps/package.json +1 -1
- package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/index.tsx +17 -10
- package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/model.ts +47 -6
- package/template/neo-bi-cmps/src/components/filterBar__c/index.tsx +21 -7
- package/template/neo-bi-cmps/src/components/forecastChart__c/index.tsx +6 -9
- package/template/neo-bi-cmps/src/components/forecastChart__c/model.ts +2 -1
- package/template/neo-bi-cmps/src/components/forecastGrid__c/model.ts +32 -4
- package/template/neo-bi-cmps/src/components/gapCloser__c/index.tsx +7 -2
- package/template/neo-bi-cmps/src/components/gapCloser__c/model.ts +6 -3
- package/template/neo-bi-cmps/src/components/kpiCards__c/model.ts +18 -3
- package/template/neo-bi-cmps/src/components/oppList__c/index.tsx +70 -13
- package/template/neo-bi-cmps/src/components/oppList__c/model.ts +50 -4
- package/template/neo-bi-cmps/src/components/pipelineFunnel__c/index.tsx +3 -1
- package/template/neo-bi-cmps/src/components/pipelineFunnel__c/model.ts +28 -4
- package/template/neo-bi-cmps/src/components/stageSwitch__c/index.tsx +21 -6
- package/template/neo-bi-cmps/src/components/stageSwitch__c/model.ts +60 -5
- package/template/neo-bi-cmps/src/components/stageTimeChart__c/model.ts +26 -4
- package/template/neo-custom-cmp-template/package.json +1 -1
- package/template/neo-h5-cmps/package.json +1 -1
- package/template/neo-order-cmps/package.json +1 -1
- package/template/neo-web-entity-grid/package.json +1 -1
- package/template/neo-web-form/package.json +1 -1
- package/template/neo-web-form/src/components/batchAddTable__c/index.tsx +17 -17
- package/template/react-custom-cmp-template/package.json +1 -1
- package/template/react-ts-custom-cmp-template/package.json +1 -1
- package/template/vue2-custom-cmp-template/package.json +1 -1
- package/template/neo-bi-cmps/docs/gartner-pipeline-apis.md +0 -279
- package/template/neo-bi-cmps/docs/gartner-pipeline-prd.md +0 -389
- package/template/neo-bi-cmps/docs/neo-backend-dev/SKILL.md +0 -188
- package/template/neo-bi-cmps/docs/neo-backend-dev/references/01-Trigger/345/274/200/345/217/221.md +0 -183
- package/template/neo-bi-cmps/docs/neo-backend-dev/references/02-/350/207/252/345/256/232/344/271/211API/345/274/200/345/217/221.md +0 -196
- package/template/neo-bi-cmps/docs/neo-backend-dev/references/03-SDK/345/267/245/345/205/267/347/261/273/346/216/245/345/217/243.md +0 -346
- package/template/neo-bi-cmps/docs/neo-backend-dev/references/04-/350/256/241/345/210/222/344/275/234/344/270/232/345/274/200/345/217/221.md +0 -188
- package/template/neo-bi-cmps/docs/neo-backend-dev/references/05-/351/241/265/351/235/242/345/274/200/345/217/221.md +0 -293
- package/template/neo-bi-cmps/docs/neo-backend-dev/references/06-/346/265/201/347/250/213/346/211/251/345/261/225/345/274/200/345/217/221.md +0 -175
- package/template/neo-bi-cmps/docs/neo-backend-dev/references/PaaS/345/271/263/345/217/260/345/274/200/345/217/221/346/211/213/345/206/214/350/247/243/350/257/273.md +0 -313
- package/template/neo-bi-cmps/docs/neo-backend-dev/references/auth-config.md +0 -77
- package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/deploy_server_script.py +0 -118
- package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/download_server_script.py +0 -74
- package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/gen_entity_desc.py +0 -69
- package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/gen_entitylist.py +0 -87
- package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/query_crm.py +0 -65
- package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/uninstall_server_script.py +0 -48
- package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/update_model_jar.py +0 -49
- package/template/neo-bi-cmps/docs/neo-frontend-dev/SKILL.md +0 -138
- package/template/neo-bi-cmps/docs/neo-frontend-dev/references/auth-config.md +0 -77
- package/template/neo-bi-cmps/docs/neo-frontend-dev/references/component-dev.md +0 -205
- package/template/neo-bi-cmps/docs/neo-frontend-dev/references/entityTable-example.md +0 -167
- package/template/neo-bi-cmps/docs/neo-frontend-dev/references/templates.md +0 -38
- package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/gen_entity_desc.py +0 -69
- package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/gen_entitylist.py +0 -87
- package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/query_crm.py +0 -65
- package/template/neo-bi-cmps/docs/prototype-pipeline-forecasting.html +0 -2453
- package/template/neo-bi-cmps/docs//350/264/246/345/217/267/347/233/270/345/205/263/344/277/241/346/201/257.md +0 -10
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
# entityTable__c 参考实现
|
|
2
|
-
|
|
3
|
-
这是一个完整的实体数据表格组件示例,支持增删改查操作。开发新组件前参考此实现了解最佳实践。
|
|
4
|
-
|
|
5
|
-
## 目录
|
|
6
|
-
|
|
7
|
-
- [关键设计模式](#关键设计模式)
|
|
8
|
-
- [组件代码](#组件代码)
|
|
9
|
-
- [模型代码](#模型代码)
|
|
10
|
-
- [样式代码](#样式代码)
|
|
11
|
-
|
|
12
|
-
## 关键设计模式
|
|
13
|
-
|
|
14
|
-
### 1. 使用 xObjectDataApi 配置项对接实体数据源
|
|
15
|
-
|
|
16
|
-
模型中使用 `type: 'xObjectDataApi'` 配置项,让设计器提供实体选择和字段选择的 UI:
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
propsSchema = [
|
|
20
|
-
{
|
|
21
|
-
type: 'xObjectDataApi',
|
|
22
|
-
name: 'xObjectDataApi',
|
|
23
|
-
label: '实体数据源',
|
|
24
|
-
value: {
|
|
25
|
-
xObjectApiKey: 'customContact__c',
|
|
26
|
-
fields: ['name', 'phone__c'],
|
|
27
|
-
},
|
|
28
|
-
custom: true, // true 表示自定义实体
|
|
29
|
-
},
|
|
30
|
-
];
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
组件通过 `this.props.xObjectDataApi` 获取配置,包含:
|
|
34
|
-
- `xObjectApiKey`:实体 API Key
|
|
35
|
-
- `fields`:选中的字段列表
|
|
36
|
-
- `fieldDescList`:字段描述信息(平台自动注入)
|
|
37
|
-
- `pageSize` / `page`:分页参数
|
|
38
|
-
|
|
39
|
-
### 2. 动态获取字段描述
|
|
40
|
-
|
|
41
|
-
通过 `xObject.getDesc()` 获取实体的字段元数据,用于动态生成表格列和表单:
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
const resultData = await xObject.getDesc(xObjectApiKey);
|
|
45
|
-
const fieldList = resultData.data.fields; // 包含 apiKey, label, type, required 等
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### 3. 根据字段类型渲染表单控件
|
|
49
|
-
|
|
50
|
-
根据 `field.type` 动态选择输入组件:
|
|
51
|
-
- `picklist` → Select 单选
|
|
52
|
-
- `multipicklist` → Select 多选
|
|
53
|
-
- `textarea` → Input.TextArea
|
|
54
|
-
- `datetime` / `date` / `time` → DatePicker
|
|
55
|
-
- `int` / `float` → InputNumber
|
|
56
|
-
- `entityType` → Select(业务类型列表)
|
|
57
|
-
- 默认 → Input
|
|
58
|
-
|
|
59
|
-
### 4. 声明组件函数(可执行动作)
|
|
60
|
-
|
|
61
|
-
使用 `@NeoEvent.function` 装饰器声明可被其他组件调用的动作:
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
@NeoEvent.function
|
|
65
|
-
async loadData(page = 1, pageSize = 10) { ... }
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
模型中声明函数列表:
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
functions = [
|
|
72
|
-
{ apiKey: 'loadData', label: '刷新表格', helpTextKey: '刷新当前表格数据' },
|
|
73
|
-
{
|
|
74
|
-
apiKey: 'handleDelete', label: '删除记录', helpTextKey: '删除指定记录',
|
|
75
|
-
funcInParams: [
|
|
76
|
-
{ apiKey: 'id', label: '记录ID', type: 'String', required: true },
|
|
77
|
-
],
|
|
78
|
-
},
|
|
79
|
-
];
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### 5. 使用 panelSwitch 配置开关
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
{ type: 'panelSwitch', name: 'showAddButton', label: '显示新增按钮' },
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 6. componentDidUpdate 响应配置变化
|
|
89
|
-
|
|
90
|
-
当设计器中修改了 xObjectDataApi 配置时,组件需要重新加载数据:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
async componentDidUpdate(prevProps) {
|
|
94
|
-
if (xObjectApiKey !== prevXObjectApiKey || !isEqual(fields, prevFields)) {
|
|
95
|
-
await this.loadFieldList();
|
|
96
|
-
this.loadData(page, pageSize);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## 组件代码
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
// index.tsx 关键结构
|
|
105
|
-
import { Table, Button, Space, Modal, Form, Input, Select, message, Popconfirm, Spin, Empty, Card } from 'antd';
|
|
106
|
-
import { PlusOutlined, EditOutlined, DeleteOutlined, ReloadOutlined } from '@ant-design/icons';
|
|
107
|
-
import { xObject } from 'neo-open-api';
|
|
108
|
-
import { BaseCmp, NeoEvent } from 'neo-ui-common';
|
|
109
|
-
|
|
110
|
-
interface EntityTableProps {
|
|
111
|
-
xObjectDataApi: {
|
|
112
|
-
xObjectApiKey: string;
|
|
113
|
-
fields: string[];
|
|
114
|
-
fieldDescList?: any[];
|
|
115
|
-
pageSize?: number;
|
|
116
|
-
page?: number;
|
|
117
|
-
};
|
|
118
|
-
showAddButton?: boolean;
|
|
119
|
-
showEditButton?: boolean;
|
|
120
|
-
showDeleteButton?: boolean;
|
|
121
|
-
className?: string;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// 组件继承 BaseCmp,实现 CRUD 操作
|
|
125
|
-
// 使用 xObject.query / create / update / delete 对接平台数据
|
|
126
|
-
// 使用 xObject.getDesc 获取字段元数据
|
|
127
|
-
// 使用 xObject.getEntityTypeList 获取业务类型列表
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## 模型代码
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
// model.ts 关键配置
|
|
134
|
-
export class EntityTableModel {
|
|
135
|
-
label = '实体数据表格';
|
|
136
|
-
description = '基于 XObject 的数据表格组件,支持增删改查操作';
|
|
137
|
-
targetPage = ['all'];
|
|
138
|
-
targetDevice = 'web';
|
|
139
|
-
|
|
140
|
-
defaultComProps = {
|
|
141
|
-
showAddButton: true,
|
|
142
|
-
showEditButton: true,
|
|
143
|
-
showDeleteButton: true,
|
|
144
|
-
xObjectDataApi: {
|
|
145
|
-
xObjectApiKey: 'customContact__c',
|
|
146
|
-
fields: ['name', 'phone__c'],
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// 组件函数声明
|
|
151
|
-
functions = [
|
|
152
|
-
{ apiKey: 'loadData', label: '刷新表格' },
|
|
153
|
-
{ apiKey: 'handleDelete', label: '删除记录', funcInParams: [...] },
|
|
154
|
-
];
|
|
155
|
-
|
|
156
|
-
propsSchema = [
|
|
157
|
-
{ type: 'xObjectDataApi', name: 'xObjectDataApi', label: '实体数据源', custom: true },
|
|
158
|
-
{ type: 'panelSwitch', name: 'showAddButton', label: '显示新增按钮' },
|
|
159
|
-
{ type: 'panelSwitch', name: 'showEditButton', label: '显示编辑按钮' },
|
|
160
|
-
{ type: 'panelSwitch', name: 'showDeleteButton', label: '显示删除按钮' },
|
|
161
|
-
];
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## 样式代码
|
|
166
|
-
|
|
167
|
-
组件根节点 class 为 `entityTable__c`(与目录名一致),使用 Card 包裹,包含响应式设计(768px / 576px 断点)。
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# 内置模板
|
|
2
|
-
|
|
3
|
-
执行 `neo init` 时可选择以下模板,也可通过 `-t <类型> -n <名称>` 非交互创建。
|
|
4
|
-
|
|
5
|
-
| 模板类型 | 说明 | 适用场景 |
|
|
6
|
-
|----------|------|----------|
|
|
7
|
-
| `neo-web-cmps` | Web 端列表组件模板 | 基础大列表、Picker 列表等 |
|
|
8
|
-
| `neo-h5-cmps` | H5 端业务组件模板 | 全局搜索、数据列表、数据 Tabs、AI 对话页等 |
|
|
9
|
-
| `neo` | 自定义业务组件模板 | 实体表单、实体详情、实体表格等 |
|
|
10
|
-
| `neo-bi-cmps` | 数值指标组件模板 | 展示实体数据源中关键数值指标 |
|
|
11
|
-
| `echarts` | ECharts 图表组件模板 | 基于 ECharts 的图表(地图场景用 `amap`) |
|
|
12
|
-
| `antd` | Ant Design 组件模板 | 数据仪表板、搜索组件等 |
|
|
13
|
-
| `amap` | 高德地图组件模板 | 基于高德地图 API 的地图组件 |
|
|
14
|
-
| `vue2` | Vue2 组件模板 | 基于 Vue2 的组件 |
|
|
15
|
-
|
|
16
|
-
## 选择建议
|
|
17
|
-
|
|
18
|
-
- 需要实体数据 CRUD → `neo`
|
|
19
|
-
- 需要图表可视化 → `echarts`
|
|
20
|
-
- 需要地图展示 → `amap`
|
|
21
|
-
- 需要丰富 UI 组件库 → `antd`
|
|
22
|
-
- H5 移动端场景 → `neo-h5-cmps`
|
|
23
|
-
- Web 端列表场景 → `neo-web-cmps`
|
|
24
|
-
- BI 数值指标展示 → `neo-bi-cmps`
|
|
25
|
-
- Vue 技术栈 → `vue2`
|
|
26
|
-
|
|
27
|
-
## 非交互创建示例
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
neo init -t neo -n myBizCmp
|
|
31
|
-
neo init -t echarts -n myChartCmp
|
|
32
|
-
neo init -t antd -n myAntdCmp
|
|
33
|
-
neo init -t amap -n myMapCmp
|
|
34
|
-
neo init -t vue2 -n myVue2Cmp
|
|
35
|
-
neo init -t neo-web-cmps -n myWebListCmp
|
|
36
|
-
neo init -t neo-h5-cmps -n myH5Cmp
|
|
37
|
-
neo init -t neo-bi-cmps -n myBiCmp
|
|
38
|
-
```
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
生成实体字段描述:通过 API 获取指定实体的字段信息,输出 <apiKey>.md
|
|
4
|
-
用法: python3 gen_entity_desc.py <项目目录> <实体apiKey>
|
|
5
|
-
示例: python3 gen_entity_desc.py NEOTrail investment__c
|
|
6
|
-
"""
|
|
7
|
-
import sys, os, json, urllib.request
|
|
8
|
-
|
|
9
|
-
if len(sys.argv) < 3:
|
|
10
|
-
print("用法: python3 gen_entity_desc.py <项目目录> <实体apiKey>")
|
|
11
|
-
sys.exit(1)
|
|
12
|
-
|
|
13
|
-
project_dir = sys.argv[1]
|
|
14
|
-
api_key = sys.argv[2]
|
|
15
|
-
token_path = os.path.join(project_dir, '.neo-cli/token.json')
|
|
16
|
-
output_dir = os.path.join(project_dir, 'src/entity-model')
|
|
17
|
-
|
|
18
|
-
if not os.path.exists(token_path):
|
|
19
|
-
print("错误: 未找到 %s,请先执行 neo login" % token_path)
|
|
20
|
-
sys.exit(1)
|
|
21
|
-
|
|
22
|
-
token = json.load(open(token_path))
|
|
23
|
-
access_token = token['access_token']
|
|
24
|
-
base_url = token['instance_uri'].rstrip('/')
|
|
25
|
-
headers = {'Authorization': 'Bearer ' + access_token, 'Content-Type': 'application/json'}
|
|
26
|
-
|
|
27
|
-
def api_get(path):
|
|
28
|
-
req = urllib.request.Request(base_url + path, method='GET')
|
|
29
|
-
for k, v in headers.items():
|
|
30
|
-
req.add_header(k, v)
|
|
31
|
-
return json.loads(urllib.request.urlopen(req).read().decode('utf-8'))
|
|
32
|
-
|
|
33
|
-
# 1. 获取实体信息
|
|
34
|
-
print("获取实体信息: %s ..." % api_key)
|
|
35
|
-
try:
|
|
36
|
-
entity_data = api_get('/rest/metadata/v2.0/xobjects/' + api_key)
|
|
37
|
-
entity = entity_data.get('data', {}).get('records', {})
|
|
38
|
-
entity_label = entity.get('label', api_key)
|
|
39
|
-
except Exception as e:
|
|
40
|
-
print("错误: 获取实体信息失败: %s" % e)
|
|
41
|
-
entity_label = api_key
|
|
42
|
-
|
|
43
|
-
# 2. 获取字段列表
|
|
44
|
-
print("获取字段列表 ...")
|
|
45
|
-
try:
|
|
46
|
-
fields_data = api_get('/rest/metadata/v2.0/xobjects/' + api_key + '/items')
|
|
47
|
-
fields = fields_data.get('data', {}).get('records', [])
|
|
48
|
-
except Exception as e:
|
|
49
|
-
print("错误: 获取字段列表失败: %s" % e)
|
|
50
|
-
sys.exit(1)
|
|
51
|
-
|
|
52
|
-
# 3. 生成 <apiKey>.md
|
|
53
|
-
os.makedirs(output_dir, exist_ok=True)
|
|
54
|
-
|
|
55
|
-
lines = ['# %s (%s)' % (entity_label, api_key), '',
|
|
56
|
-
'| 字段名称 | API Key | 字段类型 | 是否标准字段 |',
|
|
57
|
-
'|----------|---------|----------|------------|']
|
|
58
|
-
for f in fields:
|
|
59
|
-
fk = f.get('apiKey', '')
|
|
60
|
-
label = f.get('label', '')
|
|
61
|
-
ftype = f.get('type', '')
|
|
62
|
-
is_std = '是' if not fk.endswith('__c') else '否'
|
|
63
|
-
lines.append('| %s | %s | %s | %s |' % (label, fk, ftype, is_std))
|
|
64
|
-
|
|
65
|
-
output_path = os.path.join(output_dir, api_key + '.md')
|
|
66
|
-
with open(output_path, 'w', encoding='utf-8') as f:
|
|
67
|
-
f.write('\n'.join(lines))
|
|
68
|
-
|
|
69
|
-
print("完成: %s (%s, %d 个字段)" % (output_path, entity_label, len(fields)))
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
生成实体字典:下载 model.jar,解析实体列表,通过 API 获取 label,输出 entitylist.md
|
|
4
|
-
用法: python3 gen_entitylist.py <项目目录>
|
|
5
|
-
示例: python3 gen_entitylist.py NEOTrail
|
|
6
|
-
"""
|
|
7
|
-
import sys, os, json, zipfile, urllib.request
|
|
8
|
-
|
|
9
|
-
if len(sys.argv) < 2:
|
|
10
|
-
print("用法: python3 gen_entitylist.py <项目目录>")
|
|
11
|
-
sys.exit(1)
|
|
12
|
-
|
|
13
|
-
project_dir = sys.argv[1]
|
|
14
|
-
token_path = os.path.join(project_dir, '.neo-cli/token.json')
|
|
15
|
-
output_dir = os.path.join(project_dir, 'src/entity-model')
|
|
16
|
-
jar_path = os.path.join(project_dir, 'model.jar')
|
|
17
|
-
|
|
18
|
-
if not os.path.exists(token_path):
|
|
19
|
-
print("错误: 未找到 %s,请先执行 neo login" % token_path)
|
|
20
|
-
sys.exit(1)
|
|
21
|
-
|
|
22
|
-
token = json.load(open(token_path))
|
|
23
|
-
access_token = token['access_token']
|
|
24
|
-
base_url = token['instance_uri'].rstrip('/')
|
|
25
|
-
headers = {'Authorization': 'Bearer ' + access_token, 'Content-Type': 'application/json'}
|
|
26
|
-
|
|
27
|
-
def api_get(path):
|
|
28
|
-
req = urllib.request.Request(base_url + path, method='GET')
|
|
29
|
-
for k, v in headers.items():
|
|
30
|
-
req.add_header(k, v)
|
|
31
|
-
return json.loads(urllib.request.urlopen(req).read().decode('utf-8'))
|
|
32
|
-
|
|
33
|
-
# 1. 下载 model.jar
|
|
34
|
-
print("下载 model.jar ...")
|
|
35
|
-
jar_url_data = api_get('/rest/metadata/v2.0/scripts/packages/model/jar/url')
|
|
36
|
-
jar_url = jar_url_data.get('data', {}).get('records', '')
|
|
37
|
-
urllib.request.urlretrieve(jar_url, jar_path)
|
|
38
|
-
print("已下载: %s" % jar_path)
|
|
39
|
-
|
|
40
|
-
# 2. 解析 jar 获取实体列表
|
|
41
|
-
with zipfile.ZipFile(jar_path, 'r') as z:
|
|
42
|
-
classes = [n for n in z.namelist() if n.endswith('.class') and '/model/' in n]
|
|
43
|
-
|
|
44
|
-
jar_entities = {}
|
|
45
|
-
for c in classes:
|
|
46
|
-
name = c.split('/')[-1].replace('.class', '')
|
|
47
|
-
apiKey = name[0].lower() + name[1:]
|
|
48
|
-
is_standard = not (name.endswith('__c') or name.endswith('__a'))
|
|
49
|
-
jar_entities[apiKey] = {'className': name, 'apiKey': apiKey, 'isStandard': is_standard, 'label': ''}
|
|
50
|
-
|
|
51
|
-
# 3. 批量获取 label
|
|
52
|
-
print("获取实体 label ...")
|
|
53
|
-
label_map = {}
|
|
54
|
-
for custom_flag in ['true', 'false']:
|
|
55
|
-
try:
|
|
56
|
-
data = api_get('/rest/metadata/v2.0/xobjects/filter?custom=%s&active=true' % custom_flag)
|
|
57
|
-
for r in data.get('data', {}).get('records', []):
|
|
58
|
-
label_map[r.get('apiKey', '')] = r.get('label', '')
|
|
59
|
-
except Exception as e:
|
|
60
|
-
print("警告: 获取实体列表失败 (custom=%s): %s" % (custom_flag, e))
|
|
61
|
-
|
|
62
|
-
for ak, label in label_map.items():
|
|
63
|
-
if ak in jar_entities:
|
|
64
|
-
jar_entities[ak]['label'] = label
|
|
65
|
-
|
|
66
|
-
# 4. 生成 entitylist.md
|
|
67
|
-
entities = sorted(jar_entities.values(), key=lambda x: x['className'])
|
|
68
|
-
standard = [e for e in entities if e['isStandard']]
|
|
69
|
-
custom = [e for e in entities if not e['isStandard']]
|
|
70
|
-
|
|
71
|
-
os.makedirs(output_dir, exist_ok=True)
|
|
72
|
-
|
|
73
|
-
lines = ['# 实体字典', '',
|
|
74
|
-
'租户 ID: %s | 环境: %s' % (token.get('tenant_id', ''), base_url), '',
|
|
75
|
-
'共 %d 个实体(%d 个标准实体 + %d 个自定义实体)' % (len(entities), len(standard), len(custom)), '',
|
|
76
|
-
'| 实体名称 | API Key | 类型 |',
|
|
77
|
-
'|----------|---------|------|']
|
|
78
|
-
for e in entities:
|
|
79
|
-
label = e['label'] if e['label'] else e['className']
|
|
80
|
-
etype = '标准' if e['isStandard'] else '自定义'
|
|
81
|
-
lines.append('| %s | %s | %s |' % (label, e['apiKey'], etype))
|
|
82
|
-
|
|
83
|
-
output_path = os.path.join(output_dir, 'entitylist.md')
|
|
84
|
-
with open(output_path, 'w', encoding='utf-8') as f:
|
|
85
|
-
f.write('\n'.join(lines))
|
|
86
|
-
|
|
87
|
-
print("完成: %s (%d 个实体, %d 个 label)" % (output_path, len(entities), len(label_map)))
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
查询 CRM 系统数据工具。借助当前项目的登录状态执行 SQL 查询。
|
|
4
|
-
用法: python3 query_crm.py <项目目录> "<SQL查询语句>"
|
|
5
|
-
示例: python3 query_crm.py 临时验证 "SELECT id, opportunityName, amount FROM opportunity LIMIT 10"
|
|
6
|
-
"""
|
|
7
|
-
import os, json, urllib.request, urllib.error, sys
|
|
8
|
-
|
|
9
|
-
if len(sys.argv) < 3:
|
|
10
|
-
print("用法: python3 query_crm.py <项目目录> \"<SQL查询语句>\"")
|
|
11
|
-
sys.exit(1)
|
|
12
|
-
|
|
13
|
-
project_dir = sys.argv[1]
|
|
14
|
-
sql = sys.argv[2]
|
|
15
|
-
token_path = os.path.join(project_dir, '.neo-cli/token.json')
|
|
16
|
-
|
|
17
|
-
if not os.path.exists(token_path):
|
|
18
|
-
print("错误: 未找到 %s,请先执行 neo login" % token_path)
|
|
19
|
-
sys.exit(1)
|
|
20
|
-
|
|
21
|
-
token = json.load(open(token_path))
|
|
22
|
-
access_token = token['access_token']
|
|
23
|
-
base_url = token['instance_uri'].rstrip('/')
|
|
24
|
-
|
|
25
|
-
print("执行查询: %s\n" % sql)
|
|
26
|
-
|
|
27
|
-
url = base_url + '/rest/data/v2/query'
|
|
28
|
-
encoded_sql = urllib.request.quote(sql)
|
|
29
|
-
full_url = url + '?q=' + encoded_sql
|
|
30
|
-
|
|
31
|
-
req = urllib.request.Request(full_url, method='GET')
|
|
32
|
-
req.add_header('Authorization', 'Bearer ' + access_token)
|
|
33
|
-
req.add_header('Content-Type', 'application/json')
|
|
34
|
-
|
|
35
|
-
try:
|
|
36
|
-
resp = urllib.request.urlopen(req)
|
|
37
|
-
data = json.loads(resp.read().decode('utf-8'))
|
|
38
|
-
|
|
39
|
-
records = data.get('result', data.get('data', {})).get('records', [])
|
|
40
|
-
total = data.get('result', data.get('data', {})).get('totalSize', len(records) if isinstance(records, list) else 0)
|
|
41
|
-
|
|
42
|
-
if isinstance(records, list) and len(records) > 0:
|
|
43
|
-
# 提取字段名
|
|
44
|
-
fields = list(records[0].keys()) if isinstance(records[0], dict) else []
|
|
45
|
-
|
|
46
|
-
# 打印表头
|
|
47
|
-
header = ' | '.join(str(f) for f in fields)
|
|
48
|
-
print(header)
|
|
49
|
-
print('-' * len(header))
|
|
50
|
-
|
|
51
|
-
# 打印数据
|
|
52
|
-
for r in records:
|
|
53
|
-
if isinstance(r, dict):
|
|
54
|
-
row = ' | '.join(str(r.get(f, '')) for f in fields)
|
|
55
|
-
print(row)
|
|
56
|
-
|
|
57
|
-
print("\n共 %s 条记录" % total)
|
|
58
|
-
else:
|
|
59
|
-
print("无数据")
|
|
60
|
-
print("原始响应: %s" % json.dumps(data, ensure_ascii=False)[:1000])
|
|
61
|
-
|
|
62
|
-
except urllib.error.HTTPError as e:
|
|
63
|
-
print("请求失败 HTTP %d: %s" % (e.code, e.read().decode('utf-8')[:500]))
|
|
64
|
-
except Exception as e:
|
|
65
|
-
print("异常: %s" % e)
|