mta-mcp 2.14.0 → 2.16.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/agents/_TEMPLATE.md +153 -0
- package/agents/flutter.agent.md +118 -155
- package/agents/i18n.agent.md +50 -105
- package/agents/logicflow.agent.md +55 -1525
- package/agents/vue3.agent.md +84 -248
- package/agents/wechat-miniprogram.agent.md +48 -950
- package/dist/index.js +391 -443
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/standards/core/mandatory-rules.md +103 -0
- package/standards/frameworks/flutter.md +78 -0
- package/standards/libraries/logicflow.md +1007 -0
- package/standards/troubleshooting-cases/flutter/textfield-vertical-centering.md +107 -0
- package/standards/workflows/design-restoration-guide.md +164 -0
- package/standards/workflows/problem-diagnosis.md +68 -0
- package/standards/workflows/textfield-centering-guide.md +157 -0
- package/templates/config-templates/agents-section.md +9 -0
- package/templates/config-templates/custom-section.md +6 -0
- package/templates/config-templates/header.md +29 -0
- package/templates/config-templates/workflow-minimal.md +44 -0
|
@@ -1,991 +1,89 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 微信小程序开发代理
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
5
|
-
|
|
6
|
-
## 🎯 适用场景
|
|
7
|
-
|
|
8
|
-
- 微信小程序项目开发
|
|
9
|
-
- 小程序组件开发
|
|
10
|
-
- 小程序性能优化
|
|
11
|
-
- 小程序架构设计
|
|
3
|
+
> 此 Agent 引导 AI 通过 MCP 工具获取 npm 包中的详细规范
|
|
4
|
+
> 版本: v3.0.0 | 最后更新: 2026-01-16
|
|
12
5
|
|
|
13
6
|
---
|
|
14
7
|
|
|
15
|
-
##
|
|
8
|
+
## 🔴 问题诊断优先(最高优先级)
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
### 开发页面时
|
|
10
|
+
**当用户描述任何问题时,必须首先调用:**
|
|
20
11
|
|
|
21
12
|
```
|
|
22
|
-
|
|
23
|
-
fileType: "js",
|
|
24
|
-
imports: ["wx"],
|
|
25
|
-
scenario: "小程序页面开发"
|
|
26
|
-
})
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### 开发组件时
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
get_relevant_standards({
|
|
33
|
-
fileType: "js",
|
|
34
|
-
imports: ["wx", "Component"],
|
|
35
|
-
scenario: "小程序组件开发"
|
|
36
|
-
})
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### 网络请求相关
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
get_relevant_standards({
|
|
43
|
-
scenario: "小程序网络请求"
|
|
44
|
-
})
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### 本地存储相关
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
get_relevant_standards({
|
|
51
|
-
scenario: "小程序本地存储"
|
|
52
|
-
})
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### 云开发相关 🆕
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
get_relevant_standards({
|
|
59
|
-
scenario: "小程序云开发"
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
# 或具体场景
|
|
63
|
-
get_relevant_standards({
|
|
64
|
-
scenario: "云函数开发"
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
get_relevant_standards({
|
|
68
|
-
scenario: "云数据库操作"
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
get_relevant_standards({
|
|
72
|
-
scenario: "云存储管理"
|
|
73
|
-
})
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## 🏗️ 项目架构
|
|
79
|
-
|
|
80
|
-
### 目录结构
|
|
81
|
-
|
|
82
|
-
```
|
|
83
|
-
miniprogram/
|
|
84
|
-
├── app.js # 小程序逻辑
|
|
85
|
-
├── app.json # 全局配置
|
|
86
|
-
├── app.wxss # 全局样式
|
|
87
|
-
├── pages/ # 页面目录
|
|
88
|
-
├── components/ # 组件目录
|
|
89
|
-
├── utils/ # 工具函数
|
|
90
|
-
├── api/ # API 管理
|
|
91
|
-
├── config/ # 配置文件
|
|
92
|
-
└── styles/ # 公共样式
|
|
13
|
+
troubleshoot({ problem: "用户描述的问题" })
|
|
93
14
|
```
|
|
94
15
|
|
|
95
16
|
---
|
|
96
17
|
|
|
97
|
-
##
|
|
98
|
-
|
|
99
|
-
### 1. 页面开发
|
|
18
|
+
## 📚 规范获取指引
|
|
100
19
|
|
|
101
|
-
|
|
20
|
+
**⚠️ 核心原则:开发小程序代码前,必须先获取规范!**
|
|
102
21
|
|
|
103
|
-
|
|
104
|
-
Page({
|
|
105
|
-
/**
|
|
106
|
-
* 页面的初始数据
|
|
107
|
-
*/
|
|
108
|
-
data: {
|
|
109
|
-
loading: false,
|
|
110
|
-
list: [],
|
|
111
|
-
page: 1,
|
|
112
|
-
hasMore: true
|
|
113
|
-
},
|
|
22
|
+
### 按场景获取
|
|
114
23
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// 初始化数据
|
|
122
|
-
this.fetchData()
|
|
123
|
-
},
|
|
24
|
+
| 场景 | MCP 调用 |
|
|
25
|
+
|------|----------|
|
|
26
|
+
| 页面开发 | `get_standard_by_id({ id: 'wechat-miniprogram' })` |
|
|
27
|
+
| 组件开发 | `get_standard_by_id({ id: 'wechat-miniprogram' })` |
|
|
28
|
+
| 网络请求 | `get_standard_by_id({ id: 'wechat-miniprogram' })` |
|
|
29
|
+
| 云开发 | `get_standard_by_id({ id: 'wechat-cloud' })` |
|
|
124
30
|
|
|
125
|
-
|
|
126
|
-
* 生命周期函数--监听页面显示
|
|
127
|
-
*/
|
|
128
|
-
onShow() {
|
|
129
|
-
// 页面显示时的逻辑
|
|
130
|
-
},
|
|
31
|
+
### 智能获取(推荐)
|
|
131
32
|
|
|
132
|
-
/**
|
|
133
|
-
* 页面相关事件处理函数--监听用户下拉动作
|
|
134
|
-
*/
|
|
135
|
-
onPullDownRefresh() {
|
|
136
|
-
this.setData({
|
|
137
|
-
page: 1,
|
|
138
|
-
list: []
|
|
139
|
-
})
|
|
140
|
-
this.fetchData().then(() => {
|
|
141
|
-
wx.stopPullDownRefresh()
|
|
142
|
-
})
|
|
143
|
-
},
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* 页面上拉触底事件的处理函数
|
|
147
|
-
*/
|
|
148
|
-
onReachBottom() {
|
|
149
|
-
if (!this.data.hasMore || this.data.loading) return
|
|
150
|
-
|
|
151
|
-
this.setData({
|
|
152
|
-
page: this.data.page + 1
|
|
153
|
-
})
|
|
154
|
-
this.fetchData()
|
|
155
|
-
},
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* 获取数据
|
|
159
|
-
*/
|
|
160
|
-
async fetchData() {
|
|
161
|
-
try {
|
|
162
|
-
this.setData({ loading: true })
|
|
163
|
-
|
|
164
|
-
const res = await api.getData({
|
|
165
|
-
page: this.data.page
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
this.setData({
|
|
169
|
-
list: this.data.page === 1
|
|
170
|
-
? res.data.list
|
|
171
|
-
: [...this.data.list, ...res.data.list],
|
|
172
|
-
hasMore: res.data.hasMore
|
|
173
|
-
})
|
|
174
|
-
} catch (error) {
|
|
175
|
-
console.error('获取数据失败:', error)
|
|
176
|
-
wx.showToast({
|
|
177
|
-
title: '加载失败',
|
|
178
|
-
icon: 'none'
|
|
179
|
-
})
|
|
180
|
-
} finally {
|
|
181
|
-
this.setData({ loading: false })
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
33
|
```
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
```javascript
|
|
192
|
-
Component({
|
|
193
|
-
/**
|
|
194
|
-
* 组件的属性列表
|
|
195
|
-
*/
|
|
196
|
-
properties: {
|
|
197
|
-
data: {
|
|
198
|
-
type: Object,
|
|
199
|
-
value: null,
|
|
200
|
-
observer(newVal, oldVal) {
|
|
201
|
-
if (newVal) {
|
|
202
|
-
this._processData(newVal)
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
},
|
|
206
|
-
|
|
207
|
-
size: {
|
|
208
|
-
type: String,
|
|
209
|
-
value: 'medium'
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* 组件的初始数据
|
|
215
|
-
*/
|
|
216
|
-
data: {
|
|
217
|
-
processedData: null
|
|
218
|
-
},
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* 组件的方法列表
|
|
222
|
-
*/
|
|
223
|
-
methods: {
|
|
224
|
-
/**
|
|
225
|
-
* 处理数据(私有方法)
|
|
226
|
-
*/
|
|
227
|
-
_processData(data) {
|
|
228
|
-
this.setData({
|
|
229
|
-
processedData: {
|
|
230
|
-
...data,
|
|
231
|
-
// 处理逻辑
|
|
232
|
-
}
|
|
233
|
-
})
|
|
234
|
-
},
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* 处理点击事件
|
|
238
|
-
*/
|
|
239
|
-
handleClick(e) {
|
|
240
|
-
const { id } = e.currentTarget.dataset
|
|
241
|
-
|
|
242
|
-
// 触发自定义事件
|
|
243
|
-
this.triggerEvent('itemclick', {
|
|
244
|
-
id
|
|
245
|
-
})
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* 组件生命周期
|
|
251
|
-
*/
|
|
252
|
-
lifetimes: {
|
|
253
|
-
attached() {
|
|
254
|
-
// 组件挂载时执行
|
|
255
|
-
},
|
|
256
|
-
|
|
257
|
-
detached() {
|
|
258
|
-
// 组件移除时执行
|
|
259
|
-
}
|
|
260
|
-
}
|
|
34
|
+
// 根据当前文件自动匹配
|
|
35
|
+
get_compact_standards({
|
|
36
|
+
currentFile: "pages/index/index.js",
|
|
37
|
+
imports: ["wx"]
|
|
261
38
|
})
|
|
262
39
|
```
|
|
263
40
|
|
|
264
|
-
### 3. WXML 模板规范
|
|
265
|
-
|
|
266
|
-
```xml
|
|
267
|
-
<!-- ✅ 标准模板结构 -->
|
|
268
|
-
<view class="container">
|
|
269
|
-
<!-- 加载状态 -->
|
|
270
|
-
<view wx:if="{{loading}}" class="loading">
|
|
271
|
-
<text>加载中...</text>
|
|
272
|
-
</view>
|
|
273
|
-
|
|
274
|
-
<!-- 内容 -->
|
|
275
|
-
<block wx:else>
|
|
276
|
-
<!-- 列表 - 必须添加 wx:key -->
|
|
277
|
-
<view
|
|
278
|
-
wx:for="{{list}}"
|
|
279
|
-
wx:key="id"
|
|
280
|
-
class="item"
|
|
281
|
-
data-id="{{item.id}}"
|
|
282
|
-
bindtap="handleItemClick"
|
|
283
|
-
>
|
|
284
|
-
<text>{{item.title}}</text>
|
|
285
|
-
</view>
|
|
286
|
-
|
|
287
|
-
<!-- 空状态 -->
|
|
288
|
-
<view wx:if="{{list.length === 0}}" class="empty">
|
|
289
|
-
<text>暂无数据</text>
|
|
290
|
-
</view>
|
|
291
|
-
</block>
|
|
292
|
-
</view>
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### 4. WXSS 样式规范
|
|
296
|
-
|
|
297
|
-
```css
|
|
298
|
-
/* ✅ 使用 CSS 变量 */
|
|
299
|
-
page {
|
|
300
|
-
--primary-color: #1aad19;
|
|
301
|
-
--text-color: #333;
|
|
302
|
-
--border-color: #e5e5e5;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/* ✅ BEM 命名 */
|
|
306
|
-
.user-card {
|
|
307
|
-
padding: 30rpx;
|
|
308
|
-
background: #fff;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
.user-card__avatar {
|
|
312
|
-
width: 100rpx;
|
|
313
|
-
height: 100rpx;
|
|
314
|
-
border-radius: 50%;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
.user-card__name {
|
|
318
|
-
font-size: 32rpx;
|
|
319
|
-
color: var(--text-color);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/* ✅ Flex 布局 */
|
|
323
|
-
.flex-row {
|
|
324
|
-
display: flex;
|
|
325
|
-
flex-direction: row;
|
|
326
|
-
align-items: center;
|
|
327
|
-
justify-content: space-between;
|
|
328
|
-
}
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
---
|
|
332
|
-
|
|
333
|
-
## 🌐 网络请求规范
|
|
334
|
-
|
|
335
|
-
### Request 封装
|
|
336
|
-
|
|
337
|
-
必须包含以下功能:
|
|
338
|
-
|
|
339
|
-
1. **统一的错误处理**
|
|
340
|
-
2. **Token 自动添加**
|
|
341
|
-
3. **Loading 状态管理**
|
|
342
|
-
4. **401 自动跳转登录**
|
|
343
|
-
5. **请求/响应拦截**
|
|
344
|
-
|
|
345
|
-
```javascript
|
|
346
|
-
// utils/request.js
|
|
347
|
-
function request(options) {
|
|
348
|
-
const {
|
|
349
|
-
url,
|
|
350
|
-
method = 'GET',
|
|
351
|
-
data = {},
|
|
352
|
-
needAuth = true,
|
|
353
|
-
showLoading = true
|
|
354
|
-
} = options
|
|
355
|
-
|
|
356
|
-
if (showLoading) {
|
|
357
|
-
wx.showLoading({ title: '加载中...', mask: true })
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return new Promise((resolve, reject) => {
|
|
361
|
-
const header = {
|
|
362
|
-
'content-type': 'application/json'
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// 添加 Token
|
|
366
|
-
if (needAuth) {
|
|
367
|
-
const token = wx.getStorageSync('token')
|
|
368
|
-
if (token) {
|
|
369
|
-
header['Authorization'] = `Bearer ${token}`
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
wx.request({
|
|
374
|
-
url: `${BASE_URL}${url}`,
|
|
375
|
-
method,
|
|
376
|
-
data,
|
|
377
|
-
header,
|
|
378
|
-
success: (res) => {
|
|
379
|
-
if (showLoading) wx.hideLoading()
|
|
380
|
-
|
|
381
|
-
if (res.statusCode === 200) {
|
|
382
|
-
if (res.data.code === 0) {
|
|
383
|
-
resolve(res.data)
|
|
384
|
-
} else {
|
|
385
|
-
wx.showToast({
|
|
386
|
-
title: res.data.message || '请求失败',
|
|
387
|
-
icon: 'none'
|
|
388
|
-
})
|
|
389
|
-
reject(new Error(res.data.message))
|
|
390
|
-
}
|
|
391
|
-
} else if (res.statusCode === 401) {
|
|
392
|
-
// 跳转登录
|
|
393
|
-
wx.redirectTo({ url: '/pages/login/login' })
|
|
394
|
-
reject(new Error('未授权'))
|
|
395
|
-
} else {
|
|
396
|
-
wx.showToast({
|
|
397
|
-
title: '网络请求失败',
|
|
398
|
-
icon: 'none'
|
|
399
|
-
})
|
|
400
|
-
reject(new Error('Network error'))
|
|
401
|
-
}
|
|
402
|
-
},
|
|
403
|
-
fail: (error) => {
|
|
404
|
-
if (showLoading) wx.hideLoading()
|
|
405
|
-
wx.showToast({
|
|
406
|
-
title: '网络连接失败',
|
|
407
|
-
icon: 'none'
|
|
408
|
-
})
|
|
409
|
-
reject(error)
|
|
410
|
-
}
|
|
411
|
-
})
|
|
412
|
-
})
|
|
413
|
-
}
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
---
|
|
417
|
-
|
|
418
|
-
## 💾 本地存储规范
|
|
419
|
-
|
|
420
|
-
### 存储封装
|
|
421
|
-
|
|
422
|
-
```javascript
|
|
423
|
-
// utils/storage.js
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* 同步设置存储
|
|
427
|
-
*/
|
|
428
|
-
function setStorageSync(key, value) {
|
|
429
|
-
try {
|
|
430
|
-
wx.setStorageSync(key, value)
|
|
431
|
-
return true
|
|
432
|
-
} catch (error) {
|
|
433
|
-
console.error('存储失败:', error)
|
|
434
|
-
return false
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* 同步获取存储
|
|
440
|
-
*/
|
|
441
|
-
function getStorageSync(key, defaultValue = null) {
|
|
442
|
-
try {
|
|
443
|
-
const value = wx.getStorageSync(key)
|
|
444
|
-
return value !== '' ? value : defaultValue
|
|
445
|
-
} catch (error) {
|
|
446
|
-
console.error('读取存储失败:', error)
|
|
447
|
-
return defaultValue
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
```
|
|
451
|
-
|
|
452
41
|
---
|
|
453
42
|
|
|
454
|
-
##
|
|
455
|
-
|
|
456
|
-
### 关键原则
|
|
457
|
-
|
|
458
|
-
1. **禁止硬编码本地图片路径** - 避免路径不存在导致错误
|
|
459
|
-
2. **优先使用 emoji/文字图标** - 无需加载资源,性能最优
|
|
460
|
-
3. **外部图片需要备用方案** - 网络请求可能失败
|
|
461
|
-
4. **占位图使用纯色背景** - 避免依赖外部服务
|
|
462
|
-
|
|
463
|
-
### 图标资源
|
|
464
|
-
|
|
465
|
-
```xml
|
|
466
|
-
<!-- ❌ 错误:硬编码本地路径 -->
|
|
467
|
-
<image src="/images/icons/search.png" />
|
|
468
|
-
<image src="/images/icons/cart.png" />
|
|
469
|
-
|
|
470
|
-
<!-- ✅ 正确:使用 emoji 图标 -->
|
|
471
|
-
<text class="icon">🔍</text> <!-- 搜索 -->
|
|
472
|
-
<text class="icon">🛒</text> <!-- 购物车 -->
|
|
473
|
-
<text class="icon">✅</text> <!-- 选中 -->
|
|
474
|
-
<text class="icon">⭕</text> <!-- 未选中 -->
|
|
475
|
-
|
|
476
|
-
/* CSS 样式 */
|
|
477
|
-
.icon {
|
|
478
|
-
font-size: 32rpx;
|
|
479
|
-
line-height: 1;
|
|
480
|
-
}
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
### 商品图片
|
|
484
|
-
|
|
485
|
-
```javascript
|
|
486
|
-
// ❌ 错误:直接使用外部图片
|
|
487
|
-
<image src="https://via.placeholder.com/400" />
|
|
488
|
-
|
|
489
|
-
// ✅ 正确:带备用方案
|
|
490
|
-
<image
|
|
491
|
-
src="{{product.image || 'https://dummyimage.com/400x400/f5f5f5/cccccc?text=Product'}}"
|
|
492
|
-
mode="aspectFill"
|
|
493
|
-
lazy-load
|
|
494
|
-
/>
|
|
495
|
-
|
|
496
|
-
// ✅ 更好:使用纯色背景 + 文字
|
|
497
|
-
.product-image {
|
|
498
|
-
background-color: #f5f5f5;
|
|
499
|
-
display: flex;
|
|
500
|
-
align-items: center;
|
|
501
|
-
justify-content: center;
|
|
502
|
-
color: #ccc;
|
|
503
|
-
}
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
### 横幅/Banner
|
|
43
|
+
## 🎯 快速提示
|
|
507
44
|
|
|
508
|
-
|
|
509
|
-
<!-- ❌ 错误:依赖外部图片资源 -->
|
|
510
|
-
<swiper>
|
|
511
|
-
<swiper-item wx:for="{{banners}}">
|
|
512
|
-
<image src="{{item.image}}" /> <!-- 可能加载失败 -->
|
|
513
|
-
</swiper-item>
|
|
514
|
-
</swiper>
|
|
45
|
+
> 以下是简要提示,**详细规范请通过上述 MCP 工具获取**
|
|
515
46
|
|
|
516
|
-
|
|
517
|
-
<view class="banner">
|
|
518
|
-
<text class="banner-title">🛒 美业商城</text>
|
|
519
|
-
<text class="banner-desc">精选美业服务</text>
|
|
520
|
-
</view>
|
|
521
|
-
|
|
522
|
-
/* CSS */
|
|
523
|
-
.banner {
|
|
524
|
-
background: linear-gradient(135deg, #ff6034 0%, #ee0a24 100%);
|
|
525
|
-
/* 无需加载图片,性能最优 */
|
|
526
|
-
}
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
---
|
|
530
|
-
|
|
531
|
-
## ☁️ 云开发规范 🆕
|
|
532
|
-
|
|
533
|
-
### 1. 环境初始化
|
|
534
|
-
|
|
535
|
-
```javascript
|
|
536
|
-
// app.js
|
|
537
|
-
App({
|
|
538
|
-
onLaunch() {
|
|
539
|
-
// ✅ 正确:先检查再初始化
|
|
540
|
-
if (!wx.cloud) {
|
|
541
|
-
console.error('请使用 2.2.3 或以上的基础库以使用云能力')
|
|
542
|
-
return
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
try {
|
|
546
|
-
wx.cloud.init({
|
|
547
|
-
env: 'your-env-id', // 从配置文件读取
|
|
548
|
-
traceUser: true
|
|
549
|
-
})
|
|
550
|
-
console.log('云开发初始化成功')
|
|
551
|
-
} catch (error) {
|
|
552
|
-
console.error('云开发初始化失败:', error)
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
})
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
### 2. 数据库错误处理 ⚠️
|
|
559
|
-
|
|
560
|
-
```javascript
|
|
561
|
-
// ✅ 正确:检测数据库集合是否存在
|
|
562
|
-
async fetchData() {
|
|
563
|
-
try {
|
|
564
|
-
const db = wx.cloud.database()
|
|
565
|
-
const res = await db.collection('products').get()
|
|
566
|
-
this.setData({ data: res.data })
|
|
567
|
-
} catch (error) {
|
|
568
|
-
console.error('查询失败:', error)
|
|
569
|
-
|
|
570
|
-
// ⚠️ 关键:检测集合不存在错误
|
|
571
|
-
if (error.errCode === -502005 ||
|
|
572
|
-
error.message?.includes('collection not exists')) {
|
|
573
|
-
wx.showModal({
|
|
574
|
-
title: '数据库未初始化',
|
|
575
|
-
content: '请先在云开发控制台创建数据库集合',
|
|
576
|
-
confirmText: '查看教程',
|
|
577
|
-
success: (res) => {
|
|
578
|
-
if (res.confirm) {
|
|
579
|
-
// 跳转到配置引导页
|
|
580
|
-
wx.navigateTo({ url: '/pages/setup/setup' })
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
})
|
|
584
|
-
} else {
|
|
585
|
-
wx.showToast({ title: '加载失败', icon: 'none' })
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// ⚠️ 关键:清空旧数据,避免显示错误内容
|
|
589
|
-
if (this.data.page === 1) {
|
|
590
|
-
this.setData({ data: [] })
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
### 3. 云数据库封装
|
|
597
|
-
|
|
598
|
-
```javascript
|
|
599
|
-
// utils/cloudDB.js
|
|
600
|
-
class CloudDB {
|
|
601
|
-
constructor(collectionName) {
|
|
602
|
-
this.db = wx.cloud.database()
|
|
603
|
-
this.collection = this.db.collection(collectionName)
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* 查询列表(带错误处理)
|
|
608
|
-
*/
|
|
609
|
-
async getList(options = {}) {
|
|
610
|
-
try {
|
|
611
|
-
const { page = 1, pageSize = 20, where = {} } = options
|
|
612
|
-
|
|
613
|
-
// 分页查询
|
|
614
|
-
const res = await this.collection
|
|
615
|
-
.where(where)
|
|
616
|
-
.skip((page - 1) * pageSize)
|
|
617
|
-
.limit(pageSize)
|
|
618
|
-
.get()
|
|
619
|
-
|
|
620
|
-
return {
|
|
621
|
-
data: res.data,
|
|
622
|
-
hasMore: res.data.length === pageSize
|
|
623
|
-
}
|
|
624
|
-
} catch (error) {
|
|
625
|
-
console.error('查询列表失败:', error)
|
|
626
|
-
throw error // 向上抛出,由调用者处理
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
module.exports = { CloudDB }
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
### 4. 云函数开发
|
|
635
|
-
|
|
636
|
-
```javascript
|
|
637
|
-
// cloudfunctions/xxx/index.js
|
|
638
|
-
const cloud = require('wx-server-sdk')
|
|
639
|
-
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
|
|
640
|
-
|
|
641
|
-
exports.main = async (event, context) => {
|
|
642
|
-
const { OPENID } = cloud.getWXContext()
|
|
643
|
-
|
|
644
|
-
try {
|
|
645
|
-
const db = cloud.database()
|
|
646
|
-
|
|
647
|
-
// ✅ 关键:服务端验证数据
|
|
648
|
-
const { productId, price } = event
|
|
649
|
-
|
|
650
|
-
// 验证价格(防止客户端篡改)
|
|
651
|
-
const product = await db.collection('products')
|
|
652
|
-
.doc(productId)
|
|
653
|
-
.get()
|
|
654
|
-
|
|
655
|
-
if (product.data.price !== price) {
|
|
656
|
-
return {
|
|
657
|
-
success: false,
|
|
658
|
-
message: '价格不匹配'
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// 创建订单
|
|
663
|
-
const result = await db.collection('orders').add({
|
|
664
|
-
data: {
|
|
665
|
-
_openid: OPENID,
|
|
666
|
-
productId,
|
|
667
|
-
price,
|
|
668
|
-
createTime: new Date()
|
|
669
|
-
}
|
|
670
|
-
})
|
|
671
|
-
|
|
672
|
-
return {
|
|
673
|
-
success: true,
|
|
674
|
-
orderId: result._id
|
|
675
|
-
}
|
|
676
|
-
} catch (error) {
|
|
677
|
-
console.error('云函数执行失败:', error)
|
|
678
|
-
return {
|
|
679
|
-
success: false,
|
|
680
|
-
message: error.message
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
---
|
|
687
|
-
|
|
688
|
-
## 🎯 性能优化原则
|
|
689
|
-
|
|
690
|
-
### 1. setData 优化
|
|
691
|
-
|
|
692
|
-
```javascript
|
|
693
|
-
// ❌ 错误:频繁调用
|
|
694
|
-
for (let i = 0; i < items.length; i++) {
|
|
695
|
-
this.setData({
|
|
696
|
-
[`items[${i}]`]: items[i]
|
|
697
|
-
})
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
// ✅ 正确:合并更新
|
|
701
|
-
this.setData({
|
|
702
|
-
items: items
|
|
703
|
-
})
|
|
704
|
-
|
|
705
|
-
// ✅ 正确:局部更新
|
|
706
|
-
this.setData({
|
|
707
|
-
[`items[${index}].name`]: newName
|
|
708
|
-
})
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
### 2. 列表渲染优化
|
|
712
|
-
|
|
713
|
-
```xml
|
|
714
|
-
<!-- ✅ 图片懒加载 -->
|
|
715
|
-
<image src="{{item.image}}" lazy-load mode="aspectFill" />
|
|
716
|
-
|
|
717
|
-
<!-- ✅ 长列表分页 -->
|
|
718
|
-
<scroll-view
|
|
719
|
-
scroll-y
|
|
720
|
-
bindscrolltolower="onReachBottom"
|
|
721
|
-
lower-threshold="100"
|
|
722
|
-
>
|
|
723
|
-
<view wx:for="{{list}}" wx:key="id">
|
|
724
|
-
{{item.name}}
|
|
725
|
-
</view>
|
|
726
|
-
</scroll-view>
|
|
727
|
-
```
|
|
728
|
-
|
|
729
|
-
### 3. 代码分包
|
|
730
|
-
|
|
731
|
-
```json
|
|
732
|
-
{
|
|
733
|
-
"subpackages": [
|
|
734
|
-
{
|
|
735
|
-
"root": "packageA",
|
|
736
|
-
"pages": [
|
|
737
|
-
"pages/detail/detail"
|
|
738
|
-
]
|
|
739
|
-
}
|
|
740
|
-
],
|
|
741
|
-
"preloadRule": {
|
|
742
|
-
"pages/index/index": {
|
|
743
|
-
"network": "all",
|
|
744
|
-
"packages": ["packageA"]
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
```
|
|
749
|
-
|
|
750
|
-
---
|
|
751
|
-
|
|
752
|
-
## 🔐 安全规范
|
|
753
|
-
|
|
754
|
-
### 1. 敏感信息处理
|
|
755
|
-
|
|
756
|
-
```javascript
|
|
757
|
-
// ❌ 禁止:明文存储密码
|
|
758
|
-
wx.setStorageSync('password', '123456')
|
|
759
|
-
|
|
760
|
-
// ✅ 正确:加密存储
|
|
761
|
-
const encrypted = encrypt(password, key)
|
|
762
|
-
wx.setStorageSync('password', encrypted)
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
### 2. XSS 防护
|
|
766
|
-
|
|
767
|
-
```javascript
|
|
768
|
-
// ✅ 转义用户输入
|
|
769
|
-
function escapeHtml(text) {
|
|
770
|
-
const map = {
|
|
771
|
-
'&': '&',
|
|
772
|
-
'<': '<',
|
|
773
|
-
'>': '>',
|
|
774
|
-
'"': '"',
|
|
775
|
-
"'": '''
|
|
776
|
-
}
|
|
777
|
-
return text.replace(/[&<>"']/g, (m) => map[m])
|
|
778
|
-
}
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
### 3. 接口鉴权
|
|
782
|
-
|
|
783
|
-
```javascript
|
|
784
|
-
// ✅ Token 机制
|
|
785
|
-
// 1. 登录时保存 Token
|
|
786
|
-
wx.setStorageSync('token', res.data.token)
|
|
787
|
-
|
|
788
|
-
// 2. 请求时自动添加
|
|
789
|
-
header['Authorization'] = `Bearer ${token}`
|
|
790
|
-
|
|
791
|
-
// 3. 401 时跳转登录
|
|
792
|
-
if (res.statusCode === 401) {
|
|
793
|
-
wx.redirectTo({ url: '/pages/login/login' })
|
|
794
|
-
}
|
|
795
|
-
```
|
|
796
|
-
|
|
797
|
-
---
|
|
798
|
-
|
|
799
|
-
## 📱 用户体验规范
|
|
800
|
-
|
|
801
|
-
### 1. 加载状态
|
|
802
|
-
|
|
803
|
-
```javascript
|
|
804
|
-
// ✅ 所有异步操作显示 loading
|
|
805
|
-
async fetchData() {
|
|
806
|
-
try {
|
|
807
|
-
this.setData({ loading: true })
|
|
808
|
-
const res = await api.getData()
|
|
809
|
-
// 处理数据...
|
|
810
|
-
} catch (error) {
|
|
811
|
-
wx.showToast({ title: '加载失败', icon: 'none' })
|
|
812
|
-
} finally {
|
|
813
|
-
this.setData({ loading: false })
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
```
|
|
817
|
-
|
|
818
|
-
### 2. 错误提示
|
|
819
|
-
|
|
820
|
-
```javascript
|
|
821
|
-
// ✅ 清晰的错误信息
|
|
822
|
-
wx.showToast({
|
|
823
|
-
title: '操作失败,请重试',
|
|
824
|
-
icon: 'none',
|
|
825
|
-
duration: 2000
|
|
826
|
-
})
|
|
827
|
-
|
|
828
|
-
// ✅ 确认对话框
|
|
829
|
-
wx.showModal({
|
|
830
|
-
title: '提示',
|
|
831
|
-
content: '确认删除这条记录吗?',
|
|
832
|
-
confirmColor: '#ff4444',
|
|
833
|
-
success: (res) => {
|
|
834
|
-
if (res.confirm) {
|
|
835
|
-
this.handleDelete()
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
})
|
|
839
|
-
```
|
|
840
|
-
|
|
841
|
-
### 3. 空状态
|
|
47
|
+
### 目录结构
|
|
842
48
|
|
|
843
|
-
```xml
|
|
844
|
-
<!-- ✅ 无数据时显示空状态 -->
|
|
845
|
-
<view wx:if="{{list.length === 0 && !loading}}" class="empty">
|
|
846
|
-
<image src="/images/empty.png" class="empty-image" />
|
|
847
|
-
<text class="empty-text">暂无数据</text>
|
|
848
|
-
</view>
|
|
849
49
|
```
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
```javascript
|
|
858
|
-
// ❌ 直接修改 data
|
|
859
|
-
this.data.count = 10
|
|
860
|
-
|
|
861
|
-
// ✅ 使用 setData
|
|
862
|
-
this.setData({ count: 10 })
|
|
863
|
-
|
|
864
|
-
// ❌ 没有错误处理
|
|
865
|
-
async fetchData() {
|
|
866
|
-
const res = await api.getData()
|
|
867
|
-
this.setData({ data: res.data })
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
// ✅ 完善的错误处理
|
|
871
|
-
async fetchData() {
|
|
872
|
-
try {
|
|
873
|
-
const res = await api.getData()
|
|
874
|
-
this.setData({ data: res.data })
|
|
875
|
-
} catch (error) {
|
|
876
|
-
console.error('获取数据失败:', error)
|
|
877
|
-
wx.showToast({ title: '加载失败', icon: 'none' })
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
// ❌ 错误:在 catch 块中引用未定义的变量
|
|
882
|
-
async fetchData() {
|
|
883
|
-
try {
|
|
884
|
-
const { page } = this.data // page 只在 try 块中
|
|
885
|
-
// ...
|
|
886
|
-
} catch (error) {
|
|
887
|
-
if (page === 1) { // ❌ ReferenceError: page is not defined
|
|
888
|
-
this.setData({ data: [] })
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
// ✅ 正确:使用 this.data 访问
|
|
894
|
-
async fetchData() {
|
|
895
|
-
try {
|
|
896
|
-
const { page } = this.data
|
|
897
|
-
// ...
|
|
898
|
-
} catch (error) {
|
|
899
|
-
if (this.data.page === 1) { // ✅ 正确
|
|
900
|
-
this.setData({ data: [] })
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
50
|
+
miniprogram/
|
|
51
|
+
├── app.js / app.json / app.wxss
|
|
52
|
+
├── pages/ # 页面目录
|
|
53
|
+
├── components/ # 组件目录
|
|
54
|
+
├── utils/ # 工具函数
|
|
55
|
+
├── api/ # API 管理
|
|
56
|
+
└── config/ # 配置文件
|
|
904
57
|
```
|
|
905
58
|
|
|
906
|
-
###
|
|
907
|
-
|
|
908
|
-
```javascript
|
|
909
|
-
// ❌ setData 过于频繁
|
|
910
|
-
for (let i = 0; i < 100; i++) {
|
|
911
|
-
this.setData({ count: i })
|
|
912
|
-
}
|
|
59
|
+
### 必须遵守
|
|
913
60
|
|
|
914
|
-
|
|
915
|
-
|
|
61
|
+
- ✅ 使用 Component 构建自定义组件
|
|
62
|
+
- ✅ 合理使用 setData(避免频繁调用)
|
|
63
|
+
- ✅ 异步操作使用 Promise 封装
|
|
64
|
+
- ✅ 遵循小程序生命周期
|
|
916
65
|
|
|
917
|
-
|
|
918
|
-
this.setData({
|
|
919
|
-
hugeObject: entireObject // 包含很多不需要的字段
|
|
920
|
-
})
|
|
66
|
+
### 禁止
|
|
921
67
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
name: object.name
|
|
927
|
-
}
|
|
928
|
-
})
|
|
929
|
-
```
|
|
68
|
+
- ❌ 直接操作 DOM
|
|
69
|
+
- ❌ 同步阻塞操作
|
|
70
|
+
- ❌ setData 传递大量数据
|
|
71
|
+
- ❌ 未处理的 Promise reject
|
|
930
72
|
|
|
931
73
|
---
|
|
932
74
|
|
|
933
|
-
##
|
|
934
|
-
|
|
935
|
-
### 开发规范
|
|
75
|
+
## 📋 可用规范列表
|
|
936
76
|
|
|
937
|
-
|
|
938
|
-
2. **命名规范** - 使用 kebab-case/camelCase
|
|
939
|
-
3. **代码注释** - 为复杂逻辑添加注释
|
|
940
|
-
4. **错误处理** - 所有异步操作都有 try-catch
|
|
941
|
-
5. **用户反馈** - 操作结果有明确提示
|
|
942
|
-
|
|
943
|
-
### 资源管理 🆕
|
|
944
|
-
|
|
945
|
-
1. **禁止硬编码本地图片路径** - 避免 404 错误
|
|
946
|
-
2. **优先使用 emoji** - 无需加载,性能最优
|
|
947
|
-
3. **纯色背景替代图片** - CSS 渐变替代轮播图
|
|
948
|
-
4. **图片加载失败处理** - 提供备用方案
|
|
949
|
-
|
|
950
|
-
### 云开发规范 🆕
|
|
951
|
-
|
|
952
|
-
1. **环境初始化检查** - 检测 wx.cloud 是否可用
|
|
953
|
-
2. **数据库集合检测** - errCode -502005 特殊处理
|
|
954
|
-
3. **友好错误提示** - 引导用户配置数据库
|
|
955
|
-
4. **服务端数据验证** - 云函数中验证价格/库存
|
|
956
|
-
5. **清空错误数据** - 失败后清空旧数据
|
|
957
|
-
|
|
958
|
-
### 变量作用域 🆕
|
|
959
|
-
|
|
960
|
-
1. **异步函数中避免使用局部变量** - 在 catch 中使用 this.data
|
|
961
|
-
2. **解构赋值注意作用域** - const { page } 只在当前块有效
|
|
962
|
-
3. **避免变量覆盖** - 不要在内层作用域重新声明同名变量
|
|
963
|
-
|
|
964
|
-
### 性能优化
|
|
965
|
-
|
|
966
|
-
1. **setData 优化** - 减少调用频率,控制数据大小
|
|
967
|
-
2. **列表优化** - 长列表使用分页或虚拟列表
|
|
968
|
-
3. **图片优化** - 使用 lazy-load,压缩图片
|
|
969
|
-
4. **代码分包** - 合理使用分包和预加载
|
|
970
|
-
|
|
971
|
-
### 安全规范
|
|
972
|
-
|
|
973
|
-
1. **敏感信息** - 加密存储,不明文传输
|
|
974
|
-
2. **XSS 防护** - 转义用户输入
|
|
975
|
-
3. **接口鉴权** - Token 验证,刷新机制
|
|
976
|
-
4. **HTTPS** - 所有接口使用 HTTPS
|
|
977
|
-
|
|
978
|
-
---
|
|
77
|
+
通过 `get_standard_by_id({ id: 'xxx' })` 获取:
|
|
979
78
|
|
|
980
|
-
|
|
79
|
+
**核心规范**
|
|
80
|
+
- `wechat-miniprogram` - 小程序完整开发规范
|
|
981
81
|
|
|
982
|
-
|
|
983
|
-
-
|
|
984
|
-
-
|
|
985
|
-
- [小程序安全指南](https://developers.weixin.qq.com/miniprogram/dev/framework/security.html)
|
|
82
|
+
**配套规范**
|
|
83
|
+
- `api-layer` - API 层封装模式
|
|
84
|
+
- `component-design` - 组件设计模式
|
|
986
85
|
|
|
987
86
|
---
|
|
988
87
|
|
|
989
88
|
**维护团队**: MTA工作室
|
|
990
|
-
|
|
991
|
-
**更新日期**: 2025-12-17
|
|
89
|
+
**设计理念**: Agent 只提供获取指引,详细规范由 MCP 工具从 npm 包动态获取
|