@lovrabet/cli 1.3.4 → 1.4.1-beta.2
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/lib/ai-setup/config.js +1 -1
- package/lib/api/api-doc-ui.js +1 -1
- package/lib/api/api-doc.js +1 -1
- package/lib/api/api-pull-ui.js +1 -1
- package/lib/api/fetch-model-list.js +1 -1
- package/lib/api/generate-api-file.js +1 -1
- package/lib/api/main.js +1 -1
- package/lib/api/pull-silent.js +1 -1
- package/lib/app-menu/app-menu-sync-ui.js +1 -1
- package/lib/app-menu/create-menu.js +1 -1
- package/lib/app-menu/get-local-pages.js +1 -1
- package/lib/app-menu/get-online-menu-list.js +1 -1
- package/lib/app-menu/update-menu.js +1 -0
- package/lib/app-menu/use-get-online-menu-list.js +1 -1
- package/lib/app-menu/utils.js +1 -1
- package/lib/app-menu/valid-url.js +1 -1
- package/lib/app-menu-update-cdn/current-content.js +1 -1
- package/lib/app-menu-update-cdn/input-cdn-asset.js +1 -1
- package/lib/app-menu-update-cdn/main.js +1 -1
- package/lib/app-menu-update-cdn/update-menu.js +1 -0
- package/lib/auth/auth-server-ui.js +1 -1
- package/lib/auth/auth-server.js +1 -1
- package/lib/auth/constant.js +1 -1
- package/lib/auth/get-cookie.js +1 -1
- package/lib/auth/is-session-valid.js +1 -1
- package/lib/auth/logout.js +1 -1
- package/lib/cli-flags.js +1 -1
- package/lib/cli.js +1 -1
- package/lib/cmd/build-watch.js +1 -1
- package/lib/cmd/build.js +1 -1
- package/lib/cmd/logs.js +1 -1
- package/lib/cmd/preview.js +1 -1
- package/lib/cmd/start-execa.js +1 -1
- package/lib/cmd/start.js +1 -1
- package/lib/config/config-help.js +1 -1
- package/lib/config/main.js +1 -1
- package/lib/constant/domain.js +1 -1
- package/lib/constant/env.js +1 -1
- package/lib/create-app/enhanced-guided-create.js +1 -1
- package/lib/create-app/format-elapsed.js +1 -1
- package/lib/create-app/main.js +1 -1
- package/lib/create-app/non-interactive.js +1 -1
- package/lib/create-app/task-finished.js +1 -1
- package/lib/create-app/task-loading.js +1 -1
- package/lib/create-app/task-running.js +1 -1
- package/lib/create-app/task-time.js +1 -1
- package/lib/create-app/use-copy-project-template.js +1 -1
- package/lib/create-app/use-format-code.js +1 -1
- package/lib/create-app/use-install-dependencies.js +1 -1
- package/lib/help.js +1 -1
- package/lib/i18n/I18nProvider.js +1 -1
- package/lib/i18n/hooks.js +1 -1
- package/lib/i18n/index.js +1 -1
- package/lib/i18n/locales/en-US.js +1 -1
- package/lib/i18n/locales/zh-CN.js +1 -1
- package/lib/init/main.js +1 -1
- package/lib/mcp/McpInstallUI.js +1 -1
- package/lib/mcp/claude.js +1 -1
- package/lib/mcp/cursor.js +1 -1
- package/lib/mcp/main.js +1 -1
- package/lib/mcp/mcp-install-non-interactive.js +1 -1
- package/lib/mcp/mcp-installer.js +1 -1
- package/lib/skills/main.js +1 -1
- package/lib/skills/npx-skills-add.js +1 -0
- package/lib/ui/IDESelector.js +1 -1
- package/lib/ui/useIDESelection.js +1 -1
- package/lib/utils/ai_config.js +1 -1
- package/lib/utils/cdn-config.js +1 -1
- package/lib/utils/check-sdk-version.js +1 -1
- package/lib/utils/cli-version-check.js +1 -1
- package/lib/utils/config.js +1 -1
- package/lib/utils/copy-directory.js +1 -1
- package/lib/utils/file-utils.js +1 -1
- package/lib/utils/guides-cdn.js +1 -1
- package/lib/utils/http-client.js +1 -1
- package/lib/utils/logger.js +1 -1
- package/lib/utils/rules-cdn.js +1 -1
- package/lib/utils/sleep.js +1 -1
- package/lib/utils/template-replacer.js +1 -1
- package/package.json +5 -5
- package/sidecar/flags.json +10 -0
- package/templates/rules/lovrabet_rules.mdc.tpl +891 -0
- package/templates/skill/SKILL.md.tpl +120 -0
- package/lib/ai-setup/AISetupUI.js +0 -1
- package/lib/app-menu-update-cdn/update-menu-cdn-url.js +0 -1
- package/lib/skills/SkillInstallUI.js +0 -1
- package/lib/skills/skill-install-non-interactive.js +0 -1
- package/lib/skills/skill-installer.js +0 -1
|
@@ -0,0 +1,891 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: ["*.ts", "*.tsx"]
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
# Lovrabet Development Rules
|
|
6
|
+
|
|
7
|
+
You are a Lovrabet platform development assistant. Help developers use Lovrabet SDK and MCP correctly.
|
|
8
|
+
|
|
9
|
+
## Core Rules
|
|
10
|
+
|
|
11
|
+
### 1. TypeScript SDK Usage (CRITICAL)
|
|
12
|
+
|
|
13
|
+
The Lovrabet SDK has three main APIs. Use them correctly:
|
|
14
|
+
|
|
15
|
+
#### Filter API - Advanced Data Queries
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// ✅ Correct structure
|
|
19
|
+
const result = await client.models.<modelName>.filter({
|
|
20
|
+
where: {
|
|
21
|
+
status: { $eq: 'active' }, // MUST use operators
|
|
22
|
+
age: { $gte: 18, $lte: 65 },
|
|
23
|
+
},
|
|
24
|
+
select: ['id', 'name'], // NOT 'fields'
|
|
25
|
+
orderBy: [{ createTime: 'desc' }], // NOT 'sort'
|
|
26
|
+
currentPage: 1, // NOT 'page'
|
|
27
|
+
pageSize: 20, // NOT 'limit'
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Returns
|
|
31
|
+
console.log(result.tableData); // Data list
|
|
32
|
+
console.log(result.total); // Total count
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
#### SQL API - Custom Queries
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// Object parameter format
|
|
39
|
+
const data = await client.sql.execute({
|
|
40
|
+
sqlCode: 'fc8e7777-06e3847d',
|
|
41
|
+
params: { userId: '123' }
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Application layer checks business status
|
|
45
|
+
if (data.execSuccess && data.execResult) {
|
|
46
|
+
data.execResult.forEach(row => console.log(row));
|
|
47
|
+
} else {
|
|
48
|
+
console.error('SQL execution failed');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// With type safety
|
|
52
|
+
interface PageStat {
|
|
53
|
+
creation_date: string;
|
|
54
|
+
page_count: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const result = await client.sql.execute<PageStat>({
|
|
58
|
+
sqlCode: 'fc8e7777-06e3847d'
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (result.execSuccess && result.execResult) {
|
|
62
|
+
result.execResult.forEach(stat => {
|
|
63
|
+
console.log(stat.creation_date); // TypeScript autocomplete
|
|
64
|
+
console.log(stat.page_count);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**返回值结构**:
|
|
70
|
+
- SDK 返回:`{ execSuccess: boolean, execResult?: T[] }`(业务数据层)
|
|
71
|
+
- HTTP 错误:抛出 `LovrabetError` 异常
|
|
72
|
+
- 应用层职责:检查 `execSuccess` 状态,处理业务结果
|
|
73
|
+
|
|
74
|
+
#### BFF API - Backend Functions
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const dashboard = await client.bff.execute({
|
|
78
|
+
scriptName: 'getUserDashboard',
|
|
79
|
+
params: { userId: '123' }
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// With type safety
|
|
83
|
+
interface DashboardData {
|
|
84
|
+
userCount: number;
|
|
85
|
+
orderCount: number;
|
|
86
|
+
totalAmount: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const dashboard = await client.bff.execute<DashboardData>({
|
|
90
|
+
scriptName: 'getUserDashboard',
|
|
91
|
+
params: { userId: '123' }
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
console.log(dashboard.userCount); // TypeScript autocomplete
|
|
95
|
+
|
|
96
|
+
// Complete error handling
|
|
97
|
+
try {
|
|
98
|
+
const result = await client.bff.execute({
|
|
99
|
+
scriptName: 'someEndpoint',
|
|
100
|
+
params: { /* ... */ }
|
|
101
|
+
});
|
|
102
|
+
// Use result directly (it's already the business data)
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (error instanceof LovrabetError) {
|
|
105
|
+
console.error('BFF call failed:', error.message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**返回值结构**:
|
|
111
|
+
- SDK 返回:业务数据对象(直接是业务数据层,不是包装器)
|
|
112
|
+
- HTTP 错误:抛出 `LovrabetError` 异常
|
|
113
|
+
- 应用层职责:直接使用返回的业务数据
|
|
114
|
+
|
|
115
|
+
**Common Errors to Avoid:**
|
|
116
|
+
- `where: { status: 'active' }` → Use `where: { status: { $eq: 'active' } }`
|
|
117
|
+
- `fields: ['id']` → Use `select: ['id']`
|
|
118
|
+
- `orderBy: 'createTime desc'` → Use `orderBy: [{ createTime: 'desc' }]`
|
|
119
|
+
- `where: { name: 'LIKE %keyword%' }` → Use `where: { name: { $contain: 'keyword' } }`
|
|
120
|
+
- SQL: Wrong format → Use `client.sql.execute({ sqlCode, params })`
|
|
121
|
+
- BFF: Wrong format → Use `client.bff.execute({ scriptName, params })`
|
|
122
|
+
- Filter: `getList()` → Use `filter()` (getList is deprecated)
|
|
123
|
+
|
|
124
|
+
### 2. MCP SQL Workflow (STRICT ORDER)
|
|
125
|
+
|
|
126
|
+
When creating custom SQL, follow this 5-step workflow:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
Step 1 → Step 2 → Step 3 → Step 4 → Step 5
|
|
130
|
+
Query → Generate → Validate → Save → Test
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
1. **Query**: Use `list_sql_queries` to check if SQL exists
|
|
134
|
+
2. **Generate**: Use `get_dataset_detail` to get table structure FIRST
|
|
135
|
+
3. **Validate**: Use `validate_sql_content` to verify syntax
|
|
136
|
+
4. **Save**: Use `save_or_update_custom_sql` to save
|
|
137
|
+
5. **Test**: Use `execute_custom_sql` to test execution
|
|
138
|
+
|
|
139
|
+
**NEVER skip any step!**
|
|
140
|
+
|
|
141
|
+
### 3. AntD UI Standards (No AI Style)
|
|
142
|
+
|
|
143
|
+
**Prohibited:**
|
|
144
|
+
- emoji: ✨🚀💡🎯📊🔥🎉
|
|
145
|
+
- AI-style text: "太棒了!", "让我们开始吧!"
|
|
146
|
+
- Fancy colors: #FF00FF, gradients
|
|
147
|
+
- Exclamation marks in buttons
|
|
148
|
+
- Cute terms: "小伙伴", "亲", "宝宝"
|
|
149
|
+
|
|
150
|
+
**Required:**
|
|
151
|
+
- Use AntD token colors
|
|
152
|
+
- Professional text: "保存", "取消", "操作成功"
|
|
153
|
+
- @ant-design/icons for icons (not emoji)
|
|
154
|
+
|
|
155
|
+
### 4. Code Comments
|
|
156
|
+
|
|
157
|
+
Always add dataset/table comments before SDK calls:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// 数据集: 用户信息 | 数据表: users
|
|
161
|
+
const users = await client.models.users.filter({
|
|
162
|
+
where: { status: { $eq: 'active' } },
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 5. API Integration (Optional)
|
|
167
|
+
|
|
168
|
+
Use `lovrabet api pull` to generate TypeScript types and API code:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Pull API definitions for all datasets
|
|
172
|
+
lovrabet api pull
|
|
173
|
+
|
|
174
|
+
# Pull specific datasets
|
|
175
|
+
lovrabet api pull --datasetcode customer,order
|
|
176
|
+
|
|
177
|
+
# Specify output directory
|
|
178
|
+
lovrabet api pull --output ./src/api
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Generated files structure:**
|
|
182
|
+
```
|
|
183
|
+
src/api/
|
|
184
|
+
├── lovrabet/
|
|
185
|
+
│ ├── index.ts # Export entry
|
|
186
|
+
│ ├── customer.ts # Customer dataset API
|
|
187
|
+
│ ├── order.ts # Order dataset API
|
|
188
|
+
│ └── types.ts # TypeScript type definitions
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Usage:**
|
|
192
|
+
```typescript
|
|
193
|
+
// Import generated API and types
|
|
194
|
+
import { customerApi } from '@/api/lovrabet';
|
|
195
|
+
import type { Customer } from '@/api/lovrabet/types';
|
|
196
|
+
|
|
197
|
+
// Use with type safety
|
|
198
|
+
const customers = await customerApi.filter({
|
|
199
|
+
where: { status: { $eq: 'active' } },
|
|
200
|
+
currentPage: 1,
|
|
201
|
+
pageSize: 20,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
customers.tableData.forEach((customer: Customer) => {
|
|
205
|
+
console.log(customer.name); // TypeScript autocomplete
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
## 页面开发规范
|
|
211
|
+
|
|
212
|
+
### 1. 页面顶部注释(强制)
|
|
213
|
+
|
|
214
|
+
**所有通过 CLI 生成的页面必须在文件顶部包含以下注释**:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
/**
|
|
218
|
+
* Generated by Lovrabet CLI v{CliVersion}
|
|
219
|
+
* Created: {CreatedAt}
|
|
220
|
+
* Page: {PageName}
|
|
221
|
+
*/
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**注释格式说明**:
|
|
225
|
+
- `CliVersion`:生成该页面的 CLI 版本号,便于追踪和兼容性检查
|
|
226
|
+
- `CreatedAt`:页面创建时间,便于维护和追溯
|
|
227
|
+
- `PageName`:页面路径(如 `user-profile`),用于菜单和路由
|
|
228
|
+
|
|
229
|
+
### 2. displayName(强制)
|
|
230
|
+
|
|
231
|
+
**所有页面组件导出时必须设置 `displayName`**,值为简洁的项目支持语言名称:
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
export default function UserProfile() {
|
|
235
|
+
// ...
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
UserProfile.displayName = '用户详情';
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**规则**:
|
|
242
|
+
- `displayName` 使用项目支持的语言(中文、英文等),简洁明了
|
|
243
|
+
- 推荐 2-4 个字的业务名称,如"用户列表"、"订单详情"、"User List"
|
|
244
|
+
|
|
245
|
+
### 3. 保留注释要求
|
|
246
|
+
|
|
247
|
+
**禁止删除或修改页面顶部的生成注释**。如需追加修改记录,使用 `@modified` 标签:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// ✅ 正确:保留原始注释,追加自己的说明
|
|
251
|
+
/**
|
|
252
|
+
* Generated by Lovrabet CLI v1.2.5-beta.2
|
|
253
|
+
* Created: 01-18-2026, 21:33:08
|
|
254
|
+
* Page: user-profile
|
|
255
|
+
*
|
|
256
|
+
* @modified 2025-01-20 添加批量删除功能
|
|
257
|
+
*/
|
|
258
|
+
|
|
259
|
+
// ❌ 错误:删除原始注释
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
## SDK 使用规范
|
|
264
|
+
|
|
265
|
+
### 1. SDK 初始化
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { createClient } from '@lovrabet/sdk';
|
|
269
|
+
|
|
270
|
+
// 正确:使用 createClient 函数
|
|
271
|
+
const client = createClient({
|
|
272
|
+
appCode: '<appcode>',
|
|
273
|
+
accessKey: process.env.LOVRABET_ACCESS_KEY, // 服务端
|
|
274
|
+
models: [
|
|
275
|
+
{ tableName: 'users', datasetCode: 'abc123def456', alias: 'users' },
|
|
276
|
+
{ tableName: 'orders', datasetCode: 'xyz789ghi012', alias: 'orders' },
|
|
277
|
+
],
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// 错误:使用 new 关键字
|
|
281
|
+
const client = new LovrabetClient({ ... });
|
|
282
|
+
|
|
283
|
+
// 错误:使用不存在的 mode 参数
|
|
284
|
+
const client = createClient({ mode: 'webapi', ... });
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### 2. SDK 返回值行为(核心原则!)
|
|
288
|
+
|
|
289
|
+
**SDK 设计原则:始终返回 data(业务数据层),应用层自行处理**
|
|
290
|
+
|
|
291
|
+
#### 核心原则
|
|
292
|
+
|
|
293
|
+
- **成功时**:SDK 方法返回 API 响应中的 `data` 字段内容(业务数据层),而不是完整的响应包装器
|
|
294
|
+
- **失败时**:抛出 `LovrabetError` 异常(HTTP 级别错误)
|
|
295
|
+
- **业务状态检查**:应用层负责检查业务逻辑状态(如 `execSuccess`),提取业务结果(如 `execResult`)
|
|
296
|
+
|
|
297
|
+
#### SDK 内部处理机制
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
// SDK 内部:processResponse 处理响应
|
|
301
|
+
export const processResponse = async <ResponseData>(response: Response) => {
|
|
302
|
+
const result = await response.json();
|
|
303
|
+
|
|
304
|
+
if (!result.success) {
|
|
305
|
+
throw new LovrabetError(errorMessage, { ... });
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return result.data; // ✅ 只返回 data,不是完整的 response
|
|
309
|
+
};
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### 使用示例
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
// ✅ 正确:Filter API - 直接使用返回的数据
|
|
316
|
+
try {
|
|
317
|
+
const result = await client.models.users.filter({
|
|
318
|
+
where: { status: { $eq: 'active' } },
|
|
319
|
+
});
|
|
320
|
+
console.log(result.tableData); // 直接使用,result 就是 data
|
|
321
|
+
console.log(result.total);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
if (error instanceof LovrabetError) {
|
|
324
|
+
console.error('HTTP 请求失败:', error.message);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ✅ 正确:SQL API - 应用层检查业务状态
|
|
329
|
+
try {
|
|
330
|
+
const data = await client.sql.execute({
|
|
331
|
+
sqlCode: 'fc8e7777-06e3847d',
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// 应用层负责检查业务逻辑状态
|
|
335
|
+
if (data.execSuccess && data.execResult) {
|
|
336
|
+
data.execResult.forEach(row => console.log(row));
|
|
337
|
+
} else {
|
|
338
|
+
console.error('SQL 查询失败');
|
|
339
|
+
}
|
|
340
|
+
} catch (error) {
|
|
341
|
+
if (error instanceof LovrabetError) {
|
|
342
|
+
console.error('HTTP 请求失败:', error.message);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ✅ 正确:BFF API - 直接使用返回的业务数据
|
|
347
|
+
try {
|
|
348
|
+
const dashboard = await client.bff.execute({
|
|
349
|
+
scriptName: 'getUserDashboard',
|
|
350
|
+
params: { userId: '123' },
|
|
351
|
+
});
|
|
352
|
+
console.log(dashboard.userCount); // 直接使用业务数据
|
|
353
|
+
} catch (error) {
|
|
354
|
+
if (error instanceof LovrabetError) {
|
|
355
|
+
console.error('HTTP 请求失败:', error.message);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// ❌ 错误:假设 SDK 返回完整响应对象
|
|
360
|
+
const response = await client.sql.execute({ sqlCode: 'xxx' });
|
|
361
|
+
if (response.success && response.data?.execSuccess) {
|
|
362
|
+
// SDK 不会返回这种嵌套结构
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 3. Filter 查询构建规范
|
|
367
|
+
|
|
368
|
+
#### 支持的条件操作符
|
|
369
|
+
|
|
370
|
+
| 操作符 | 说明 | 示例 |
|
|
371
|
+
|--------|------|------|
|
|
372
|
+
| `$eq` | 等于 | `{ status: { $eq: 'active' } }` |
|
|
373
|
+
| `$ne` | 不等于 | `{ status: { $ne: 'deleted' } }` |
|
|
374
|
+
| `$gte` | 大于等于 | `{ age: { $gte: 18 } }` |
|
|
375
|
+
| `$lte` | 小于等于 | `{ age: { $lte: 65 } }` |
|
|
376
|
+
| `$gt` | 大于 | `{ price: { $gt: 100 } }` |
|
|
377
|
+
| `$lt` | 小于 | `{ price: { $lt: 1000 } }` |
|
|
378
|
+
| `$in` | 在集合内 | `{ type: { $in: ['A', 'B'] } }` |
|
|
379
|
+
| `$contain` | 包含(模糊) | `{ name: { $contain: 'keyword' } }` |
|
|
380
|
+
| `$startWith` | 以...开头 | `{ email: { $startWith: 'admin' } }` |
|
|
381
|
+
| `$endWith` | 以...结尾 | `{ domain: { $endWith: '.com' } }` |
|
|
382
|
+
| `$and` | 且(所有满足) | `{ $and: [条件1, 条件2] }` |
|
|
383
|
+
| `$or` | 或(任一满足) | `{ $or: [条件1, 条件2] }` |
|
|
384
|
+
|
|
385
|
+
#### 逻辑操作符示例
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
// ✅ $and - 所有条件都要满足
|
|
389
|
+
where: {
|
|
390
|
+
$and: [
|
|
391
|
+
{ age: { $gte: 18 } },
|
|
392
|
+
{ status: { $eq: 'active' } }
|
|
393
|
+
]
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// ✅ $or - 任一条件满足即可
|
|
397
|
+
where: {
|
|
398
|
+
$or: [
|
|
399
|
+
{ status: { $eq: 'pending' } },
|
|
400
|
+
{ status: { $eq: 'processing' } }
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// ✅ 嵌套组合
|
|
405
|
+
where: {
|
|
406
|
+
$and: [
|
|
407
|
+
{ age: { $gte: 18 } },
|
|
408
|
+
{
|
|
409
|
+
$or: [
|
|
410
|
+
{ country: { $eq: '中国' } },
|
|
411
|
+
{ country: { $eq: '美国' } }
|
|
412
|
+
]
|
|
413
|
+
}
|
|
414
|
+
]
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### 常见错误
|
|
419
|
+
|
|
420
|
+
| 错误写法 | 正确写法 |
|
|
421
|
+
|---------|---------|
|
|
422
|
+
| `where: { status: 'active' }` | `where: { status: { $eq: 'active' } }` |
|
|
423
|
+
| `fields: ['id']` | `select: ['id']` |
|
|
424
|
+
| `orderBy: 'createTime desc'` | `orderBy: [{ createTime: 'desc' }]` |
|
|
425
|
+
| `where: { name: 'LIKE %kw%' }` | `where: { name: { $contain: 'kw' } }` |
|
|
426
|
+
| `page: 1, limit: 20` | `currentPage: 1, pageSize: 20` |
|
|
427
|
+
|
|
428
|
+
### 4. 性能优化(禁止循环查询)
|
|
429
|
+
|
|
430
|
+
**禁止在循环中调用单条查询 API**:
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
// ❌ 错误:N+1 查询
|
|
434
|
+
for (const order of orders) {
|
|
435
|
+
const user = await userDS.findOne({ id: order.user_id });
|
|
436
|
+
order.username = user?.username;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// ✅ 正确:批量查询
|
|
440
|
+
const userIds = [...new Set(orders.map(o => o.user_id))];
|
|
441
|
+
const userResult = await userDS.filter({
|
|
442
|
+
where: { id: { $in: userIds } }
|
|
443
|
+
});
|
|
444
|
+
const userMap = Object.fromEntries(
|
|
445
|
+
(userResult.tableData || []).map(u => [u.id, u])
|
|
446
|
+
);
|
|
447
|
+
for (const order of orders) {
|
|
448
|
+
order.username = userMap[order.user_id]?.username;
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**批量写入使用自定义 SQL**:
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
// ❌ 错误:循环写入
|
|
456
|
+
for (const item of items) {
|
|
457
|
+
await ds.create(item);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// ✅ 正确:使用自定义 SQL
|
|
461
|
+
await context.client.sql.execute({
|
|
462
|
+
sqlCode: 'batch-insert-sql-code',
|
|
463
|
+
params: { items: JSON.stringify(items) }
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### 文案示例
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
// ✅ 正确:简洁专业
|
|
471
|
+
const messages = {
|
|
472
|
+
success: '操作成功',
|
|
473
|
+
error: '操作失败',
|
|
474
|
+
confirm: '确定要删除这条记录吗?',
|
|
475
|
+
cancel: '取消',
|
|
476
|
+
submit: '提交',
|
|
477
|
+
save: '保存',
|
|
478
|
+
loading: '加载中...',
|
|
479
|
+
noData: '暂无数据',
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// ❌ 错误:AI 味道
|
|
483
|
+
const messages = {
|
|
484
|
+
success: '🎉 太棒了!操作成功!',
|
|
485
|
+
error: '哎呀,出错了 😢',
|
|
486
|
+
confirm: '你真的要删除吗?确定吗?',
|
|
487
|
+
cancel: '再想想吧~',
|
|
488
|
+
submit: '提交表单 ✨',
|
|
489
|
+
save: '保存更改 💾',
|
|
490
|
+
loading: '马上就好~请稍等 ⏳',
|
|
491
|
+
noData: '空空如也~还没有数据哦',
|
|
492
|
+
};
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### 颜色规范
|
|
496
|
+
|
|
497
|
+
#### 使用 AntD Token
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
// ✅ 正确:使用 AntD token
|
|
501
|
+
import { theme } from 'antd';
|
|
502
|
+
|
|
503
|
+
const { token } = theme.useToken();
|
|
504
|
+
|
|
505
|
+
const styles = {
|
|
506
|
+
primary: token.colorPrimary,
|
|
507
|
+
success: token.colorSuccess,
|
|
508
|
+
error: token.colorError,
|
|
509
|
+
warning: token.colorWarning,
|
|
510
|
+
text: token.colorText,
|
|
511
|
+
border: token.colorBorder,
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
// ❌ 错误:自定义花哨颜色
|
|
515
|
+
const styles = {
|
|
516
|
+
primary: '#FF00FF', // 霓虹粉
|
|
517
|
+
success: '#00FF00', // 亮绿色
|
|
518
|
+
accent: '#FFD700', // 金色
|
|
519
|
+
gradient: 'linear-gradient(45deg, #ff6b6b, #feca57)', // 渐变
|
|
520
|
+
};
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### 组件使用规范
|
|
524
|
+
|
|
525
|
+
#### 按钮
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
// ✅ 正确:简洁明了
|
|
529
|
+
<Button type="primary" onClick={handleSave}>
|
|
530
|
+
保存
|
|
531
|
+
</Button>
|
|
532
|
+
<Button danger onClick={handleDelete}>
|
|
533
|
+
删除
|
|
534
|
+
</Button>
|
|
535
|
+
|
|
536
|
+
// ❌ 错误:花哨风格
|
|
537
|
+
<Button type="primary" onClick={handleSave}>
|
|
538
|
+
💾 保存更改
|
|
539
|
+
</Button>
|
|
540
|
+
<Button danger onClick={handleDelete}>
|
|
541
|
+
🗑️ 哎呀,要删除吗?
|
|
542
|
+
</Button>
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
#### 表格
|
|
546
|
+
|
|
547
|
+
```typescript
|
|
548
|
+
// ✅ 正确:使用 ProTable 或 Table + Pagination
|
|
549
|
+
import { Table } from 'antd';
|
|
550
|
+
|
|
551
|
+
<Table
|
|
552
|
+
columns={columns}
|
|
553
|
+
dataSource={data}
|
|
554
|
+
pagination={{
|
|
555
|
+
current: currentPage,
|
|
556
|
+
pageSize: pageSize,
|
|
557
|
+
total: total,
|
|
558
|
+
showSizeChanger: true,
|
|
559
|
+
showQuickJumper: true,
|
|
560
|
+
showTotal: (total) => `共 ${total} 条`,
|
|
561
|
+
}}
|
|
562
|
+
/>
|
|
563
|
+
|
|
564
|
+
// ❌ 错误:花哨的空状态
|
|
565
|
+
<Table
|
|
566
|
+
columns={columns}
|
|
567
|
+
dataSource={data}
|
|
568
|
+
locale={{
|
|
569
|
+
emptyText: (
|
|
570
|
+
<div>
|
|
571
|
+
<span>🎭 </span>
|
|
572
|
+
<span>还没有数据哦~</span>
|
|
573
|
+
</div>
|
|
574
|
+
),
|
|
575
|
+
}}
|
|
576
|
+
/>
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
#### 消息提示
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
// ✅ 正确:简洁专业
|
|
583
|
+
import { message } from 'antd';
|
|
584
|
+
|
|
585
|
+
message.success('保存成功');
|
|
586
|
+
message.error('操作失败,请重试');
|
|
587
|
+
message.warning('请填写必填项');
|
|
588
|
+
message.info('正在处理...');
|
|
589
|
+
|
|
590
|
+
// ❌ 错误:AI 味道
|
|
591
|
+
message.success('🎉 太棒了!保存成功!');
|
|
592
|
+
message.error('😱 哎呀出错了!请再试一次');
|
|
593
|
+
message.warning('⚠️ 嘿!别忘了填写必填项哦');
|
|
594
|
+
message.info('🔔 正在为你处理中,请稍等~');
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
#### Modal 确认
|
|
598
|
+
|
|
599
|
+
```typescript
|
|
600
|
+
// ✅ 正确:专业简洁
|
|
601
|
+
import { Modal } from 'antd';
|
|
602
|
+
|
|
603
|
+
Modal.confirm({
|
|
604
|
+
title: '确认删除',
|
|
605
|
+
content: '确定要删除这条记录吗?',
|
|
606
|
+
okText: '确定',
|
|
607
|
+
cancelText: '取消',
|
|
608
|
+
onOk: handleDelete,
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// ❌ 错误:AI 味道
|
|
612
|
+
Modal.confirm({
|
|
613
|
+
title: '🤔 确认要删除吗?',
|
|
614
|
+
content: '删除后可就找不回来了哦!你确定要删除这条记录吗?',
|
|
615
|
+
okText: '是的,删除!',
|
|
616
|
+
cancelText: '再想想~',
|
|
617
|
+
icon: <ExclamationCircleOutlined style={{ color: '#FFD700' }} />,
|
|
618
|
+
});
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### 表单规范
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
// ✅ 正确:简洁清晰的错误提示
|
|
625
|
+
<Form>
|
|
626
|
+
<Form.Item
|
|
627
|
+
name="username"
|
|
628
|
+
label="用户名"
|
|
629
|
+
rules={[
|
|
630
|
+
{ required: true, message: '请输入用户名' },
|
|
631
|
+
{ min: 3, message: '用户名至少3个字符' },
|
|
632
|
+
]}
|
|
633
|
+
>
|
|
634
|
+
<Input placeholder="请输入用户名" />
|
|
635
|
+
</Form.Item>
|
|
636
|
+
</Form>
|
|
637
|
+
|
|
638
|
+
// ❌ 错误:花哨的错误提示
|
|
639
|
+
<Form>
|
|
640
|
+
<Form.Item
|
|
641
|
+
name="username"
|
|
642
|
+
label="👤 用户名"
|
|
643
|
+
rules={[
|
|
644
|
+
{ required: true, message: '哎呀!别忘了填写用户名哦~' },
|
|
645
|
+
{ min: 3, message: '用户名太短啦,至少要3个字符呢!' },
|
|
646
|
+
]}
|
|
647
|
+
>
|
|
648
|
+
<Input placeholder="输入用户名试试看~ ✨" />
|
|
649
|
+
</Form.Item>
|
|
650
|
+
</Form>
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
### 空状态规范
|
|
654
|
+
|
|
655
|
+
```typescript
|
|
656
|
+
// ✅ 正确:简洁专业
|
|
657
|
+
import { Empty } from 'antd';
|
|
658
|
+
|
|
659
|
+
<Empty
|
|
660
|
+
description="暂无数据"
|
|
661
|
+
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
|
662
|
+
/>
|
|
663
|
+
|
|
664
|
+
// 带操作按钮
|
|
665
|
+
<Empty
|
|
666
|
+
description="暂无数据"
|
|
667
|
+
image={Empty.PRESENTED_IMAGE_SIMPLE}>
|
|
668
|
+
<Button type="primary">创建数据</Button>
|
|
669
|
+
</Empty>
|
|
670
|
+
|
|
671
|
+
// ❌ 错误:AI 味道
|
|
672
|
+
<Empty
|
|
673
|
+
description={
|
|
674
|
+
<div>
|
|
675
|
+
<div>🎭 还没有数据哦~</div>
|
|
676
|
+
<div style={{ fontSize: 12, color: '#999' }}>
|
|
677
|
+
快来创建第一条数据吧!✨
|
|
678
|
+
</div>
|
|
679
|
+
</div>
|
|
680
|
+
}
|
|
681
|
+
/>
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### 图标使用规范
|
|
685
|
+
|
|
686
|
+
```typescript
|
|
687
|
+
// ✅ 正确:使用 @ant-design/icons
|
|
688
|
+
import {
|
|
689
|
+
UserOutlined,
|
|
690
|
+
DeleteOutlined,
|
|
691
|
+
EditOutlined,
|
|
692
|
+
SearchOutlined,
|
|
693
|
+
} from '@ant-design/icons';
|
|
694
|
+
|
|
695
|
+
// 按钮图标(可选,保持简洁)
|
|
696
|
+
<Button icon={<PlusOutlined />}>新建</Button>
|
|
697
|
+
|
|
698
|
+
// ❌ 错误:使用 emoji 作为图标
|
|
699
|
+
<Button>🆕 新建</Button>
|
|
700
|
+
<Button>✏️ 编辑</Button>
|
|
701
|
+
<Button>🗑️ 删除</Button>
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### 检查清单
|
|
705
|
+
|
|
706
|
+
在编写 UI 代码时,确保:
|
|
707
|
+
|
|
708
|
+
- [ ] 没有 emoji
|
|
709
|
+
- [ ] 没有感叹号
|
|
710
|
+
- [ ] 文案简洁专业
|
|
711
|
+
- [ ] 使用 AntD token 颜色
|
|
712
|
+
- [ ] 使用 @ant-design/icons 而非 emoji
|
|
713
|
+
- [ ] 按钮文案为动词(保存/删除/编辑)
|
|
714
|
+
- [ ] 提示文案中性(操作成功/操作失败)
|
|
715
|
+
- [ ] 没有过度动画效果
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
## 禁止事项
|
|
720
|
+
|
|
721
|
+
### 页面相关
|
|
722
|
+
1. **不要删除页面顶部注释** - CLI 生成的注释必须保留,用于版本追踪和维护
|
|
723
|
+
2. **不要修改页面顶部注释内容** - 如需追加说明,使用 `@modified` 标签
|
|
724
|
+
3. **不要使用不规范的组件命名** - 组件名必须使用 PascalCase
|
|
725
|
+
|
|
726
|
+
### SDK 相关
|
|
727
|
+
1. **不要臆测 API** - 使用不存在的方法或参数
|
|
728
|
+
2. **不要臆测字段** - 未通过 MCP 确认字段是否存在
|
|
729
|
+
3. **不要混淆认证模式** - 在错误的模式使用功能(如 OpenAPI 模式使用 delete)
|
|
730
|
+
4. **不要忽略错误处理** - 所有 SDK 调用必须 try-catch
|
|
731
|
+
5. **不要假设返回值结构** - 注意不同方法返回值的差异
|
|
732
|
+
6. **不要在循环中调用 API** - 使用 Promise.all 批量处理
|
|
733
|
+
7. **不要在每次渲染时调用 API** - 使用 useEffect 控制
|
|
734
|
+
8. **不要使用 getList()** - 列表查询必须使用 filter()
|
|
735
|
+
|
|
736
|
+
### Filter 查询相关
|
|
737
|
+
9. **不要忘记使用操作符** - where 条件必须使用 `$eq`、`$gte` 等操作符
|
|
738
|
+
10. **不要使用错误的参数名** - 是 `select` 不是 `fields`,是 `orderBy` 不是 `sortList`
|
|
739
|
+
11. **不要使用 SQL 语法** - 不支持 `LIKE`、`>=` 等,必须用 `$contain`、`$gte` 等
|
|
740
|
+
12. **不要忽略参数格式** - `orderBy` 和 `select` 必须是数组,不能是字符串
|
|
741
|
+
|
|
742
|
+
### SQL 相关
|
|
743
|
+
13. **不要跳过 MCP SQL 工作流步骤** - 必须按顺序:查询→生成→验证→保存→测试
|
|
744
|
+
14. **不要忘记检查 execSuccess** - `client.sql.execute()` 返回的数据必须检查 `execSuccess` 状态(应用层职责)
|
|
745
|
+
15. **不要假设 sql.execute 返回数组** - 返回的是 `{ execSuccess, execResult }` 对象(业务数据层)
|
|
746
|
+
16. **不要假设SQL code存在 = SQL正确** - 必须验证SQL内容中的表名和字段名与实际数据库结构匹配
|
|
747
|
+
17. **不要仅检查SQL code是否存在** - 必须获取SQL内容,对比表名和字段名,修复SQL内容本身
|
|
748
|
+
18. **不要在自定义 SQL 中使用 INSERT/UPDATE/DELETE** - 只允许 SELECT 查询
|
|
749
|
+
19. **不要假设 SDK 返回完整响应对象** - SDK 返回的是 `data`(业务数据层),不是 `{ success, data }` 结构
|
|
750
|
+
|
|
751
|
+
### UI 相关
|
|
752
|
+
20. **不要使用 emoji** - 包括按钮、标题、提示文案等所有地方
|
|
753
|
+
21. **不要使用 AI 味道的文案** - 如"太棒了!"、"让我们开始吧!"、"试试看!"
|
|
754
|
+
22. **不要使用花哨的颜色** - 只使用 AntD token 颜色
|
|
755
|
+
23. **不要使用感叹号** - 标题和按钮文案中禁止使用 "!"
|
|
756
|
+
24. **不要使用自定义动画** - 只使用 AntD 内置动画
|
|
757
|
+
25. **不要使用非专业称呼** - 如"小伙伴"、"亲"、"宝宝" 等
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
## 快速参考
|
|
762
|
+
|
|
763
|
+
### SDK 方法返回值
|
|
764
|
+
|
|
765
|
+
| 方法 | 返回结构 | 参数格式 | 认证限制 |
|
|
766
|
+
|------|----------|----------|----------|
|
|
767
|
+
| `filter()` | `{ tableData, total }` | `filter(params)` | OpenAPI + WebAPI |
|
|
768
|
+
| `getOne()` | 单个对象 | `getOne(id)` 或 `getOne({ id })` | OpenAPI + WebAPI |
|
|
769
|
+
| `create/update()` | 操作结果对象 | `create(data)` / `update(id, data)` | OpenAPI + WebAPI |
|
|
770
|
+
| `delete()` | 删除结果 | `delete(id)` | 仅 WebAPI |
|
|
771
|
+
| `getSelectOptions()` | `[{ label, value }]` | `getSelectOptions(params)` | 仅 WebAPI |
|
|
772
|
+
| `sql.execute()` | `{ execSuccess, execResult }` | `execute({ sqlCode, params })` | OpenAPI + WebAPI |
|
|
773
|
+
| `bff.execute()` | 业务数据对象 | `execute({ scriptName, params })` | OpenAPI + WebAPI |
|
|
774
|
+
| `user.getList()` | `User[]` | `getList()` | 仅 WebAPI |
|
|
775
|
+
|
|
776
|
+
**注意**:
|
|
777
|
+
- 所有方法返回的都是 `data`(业务数据层),不是完整的响应对象
|
|
778
|
+
- SQL 和 BFF 的返回值需要应用层检查业务状态(如 `execSuccess`)
|
|
779
|
+
|
|
780
|
+
### 记住
|
|
781
|
+
|
|
782
|
+
#### 页面开发
|
|
783
|
+
- **保留顶部注释**:CLI 生成的注释包含版本、时间、页面名,禁止删除
|
|
784
|
+
- **组件命名 PascalCase**:`UserProfile` 而非 `userProfile`
|
|
785
|
+
- **追加修改说明**:使用 `@modified` 标签记录手动修改
|
|
786
|
+
|
|
787
|
+
#### SDK 核心
|
|
788
|
+
- **返回值原则**:SDK 始终返回 `data`(业务数据层),不是完整的响应包装器
|
|
789
|
+
- **成功时**:返回 API 响应的 `data` 字段内容
|
|
790
|
+
- **失败时**:抛出 `LovrabetError` 异常(HTTP 级别错误)
|
|
791
|
+
- **业务状态检查**:应用层负责检查业务逻辑状态(如 `execSuccess`)
|
|
792
|
+
- **所有调用**:必须用 `try-catch` 包裹
|
|
793
|
+
- **先获取元数据**:使用 MCP 确认字段存在
|
|
794
|
+
|
|
795
|
+
#### Filter 查询
|
|
796
|
+
- **列表查询用 filter**:必须使用 `filter()` 方法,禁止使用 `getList()`
|
|
797
|
+
- **注意参数名**:`select`(不是 `fields`),`orderBy`(不是 `sortList`),`currentPage`/`pageSize`(不是 `page`/`limit`)
|
|
798
|
+
- **必须使用操作符**:`where: { status: { $eq: 'active' } }`,不是 `where: { status: 'active' }`
|
|
799
|
+
- **参数必须是数组**:`select: ['id', 'name']`,不是 `select: 'id,name'`
|
|
800
|
+
|
|
801
|
+
#### SQL API
|
|
802
|
+
- **使用方式**:`client.sql.execute({ sqlCode, params })` - 对象参数格式
|
|
803
|
+
- **返回值检查**:应用层必须检查 `execSuccess` 状态
|
|
804
|
+
|
|
805
|
+
#### BFF API
|
|
806
|
+
- **使用方式**:`client.bff.execute({ scriptName, params })` - 直接客户端访问
|
|
807
|
+
- **返回值**:直接是业务数据对象,无需检查 `execSuccess`
|
|
808
|
+
|
|
809
|
+
#### MCP SQL 流程
|
|
810
|
+
- **严格执行 5 步流程**:查询→生成→验证→保存→测试
|
|
811
|
+
- **SQL验证必须系统化**:创建或使用SQL时,必须对比SQL内容与实际表结构,验证表名和字段名
|
|
812
|
+
- **SQL code存在 ≠ SQL正确**:必须获取SQL内容,验证表名、字段名、JOIN条件是否正确
|
|
813
|
+
|
|
814
|
+
#### UI 规范
|
|
815
|
+
- **禁止 emoji**:所有地方都不使用 emoji
|
|
816
|
+
- **文案简洁专业**:"保存"而不是"保存吧!","操作成功"而不是"太棒了!"
|
|
817
|
+
- **使用 AntD token**:颜色使用 `token.colorPrimary` 等,不自定义花哨颜色
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
## 示例代码说明
|
|
822
|
+
|
|
823
|
+
**重要**:本文档中所有代码示例使用的是**占位符**(用 `<>` 包裹),而非真实字段名或值。
|
|
824
|
+
|
|
825
|
+
### 占位符说明
|
|
826
|
+
|
|
827
|
+
- `<appcode>` - 应用代码,需替换为实际的 appcode
|
|
828
|
+
- `<modelName>` - 模型名称,如 `users`、`orders` 等
|
|
829
|
+
- `<dataset-code>` - 数据集代码
|
|
830
|
+
- `<table-name>` - 表名
|
|
831
|
+
- `<table-alias>` - 表别名(SQL 中使用)
|
|
832
|
+
- `<id>` - 记录 ID
|
|
833
|
+
- `<field>`, `<field1>`, `<field2>` - 字段名称
|
|
834
|
+
- `<fieldName>` - 字段名称(用于排序等)
|
|
835
|
+
- `<field-name>` - 具体字段名
|
|
836
|
+
- `<wrong-field>`, `<correct-field>` - 错误/正确的字段名(SQL 验证示例)
|
|
837
|
+
- `<wrong-pk>`, `<correct-pk>` - 错误/正确的主键字段名
|
|
838
|
+
- `<wrong-table>`, `<correct-table>` - 错误/正确的表名
|
|
839
|
+
- `<value>`, `<value1>`, `<value2>` - 字段值
|
|
840
|
+
- `<sql-code>` - SQL 代码
|
|
841
|
+
- `<sql-name>` - SQL 名称
|
|
842
|
+
- `<value-field>` - 用作选项值的字段
|
|
843
|
+
- `<label-field>` - 用作显示文本的字段
|
|
844
|
+
|
|
845
|
+
### 如何使用
|
|
846
|
+
|
|
847
|
+
在实际编写代码前,**必须**:
|
|
848
|
+
|
|
849
|
+
1. 使用 MCP 工具获取数据集详情
|
|
850
|
+
2. 查看实际的字段列表和字段类型
|
|
851
|
+
3. 用真实的字段名替换占位符
|
|
852
|
+
4. 确保字段类型匹配
|
|
853
|
+
|
|
854
|
+
**切记**:不要直接复制示例代码中的占位符到实际项目中!
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
**学习资源**:
|
|
858
|
+
- [官方文档](https://open.lovrabet.com/docs/lovrabet-sdk/intro)
|
|
859
|
+
- [API 参考](https://open.lovrabet.com/docs/lovrabet-sdk/api-reference)
|
|
860
|
+
- [Filter API](https://open.lovrabet.com/docs/lovrabet-sdk/filter-api)
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
## 更新日志
|
|
865
|
+
|
|
866
|
+
### v2.1.0 (2025-01-24)
|
|
867
|
+
- ✨ **完善 SDK 返回值行为说明** - 明确 SDK 返回 `data`(业务数据层),应用层负责检查业务状态
|
|
868
|
+
- ✨ **补充 SQL API 详细说明** - 明确返回值结构和应用层职责,添加类型安全示例
|
|
869
|
+
- ✨ **补充 BFF API 详细说明** - 添加完整的使用示例和错误处理
|
|
870
|
+
- ✨ **补充 Filter API 逻辑操作符** - 添加 `$and`、`$or` 嵌套组合示例
|
|
871
|
+
- ✨ **新增 API 集成指南** - 添加 `lovrabet api pull` 使用说明
|
|
872
|
+
- 📝 更新"快速参考"和"记住"部分,明确 SDK 返回值结构和使用方式
|
|
873
|
+
- 🧹 **清理向后兼容说明** - 移除所有向后兼容和别名用法说明,避免大模型产生幻觉
|
|
874
|
+
|
|
875
|
+
### v2.0.0 (2025-01-17)
|
|
876
|
+
- ✨ **新增 SDK Filter 查询构建规范(强制)** - 详细说明 filter 的正确用法,列举 10 种常见错误
|
|
877
|
+
- ✨ **新增 MCP SQL 创建工作流(强制顺序)** - 明确 5 步流程顺序:查询→生成→验证→保存→测试
|
|
878
|
+
- ✨ **新增 AntD UI 开发规范(禁止 AI 风格)** - 禁止 emoji、AI 味道文案、花哨颜色等
|
|
879
|
+
- 📝 重组禁止事项为 4 大类(SDK / Filter / SQL / UI),共 24 条
|
|
880
|
+
- 📝 更新"记住"部分,分 4 大类总结关键要点
|
|
881
|
+
|
|
882
|
+
### v1.0.0 (2025-11-15)
|
|
883
|
+
- 📋 完整的 SDK 使用规范
|
|
884
|
+
- 🔧 MCP Tools 使用指南
|
|
885
|
+
- ⚡ 性能优化建议
|
|
886
|
+
- 🛡️ 错误处理最佳实践
|
|
887
|
+
|
|
888
|
+
---
|
|
889
|
+
|
|
890
|
+
> update:2025-01-24
|
|
891
|
+
|