@lovrabet/cli 1.2.3 → 1.2.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -17
- package/lib/add-page/input-page-router.js +1 -1
- package/lib/add-page/main.js +1 -1
- package/lib/add-page/select-page-template.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/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-cdn-url.js +1 -1
- 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.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.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/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/init/main.js +1 -1
- package/lib/mcp/claude.js +1 -0
- package/lib/mcp/cursor.js +1 -1
- package/lib/mcp/main.js +1 -1
- package/lib/skills/main.js +1 -0
- package/lib/utils/check-sdk-version.js +1 -1
- package/lib/utils/config.js +1 -1
- package/lib/utils/copy-directory.js +1 -1
- package/lib/utils/http-client.js +1 -1
- package/lib/utils/logger.js +1 -1
- package/lib/utils/router-updater.js +1 -1
- package/lib/utils/sleep.js +1 -1
- package/lib/utils/template-replacer.js +1 -1
- package/package.json +1 -1
- package/templates/projects/sub-app-react-demo/index.html +22 -34
- package/templates/projects/sub-app-react-demo/public/logo.svg +1 -0
- package/templates/projects/sub-app-react-demo/src/api/api.ts +1 -1
- package/templates/projects/sub-app-react-demo/src/api/client.ts +1 -1
- package/templates/projects/sub-app-react-demo/src/layouts/MainLayout.tsx +44 -71
- package/templates/projects/sub-app-react-demo/src/pages/index.tsx +387 -927
- package/templates/projects/sub-app-react-demo/src/pages/sdk-demo/index.tsx +1 -1
- package/templates/projects/sub-app-react-demo/src/pages/workbench/index.module.css +293 -0
- package/templates/projects/sub-app-react-demo/src/pages/workbench/index.tsx +100 -414
- package/templates/projects/sub-app-react-demo/src/style.css +21 -15
- package/templates/projects/sub-app-react-demo/vite.config.ts +18 -13
- package/templates/rules/lovrabet_rules.mdc.tpl +636 -43
- package/templates/skills/.claude/skills/lovrabet/SKILL.md +257 -0
- package/templates/skills/.cursor/commands/lovrabet.md +247 -0
- package/templates/skills/.cursorrules +109 -0
- package/templates/skills/.shared/README.md +45 -0
- package/templates/skills/.shared/guides/01-filter-query/guide.md +300 -0
- package/templates/skills/.shared/guides/02-mcp-sql-workflow/guide.md +272 -0
- package/templates/skills/.shared/guides/03-antd-style/guide.md +227 -0
- package/templates/skills/.shared/guides/04-troubleshooting/guide.md +426 -0
- package/templates/skills/.shared/guides/05-api-integration/guide.md +327 -0
- package/templates/skills/.shared/guides/06-menu-management/guide.md +305 -0
- package/templates/skills/.windsurf/workflows/lovrabet.md +256 -0
- package/templates/projects/sub-app-react-demo/.vscode/extensions.json +0 -3
- package/templates/projects/sub-app-react-demo/.vscode/settings.json +0 -57
- package/templates/projects/sub-app-react-demo/src/pages/intro/index.tsx +0 -560
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# AntD UI 开发规范
|
|
2
|
+
|
|
3
|
+
> **目标**:统一 AntD 组件使用风格,避免代码充满 AI 味道
|
|
4
|
+
|
|
5
|
+
## 🎯 为什么这个技能重要?
|
|
6
|
+
|
|
7
|
+
ToB 企业应用需要**专业、简洁**的界面风格。但 AI 生成的代码往往充满:
|
|
8
|
+
- emoji:✨ 🚀 💡 🎯 📊
|
|
9
|
+
- 花哨的文案:"太棒了!"、"让我们开始吧!"
|
|
10
|
+
- 过度的动画和渐变
|
|
11
|
+
|
|
12
|
+
这会让应用看起来不专业,用户会质疑系统的可靠性。
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 🚫 7 条禁止规则
|
|
17
|
+
|
|
18
|
+
### 1. 禁止 emoji
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
// ❌ 错误
|
|
22
|
+
<Button>🚀 开始使用</Button>
|
|
23
|
+
<message.success="🎉 操作成功!" />
|
|
24
|
+
|
|
25
|
+
// ✅ 正确
|
|
26
|
+
<Button>开始使用</Button>
|
|
27
|
+
<message.success="操作成功" />
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2. 禁止 AI 味道的文案
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// ❌ 错误
|
|
34
|
+
const messages = {
|
|
35
|
+
success: '太棒了!操作成功!',
|
|
36
|
+
confirm: '你确定要删除吗?',
|
|
37
|
+
cancel: '再想想吧~',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// ✅ 正确
|
|
41
|
+
const messages = {
|
|
42
|
+
success: '操作成功',
|
|
43
|
+
confirm: '确定要删除吗?',
|
|
44
|
+
cancel: '取消',
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. 禁止花哨的颜色
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// ❌ 错误
|
|
52
|
+
const colors = {
|
|
53
|
+
primary: '#FF00FF', // 霓虹粉
|
|
54
|
+
success: '#00FF00', // 亮绿色
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// ✅ 正确
|
|
58
|
+
import { theme } from 'antd';
|
|
59
|
+
const { token } = theme.useToken();
|
|
60
|
+
const colors = {
|
|
61
|
+
primary: token.colorPrimary,
|
|
62
|
+
success: token.colorSuccess,
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 4. 禁止感叹号
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
// ❌ 错误
|
|
70
|
+
<Button type="primary">保存!</Button>
|
|
71
|
+
<Modal title="确认删除!">
|
|
72
|
+
|
|
73
|
+
// ✅ 正确
|
|
74
|
+
<Button type="primary">保存</Button>
|
|
75
|
+
<Modal title="确认删除">
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 5. 禁止非专业称呼
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
// ❌ 错误
|
|
82
|
+
console.log('你好,小伙伴!');
|
|
83
|
+
alert('亲,请填写完整信息哦');
|
|
84
|
+
|
|
85
|
+
// ✅ 正确
|
|
86
|
+
console.log('操作完成');
|
|
87
|
+
alert('请填写完整信息');
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 6. 禁止过度动画
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
// ❌ 错误:自定义花哨动画
|
|
94
|
+
const customAnimation = keyframes`
|
|
95
|
+
0% { transform: scale(0) rotate(0deg); }
|
|
96
|
+
50% { transform: scale(1.2) rotate(180deg); }
|
|
97
|
+
100% { transform: scale(1) rotate(360deg); }
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
// ✅ 正确:使用 AntD 内置动画
|
|
101
|
+
import { fade-in } from 'antd/es/_util/motion';
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 7. 禁止自定义可爱图标
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// ❌ 错误:使用 emoji 作为图标
|
|
108
|
+
<Button>🆕 新建</Button>
|
|
109
|
+
<Button>✏️ 编辑</Button>
|
|
110
|
+
|
|
111
|
+
// ✅ 正确:使用 @ant-design/icons
|
|
112
|
+
import { PlusOutlined, EditOutlined } from '@ant-design/icons';
|
|
113
|
+
<Button icon={<PlusOutlined />}>新建</Button>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 📝 组件规范
|
|
119
|
+
|
|
120
|
+
### Button 按钮
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
// ✅ 正确
|
|
124
|
+
<Button type="primary" onClick={handleSave}>
|
|
125
|
+
保存
|
|
126
|
+
</Button>
|
|
127
|
+
<Button onClick={handleCancel}>取消</Button>
|
|
128
|
+
<Button danger onClick={handleDelete}>删除</Button>
|
|
129
|
+
|
|
130
|
+
// 带图标(可选)
|
|
131
|
+
<Button icon={<PlusOutlined />} type="primary">
|
|
132
|
+
新建
|
|
133
|
+
</Button>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Modal 确认弹窗
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// ✅ 正确
|
|
140
|
+
Modal.confirm({
|
|
141
|
+
title: '确认删除',
|
|
142
|
+
content: '确定要删除这条记录吗?',
|
|
143
|
+
okText: '确定',
|
|
144
|
+
cancelText: '取消',
|
|
145
|
+
onOk: handleDelete,
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### message 消息提示
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
// ✅ 正确
|
|
153
|
+
import { message } from 'antd';
|
|
154
|
+
|
|
155
|
+
message.success('保存成功');
|
|
156
|
+
message.error('操作失败,请重试');
|
|
157
|
+
message.warning('请填写必填项');
|
|
158
|
+
message.info('正在处理...');
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Form 表单
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
// ✅ 正确
|
|
165
|
+
<Form.Item
|
|
166
|
+
name="username"
|
|
167
|
+
label="用户名"
|
|
168
|
+
rules={[
|
|
169
|
+
{ required: true, message: '请输入用户名' },
|
|
170
|
+
{ min: 3, message: '用户名至少3个字符' },
|
|
171
|
+
]}
|
|
172
|
+
>
|
|
173
|
+
<Input placeholder="请输入用户名" />
|
|
174
|
+
</Form.Item>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Empty 空状态
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
// ✅ 正确
|
|
181
|
+
<Empty
|
|
182
|
+
description="暂无数据"
|
|
183
|
+
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
|
184
|
+
/>
|
|
185
|
+
|
|
186
|
+
// 带操作按钮
|
|
187
|
+
<Empty description="暂无数据">
|
|
188
|
+
<Button type="primary">创建数据</Button>
|
|
189
|
+
</Empty>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 📋 文案规范对照表
|
|
195
|
+
|
|
196
|
+
| 场景 | 正确 ✅ | 错误 ❌ |
|
|
197
|
+
|------|--------|--------|
|
|
198
|
+
| 按钮保存 | 保存 | 保存吧! / 好的 / 确定 |
|
|
199
|
+
| 按钮取消 | 取消 | 再想想 / 算了吧 |
|
|
200
|
+
| 按钮删除 | 删除 | 删除掉 / 哎呀删除 |
|
|
201
|
+
| 成功提示 | 操作成功 | 太棒了! / 成功啦! |
|
|
202
|
+
| 失败提示 | 操作失败 | 哎呀出错了 / 失败了 |
|
|
203
|
+
| 加载中 | 加载中... | 马上就好~ / 请稍等哦 |
|
|
204
|
+
| 空状态 | 暂无数据 | 还没有数据哦~ / 空空如也 |
|
|
205
|
+
| 确认删除 | 确定要删除吗? | 你真的要删除吗?/ 三思而后行! |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## ✅ 自检清单
|
|
210
|
+
|
|
211
|
+
提交代码前,检查:
|
|
212
|
+
|
|
213
|
+
- [ ] 没有 emoji(✨🚀💡等)
|
|
214
|
+
- [ ] 没有感叹号(!)
|
|
215
|
+
- [ ] 文案简洁专业("保存"不是"保存吧")
|
|
216
|
+
- [ ] 使用 AntD token 颜色
|
|
217
|
+
- [ ] 使用 @ant-design/icons 而非 emoji
|
|
218
|
+
- [ ] 按钮文案为动词(保存/删除/编辑)
|
|
219
|
+
- [ ] 提示文案中性(操作成功/操作失败)
|
|
220
|
+
- [ ] 没有过度动画效果
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 🔗 相关资源
|
|
225
|
+
|
|
226
|
+
- [组件规范](./components.md) - 各组件的详细规范
|
|
227
|
+
- [自检清单](./checklist.md) - 详细的代码检查清单
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
# 问题排查指南
|
|
2
|
+
|
|
3
|
+
> 遇到 Lovrabet 开发问题时,按照本指南快速定位和解决问题。
|
|
4
|
+
|
|
5
|
+
## 🔍 快速诊断流程
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
1. 确认问题类型
|
|
9
|
+
↓
|
|
10
|
+
2. 查看错误信息
|
|
11
|
+
↓
|
|
12
|
+
3. 定位问题根源
|
|
13
|
+
↓
|
|
14
|
+
4. 应用解决方案
|
|
15
|
+
↓
|
|
16
|
+
5. 验证问题已解决
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 常见问题
|
|
22
|
+
|
|
23
|
+
### 问题 1: Filter 查询没有结果
|
|
24
|
+
|
|
25
|
+
**现象**:
|
|
26
|
+
```typescript
|
|
27
|
+
const result = await client.models.users.filter({
|
|
28
|
+
where: { status: "active" }, // ❌ 忘记操作符!
|
|
29
|
+
});
|
|
30
|
+
console.log(result.tableData); // 空数组
|
|
31
|
+
console.log(result.total); // 0
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**原因**:忘记使用操作符
|
|
35
|
+
|
|
36
|
+
**解决方案**:
|
|
37
|
+
```typescript
|
|
38
|
+
// ✅ 正确:使用 $eq 操作符
|
|
39
|
+
const result = await client.models.users.filter({
|
|
40
|
+
where: { status: { $eq: "active" } },
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
console.log(result.tableData); // 正确获取数据
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### 问题 2: 报错 "参数格式不正确"
|
|
49
|
+
|
|
50
|
+
**现象**:
|
|
51
|
+
```typescript
|
|
52
|
+
const result = await client.models.users.filter({
|
|
53
|
+
fields: ["id", "name"], // ❌ 错误:应该是 select
|
|
54
|
+
sort: [{ id: "desc" }], // ❌ 错误:应该是 orderBy
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**原因**:参数名错误
|
|
59
|
+
|
|
60
|
+
**解决方案**:
|
|
61
|
+
```typescript
|
|
62
|
+
// ✅ 正确的参数名
|
|
63
|
+
const result = await client.models.users.filter({
|
|
64
|
+
select: ["id", "name"], // 正确
|
|
65
|
+
orderBy: [{ id: "desc" }], // 正确
|
|
66
|
+
currentPage: 1,
|
|
67
|
+
参数名错误:fields → select
|
|
68
|
+
参数名错误:sort → orderBy
|
|
69
|
+
参数名错误:page → currentPage
|
|
70
|
+
参数名:limit → pageSize
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### 问题 3: MCP 工具调用失败
|
|
76
|
+
|
|
77
|
+
**现象**:
|
|
78
|
+
```
|
|
79
|
+
使用 MCP 工具时返回错误:Error: Dataset not found
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**原因**:
|
|
83
|
+
1. appcode 配置错误
|
|
84
|
+
2. 数据集代码错误
|
|
85
|
+
3. 未登录或 Cookie 过期
|
|
86
|
+
|
|
87
|
+
**解决方案**:
|
|
88
|
+
|
|
89
|
+
1. 检查配置文件
|
|
90
|
+
```typescript
|
|
91
|
+
// .lovrabetrc
|
|
92
|
+
{
|
|
93
|
+
"appcode": "app-xxx",
|
|
94
|
+
"env": "online"
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
2. 使用 list_datasets 验证
|
|
99
|
+
```typescript
|
|
100
|
+
// 先验证数据集是否存在
|
|
101
|
+
const datasets = await list_datasets();
|
|
102
|
+
console.log(datasets.datasets.map(d => d.code)); // 查看所有数据集代码
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
3. 检查登录状态
|
|
106
|
+
```bash
|
|
107
|
+
# 检查是否已登录
|
|
108
|
+
lovrabet auth
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### 问题 4: SQL 执行错误
|
|
114
|
+
|
|
115
|
+
**现象**:
|
|
116
|
+
```
|
|
117
|
+
execSuccess: false
|
|
118
|
+
execError: Table 'wrong_table' doesn't exist
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**原因**:SQL 中的表名或字段名与实际不符
|
|
122
|
+
|
|
123
|
+
**解决方案**:
|
|
124
|
+
|
|
125
|
+
1. **先验证表结构**
|
|
126
|
+
```typescript
|
|
127
|
+
// 必须先获取表结构
|
|
128
|
+
const detail = await get_dataset_detail({
|
|
129
|
+
datasetCode: "users",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// 检查实际表名
|
|
133
|
+
console.log("表名:", detail.basic.tableName); // 使用实际的表名
|
|
134
|
+
|
|
135
|
+
// 检查字段名
|
|
136
|
+
const fieldCodes = detail.fields.map(f => f.code);
|
|
137
|
+
console.log可用字段:", fieldCodes);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
2. **验证 SQL 内容**
|
|
141
|
+
```typescript
|
|
142
|
+
// 验证 SQL 语法
|
|
143
|
+
const validation = await validate_sql_content({
|
|
144
|
+
sqlContent: `
|
|
145
|
+
SELECT id, name
|
|
146
|
+
FROM correct_table_name -- 使用实际的表名
|
|
147
|
+
WHERE status = 1
|
|
148
|
+
`,
|
|
149
|
+
dbId: detail.basic.database.dbId,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (!validation.validation.valid) {
|
|
153
|
+
console.log("SQL 错误:", validation.validation.errors);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
3. **修复并保存**
|
|
158
|
+
```typescript
|
|
159
|
+
// 使用正确的表名和字段名
|
|
160
|
+
const sqlContent = `
|
|
161
|
+
SELECT id, name
|
|
162
|
+
FROM users -- 实际表名
|
|
163
|
+
WHERE status = 1
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
await save_or_update_custom_sql({
|
|
167
|
+
sqlContent,
|
|
168
|
+
sqlCode: "user_list",
|
|
169
|
+
sqlName: "用户列表",
|
|
170
|
+
dbId: detail.basic.database.dbId,
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### 问题 5: SDK 返回错误
|
|
177
|
+
|
|
178
|
+
**现象**:
|
|
179
|
+
```typescript
|
|
180
|
+
try {
|
|
181
|
+
const user = await client.models.users.getOne(userId);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.log(error); // LovrabetError 对象
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**解决方案**:
|
|
188
|
+
|
|
189
|
+
1. **查看错误信息**
|
|
190
|
+
```typescript
|
|
191
|
+
if (error instanceof LovrabetError) {
|
|
192
|
+
console.error("业务错误:", error.message); // 业务错误信息
|
|
193
|
+
console.error("错误代码:", error.code); // 错误代码
|
|
194
|
+
console.error("HTTP状态:", error.status); // HTTP 状态码
|
|
195
|
+
console.error("服务端响应:", error.response); // 完整响应
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
2. **常见错误代码**
|
|
201
|
+
```
|
|
202
|
+
- "0000": 成功
|
|
203
|
+
- "API_ERROR": API 处理错误
|
|
204
|
+
- "AUTH_FAILED": 认证失败
|
|
205
|
+
- "PARAMETER_ERROR": 参数错误
|
|
206
|
+
- "PERMISSION_DENIED": 权限不足
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### 问题 6: 类型定义错误
|
|
212
|
+
|
|
213
|
+
**现象**:
|
|
214
|
+
```typescript
|
|
215
|
+
import { createClient } from '@lovrabet/sdk';
|
|
216
|
+
|
|
217
|
+
// 类型错误
|
|
218
|
+
const client = createClient({
|
|
219
|
+
appCode: "app-xxx",
|
|
220
|
+
models: {
|
|
221
|
+
users: {
|
|
222
|
+
tableName: "users",
|
|
223
|
+
datasetCode: "xxx",
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// ❌ 类型错误:类型不匹配
|
|
229
|
+
const user: User = await client.models.users.getOne(id);
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**解决方案**:
|
|
233
|
+
|
|
234
|
+
1. **定义正确的类型**
|
|
235
|
+
```typescript
|
|
236
|
+
// 定义与返回值匹配的类型
|
|
237
|
+
interface User {
|
|
238
|
+
id: string;
|
|
239
|
+
name: string;
|
|
240
|
+
email: string;
|
|
241
|
+
createdAt: string;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// 使用泛型
|
|
245
|
+
const user = await client.models.users.getOne<User>(id);
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
2. **使用 MCP 获取元数据**
|
|
249
|
+
```typescript
|
|
250
|
+
// 先获取数据集详情,确保类型正确
|
|
251
|
+
const detail = await get_dataset_detail({
|
|
252
|
+
datasetCode: "users",
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// 基于 fields 生成类型
|
|
256
|
+
interface User {
|
|
257
|
+
// 从 MCP 获取的字段动态生成类型
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const user = await client.models.users.getOne<User>(id);
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### 问题 7: AntD 样式问题
|
|
266
|
+
|
|
267
|
+
**现象**:
|
|
268
|
+
- 团队反馈:界面看起来不专业
|
|
269
|
+
- 需求文档中提到 "不要 AI 味道"
|
|
270
|
+
|
|
271
|
+
**解决方案**:
|
|
272
|
+
|
|
273
|
+
1. **检查清单**
|
|
274
|
+
- [ ] 没有 emoji
|
|
275
|
+
- [ ] 没有感叹号
|
|
276
|
+
- [ ] 文案简洁专业("保存"不是"保存吧!")
|
|
277
|
+
- [ ] 使用 AntD token 颜色
|
|
278
|
+
- [ ] 使用 @ant-design/icons
|
|
279
|
+
|
|
280
|
+
2. **代码示例**
|
|
281
|
+
```typescript
|
|
282
|
+
// ✅ 正确
|
|
283
|
+
<Button type="primary">保存</Button>
|
|
284
|
+
<Button danger>删除</Button>
|
|
285
|
+
<Message success>操作成功</Message>
|
|
286
|
+
<Modal title="确认删除">...</Modal>
|
|
287
|
+
<Empty description="暂无数据" />
|
|
288
|
+
|
|
289
|
+
// ❌ 错误(AI 常见错误)
|
|
290
|
+
<Button>保存!</Button>
|
|
291
|
+
<Message success="🎉 操作成功!"></Message>
|
|
292
|
+
<Modal title="确认删除?"><Icon type="question-circle" /></Modal>
|
|
293
|
+
<Empty description="还没有数据哦~"></Empty>
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## 🔧 排查工具
|
|
299
|
+
|
|
300
|
+
### 1. 检查 SDK 配置
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# 查看 SDK 初始化代码
|
|
304
|
+
cat src/api/client.ts
|
|
305
|
+
|
|
306
|
+
# 检查 appcode 配置
|
|
307
|
+
cat .lovrabetrc
|
|
308
|
+
|
|
309
|
+
# 检查 MCP 配置(IDE 不同,配置文件位置不同)
|
|
310
|
+
cat .cursor/mcp.json # Cursor
|
|
311
|
+
# 或
|
|
312
|
+
cat .claude/config.json # claude code
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### 2. 查看日志
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
# 查看 Lovrabet 日志
|
|
319
|
+
lovrabet logs
|
|
320
|
+
|
|
321
|
+
# 清空日志
|
|
322
|
+
lovrabet logs --clear
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### 3. 使用 MCP 工具验证
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
// 验证数据集是否存在
|
|
329
|
+
const datasets = await list_datasets();
|
|
330
|
+
const exists = datasets.datasets.some(d => d.code === "users");
|
|
331
|
+
|
|
332
|
+
// 验证字段是否存在
|
|
333
|
+
const detail = await get_dataset_detail({
|
|
334
|
+
datasetCode: "users",
|
|
335
|
+
});
|
|
336
|
+
const hasField = detail.fields.some(f => f.code === "email");
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### 4. 检查类型定义
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// 打印实际返回的数据结构
|
|
343
|
+
const user = await client.models.users.getOne("test-id");
|
|
344
|
+
console.log("实际返回:", JSON.stringify(user, null, 2));
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## 📋 检查清单
|
|
350
|
+
|
|
351
|
+
在提交代码前,确认:
|
|
352
|
+
|
|
353
|
+
### SDK 部分
|
|
354
|
+
- [ ] Filter 查询使用了操作符 (`$eq`, `$gte` 等)
|
|
355
|
+
- [ ] 参数名正确(`select` 不是 `fields`)
|
|
356
|
+
- [ ] 排序参数名正确(`orderBy` 不是 `sort`)
|
|
357
|
+
- [ ] 分页参数名正确(`currentPage`/`pageSize` 不是 `page`/`limit`)
|
|
358
|
+
- [ ] 添加了数据集和数据表注释
|
|
359
|
+
- [ ] 所有 SDK 调用都包含在 try-catch 中
|
|
360
|
+
|
|
361
|
+
### MCP 部分
|
|
362
|
+
- [ ] 创建 SQL 前验证表名和字段名
|
|
363
|
+
- - 使用 `get_dataset_detail` 获取表结构
|
|
364
|
+
- - 对比 SQL 内容与实际表结构
|
|
365
|
+
- [ ] 创建 SQL 时执行了所有 5 个步骤
|
|
366
|
+
- - 查询 → 生成 → 验证 → 保存 → 测试
|
|
367
|
+
- [ ] SQL 中只使用 SELECT 查询
|
|
368
|
+
- - 没有 INSERT/UPDATE/DELETE
|
|
369
|
+
|
|
370
|
+
### UI 部分
|
|
371
|
+
- [ ] 没有 emoji
|
|
372
|
+
- [ ] 没有感叹号
|
|
373
|
+
- [ ] 文案简洁专业
|
|
374
|
+
- [ ] 使用 AntD token 颜色
|
|
375
|
+
- [ ] 使用 @ant-design/icons(不是 emoji)
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## 🚨 常见错误速查表
|
|
380
|
+
|
|
381
|
+
| 错误现象 | 可能原因 | 解决方案 |
|
|
382
|
+
|---------|---------|---------|
|
|
383
|
+
| 查询无结果 | 忘记使用操作符 | `where: { status: { $eq: "active" } }` |
|
|
384
|
+
| 参数不正确 | 参数名错误 | `fields` → `select`,`sort` → `orderBy` |
|
|
385
|
+
| SQL 表不存在 | 表名或字段名错误 | 先用 `get_dataset_detail` 验证 |
|
|
386
|
+
| 认证失败 | Cookie 过期或 appcode 错误 | 运行 `lovrabet auth` 重新登录 |
|
|
387
|
+
| 类型错误 | 类型定义与实际返回值不匹配 | 使用 `getOne<类型>()` 泛型 |
|
|
388
|
+
| MCP 调用失败 | MCP 服务未配置 | 运行 `lovrabet mcp install <ide>` 配置 |
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## 🔗 获取帮助
|
|
393
|
+
|
|
394
|
+
### CLI 命令
|
|
395
|
+
```bash
|
|
396
|
+
lovrabet logs # 查看日志
|
|
397
|
+
lovrabet logs --clear # 清空日志
|
|
398
|
+
lovrabet auth # 重新登录
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### MCP 工具
|
|
402
|
+
```typescript
|
|
403
|
+
// 验证配置和数据集
|
|
404
|
+
const datasets = await list_datasets();
|
|
405
|
+
const detail = await get_dataset_detail({ datasetCode: "users" });
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### 开发者指南
|
|
409
|
+
```bash
|
|
410
|
+
# 查看 Filter 查询指南
|
|
411
|
+
cat .lovrabet/skill/.shared/guides/01-filter-query/guide.md
|
|
412
|
+
|
|
413
|
+
# 查看 MCP SQL 工作流指南
|
|
414
|
+
cat .lovrabet/skill/.shared/guides/02-mcp-sql-workflow/guide.md
|
|
415
|
+
|
|
416
|
+
# 查看 AntD 样式指南
|
|
417
|
+
cat .lovrabet/skill/.shared/guides/03-antd-style/guide.md
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
**记住**:
|
|
423
|
+
- 遇到问题先看日志:`lovrabet logs`
|
|
424
|
+
- 验证 SQL 前先验证表结构:`get_dataset_detail`
|
|
425
|
+
- 检查错误代码:`error.code`
|
|
426
|
+
- 使用 MCP 工具验证:`list_datasets`
|