提交代码

This commit is contained in:
zlwu committed 2025-10-24 22:21:01 +08:00
1 parent a0e5c9a024
commit e97c97aa0b
2 files changed
-613

No files matched your search

-413
View File
@@ -1,413 +0,0 @@
# 移动端API调用标准规范
> 📌 **重要提示**: 移动端与Web端的API调用方式完全不同,请严格遵守本规范!
## 🚫 常见错误
### ❌ 不要这样做(Web端方式)
```javascript
// 错误1:使用 this.$http
const res = await this.$http.get('/api/path');
const res = await this.$http.post('/api/path', data);
const res = await this.$http.upload('/api/upload', options);
// 错误2:使用 getDicts
import { getDicts } from '@/api/system/dict/data.js';
const res = await getDicts('dict_type');
this.dictData = res.data; // Web端返回格式
// 错误3:使用 this.$u.toast
this.$u.toast('提示信息');
```
## ✅ 正确做法(移动端方式)
### 1. HTTP请求
```javascript
// 导入
import { request } from '@/common/request.js';
// GET请求(无参数)
const res = await request({
url: '/api/path',
method: 'GET',
});
// GET请求(带参数)
const res = await request({
url: '/api/path',
method: 'GET',
params: {
key1: 'value1',
key2: 'value2'
},
});
// POST请求
const res = await request({
url: '/api/path',
method: 'POST',
data: {
key1: 'value1',
key2: 'value2'
},
});
// PUT请求
const res = await request({
url: '/api/path',
method: 'PUT',
data: { ... },
});
// DELETE请求
const res = await request({
url: '/api/path',
method: 'DELETE',
});
```
### 2. 字典数据获取
```javascript
// 导入
import { getDict, getDictLabel, getDictTagType } from '@/common/dict.js';
// 获取字典数据(直接返回数组)
const dictData = await getDict('dict_type'); // 返回: [{label, value, ...}, ...]
// 批量获取字典
const [dict1, dict2] = await Promise.all([
getDict('dict_type_1'),
getDict('dict_type_2'),
]);
// 获取字典标签
const label = getDictLabel(dictData, '1'); // 返回: '标签名'
// 获取字典Tag类型(用于u-tag组件)
const tagType = getDictTagType(dictData, '1'); // 返回: 'success', 'warning', 'error' 等
```
### 3. 字典展示(u-tag)
```vue
<template>
<!-- 基础用法 -->
<u-tag :type="getDictTagType(xg_dict_type, value)">
{{ getDictLabel(xg_dict_type, value) }}
</u-tag>
<!-- 带降级处理 -->
<u-tag :type="getDictTagType(xg_dict_type, value, tagTypeFallback)">
{{ getDictLabel(xg_dict_type, value) }}
</u-tag>
<!-- 选择器显示 -->
<u-picker
:show="showPicker"
:columns="dictColumns"
keyName="text"
@confirm="handleConfirm"
@cancel="showPicker = false"
></u-picker>
</template>
<script>
import { getDict, getDictLabel, getDictTagType } from '@/common/dict.js';
export default {
data() {
return {
xg_dict_type: [],
value: '1',
showPicker: false,
// 降级映射(当字典未加载时使用)
tagTypeFallback: {
'1': 'success',
'2': 'warning',
'3': 'error',
},
};
},
computed: {
// 转换为选择器格式
dictColumns() {
return [
this.xg_dict_type.map(item => ({
text: item.label,
value: item.value,
}))
];
},
},
async mounted() {
// 加载字典
this.xg_dict_type = await getDict('xg_dict_type');
},
methods: {
getDictLabel,
getDictTagType,
handleConfirm(e) {
if (e && e.value && e.value.length > 0) {
this.value = e.value[0].value;
}
this.showPicker = false;
},
},
};
</script>
```
### 4. 文件上传
```javascript
// 导入
import { uploadFile } from '@/utils/upload.js';
// 选择并上传图片
uni.chooseImage({
count: 1,
success: async (res) => {
const filePath = res.tempFilePaths[0];
// 上传文件
const result = await uploadFile(filePath, (progress) => {
console.log('上传进度:', progress);
// 更新进度条
this.uploadProgress = progress;
});
if (result && result.code === 200 && result.data) {
// 上传成功
this.ossId = result.data.ossId;
this.fileUrl = result.data.url;
}
}
});
```
### 5. Toast提示
```javascript
// 普通提示
uni.showToast({
title: '提示信息',
icon: 'none'
});
// 成功提示
uni.showToast({
title: '操作成功',
icon: 'success'
});
// 失败提示
uni.showToast({
title: '操作失败',
icon: 'error'
});
// 加载中
uni.showLoading({
title: '加载中...',
mask: true
});
// 关闭加载
uni.hideLoading();
```
## 📊 完整示例
```vue
<template>
<view class="page-container">
<!-- 字典展示 -->
<u-tag :type="getDictTagType(xg_status_dict, formData.status)">
{{ getDictLabel(xg_status_dict, formData.status) }}
</u-tag>
<!-- 字典选择器 -->
<u-form-item label="状态" prop="status">
<view @click="showStatusPicker = true">
<u-input
:value="getDictLabel(xg_status_dict, formData.status)"
placeholder="请选择状态"
readonly
suffix-icon="arrow-down"
/>
</view>
<u-picker
:show="showStatusPicker"
:columns="statusColumns"
keyName="text"
@confirm="handleStatusConfirm"
@cancel="showStatusPicker = false"
></u-picker>
</u-form-item>
<!-- 提交按钮 -->
<u-button type="primary" @click="handleSubmit">提交</u-button>
</view>
</template>
<script>
import { request } from '@/common/request.js';
import { getDict, getDictLabel, getDictTagType } from '@/common/dict.js';
import { uploadFile } from '@/utils/upload.js';
export default {
data() {
return {
formData: {
title: '',
status: '1',
},
xg_status_dict: [],
showStatusPicker: false,
};
},
computed: {
statusColumns() {
return [
this.xg_status_dict.map(item => ({
text: item.label,
value: item.value,
}))
];
},
},
async mounted() {
await this.init();
},
methods: {
getDictLabel,
getDictTagType,
async init() {
// 加载字典
this.xg_status_dict = await getDict('xg_status');
// 加载数据
await this.loadData();
},
async loadData() {
try {
const res = await request({
url: '/api/getData',
method: 'GET',
params: { id: this.id },
});
if (res.code === 200) {
this.formData = res.data;
}
} catch (error) {
console.error('加载数据失败:', error);
uni.showToast({
title: '加载失败',
icon: 'none'
});
}
},
handleStatusConfirm(e) {
if (e && e.value && e.value.length > 0) {
this.formData.status = e.value[0].value;
}
this.showStatusPicker = false;
},
async handleSubmit() {
try {
uni.showLoading({ title: '提交中...', mask: true });
const res = await request({
url: '/api/submit',
method: 'POST',
data: this.formData,
});
uni.hideLoading();
if (res.code === 200) {
uni.showToast({
title: '提交成功',
icon: 'success'
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({
title: res.msg || '提交失败',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
console.error('提交失败:', error);
uni.showToast({
title: '提交失败',
icon: 'error'
});
}
},
},
};
</script>
```
## 🔑 核心差异对照表
| 功能 | Web端 | 移动端 |
|------|-------|--------|
| **HTTP请求** | `this.$http.get('/api')` | `request({ url: '/api', method: 'GET' })` |
| **字典获取** | `getDicts('type')` 返回 `{data:[]}` | `getDict('type')` 返回 `[...]` |
| **字典标签** | `selectDictLabel(dict, value)` | `getDictLabel(dict, value)` |
| **Tag类型** | 手动映射 | `getDictTagType(dict, value)` |
| **文件上传** | `this.$http.upload()` | `uploadFile(path, callback)` |
| **Toast提示** | `this.$u.toast('msg')` | `uni.showToast({ title: 'msg' })` |
| **加载提示** | `this.$u.loading.show()` | `uni.showLoading({ title: '...' })` |
## 📝 注意事项
1. **导入路径固定**:
- HTTP请求: `@/common/request.js`
- 字典方法: `@/common/dict.js`
- 文件上传: `@/utils/upload.js`
2. **字典数据格式**:
- 移动端 `getDict()` 直接返回数组,不需要 `.data`
- 字典项格式: `{ label, value, elTagType, elTagClass, remark }`
3. **Tag类型自动转换**:
- `danger` → `error`
- `default` → `primary`
4. **文件上传进度**:
- 进度回调返回 0-100 的数字
- Web端可能是 `progress.progress`,移动端直接是数字
5. **错误处理**:
- 统一使用 `try-catch`
- 错误时使用 `uni.showToast` 提示
## 🔗 相关文档
- `mobile/src/common/request.js` - HTTP请求源码
- `mobile/src/common/dict.js` - 字典方法源码
- `mobile/src/utils/upload.js` - 文件上传源码
- `.cursor/cursorrules-mobile.md` - 移动端开发规范
---
**最后更新**: 2025-01-24
**适用范围**: 移动端工程(Vue 2.6.14 + uni-app 2.x)
-200
View File
@@ -1,200 +0,0 @@
# 移动端字典工具使用指南
## 📋 简介
为移动端(Vue 2.6.14 + uni-app 2.x)提供完整的字典数据获取和管理功能,与web端保持一致的API设计。
## 🚀 快速开始
### 1. 基础导入
```javascript
import { useDict, getDict, getDictLabel } from '@/common/dict.js'
```
### 2. 在页面中使用
```javascript
export default {
data() {
return {
dictionaries: {},
userInfo: {
gender: '0',
status: '1'
}
}
},
created() {
this.loadDictionaries()
},
methods: {
async loadDictionaries() {
// 批量加载字典
const dictManager = useDict('sys_user_sex', 'sys_normal_disable')
// Vue 2响应式更新(必须设置)
dictManager.setUpdateCallback((dictType, data) => {
this.$set(this.dictionaries, dictType, data)
})
},
// 获取字典标签显示
getDictText(dictType, value) {
const dictData = this.dictionaries[dictType] || []
return getDictLabel(dictData, value)
}
}
}
```
### 3. 在模板中显示
```vue
<template>
<view>
<!-- 显示用户性别 -->
<text>性别: {{ getDictText('sys_user_sex', userInfo.gender) }}</text>
<!-- 显示用户状态 -->
<text>状态: {{ getDictText('sys_normal_disable', userInfo.status) }}</text>
</view>
</template>
```
## 📚 主要功能
| 功能 | 方法 | 说明 |
|------|------|------|
| 批量字典管理 | `useDict(...types)` | 推荐使用,支持多字典并发加载 |
| 单个字典获取 | `getDict(type, cache?)` | 获取单个字典数据 |
| 字典标签获取 | `getDictLabel(data, value)` | 根据值获取标签 |
| 字典值获取 | `getDictValue(data, label)` | 根据标签获取值 |
| 值存在检查 | `hasDictValue(data, value)` | 检查值是否存在 |
| 缓存刷新 | `refreshDict(types)` | 刷新指定字典缓存 |
## 🎯 使用场景
### 场景1: uview组件集成
```javascript
// radio-group
<u-radio-group v-model="form.gender">
<u-radio
v-for="item in dictionaries.sys_user_sex"
:key="item.value"
:name="item.value"
>
{{ item.label }}
</u-radio>
</u-radio-group>
// select组件
computed: {
selectOptions() {
return (this.dictionaries.sys_user_sex || []).map(item => ({
value: item.value,
label: item.label
}))
}
}
```
### 场景2: 表格数据转换
```javascript
computed: {
processedData() {
return this.tableData.map(row => ({
...row,
genderText: getDictLabel(this.dictionaries.sys_user_sex || [], row.gender),
statusText: getDictLabel(this.dictionaries.sys_normal_disable || [], row.status)
}))
}
}
```
### 场景3: 单独获取字典
```javascript
async methods: {
async loadSingleDict() {
try {
const genderDict = await getDict('sys_user_sex')
console.log('性别字典:', genderDict)
} catch (error) {
console.error('加载失败:', error)
}
}
}
```
## ⚡ 性能特性
- **智能缓存**: 24小时有效期,自动管理
- **并发加载**: 多字典同时请求,提升加载速度
- **响应式更新**: 完美适配Vue 2响应式系统
- **错误处理**: 完善的错误处理和兜底机制
## 🔧 高级用法
### 缓存管理
```javascript
import { dictCache, refreshDict } from '@/common/dict.js'
// 清除指定缓存
dictCache.remove('sys_user_sex')
// 清除所有缓存
dictCache.clear()
// 刷新缓存
await refreshDict(['sys_user_sex', 'sys_normal_disable'])
```
### 错误处理
```javascript
// 安全的字典获取(带默认值)
safeDictLabel(dictType, value, defaultLabel = '-') {
try {
const dictData = this.dictionaries[dictType] || []
const label = getDictLabel(dictData, value)
return label || defaultLabel
} catch (error) {
console.error(`获取字典失败 ${dictType}:${value}`, error)
return defaultLabel
}
}
```
## 📖 相关文件
- **核心实现**: `/mobile/src/common/dict.js`
- **使用示例**: `/mobile/src/common/dict-usage-example.js`
- **变更记录**: `/docs/变更管理/code-adjust-record-2025-01-27-移动端字典工具实现.md`
## ⚠️ 重要提醒
### Vue 2必须使用回调机制
```javascript ❌
// 错误:直接赋值不会触发响应式更新
this.dictionaries = dictManager.data
// 正确:使用回调确保响应式更新 ✅
dictManager.setUpdateCallback((dictType, data) => {
this.$set(this.dictionaries, dictType, data)
})
```
### 兼容性
- ✅ Vue 2.6.14+
- ✅ uni-app 2.x
- ✅ H5 / 小程序 / App
## 🎯 最佳实践
1. **优先使用useDict**: 支持并发加载,性能更好
2. **合理使用缓存**: 频繁变动的字典设置`useCache=false`
3. **添加错误处理**: 关键业务场景要有异常处理
4. **使用callback机制**: Vue 2中必须使用setUpdateCallback
---
✨ **完成时间**: 2025-01-27 20:15:00
👨‍💻 **开发者**: wuzilong
📱 **适用版本**: Vue 2.6.14 + uni-app 2.x