scaffold-engine 0.1.0
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 +117 -0
- package/engine.project.example.json +23 -0
- package/package.json +49 -0
- package/scripts/postinstall.cjs +42 -0
- package/specs/catalogs/action-templates.yaml +189 -0
- package/specs/catalogs/child-templates.yaml +54 -0
- package/specs/catalogs/field-fragments.yaml +203 -0
- package/specs/catalogs/object-catalog.yaml +35 -0
- package/specs/catalogs/object-name-suggestions.yaml +30 -0
- package/specs/catalogs/object-templates.yaml +45 -0
- package/specs/catalogs/pattern-catalog.yaml +48 -0
- package/specs/catalogs/status-templates.yaml +16 -0
- package/specs/projects/crm-pilot/customer.yaml +122 -0
- package/specs/projects/crm-pilot/lead.from-nl.yaml +76 -0
- package/specs/projects/crm-pilot/lead.yaml +82 -0
- package/specs/projects/generated-from-nl/crm-customer.yaml +158 -0
- package/specs/projects/generated-from-nl/crm-lead.yaml +76 -0
- package/specs/projects/generated-from-nl/crm-opportunity.yaml +78 -0
- package/specs/projects/generated-from-nl/crm-quote.yaml +78 -0
- package/specs/projects/generated-from-nl/custom-documentLines.yaml +125 -0
- package/specs/projects/generated-from-nl/custom-treeEntity.yaml +78 -0
- package/specs/projects/generated-from-nl/erp-material-pattern-test.yaml +79 -0
- package/specs/projects/generated-from-nl/erp-material.yaml +78 -0
- package/specs/projects/generated-from-nl/hr-orgUnit.yaml +100 -0
- package/specs/projects/pattern-examples/document-lines-demo.yaml +125 -0
- package/specs/projects/pattern-examples/tree-entity-demo.yaml +79 -0
- package/specs/rules/business-model.schema.json +262 -0
- package/specs/rules/extension-boundaries.json +26 -0
- package/specs/rules/requirement-draft.schema.json +75 -0
- package/specs/rules/spec-governance.json +29 -0
- package/specs/templates/crm/customer.template.yaml +121 -0
- package/specs/templates/crm/lead.template.yaml +82 -0
- package/tools/analyze-requirement.cjs +950 -0
- package/tools/cli.cjs +59 -0
- package/tools/create-draft.cjs +18 -0
- package/tools/engine.cjs +47 -0
- package/tools/generate-draft.cjs +33 -0
- package/tools/generate-module.cjs +1218 -0
- package/tools/init-project.cjs +194 -0
- package/tools/lib/draft-toolkit.cjs +357 -0
- package/tools/lib/model-toolkit.cjs +482 -0
- package/tools/lib/pattern-renderers.cjs +166 -0
- package/tools/lib/renderers/detail-page-renderer.cjs +327 -0
- package/tools/lib/renderers/form-page-renderer.cjs +553 -0
- package/tools/lib/renderers/list-page-renderer.cjs +371 -0
- package/tools/lib/runtime-config.cjs +154 -0
- package/tools/patch-draft.cjs +57 -0
- package/tools/prompts/business-model-prompt.md +58 -0
- package/tools/run-requirement.cjs +672 -0
- package/tools/validate-draft.cjs +32 -0
- package/tools/validate-model.cjs +140 -0
- package/tools/verify-patterns.cjs +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Scaffold Monorepo
|
|
2
|
+
|
|
3
|
+
多项目 monorepo 脚手架,包含 **api**、**admin**、**mobile**、**shared**、**shared-auth**。
|
|
4
|
+
|
|
5
|
+
## 快速启动
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# 1. 进入 scaffold 目录
|
|
9
|
+
cd scaffold
|
|
10
|
+
|
|
11
|
+
# 2. 安装依赖(首次或依赖变更后)
|
|
12
|
+
pnpm install
|
|
13
|
+
|
|
14
|
+
# 3. 初始化数据库(首次)
|
|
15
|
+
pnpm init-db
|
|
16
|
+
|
|
17
|
+
# 4. 启动 API 服务
|
|
18
|
+
pnpm dev:api
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**启动成功后访问:**
|
|
22
|
+
- API 服务: http://localhost:3001
|
|
23
|
+
- API 文档: http://localhost:3001/api
|
|
24
|
+
|
|
25
|
+
**测试登录:**
|
|
26
|
+
```bash
|
|
27
|
+
curl -X POST http://localhost:3001/api/auth/login \
|
|
28
|
+
-H "Content-Type: application/json" \
|
|
29
|
+
-d '{"username":"admin","password":"admin123"}'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 目录结构
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
scaffold/
|
|
36
|
+
├── packages/
|
|
37
|
+
│ ├── api # 后端 API(aiko-boot,当前实现用户登录)
|
|
38
|
+
│ ├── shared # 公共常量(API 基地址、存储 key 等)
|
|
39
|
+
│ ├── shared-auth # 前端鉴权公共模块(AuthProvider、useAuth、登录态持久化)
|
|
40
|
+
│ ├── admin # 管理端(Vite + React,共用 shared-auth 登录)
|
|
41
|
+
│ └── mobile # 移动端 H5(Next.js,共用 shared-auth 登录)
|
|
42
|
+
├── docs/
|
|
43
|
+
│ ├── auth-shared-design.md # Auth 公共模块设计说明
|
|
44
|
+
│ └── cli-auth-feature-boundary.md # CLI 生成时「是否需要系统功能」边界(供生成器排除登录用)
|
|
45
|
+
└── package.json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 只运行这一个项目
|
|
49
|
+
|
|
50
|
+
可以。scaffold 依赖仓库内的 `@ai-partner-x/*` 等包,因此需要在 **ai-frist-framework 仓库内** 使用,但日常只需操作 scaffold 本身:
|
|
51
|
+
|
|
52
|
+
1. 在仓库根 **执行一次** `pnpm install`(或进入 scaffold 后执行 `pnpm install`)。
|
|
53
|
+
2. 之后所有开发、构建、启动都在 **scaffold 目录** 下完成,无需运行或构建仓库里其他项目(如 user-crud、其他 examples)。
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
cd scaffold
|
|
57
|
+
pnpm init-db # 首次
|
|
58
|
+
pnpm dev # 并行启动 api + admin + mobile
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**测试登录**:mobile / admin 的登录页会请求 `http://localhost:3001/api/auth/login`,需先保证 API 已启动(`pnpm dev:api` 或 `pnpm dev` 已包含)。两端共用 **@scaffold/shared-auth** 的登录态与持久化(localStorage),详见 [Auth 公共模块设计](docs/auth-shared-design.md)。
|
|
62
|
+
|
|
63
|
+
## 前置
|
|
64
|
+
|
|
65
|
+
- Node 18+
|
|
66
|
+
- pnpm
|
|
67
|
+
|
|
68
|
+
**安装依赖**(在仓库根或 scaffold 目录下执行均可,会使用仓库根 workspace):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
cd /path/to/ai-frist-framework
|
|
72
|
+
pnpm install
|
|
73
|
+
# 或在 scaffold 目录下
|
|
74
|
+
cd scaffold && pnpm install
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`init-db` 使用纯 JS 的 sql.js,无需编译。**运行 API 服务**(`pnpm dev:api`)时依赖 better-sqlite3 原生模块;若报错找不到 bindings,在**仓库根**执行(会进入 better-sqlite3 目录执行 `node-gyp rebuild`):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pnpm run rebuild:sqlite
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 开发
|
|
84
|
+
|
|
85
|
+
依赖在仓库根安装完成后,在 **scaffold 目录** 下执行:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
cd scaffold
|
|
89
|
+
pnpm init-db # 首次运行:初始化 SQLite 数据库
|
|
90
|
+
pnpm dev # 并行启动 api + admin + mobile
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
或分别启动:
|
|
94
|
+
|
|
95
|
+
- `pnpm dev:api` — API 默认 http://localhost:3001
|
|
96
|
+
- `pnpm dev:admin` — Admin 管理端(留空)
|
|
97
|
+
- `pnpm dev:mobile` — Mobile 默认 http://localhost:3002
|
|
98
|
+
|
|
99
|
+
**API 热更新**(与 user-crud 一致):`pnpm dev:api` 会同时跑 **codegen watch** 与 **HTTP 服务**。修改 `entity/`、`dto/`、`controller/` 后会自动重新生成 `dist/client`,前端可即时引用新类型与接口;改 `src/server.ts` 会触发服务重启。
|
|
100
|
+
|
|
101
|
+
## 构建
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pnpm build
|
|
105
|
+
# 或
|
|
106
|
+
pnpm build:api
|
|
107
|
+
pnpm build:admin
|
|
108
|
+
pnpm build:mobile
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## API 说明
|
|
112
|
+
|
|
113
|
+
- **POST /api/auth/login**
|
|
114
|
+
请求体:`{ "username": "admin", "password": "admin123" }`
|
|
115
|
+
成功返回:`{ "success": true, "data": { "id", "username", "email" } }`
|
|
116
|
+
|
|
117
|
+
默认测试账号(见 `packages/api` 的 init-db):`admin` / `admin123`。
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"projectRoot": "/absolute/path/to/your-empty-project",
|
|
3
|
+
"catalogs": {
|
|
4
|
+
"rootDir": "/Users/taishanglaojun/ai-frist-framework_owner/scaffold/specs/catalogs"
|
|
5
|
+
},
|
|
6
|
+
"rules": {
|
|
7
|
+
"rootDir": "/Users/taishanglaojun/ai-frist-framework_owner/scaffold/specs/rules"
|
|
8
|
+
},
|
|
9
|
+
"drafts": {
|
|
10
|
+
"rootDir": "/absolute/path/to/your-empty-project/.codex/scaffold-drafts"
|
|
11
|
+
},
|
|
12
|
+
"generatedSpecs": {
|
|
13
|
+
"rootDir": "/absolute/path/to/your-empty-project/.codex/generated-specs"
|
|
14
|
+
},
|
|
15
|
+
"targets": {
|
|
16
|
+
"adapter": "external-project",
|
|
17
|
+
"apiSrcDir": "/absolute/path/to/your-empty-project/src/generated/api",
|
|
18
|
+
"adminSrcDir": "/absolute/path/to/your-empty-project/src/generated/admin",
|
|
19
|
+
"toolCwd": "/Users/taishanglaojun/ai-frist-framework_owner/scaffold",
|
|
20
|
+
"pnpmCwd": "/Users/taishanglaojun/ai-frist-framework_owner",
|
|
21
|
+
"apiPackageDir": "/Users/taishanglaojun/ai-frist-framework_owner/scaffold/packages/api"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "scaffold-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Requirement-driven scaffold engine for analyze, draft, validate, and generate workflows.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "./tools/engine.cjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"scaffold-engine": "./tools/cli.cjs"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./tools/engine.cjs",
|
|
12
|
+
"./engine": "./tools/engine.cjs",
|
|
13
|
+
"./cli": "./tools/cli.cjs"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"tools",
|
|
17
|
+
"specs",
|
|
18
|
+
"scripts/postinstall.cjs",
|
|
19
|
+
"engine.project.example.json"
|
|
20
|
+
],
|
|
21
|
+
"keywords": [
|
|
22
|
+
"scaffold",
|
|
23
|
+
"generator",
|
|
24
|
+
"cursor",
|
|
25
|
+
"codex",
|
|
26
|
+
"requirements",
|
|
27
|
+
"cli"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"init": "node ./tools/cli.cjs init",
|
|
31
|
+
"draft:create": "node ./tools/create-draft.cjs",
|
|
32
|
+
"draft:patch": "node ./tools/patch-draft.cjs",
|
|
33
|
+
"draft:validate": "node ./tools/validate-draft.cjs",
|
|
34
|
+
"draft:generate": "node ./tools/generate-draft.cjs",
|
|
35
|
+
"requirement:analyze": "node ./tools/analyze-requirement.cjs",
|
|
36
|
+
"requirement:run": "node ./tools/run-requirement.cjs",
|
|
37
|
+
"model:validate": "node ./tools/validate-model.cjs",
|
|
38
|
+
"model:generate": "node ./tools/generate-module.cjs",
|
|
39
|
+
"verify:patterns": "node ./tools/verify-patterns.cjs"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"ajv": "^8.17.1",
|
|
43
|
+
"yaml": "^2.8.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"npm-packlist": "^9.0.0",
|
|
47
|
+
"typescript": "^5.3.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require('node:child_process');
|
|
4
|
+
|
|
5
|
+
function shouldSkip() {
|
|
6
|
+
if (process.env.SKIP_SQLITE_REBUILD === 'true') {
|
|
7
|
+
console.log('[postinstall] SKIP_SQLITE_REBUILD=true, skipping better-sqlite3 rebuild.');
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (process.env.CI === 'true') {
|
|
11
|
+
console.log('[postinstall] CI environment detected, skipping better-sqlite3 rebuild.');
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function main() {
|
|
18
|
+
if (shouldSkip()) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const pkgManager = process.env.npm_execpath || 'pnpm';
|
|
23
|
+
console.log('[postinstall] Rebuilding better-sqlite3 via', pkgManager);
|
|
24
|
+
|
|
25
|
+
const result = spawnSync(
|
|
26
|
+
pkgManager,
|
|
27
|
+
['rebuild', 'better-sqlite3'],
|
|
28
|
+
{ stdio: 'inherit', shell: false }
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
if (result.error) {
|
|
32
|
+
console.warn('[postinstall] better-sqlite3 rebuild errored but is non-fatal:', result.error);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (result.status !== 0) {
|
|
37
|
+
console.warn('[postinstall] better-sqlite3 rebuild exited with code', result.status, '(treated as non-fatal).');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
main();
|
|
42
|
+
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
templates:
|
|
2
|
+
crudBasic:
|
|
3
|
+
actions: [create, update, list, detail]
|
|
4
|
+
responseContract:
|
|
5
|
+
envelope: standard
|
|
6
|
+
listSchema: pagedList
|
|
7
|
+
detailSchema: object
|
|
8
|
+
mutationSchema: object
|
|
9
|
+
permissionProfile:
|
|
10
|
+
mode: inherit
|
|
11
|
+
resourceScope: object
|
|
12
|
+
actionPolicies:
|
|
13
|
+
- action: create
|
|
14
|
+
permission: create
|
|
15
|
+
- action: update
|
|
16
|
+
permission: update
|
|
17
|
+
- action: list
|
|
18
|
+
permission: list
|
|
19
|
+
- action: detail
|
|
20
|
+
permission: detail
|
|
21
|
+
validationRules:
|
|
22
|
+
- name: uniqueCode
|
|
23
|
+
scope: service
|
|
24
|
+
rule: unique
|
|
25
|
+
message: 编码必须唯一
|
|
26
|
+
errorCodes:
|
|
27
|
+
- code: VALIDATION_FAILED
|
|
28
|
+
message: 输入校验失败
|
|
29
|
+
- code: RECORD_NOT_FOUND
|
|
30
|
+
message: 记录不存在
|
|
31
|
+
- code: DUPLICATE_KEY
|
|
32
|
+
message: 唯一键冲突
|
|
33
|
+
|
|
34
|
+
crudWithToggle:
|
|
35
|
+
actions: [create, update, list, detail, activate, deactivate]
|
|
36
|
+
responseContract:
|
|
37
|
+
envelope: standard
|
|
38
|
+
listSchema: pagedList
|
|
39
|
+
detailSchema: object
|
|
40
|
+
mutationSchema: object
|
|
41
|
+
permissionProfile:
|
|
42
|
+
mode: inherit
|
|
43
|
+
resourceScope: object
|
|
44
|
+
actionPolicies:
|
|
45
|
+
- action: create
|
|
46
|
+
permission: create
|
|
47
|
+
- action: update
|
|
48
|
+
permission: update
|
|
49
|
+
- action: list
|
|
50
|
+
permission: list
|
|
51
|
+
- action: detail
|
|
52
|
+
permission: detail
|
|
53
|
+
- action: activate
|
|
54
|
+
permission: activate
|
|
55
|
+
- action: deactivate
|
|
56
|
+
permission: deactivate
|
|
57
|
+
statusFlow:
|
|
58
|
+
enabled: true
|
|
59
|
+
states: [draft, active, inactive]
|
|
60
|
+
transitions:
|
|
61
|
+
- action: activate
|
|
62
|
+
from: [draft, inactive]
|
|
63
|
+
to: active
|
|
64
|
+
- action: deactivate
|
|
65
|
+
from: [active]
|
|
66
|
+
to: inactive
|
|
67
|
+
validationRules:
|
|
68
|
+
- name: statusTransition
|
|
69
|
+
scope: workflow
|
|
70
|
+
rule: statusTransition
|
|
71
|
+
fields: [status]
|
|
72
|
+
message: 状态流转必须符合既定规则
|
|
73
|
+
errorCodes:
|
|
74
|
+
- code: VALIDATION_FAILED
|
|
75
|
+
message: 输入校验失败
|
|
76
|
+
- code: RECORD_NOT_FOUND
|
|
77
|
+
message: 记录不存在
|
|
78
|
+
- code: DUPLICATE_KEY
|
|
79
|
+
message: 唯一键冲突
|
|
80
|
+
- code: INVALID_STATUS_TRANSITION
|
|
81
|
+
message: 当前状态不允许执行该动作
|
|
82
|
+
|
|
83
|
+
crudWithStatusFlow:
|
|
84
|
+
actions: [create, update, list, detail, submit, approve, reject]
|
|
85
|
+
responseContract:
|
|
86
|
+
envelope: standard
|
|
87
|
+
listSchema: pagedList
|
|
88
|
+
detailSchema: object
|
|
89
|
+
mutationSchema: object
|
|
90
|
+
permissionProfile:
|
|
91
|
+
mode: inherit
|
|
92
|
+
resourceScope: object
|
|
93
|
+
actionPolicies:
|
|
94
|
+
- action: create
|
|
95
|
+
permission: create
|
|
96
|
+
- action: update
|
|
97
|
+
permission: update
|
|
98
|
+
- action: list
|
|
99
|
+
permission: list
|
|
100
|
+
- action: detail
|
|
101
|
+
permission: detail
|
|
102
|
+
- action: submit
|
|
103
|
+
permission: submit
|
|
104
|
+
- action: approve
|
|
105
|
+
permission: approve
|
|
106
|
+
- action: reject
|
|
107
|
+
permission: reject
|
|
108
|
+
statusFlow:
|
|
109
|
+
enabled: true
|
|
110
|
+
states: [draft, submitted, approved, rejected]
|
|
111
|
+
transitions:
|
|
112
|
+
- action: submit
|
|
113
|
+
from: [draft, rejected]
|
|
114
|
+
to: submitted
|
|
115
|
+
- action: approve
|
|
116
|
+
from: [submitted]
|
|
117
|
+
to: approved
|
|
118
|
+
- action: reject
|
|
119
|
+
from: [submitted]
|
|
120
|
+
to: rejected
|
|
121
|
+
validationRules:
|
|
122
|
+
- name: statusTransition
|
|
123
|
+
scope: workflow
|
|
124
|
+
rule: statusTransition
|
|
125
|
+
fields: [status]
|
|
126
|
+
message: 状态流转必须符合既定规则
|
|
127
|
+
errorCodes:
|
|
128
|
+
- code: VALIDATION_FAILED
|
|
129
|
+
message: 输入校验失败
|
|
130
|
+
- code: RECORD_NOT_FOUND
|
|
131
|
+
message: 记录不存在
|
|
132
|
+
- code: DUPLICATE_KEY
|
|
133
|
+
message: 唯一键冲突
|
|
134
|
+
- code: INVALID_STATUS_TRANSITION
|
|
135
|
+
message: 当前状态不允许执行该动作
|
|
136
|
+
|
|
137
|
+
crudWithSubmitApprove:
|
|
138
|
+
actions: [create, update, list, detail, submit, approve, reject]
|
|
139
|
+
responseContract:
|
|
140
|
+
envelope: standard
|
|
141
|
+
listSchema: pagedList
|
|
142
|
+
detailSchema: object
|
|
143
|
+
mutationSchema: object
|
|
144
|
+
permissionProfile:
|
|
145
|
+
mode: inherit
|
|
146
|
+
resourceScope: object
|
|
147
|
+
actionPolicies:
|
|
148
|
+
- action: create
|
|
149
|
+
permission: create
|
|
150
|
+
- action: update
|
|
151
|
+
permission: update
|
|
152
|
+
- action: list
|
|
153
|
+
permission: list
|
|
154
|
+
- action: detail
|
|
155
|
+
permission: detail
|
|
156
|
+
- action: submit
|
|
157
|
+
permission: submit
|
|
158
|
+
- action: approve
|
|
159
|
+
permission: approve
|
|
160
|
+
- action: reject
|
|
161
|
+
permission: reject
|
|
162
|
+
statusFlow:
|
|
163
|
+
enabled: true
|
|
164
|
+
states: [draft, submitted, approved, rejected]
|
|
165
|
+
transitions:
|
|
166
|
+
- action: submit
|
|
167
|
+
from: [draft, rejected]
|
|
168
|
+
to: submitted
|
|
169
|
+
- action: approve
|
|
170
|
+
from: [submitted]
|
|
171
|
+
to: approved
|
|
172
|
+
- action: reject
|
|
173
|
+
from: [submitted]
|
|
174
|
+
to: rejected
|
|
175
|
+
validationRules:
|
|
176
|
+
- name: statusTransition
|
|
177
|
+
scope: workflow
|
|
178
|
+
rule: statusTransition
|
|
179
|
+
fields: [status]
|
|
180
|
+
message: 状态流转必须符合既定规则
|
|
181
|
+
errorCodes:
|
|
182
|
+
- code: VALIDATION_FAILED
|
|
183
|
+
message: 输入校验失败
|
|
184
|
+
- code: RECORD_NOT_FOUND
|
|
185
|
+
message: 记录不存在
|
|
186
|
+
- code: DUPLICATE_KEY
|
|
187
|
+
message: 唯一键冲突
|
|
188
|
+
- code: INVALID_STATUS_TRANSITION
|
|
189
|
+
message: 当前状态不允许执行该动作
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
templates:
|
|
2
|
+
customerContacts:
|
|
3
|
+
name: contacts
|
|
4
|
+
label: 联系人
|
|
5
|
+
tableSuffix: contact
|
|
6
|
+
foreignKey: customerId
|
|
7
|
+
formGroupTitle: 联系人
|
|
8
|
+
detailSection: contacts
|
|
9
|
+
fields:
|
|
10
|
+
- name: contactName
|
|
11
|
+
label: 联系人姓名
|
|
12
|
+
type: string
|
|
13
|
+
required: true
|
|
14
|
+
- name: mobile
|
|
15
|
+
label: 手机号
|
|
16
|
+
type: string
|
|
17
|
+
- name: email
|
|
18
|
+
label: 邮箱
|
|
19
|
+
type: string
|
|
20
|
+
- name: isPrimary
|
|
21
|
+
label: 是否主联系人
|
|
22
|
+
type: boolean
|
|
23
|
+
default: false
|
|
24
|
+
|
|
25
|
+
documentLineItems:
|
|
26
|
+
name: lines
|
|
27
|
+
label: 明细行
|
|
28
|
+
tableSuffix: line
|
|
29
|
+
foreignKey: documentId
|
|
30
|
+
formGroupTitle: 明细行
|
|
31
|
+
detailSection: lines
|
|
32
|
+
fields:
|
|
33
|
+
- name: lineNo
|
|
34
|
+
label: 行号
|
|
35
|
+
type: string
|
|
36
|
+
required: true
|
|
37
|
+
- name: itemCode
|
|
38
|
+
label: 项目编码
|
|
39
|
+
type: string
|
|
40
|
+
required: true
|
|
41
|
+
- name: itemName
|
|
42
|
+
label: 项目名称
|
|
43
|
+
type: string
|
|
44
|
+
required: true
|
|
45
|
+
- name: quantity
|
|
46
|
+
label: 数量
|
|
47
|
+
type: number
|
|
48
|
+
required: true
|
|
49
|
+
- name: unitPrice
|
|
50
|
+
label: 单价
|
|
51
|
+
type: number
|
|
52
|
+
- name: amount
|
|
53
|
+
label: 金额
|
|
54
|
+
type: number
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
fragments:
|
|
2
|
+
leadCode:
|
|
3
|
+
name: leadCode
|
|
4
|
+
label: 线索编号
|
|
5
|
+
type: string
|
|
6
|
+
required: true
|
|
7
|
+
unique: true
|
|
8
|
+
|
|
9
|
+
leadName:
|
|
10
|
+
name: leadName
|
|
11
|
+
label: 线索名称
|
|
12
|
+
type: string
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
customerCode:
|
|
16
|
+
name: customerCode
|
|
17
|
+
label: 客户编码
|
|
18
|
+
type: string
|
|
19
|
+
required: true
|
|
20
|
+
unique: true
|
|
21
|
+
|
|
22
|
+
customerName:
|
|
23
|
+
name: customerName
|
|
24
|
+
label: 客户名称
|
|
25
|
+
type: string
|
|
26
|
+
required: true
|
|
27
|
+
|
|
28
|
+
opportunityCode:
|
|
29
|
+
name: opportunityCode
|
|
30
|
+
label: 商机编号
|
|
31
|
+
type: string
|
|
32
|
+
required: true
|
|
33
|
+
unique: true
|
|
34
|
+
|
|
35
|
+
opportunityName:
|
|
36
|
+
name: opportunityName
|
|
37
|
+
label: 商机名称
|
|
38
|
+
type: string
|
|
39
|
+
required: true
|
|
40
|
+
|
|
41
|
+
quoteCode:
|
|
42
|
+
name: quoteCode
|
|
43
|
+
label: 报价编号
|
|
44
|
+
type: string
|
|
45
|
+
required: true
|
|
46
|
+
unique: true
|
|
47
|
+
|
|
48
|
+
quoteName:
|
|
49
|
+
name: quoteName
|
|
50
|
+
label: 报价名称
|
|
51
|
+
type: string
|
|
52
|
+
required: true
|
|
53
|
+
|
|
54
|
+
materialCode:
|
|
55
|
+
name: materialCode
|
|
56
|
+
label: 物料编码
|
|
57
|
+
type: string
|
|
58
|
+
required: true
|
|
59
|
+
unique: true
|
|
60
|
+
|
|
61
|
+
materialName:
|
|
62
|
+
name: materialName
|
|
63
|
+
label: 物料名称
|
|
64
|
+
type: string
|
|
65
|
+
required: true
|
|
66
|
+
|
|
67
|
+
customerNameOptional:
|
|
68
|
+
name: customerName
|
|
69
|
+
label: 客户名称
|
|
70
|
+
type: string
|
|
71
|
+
|
|
72
|
+
ownerName:
|
|
73
|
+
name: ownerName
|
|
74
|
+
label: 负责人
|
|
75
|
+
type: string
|
|
76
|
+
|
|
77
|
+
phone:
|
|
78
|
+
name: phone
|
|
79
|
+
label: 联系电话
|
|
80
|
+
type: string
|
|
81
|
+
|
|
82
|
+
sourceLead:
|
|
83
|
+
name: source
|
|
84
|
+
label: 线索来源
|
|
85
|
+
type: enum
|
|
86
|
+
options: [website, referral, campaign, manual]
|
|
87
|
+
default: manual
|
|
88
|
+
|
|
89
|
+
sourceCustomer:
|
|
90
|
+
name: source
|
|
91
|
+
label: 客户来源
|
|
92
|
+
type: enum
|
|
93
|
+
options: [manual, import, campaign]
|
|
94
|
+
default: manual
|
|
95
|
+
|
|
96
|
+
levelCustomer:
|
|
97
|
+
name: level
|
|
98
|
+
label: 客户等级
|
|
99
|
+
type: enum
|
|
100
|
+
options: [A, B, C]
|
|
101
|
+
default: B
|
|
102
|
+
|
|
103
|
+
stageOpportunity:
|
|
104
|
+
name: stage
|
|
105
|
+
label: 商机阶段
|
|
106
|
+
type: enum
|
|
107
|
+
options: [new, qualifying, proposal, won, lost]
|
|
108
|
+
default: new
|
|
109
|
+
|
|
110
|
+
stageQuote:
|
|
111
|
+
name: stage
|
|
112
|
+
label: 报价阶段
|
|
113
|
+
type: enum
|
|
114
|
+
options: [draft, reviewing, sent, accepted, rejected]
|
|
115
|
+
default: draft
|
|
116
|
+
|
|
117
|
+
statusCrmFollow:
|
|
118
|
+
name: status
|
|
119
|
+
label: 状态
|
|
120
|
+
type: enum
|
|
121
|
+
statusTemplateRef: crmFollow
|
|
122
|
+
|
|
123
|
+
statusCrmBase:
|
|
124
|
+
name: status
|
|
125
|
+
label: 状态
|
|
126
|
+
type: enum
|
|
127
|
+
statusTemplateRef: crmBase
|
|
128
|
+
|
|
129
|
+
statusCrmClosed:
|
|
130
|
+
name: status
|
|
131
|
+
label: 状态
|
|
132
|
+
type: enum
|
|
133
|
+
statusTemplateRef: crmClosed
|
|
134
|
+
|
|
135
|
+
materialType:
|
|
136
|
+
name: materialType
|
|
137
|
+
label: 物料类型
|
|
138
|
+
type: enum
|
|
139
|
+
options: [ROH, HALB, FERT, HIBE, NLAG]
|
|
140
|
+
default: FERT
|
|
141
|
+
|
|
142
|
+
materialGroup:
|
|
143
|
+
name: materialGroup
|
|
144
|
+
label: 物料组
|
|
145
|
+
type: string
|
|
146
|
+
|
|
147
|
+
baseUnit:
|
|
148
|
+
name: baseUnit
|
|
149
|
+
label: 基本计量单位
|
|
150
|
+
type: string
|
|
151
|
+
|
|
152
|
+
documentNo:
|
|
153
|
+
name: documentNo
|
|
154
|
+
label: 单据编号
|
|
155
|
+
type: string
|
|
156
|
+
required: true
|
|
157
|
+
unique: true
|
|
158
|
+
|
|
159
|
+
documentTitle:
|
|
160
|
+
name: documentTitle
|
|
161
|
+
label: 单据标题
|
|
162
|
+
type: string
|
|
163
|
+
required: true
|
|
164
|
+
|
|
165
|
+
bizDate:
|
|
166
|
+
name: bizDate
|
|
167
|
+
label: 业务日期
|
|
168
|
+
type: date
|
|
169
|
+
required: true
|
|
170
|
+
|
|
171
|
+
statusErpBase:
|
|
172
|
+
name: status
|
|
173
|
+
label: 状态
|
|
174
|
+
type: enum
|
|
175
|
+
statusTemplateRef: erpBase
|
|
176
|
+
|
|
177
|
+
categoryCode:
|
|
178
|
+
name: categoryCode
|
|
179
|
+
label: 节点编码
|
|
180
|
+
type: string
|
|
181
|
+
required: true
|
|
182
|
+
unique: true
|
|
183
|
+
|
|
184
|
+
categoryName:
|
|
185
|
+
name: categoryName
|
|
186
|
+
label: 节点名称
|
|
187
|
+
type: string
|
|
188
|
+
required: true
|
|
189
|
+
|
|
190
|
+
parentId:
|
|
191
|
+
name: parentId
|
|
192
|
+
label: 父节点ID
|
|
193
|
+
type: integer
|
|
194
|
+
|
|
195
|
+
parentName:
|
|
196
|
+
name: parentName
|
|
197
|
+
label: 父节点名称
|
|
198
|
+
type: string
|
|
199
|
+
|
|
200
|
+
sortOrder:
|
|
201
|
+
name: sortOrder
|
|
202
|
+
label: 排序号
|
|
203
|
+
type: integer
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
objects:
|
|
2
|
+
- keywords: [线索管理, 线索]
|
|
3
|
+
domain: crm
|
|
4
|
+
object: lead
|
|
5
|
+
label: 线索
|
|
6
|
+
objectTemplateRef: crmRootCrud
|
|
7
|
+
fieldRefs: [leadCode, leadName, sourceLead, phone, statusCrmFollow]
|
|
8
|
+
|
|
9
|
+
- keywords: [客户管理, 客户]
|
|
10
|
+
domain: crm
|
|
11
|
+
object: customer
|
|
12
|
+
label: 客户
|
|
13
|
+
objectTemplateRef: crmCustomerObject
|
|
14
|
+
fieldRefs: [customerCode, customerName, levelCustomer, statusCrmBase]
|
|
15
|
+
|
|
16
|
+
- keywords: [商机管理, 商机]
|
|
17
|
+
domain: crm
|
|
18
|
+
object: opportunity
|
|
19
|
+
label: 商机
|
|
20
|
+
objectTemplateRef: crmRootCrud
|
|
21
|
+
fieldRefs: [opportunityCode, opportunityName, customerNameOptional, stageOpportunity, statusCrmClosed]
|
|
22
|
+
|
|
23
|
+
- keywords: [报价管理, 报价单, 报价]
|
|
24
|
+
domain: crm
|
|
25
|
+
object: quote
|
|
26
|
+
label: 报价
|
|
27
|
+
objectTemplateRef: crmRootCrud
|
|
28
|
+
fieldRefs: [quoteCode, quoteName, customerNameOptional, stageQuote, statusCrmClosed]
|
|
29
|
+
|
|
30
|
+
- keywords: [erp物料台账, ERP物料台账, 物料台账, 物料主数据, 物料]
|
|
31
|
+
domain: erp
|
|
32
|
+
object: material
|
|
33
|
+
label: 物料
|
|
34
|
+
objectTemplateRef: erpMasterData
|
|
35
|
+
fieldRefs: [materialCode, materialName, materialType, materialGroup, baseUnit, statusErpBase]
|