Browse Source
- 移除uploadFile组件的冗余JSON配置 - 修改隐私协议页面的样式和内容 - 更新游客首页的隐私协议链接路径 - 修复昵称保存事件从onNicknameReview改为onNicknameBlur - 为图片添加mode="aspectFill"属性master
14 changed files with 29 additions and 746 deletions
@ -1,125 +0,0 @@ |
|||||||
# 组件复用性分析与优化计划 |
|
||||||
|
|
||||||
## 项目概述 |
|
||||||
对药品查询微信小程序进行全面的组件复用性分析与优化,建立标准化的组件体系,提升代码质量和开发效率。 |
|
||||||
|
|
||||||
## 执行步骤 |
|
||||||
|
|
||||||
### 第一阶段:组件梳理与评估(预计2-3小时) |
|
||||||
|
|
||||||
#### 1.1 组件盘点 |
|
||||||
- [ ] 扫描项目所有页面和组件目录 |
|
||||||
- [ ] 识别所有自定义组件(components目录) |
|
||||||
- [ ] 识别页面内重复使用的UI片段 |
|
||||||
- [ ] 识别可复用的业务逻辑模块 |
|
||||||
|
|
||||||
#### 1.2 复用价值评估 |
|
||||||
建立评估矩阵,从以下维度评估: |
|
||||||
- 使用频率(≥3次为高频) |
|
||||||
- 功能独立性(是否耦合业务逻辑) |
|
||||||
- 通用性(跨页面/跨业务可用性) |
|
||||||
- 复杂度(提取难度) |
|
||||||
|
|
||||||
### 第二阶段:公共控件提取(预计4-6小时) |
|
||||||
|
|
||||||
#### 2.1 基础组件提取 |
|
||||||
- [ ] **导航栏组件(navbar)** - 已存在,评估优化空间 |
|
||||||
- [ ] **分页组件(pagination)** - 已存在,评估使用一致性 |
|
||||||
- [ ] **弹窗组件(popup)** - 已存在,评估功能扩展 |
|
||||||
- [ ] **标签栏组件(doctor-tab-bar/ground-tab-bar)** - 评估合并可能性 |
|
||||||
|
|
||||||
#### 2.2 业务组件提取 |
|
||||||
- [ ] **项目选择器** - 地推端/药店端/患者端均有项目切换功能 |
|
||||||
- [ ] **日期选择器** - 多处使用日期范围选择 |
|
||||||
- [ ] **状态标签** - 审核状态、跳转状态等标签展示 |
|
||||||
- [ ] **患者卡片** - 患者列表卡片展示 |
|
||||||
- [ ] **统计卡片** - 首页统计数据展示卡片 |
|
||||||
|
|
||||||
#### 2.3 复合组件提取 |
|
||||||
- [ ] **上传材料弹窗** - popup + 上传功能的复合组件 |
|
||||||
- [ ] **筛选栏组件** - 搜索+筛选条件的组合 |
|
||||||
|
|
||||||
### 第三阶段:组件体系构建(预计2-3小时) |
|
||||||
|
|
||||||
#### 3.1 目录结构规划 |
|
||||||
``` |
|
||||||
src/ |
|
||||||
├── components/ |
|
||||||
│ ├── base/ # 基础组件 |
|
||||||
│ │ ├── navbar/ |
|
||||||
│ │ ├── pagination/ |
|
||||||
│ │ └── popup/ |
|
||||||
│ ├── business/ # 业务组件 |
|
||||||
│ │ ├── project-picker/ |
|
||||||
│ │ ├── date-picker/ |
|
||||||
│ │ ├── status-tag/ |
|
||||||
│ │ └── patient-card/ |
|
||||||
│ └── composite/ # 复合组件 |
|
||||||
│ ├── upload-material/ |
|
||||||
│ └── filter-bar/ |
|
||||||
``` |
|
||||||
|
|
||||||
#### 3.2 命名规范制定 |
|
||||||
- 基础组件:小写短横线命名 |
|
||||||
- 业务组件:业务前缀+功能命名 |
|
||||||
- 复合组件:功能组合命名 |
|
||||||
|
|
||||||
### 第四阶段:组件文档编写(预计3-4小时) |
|
||||||
|
|
||||||
为每个提取的组件编写: |
|
||||||
- 功能描述 |
|
||||||
- 使用场景 |
|
||||||
- 参数列表(类型、默认值、必填、说明) |
|
||||||
- 使用示例 |
|
||||||
- 事件回调说明 |
|
||||||
- 注意事项 |
|
||||||
|
|
||||||
### 第五阶段:代码替换实施(预计6-8小时) |
|
||||||
|
|
||||||
#### 5.1 组件替换 |
|
||||||
- [ ] 替换地推端首页项目选择器 |
|
||||||
- [ ] 替换药店端首页项目选择器 |
|
||||||
- [ ] 替换患者端首页项目选择器 |
|
||||||
- [ ] 替换患者列表日期筛选 |
|
||||||
- [ ] 替换统计页面日期筛选 |
|
||||||
- [ ] 替换审核状态标签 |
|
||||||
- [ ] 替换患者卡片 |
|
||||||
|
|
||||||
#### 5.2 验证测试 |
|
||||||
- [ ] 功能完整性测试 |
|
||||||
- [ ] 样式一致性测试 |
|
||||||
- [ ] 交互逻辑测试 |
|
||||||
|
|
||||||
### 第六阶段:成果交付(预计2小时) |
|
||||||
|
|
||||||
#### 6.1 文档输出 |
|
||||||
- [ ] 组件复用性分析报告 |
|
||||||
- [ ] 组件库目录结构说明 |
|
||||||
- [ ] 组件使用文档 |
|
||||||
- [ ] 代码替换实施指南 |
|
||||||
|
|
||||||
#### 6.2 代码审查 |
|
||||||
- [ ] 组件代码质量检查 |
|
||||||
- [ ] 引用替换完整性检查 |
|
||||||
|
|
||||||
## 预期成果 |
|
||||||
|
|
||||||
1. **组件库目录**:标准化的组件分类体系 |
|
||||||
2. **公共组件**:提取5-8个高频复用组件 |
|
||||||
3. **技术文档**:完整的组件使用文档 |
|
||||||
4. **代码优化**:减少重复代码30%以上 |
|
||||||
|
|
||||||
## 时间预估 |
|
||||||
总计:约19-26小时 |
|
||||||
|
|
||||||
## 风险评估 |
|
||||||
|
|
||||||
| 风险点 | 影响 | 应对措施 | |
|
||||||
|--------|------|----------| |
|
||||||
| 组件耦合度高 | 提取困难 | 先解耦再提取 | |
|
||||||
| 样式差异大 | 统一困难 | 制定样式规范 | |
|
||||||
| 替换影响功能 | 回归测试 | 分阶段替换验证 | |
|
||||||
|
|
||||||
## 下一步行动 |
|
||||||
|
|
||||||
等待用户确认计划后,开始第一阶段:组件梳理与评估。 |
|
||||||
@ -1,7 +1,6 @@ |
|||||||
{ |
{ |
||||||
"component": true, |
"component": true, |
||||||
"usingComponents": { |
"usingComponents": { |
||||||
"van-popup": "@vant/weapp/popup/index", |
"van-popup": "@vant/weapp/popup/index" |
||||||
"uploadFile": "/components/uploadFile/index" |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,287 +0,0 @@ |
|||||||
// components/uploadFile/index.js
|
|
||||||
const app = getApp() |
|
||||||
Component({ |
|
||||||
/** |
|
||||||
* 组件的属性列表 |
|
||||||
*/ |
|
||||||
properties: { |
|
||||||
// 是否可以上传
|
|
||||||
upload: { |
|
||||||
type: Boolean, |
|
||||||
value: true, |
|
||||||
}, |
|
||||||
// 是否可以删除
|
|
||||||
delete: { |
|
||||||
type: Boolean, |
|
||||||
value: true, |
|
||||||
}, |
|
||||||
// 附件data
|
|
||||||
fileList: { |
|
||||||
type: Array, |
|
||||||
value: [], |
|
||||||
}, |
|
||||||
// 最大上传数量, -1为不限制
|
|
||||||
maxNum: { |
|
||||||
type: Number, |
|
||||||
value: -1, |
|
||||||
}, |
|
||||||
isSlot: { |
|
||||||
type: Boolean, |
|
||||||
value: false, |
|
||||||
}, |
|
||||||
count: { |
|
||||||
type: Number, |
|
||||||
value: 0, |
|
||||||
}, |
|
||||||
}, |
|
||||||
|
|
||||||
/** |
|
||||||
* 组件的初始数据 |
|
||||||
*/ |
|
||||||
data: { |
|
||||||
Timestamp: app.globalData.Timestamp, |
|
||||||
imageUrl: app.globalData.imageUrl, |
|
||||||
|
|
||||||
show: false, |
|
||||||
actions: [ |
|
||||||
{ |
|
||||||
id: 1, |
|
||||||
name: '选择视频或图片', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 2, |
|
||||||
name: '选择聊天文件', |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
|
|
||||||
/** |
|
||||||
* 组件的方法列表 |
|
||||||
*/ |
|
||||||
methods: { |
|
||||||
viewFile(e) { |
|
||||||
const { index } = e.currentTarget.dataset |
|
||||||
const { fileList } = this.properties |
|
||||||
const params = fileList[index] |
|
||||||
if (['image', 'video'].includes(params.fileType)) { |
|
||||||
let sources = [] |
|
||||||
|
|
||||||
fileList.forEach((item) => { |
|
||||||
let obj = {} |
|
||||||
if (item.fileType === 'image') { |
|
||||||
obj = { |
|
||||||
url: item.url, |
|
||||||
type: item.fileType, |
|
||||||
poster: item.url, |
|
||||||
} |
|
||||||
} |
|
||||||
if (item.fileType === 'video') { |
|
||||||
obj = { |
|
||||||
url: item.vidoeUrl, |
|
||||||
type: item.fileType, |
|
||||||
poster: item.url, |
|
||||||
} |
|
||||||
} |
|
||||||
sources.push(obj) |
|
||||||
}) |
|
||||||
wx.previewMedia({ |
|
||||||
current: index, |
|
||||||
sources, |
|
||||||
}) |
|
||||||
} else if (params.fileType !== 'audio') { |
|
||||||
wx.downloadFile({ |
|
||||||
url: params.url, |
|
||||||
success(res) { |
|
||||||
wx.openDocument({ |
|
||||||
filePath: res.tempFilePath, |
|
||||||
showMenu: true, |
|
||||||
fail() { |
|
||||||
wx.showToast({ |
|
||||||
title: '该文件无法预览', |
|
||||||
icon: 'none', |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
}, |
|
||||||
deleteFile(e) { |
|
||||||
const { index, item } = e.currentTarget.dataset |
|
||||||
this.triggerEvent('deleteFile', { |
|
||||||
index, |
|
||||||
item, |
|
||||||
}) |
|
||||||
}, |
|
||||||
downFile(e) { |
|
||||||
const { item } = e.currentTarget.dataset |
|
||||||
wx.showToast({ |
|
||||||
title: '正在下载,请稍后...', |
|
||||||
icon: 'none', |
|
||||||
}) |
|
||||||
wx.downloadFile({ |
|
||||||
url: item.url || item.fileUrl, |
|
||||||
success(res) { |
|
||||||
if (item.type === 'image') { |
|
||||||
wx.saveImageToPhotosAlbum({ |
|
||||||
filePath: res.tempFilePath, |
|
||||||
success: () => { |
|
||||||
wx.showToast({ |
|
||||||
title: '下载成功', |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} else if (item.type === 'video') { |
|
||||||
wx.saveVideoToPhotosAlbum({ |
|
||||||
filePath: res.tempFilePath, |
|
||||||
success: () => { |
|
||||||
wx.showToast({ |
|
||||||
title: '下载成功', |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} else { |
|
||||||
wx.showToast({ |
|
||||||
title: '附件请到pc端下载!', |
|
||||||
icon: 'none', |
|
||||||
}) |
|
||||||
} |
|
||||||
}, |
|
||||||
}) |
|
||||||
}, |
|
||||||
uploadFile(item) { |
|
||||||
return new Promise((resolve, resject) => { |
|
||||||
let url = `${app.globalData.upFileUrl}?r=file-service/upload-` |
|
||||||
if (item.type === 'image') { |
|
||||||
url += 'img' |
|
||||||
} |
|
||||||
if (item.type === 'video') { |
|
||||||
url += 'video' |
|
||||||
} |
|
||||||
if (item.type === 'file') { |
|
||||||
url += 'doc' |
|
||||||
} |
|
||||||
wx.uploadFile({ |
|
||||||
filePath: item.tempFilePath, |
|
||||||
name: 'file', |
|
||||||
url, |
|
||||||
success: (res) => { |
|
||||||
let data = JSON.parse(res.data) |
|
||||||
let expandJson = { |
|
||||||
name: item.name, |
|
||||||
fileType: item.fileType, |
|
||||||
} |
|
||||||
if (item.type === 'image') { |
|
||||||
expandJson.url = data.data.Url |
|
||||||
} |
|
||||||
if (item.type === 'video') { |
|
||||||
expandJson.url = data.data.SnapshotUrl |
|
||||||
expandJson.videoUrl = data.data.Url |
|
||||||
expandJson.duration = data.data.Duration |
|
||||||
} |
|
||||||
if (item.type === 'file') { |
|
||||||
expandJson.url = data.data.Url |
|
||||||
} |
|
||||||
resolve(expandJson) |
|
||||||
}, |
|
||||||
fail() { |
|
||||||
resject() |
|
||||||
}, |
|
||||||
}) |
|
||||||
}) |
|
||||||
}, |
|
||||||
GetExtensionFileName(pathfilename) { |
|
||||||
let reg = /(\\+)/g |
|
||||||
let pString = pathfilename.replace(reg, '#') //用正则表达式来将\或\\替换成#
|
|
||||||
let arr = pString.split('#') // 以“#”为分隔符,将字符分解为数组 例如 D Program Files bg.png
|
|
||||||
let lastString = arr[arr.length - 1] //取最后一个字符
|
|
||||||
let arr2 = lastString.split('.') // 再以"."作为分隔符
|
|
||||||
return arr2[arr2.length - 1] //将后缀名返回出来
|
|
||||||
}, |
|
||||||
upFile(data) { |
|
||||||
wx.showLoading({ |
|
||||||
title: '正在上传', |
|
||||||
}) |
|
||||||
let apiArr = [] |
|
||||||
data.map((e) => { |
|
||||||
apiArr.push(this.uploadFile(e)) |
|
||||||
}) |
|
||||||
Promise.all(apiArr) |
|
||||||
.then((res) => { |
|
||||||
wx.hideLoading({ |
|
||||||
success: () => { |
|
||||||
this.triggerEvent('setData', res) |
|
||||||
}, |
|
||||||
}) |
|
||||||
}) |
|
||||||
.catch(() => { |
|
||||||
wx.showToast({ |
|
||||||
title: '上传失败', |
|
||||||
icon: 'error', |
|
||||||
}) |
|
||||||
}) |
|
||||||
}, |
|
||||||
handleAction() { |
|
||||||
this.selectMedia() |
|
||||||
}, |
|
||||||
onSelect(e) { |
|
||||||
const { id } = e.currentTarget.dataset |
|
||||||
if (id == 1) { |
|
||||||
this.setData({ |
|
||||||
show: false, |
|
||||||
}) |
|
||||||
this.selectMedia() |
|
||||||
} |
|
||||||
if (id == 2) { |
|
||||||
this.setData({ |
|
||||||
show: false, |
|
||||||
}) |
|
||||||
this.selectFiles() |
|
||||||
} |
|
||||||
}, |
|
||||||
selectMedia() { |
|
||||||
let { fileList, maxNum, count = 0 } = this.properties |
|
||||||
if (maxNum >= 0 && count == 0) { |
|
||||||
count = maxNum - fileList.length |
|
||||||
} |
|
||||||
wx.chooseMedia({ |
|
||||||
mediaType: ['image', 'video'], |
|
||||||
count, |
|
||||||
sourceType: ['album', 'camera'], |
|
||||||
sizeType: ['original'], |
|
||||||
success: (res) => { |
|
||||||
res.tempFiles.map((e) => { |
|
||||||
e.name = e.tempFilePath |
|
||||||
e.extend = this.GetExtensionFileName(e.tempFilePath) |
|
||||||
e.tempFilePath = e.tempFilePath |
|
||||||
e.type = e.fileType |
|
||||||
e.fileType = e.fileType |
|
||||||
}) |
|
||||||
this.upFile(res.tempFiles) |
|
||||||
}, |
|
||||||
}) |
|
||||||
}, |
|
||||||
selectFiles() { |
|
||||||
let { fileList, maxNum, count = 0 } = this.properties |
|
||||||
if (maxNum >= 0 && count == 0) { |
|
||||||
count = maxNum - fileList.length |
|
||||||
} |
|
||||||
wx.chooseMessageFile({ |
|
||||||
count, |
|
||||||
type: 'file', |
|
||||||
extension: ['doc', 'docx', 'pdf', 'xlsx', 'xls', 'ppt', 'pptx'], |
|
||||||
success: (res) => { |
|
||||||
res.tempFiles.map((e) => { |
|
||||||
e.type = 'file' |
|
||||||
e.tempFilePath = e.path |
|
||||||
e.fileType = this.GetExtensionFileName(e.path) |
|
||||||
}) |
|
||||||
this.upFile(res.tempFiles) |
|
||||||
}, |
|
||||||
}) |
|
||||||
}, |
|
||||||
onClose() { |
|
||||||
this.setData({ show: false }) |
|
||||||
}, |
|
||||||
}, |
|
||||||
}) |
|
||||||
@ -1,9 +0,0 @@ |
|||||||
{ |
|
||||||
"component": true, |
|
||||||
"usingComponents": { |
|
||||||
"van-icon": "@vant/weapp/icon/index", |
|
||||||
"van-image": "@vant/weapp/image/index", |
|
||||||
"van-action-sheet": "@vant/weapp/action-sheet/index", |
|
||||||
"van-popup": "@vant/weapp/popup/index" |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,3 +0,0 @@ |
|||||||
<view catchtap="handleAction"> |
|
||||||
<slot></slot> |
|
||||||
</view> |
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue