提交代码
This commit is contained in:
1 parent
a0e5c9a024
commit
e97c97aa0b
2 files changed
-613
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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
|
||||
Reference in new issue
Block a user