|
@@ -0,0 +1,279 @@
|
|
|
|
|
+# 文件上传分析文档
|
|
|
|
|
+
|
|
|
|
|
+## 概述
|
|
|
|
|
+
|
|
|
|
|
+本文档分析了项目中购机者照片、证件附件和发票附件这三个文件上传功能的接口和参数。
|
|
|
|
|
+
|
|
|
|
|
+## 文件上传接口
|
|
|
|
|
+
|
|
|
|
|
+所有文件上传都使用同一个接口:
|
|
|
|
|
+
|
|
|
|
|
+- **接口地址**: `/api/attachment/addimg`
|
|
|
|
|
+- **请求方法**: POST
|
|
|
|
|
+- **请求类型**: multipart/form-data
|
|
|
|
|
+- **认证方式**: 通过请求头中的 token 参数进行用户认证
|
|
|
|
|
+
|
|
|
|
|
+## 1. 购机者照片上传
|
|
|
|
|
+
|
|
|
|
|
+### 接口参数
|
|
|
|
|
+
|
|
|
|
|
+| 参数名 | 类型 | 必填 | 说明 |
|
|
|
|
|
+| -------- | ------ | ---- | --------------------------- |
|
|
|
|
|
+| file | File | 是 | 上传的图片文件 |
|
|
|
|
|
+| attmodel | String | 是 | "coupon_buyer" (关联模块) |
|
|
|
|
|
+| attpath | String | 是 | "/coupon_buyer/" (上传路径) |
|
|
|
|
|
+| token | String | 是 | 用户认证token (在请求头中) |
|
|
|
|
|
+
|
|
|
|
|
+### 使用场景
|
|
|
|
|
+
|
|
|
|
|
+- **页面位置**: `src/pages/coupon/modify-info.vue`
|
|
|
|
|
+- **是否必填**: 否
|
|
|
|
|
+- **用途**: 用于确认购机者身份
|
|
|
|
|
+- **限制**: 最多上传1张图片
|
|
|
|
|
+
|
|
|
|
|
+### 代码示例
|
|
|
|
|
+
|
|
|
|
|
+```vue
|
|
|
|
|
+<UploadComponent
|
|
|
|
|
+ v-model="formData.buyerPhoto"
|
|
|
|
|
+ v-model:fileIds="formData.buyerPhotoIds"
|
|
|
|
|
+ :limit="1"
|
|
|
|
|
+ :required="false"
|
|
|
|
|
+ attmodel="coupon_buyer"
|
|
|
|
|
+ attpath="/coupon_buyer/"
|
|
|
|
|
+ modelStats="buyerPhotoIds"
|
|
|
|
|
+ message="请上传购机者照片"
|
|
|
|
|
+ tips="用于确认购机者身份"
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 2. 证件附件上传
|
|
|
|
|
+
|
|
|
|
|
+### 接口参数
|
|
|
|
|
+
|
|
|
|
|
+| 参数名 | 类型 | 必填 | 说明 |
|
|
|
|
|
+| -------- | ------ | ---- | ------------------------------ |
|
|
|
|
|
+| file | File | 是 | 上传的图片文件 |
|
|
|
|
|
+| attmodel | String | 是 | "coupon_identity" (关联模块) |
|
|
|
|
|
+| attpath | String | 是 | "/coupon_identity/" (上传路径) |
|
|
|
|
|
+| token | String | 是 | 用户认证token (在请求头中) |
|
|
|
|
|
+
|
|
|
|
|
+### 使用场景
|
|
|
|
|
+
|
|
|
|
|
+- **页面位置**: `src/pages/coupon/modify-info.vue`
|
|
|
|
|
+- **是否必填**: 是
|
|
|
|
|
+- **用途**: 根据用户类型上传不同的证件
|
|
|
|
|
+ - 个人用户:上传身份证照片
|
|
|
|
|
+ - 企业用户:上传营业执照照片
|
|
|
|
|
+- **限制**: 最多上传1张图片
|
|
|
|
|
+
|
|
|
|
|
+### 代码示例
|
|
|
|
|
+
|
|
|
|
|
+```vue
|
|
|
|
|
+<!-- 个人身份证上传 -->
|
|
|
|
|
+<UploadComponent
|
|
|
|
|
+ v-model="formData.idCardFiles"
|
|
|
|
|
+ v-model:fileIds="formData.idCardIds"
|
|
|
|
|
+ :limit="1"
|
|
|
|
|
+ attmodel="coupon_identity"
|
|
|
|
|
+ attpath="/coupon_identity/"
|
|
|
|
|
+ modelStats="idCardIds"
|
|
|
|
|
+ message="请上传身份证照片"
|
|
|
|
|
+ tips="请上传身份证正面照片"
|
|
|
|
|
+/>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 企业营业执照上传 -->
|
|
|
|
|
+<UploadComponent
|
|
|
|
|
+ v-model="formData.businessLicenseFiles"
|
|
|
|
|
+ v-model:fileIds="formData.businessLicenseIds"
|
|
|
|
|
+ :limit="1"
|
|
|
|
|
+ attmodel="coupon_identity"
|
|
|
|
|
+ attpath="/coupon_identity/"
|
|
|
|
|
+ modelStats="businessLicenseIds"
|
|
|
|
|
+ message="请上传营业执照照片"
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 3. 发票附件上传
|
|
|
|
|
+
|
|
|
|
|
+### 接口参数
|
|
|
|
|
+
|
|
|
|
|
+| 参数名 | 类型 | 必填 | 说明 |
|
|
|
|
|
+| -------- | ------ | ---- | ----------------------------- |
|
|
|
|
|
+| file | File | 是 | 上传的文件(支持图片和PDF) |
|
|
|
|
|
+| attmodel | String | 是 | "coupon_invoice" (关联模块) |
|
|
|
|
|
+| attpath | String | 是 | "/coupon_invoice/" (上传路径) |
|
|
|
|
|
+| token | String | 是 | 用户认证token (在请求头中) |
|
|
|
|
|
+
|
|
|
|
|
+### 使用场景
|
|
|
|
|
+
|
|
|
|
|
+- **页面位置**: `src/pages/form/formStep4.vue`
|
|
|
|
|
+- **是否必填**: 是
|
|
|
|
|
+- **用途**: 上传购买发票
|
|
|
|
|
+- **限制**:
|
|
|
|
|
+ - 最多上传1个文件
|
|
|
|
|
+ - 支持格式:JPG、PNG、PDF
|
|
|
|
|
+ - 文件大小:不超过10MB
|
|
|
|
|
+
|
|
|
|
|
+### 代码示例
|
|
|
|
|
+
|
|
|
|
|
+```vue
|
|
|
|
|
+<UploadComponent
|
|
|
|
|
+ v-model="formData.invoiceFiles"
|
|
|
|
|
+ v-model:fileIds="formData.invoiceFileIds"
|
|
|
|
|
+ :limit="1"
|
|
|
|
|
+ :required="true"
|
|
|
|
|
+ accept="all"
|
|
|
|
|
+ :extension="['.jpg', '.jpeg', '.png', '.pdf']"
|
|
|
|
|
+ attmodel="coupon_invoice"
|
|
|
|
|
+ attpath="/coupon_invoice/"
|
|
|
|
|
+ modelStats="invoiceFileIds"
|
|
|
|
|
+ message="请上传发票照片或PDF文件"
|
|
|
|
|
+ tips="支持图片格式(JPG、PNG)和PDF文件,文件大小不超过10MB"
|
|
|
|
|
+/>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 文件上传流程
|
|
|
|
|
+
|
|
|
|
|
+1. 所有文件上传都使用同一个接口 `/api/attachment/addimg`
|
|
|
|
|
+2. 通过 `attmodel` 和 `attpath` 参数区分不同类型的文件
|
|
|
|
|
+3. 上传成功后,服务器返回文件ID,前端将文件ID保存到相应的数组中
|
|
|
|
|
+4. 提交表单时,将所有文件ID通过逗号连接成一个字符串,通过 `filesid` 参数提交给后端
|
|
|
|
|
+
|
|
|
|
|
+## 文件ID处理
|
|
|
|
|
+
|
|
|
|
|
+在表单提交时,不同类型的文件ID会被收集到同一个数组中,然后通过逗号连接成一个字符串:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 示例代码
|
|
|
|
|
+const fileIds = [
|
|
|
|
|
+ ...idCardIds.map((item) => item.id), // 证件照片ID
|
|
|
|
|
+ ...buyerPhotoIds.map((item) => item.id), // 购机者照片ID
|
|
|
|
|
+ ...invoiceFileIds.map((item) => item.id), // 发票文件ID
|
|
|
|
|
+];
|
|
|
|
|
+const fileIdsString = fileIds.join(',');
|
|
|
|
|
+
|
|
|
|
|
+// 提交参数
|
|
|
|
|
+const submitParams = {
|
|
|
|
|
+ // ...其他参数
|
|
|
|
|
+ filesid: fileIdsString, // 文件ID字符串
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 上传组件实现
|
|
|
|
|
+
|
|
|
|
|
+文件上传功能通过 `UploadComponent` 组件实现,该组件位于 `src/components/UploadComponent.vue`。
|
|
|
|
|
+
|
|
|
|
|
+### 主要功能
|
|
|
|
|
+
|
|
|
|
|
+1. 文件选择和预览
|
|
|
|
|
+2. 文件上传前的验证
|
|
|
|
|
+3. 自定义上传方法
|
|
|
|
|
+4. 文件ID管理
|
|
|
|
|
+5. 文件删除功能
|
|
|
|
|
+
|
|
|
|
|
+### 核心方法
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 创建自定义上传方法
|
|
|
|
|
+function createCustomUpload({ attmodel, attpath, modelStats }) {
|
|
|
|
|
+ return async function (file, formData, options) {
|
|
|
|
|
+ const requestFromData = {
|
|
|
|
|
+ attmodel,
|
|
|
|
|
+ attpath,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (props.attlsh) {
|
|
|
|
|
+ requestFromData.attlsh = props.attlsh;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ await uploadFile({
|
|
|
|
|
+ tempFilePath: file.url,
|
|
|
|
|
+ formData: requestFromData,
|
|
|
|
|
+ data,
|
|
|
|
|
+ error,
|
|
|
|
|
+ loading,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!error.value) {
|
|
|
|
|
+ options.onSuccess('', file, formData);
|
|
|
|
|
+ // 处理返回的文件ID
|
|
|
|
|
+ let dataObject = data.value;
|
|
|
|
|
+ if (typeof data.value === 'string') {
|
|
|
|
|
+ dataObject = JSON.parse(data.value);
|
|
|
|
|
+ }
|
|
|
|
|
+ const newFileIds = [...props.fileIds];
|
|
|
|
|
+ newFileIds.push({
|
|
|
|
|
+ url: file.url,
|
|
|
|
|
+ id: dataObject.Data,
|
|
|
|
|
+ });
|
|
|
|
|
+ emit('update:fileIds', newFileIds);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 上传钩子实现
|
|
|
|
|
+
|
|
|
|
|
+文件上传的核心逻辑在 `src/hooks/useUpload.ts` 中实现:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+export function uploadFile<T>({ tempFilePath, formData, data, error, loading }) {
|
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
|
+ const appStore = useAppStore()
|
|
|
|
|
+ uni.uploadFile({
|
|
|
|
|
+ url: VITE_UPLOAD_BASEURL + '/api/attachment/addimg',
|
|
|
|
|
+ filePath: tempFilePath,
|
|
|
|
|
+ name: 'file',
|
|
|
|
|
+ formData,
|
|
|
|
|
+ header: {
|
|
|
|
|
+ token: `${appStore.appInfo.token}`, // 请求token
|
|
|
|
|
+ },
|
|
|
|
|
+ success: (uploadFileRes) => {
|
|
|
|
|
+ const decryptedRes = decryptResponse(uploadFileRes)
|
|
|
|
|
+ data.value = decryptedRes.data as T
|
|
|
|
|
+ resolve(data.value)
|
|
|
|
|
+ },
|
|
|
|
|
+ fail: (err) => {
|
|
|
|
|
+ console.error('uni.uploadFile err->', err)
|
|
|
|
|
+ error.value = true
|
|
|
|
|
+ reject(err)
|
|
|
|
|
+ },
|
|
|
|
|
+ complete: () => {
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 数据库表结构
|
|
|
|
|
+
|
|
|
|
|
+文件上传相关的数据存储在 `attachment` 表中,表结构如下:
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+CREATE TABLE `attachment` (
|
|
|
|
|
+ `attid` varchar(32) NOT NULL COMMENT '附件ID(查询条件)',
|
|
|
|
|
+ `attname` varchar(32) NOT NULL COMMENT '文件名',
|
|
|
|
|
+ `attpath` varchar(200) NOT NULL COMMENT '路径',
|
|
|
|
|
+ `atttype` varchar(10) NOT NULL COMMENT '扩展名',
|
|
|
|
|
+ `attsize` varchar(20) NOT NULL COMMENT '文件大小',
|
|
|
|
|
+ `attmodel` varchar(20) NOT NULL COMMENT '关联模块(查询条件)',
|
|
|
|
|
+ `attlsh` varchar(32) DEFAULT NULL COMMENT '关联表单流水号(查询条件)',
|
|
|
|
|
+ `attcreate` datetime NOT NULL COMMENT '创建时间#不可编辑(禁止前端编辑)(查询条件)',
|
|
|
|
|
+ `attcreateuser` varchar(30) DEFAULT NULL COMMENT '上传者#不可编辑(禁止前端编辑)',
|
|
|
|
|
+ `attdelcode` tinyint(4) DEFAULT NULL COMMENT '删除标记(禁止前端编辑)(禁止插入)',
|
|
|
|
|
+ `attother1` varchar(50) DEFAULT NULL COMMENT '附加参数1',
|
|
|
|
|
+ `attother2` varchar(50) DEFAULT NULL COMMENT '附加参数2',
|
|
|
|
|
+ `attother3` varchar(50) DEFAULT NULL COMMENT '附加参数3',
|
|
|
|
|
+ `attorginname` varchar(255) DEFAULT NULL COMMENT '文件原始名称',
|
|
|
|
|
+ `attfileSHA1` varchar(100) DEFAULT NULL COMMENT '文件SHA1值',
|
|
|
|
|
+ `attfileSHA256` varchar(100) DEFAULT NULL COMMENT '文件SHA256值',
|
|
|
|
|
+ `attfileMD5` varchar(100) DEFAULT NULL COMMENT '文件MD5值',
|
|
|
|
|
+ PRIMARY KEY (`attid`)
|
|
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='附件';
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 总结
|
|
|
|
|
+
|
|
|
|
|
+项目中的文件上传功能采用了统一的上传接口,通过不同的参数来区分不同类型的文件。上传成功后,服务器返回文件ID,前端将这些ID收集起来,在表单提交时统一提交给后端。这种设计简化了文件上传的实现,同时保持了足够的灵活性来处理不同类型的文件上传需求。
|