uniapp 实现选择文件上传相册选择拍摄的upload

使用技术 uniapp vue3 应用场景:微信小程序上传图片, 使用组件:uview-plus组件库

实现思路 移除组件自带的upload的上传事件,加插槽事件选择三种类型

实现效果如下:

html

javascript 复制代码
<template>
	<view class="box_centent">
		<view class="uni-padding-wrap uni-common-mt"></view>
		<view class="">
			<template v-for="item in array" :key="item.id">
				<view class="customs-declaration-box" v-if="shouldShowComponent(item.key)">
					<view class="customs-declaration-title">
						{{ item.name }}
						<text class="required-label">必填</text>
						&nbsp;
						<uni-icons custom-prefix="iconfont" v-if="item.demo&&item.key=='id'" @click="previewDemoImage(item.demo)" type="icon-hetongmoban" size="20"  />
						<!-- <image  v-if="item.demo&&item.key!=='id'" @click="previewDemoImage(item.demo)" src="/static/icons/word.png" style="width:22px;height:22px" mode=""></image> -->
						<uni-icons custom-prefix="iconfont" v-if="item.demo&&item.key!=='id'" @click="previewDemoImage(item.demo)" type="icon-hetongmoban" size="20"  />
						
						<!-- <uni-icons custom-prefix="iconfont" type="icon-moban" size="20" /> -->
					</view>
					<!-- 通用上传组件 -->
					<view style="margin:auto;width: 92%;" class="">
						<view class="uniheight"></view>
			<up-upload 
			  class="custom-upload" 
			  v-if="item.key !== 'id'" 
			  :fileList="fileList[item.key]"
			  @delete="(event) => deletePic(event, item.key)"
			  multiple 
			  :maxCount="item.key=='other'?5:3"
			  :disabled="true" 
			  :show-choose-btn="false"
			  accept="image/*,.pdf,.doc,.docx,.xls,.xlsx" 
			>
			  <!-- 触发按钮(不变) -->
			  <template #trigger>
			    <view class="upload-trigger" @click="showUploadOptions(item.key)">
			      <image src="/static/carlm.png" style="width:30px;height:30px" mode=""></image>
			      <view style="font-size:14px;">{{ fileList[item.key]?.length || 0 }}/{{item.key=='other'?5:3}}</view>
			    </view>
			  </template>
			
			  <!-- 自定义文件列表项:根据文件类型显示图片或图标 -->
			  <template #file="{ file }">
			    <view class="file-item">
			      <!-- 图片文件:直接显示图片 -->
			      <image 
			        v-if="isImage(file.url)" 
			        :src="file.url" 
			        class="file-preview"
			        mode="widthFix"
			      ></image>
			      
			      <!-- 非图片文件:显示file.png图标 -->
			<!--      <image 
			        v-else 
			        src="/static/icons/file.png" 
			        class="file-icon"
			      ></image> -->
			      
			      <!-- 文件信息(名称、状态等) -->
			      <view class="file-info">
			        <view class="file-name">{{ getFileName(file.url) }}</view>
			        <view class="file-status" v-if="file.status === 'uploading'">上传中...</view>
			        <view class="file-status error" v-if="file.status === 'fail'">上传失败</view>
			      </view>
			    </view>
			  </template>
			</up-upload>
					</view>
					<!-- 身份证信息部分 -->
					<view class="customs-declaration-box" v-if="item.key === 'id'">
						<view style="margin:auto;width: 92%;" class="">
							<view class="uniheight"></view>
							<!-- 上传人像页 -->
							<view class=""
								style="margin:auto;width: 92%;height: 160px;background-color: #FAFBFF;border-radius: 4px;border:1px solid #DFE5F0;display: flex;align-items: center;justify-content: center;position: relative;">
								<!-- 显示已上传的人像页图片 -->
								<image v-if="fileList['id'] && fileList['id'][0]"
									:src="fileList['id'][0].status === 'success' ? fileList['id'][0].url : '/static/wImage@1x.png'"
									style="width:100%;height: 160px;" mode=""></image>
								<image v-else src="/static/wImage@1x.png" style="width:80%;height: 145px;" mode="">
								</image>

								<!-- 上传按钮 -->
								<view class="" style="position: absolute;right:26%">
									<view class=""
										v-if="!fileList['id'] || !fileList['id'][0] || fileList['id'][0].status !== 'success'">
										<up-upload :fileList="fileList['id'] || []"
											@afterRead="(event) => handleIdUpload(event, 'id')"
											@delete="(event) => deletePic(event, 'id')" :maxCount="1">
											<template #trigger>
												<view class=""
													v-if="!fileList['id'] || !fileList['id'][0] || fileList['id'][0].status !== 'success'"
													style="width: 35px;height: 35px;border-radius: 35px;background-color: #4C7CEE;display:flex;align-items:center;justify-content: center;cursor: pointer;">
													<image src="/static/md-photo_camera 1@1x.png"
														style="width: 23px;height:23px" mode=""></image>
												</view>
											</template>
										</up-upload>
									</view>

									<view class="" v-else>
										<up-upload @afterRead="(event) => handleIdUpload(event, 'id')"
											@delete="(event) => deletePic(event, 'id')" :maxCount="1">
											<template #trigger>
												<view class=""
													style="width: 35px;height: 35px;border-radius: 35px;background-color: #8fc480;display:flex;align-items:center;justify-content: center;cursor: pointer;">
													<image src="/static/md-photo_camera 1@1x.png"
														style="width: 23px;height:23px" mode=""></image>
												</view>
											</template>
										</up-upload>
									</view>
									<view class="" :style="{
			               color: fileList['id'] && fileList['id'][0] && fileList['id'][0].status === 'success' ? '#666666' : '#666666',
			               marginLeft: '-29px'
			             }">
										{{ fileList['id'] && fileList['id'][0] && fileList['id'][0].status === 'success' 
			               ? '点击替换人像頁' : '点击上传人像頁' }}
									</view>
								</view>
							</view>

							<view class="uniheight"></view>
							<view class="uniheight"></view>

							<!-- 上传国徽页 -->
							<view class=""
								style="margin:auto;width: 92%;height: 160px;background-color: #FAFBFF;border-radius: 4px;border:1px solid #DFE5F0;display: flex;align-items: center;justify-content: center;position: relative;">
								<!-- 显示已上传的国徽页图片 -->
								<image v-if="fileList['idB'] && fileList['idB'][0]"
									:src="fileList['idB'][0].status === 'success' ? fileList['idB'][0].url : '/static/wImage@2x.png'"
									style="width:100%;height: 160px;position:relative" mode=""></image>
								<image v-else src="/static/wImage@2x.png"
									style="width:80%;height: 145px;position:relative" mode=""></image>

								<!-- 上传按钮 -->
								<view class="" style="position: absolute;right:26%">
									<!-- 未上传或上传失败状态 -->
									<view class=""
										v-if="!fileList['idB'] || !fileList['idB'][0] || fileList['idB'][0].status !== 'success'">
										<up-upload :fileList="fileList['idB'] || []"
											@afterRead="(event) => handleIdUpload(event, 'idB')"
											@delete="(event) => deletePic(event, 'idB')" :maxCount="1">
											<template #trigger>
												<view class=""
													style="width: 35px;height: 35px;border-radius: 35px;background-color: #4C7CEE;display:flex;align-items:center;justify-content: center;cursor: pointer;">
													<image src="/static/md-photo_camera 1@1x.png"
														style="width: 23px;height:23px" mode=""></image>
												</view>
											</template>
										</up-upload>
									</view>

									<!-- 上传成功状态 -->
									<view class="" v-else>
										<up-upload @afterRead="(event) => handleIdUpload(event, 'idB')"
											@delete="(event) => deletePic(event, 'idB')" :maxCount="1">
											<template #trigger>
												<view class=""
													style="width: 35px;height: 35px;border-radius: 35px;background-color: #8fc480;display:flex;align-items:center;justify-content: center;cursor: pointer;">
													<image src="/static/md-photo_camera 1@1x.png"
														style="width: 23px;height:23px" mode=""></image>
												</view>
											</template>
										</up-upload>
									</view>

									<!-- 提示文本 -->
									<view class="" :style="{
			            color: fileList['idB'] && fileList['idB'][0] && fileList['idB'][0].status === 'success' ? '#666666' : '#666666',
			            marginLeft: '-29px'
			          }">
										{{ fileList['idB'] && fileList['idB'][0] && fileList['idB'][0].status === 'success' 
			            ? '点击替换国徽页' : '点击上传国徽页' }}
									</view>
								</view>
							</view>
						</view>
						<view class="uni-padding-wrap uni-common-mt"></view>
						<view class="uni-padding-wrap uni-common-mt"></view>
					<!-- 	<view class="" style="margin:auto;width: 86%;height: 30px;">
							确认身份信息
						</view>
						<view class="" style="margin:auto;width: 86%;color: #BABABA;">
							系统将根据您的上传照片自动识别填充
						</view>
						<view style="height: 15px;"></view>
						<view class=""
							style="margin:auto;width: 80%;height: 30px;display: flex;align-items: center;justify-content: space-between;">
							<view class="">
								真实姓名
							</view>
							<view class="">
								李天霸
							</view>
						</view>
						<view style="height: 15px;"></view>
						<view class=""
							style="margin:auto;width: 80%;height: 30px;display: flex;align-items: center;justify-content: space-between;">
							<view class="">
								证件号码
							</view>
							<view class="" style="color: #BABABA;">
								41027749921099847
							</view>
						</view>
						<view style="height: 15px;"></view> -->
					</view>
				</view>

				<view class="uni-padding-wrap uni-common-mt"></view>
			</template>
		</view>
		<view class="uni-padding-wrap uni-common-mt" v-show="suipupload"></view>
		<!-- 3 -->
	<!-- 	<view class="customs-declaration-box" v-if="classhow">
			<view class="customs-declaration-title">
				其他
			</view>
			<view style="margin:auto;width: 92%;" class="">
				<view class="uniheight"></view>
				<up-upload class="custom-upload" :fileList="fileList_other" @afterRead="afterRead_other"
					@delete="deletePic_other" multiple :maxCount="5">
					<template #trigger>
						<view class="upload-trigger">
							<image src="/static/carlm.png" style="width:30px;height:30px" mode="">
							</image>
							<view class="" style="font-size: 14px;">
								{{fileList_other.length}}/5
							</view>
						</view>
					</template>
				</up-upload>
			</view>
		</view> -->
		<view class="uni-padding-wrap uni-common-mt"></view>
		<view class="uni-padding-wrap uni-common-mt"></view>
		<view class="uni-padding-wrap uni-common-mt"></view>
		<view class=""
			style="width: 100%;height: 80px;background-color: white;position: fixed;bottom: 0px;display: flex;align-items: center;justify-content: center;z-index: 99;">
			<!-- <up-bottom>确定</up-bottom> -->
			<up-button type="" customStyle="border-radius:20px;width:90%;background-color:#E44A6C;color:white"
				@click="shore" :text="chillr?'關閉':'確認'"></up-button>
		</view>
	</view>
</template>

js

javascript 复制代码
<script setup>
	import {
		ref,
		watch
	} from 'vue';
	import {
		onShow,
		onLoad
	} from '@dcloudio/uni-app';
	const chillr = ref('')
	onLoad((options) => {
		chillr.value = options.colse
	})
// 3. 匹配图标(确保与扩展名对应)
// 统一使用 file.png 作为非图片文件的图标
const getFileIcon = (url) => {
  // 调用 isImage 判断是否为图片:非图片 → 返回 pdf.png
  return isImage(url) ? '' : '/static/icons/pdf.png';
};
const previewFile = (url) => {
  console.log('预览文件 URL:', url); // 关键调试:打印 URL
  
  if (!url) {
    uni.showToast({ title: '文件路径无效', icon: 'none' });
    return;
  }
  
  // ...原有代码...
};
	// 显示上传选项弹窗
// 显示上传选项弹窗(新增微信聊天文件选项)
const showUploadOptions = (key) => {
  uni.showActionSheet({
    itemList: ['拍摄', '从相册选择', '選擇文件'], // 新增选项
    success: (res) => {
      switch (res.tapIndex) {
        case 0: // 拍摄
          chooseImage('camera', key);
          break;
        case 1: // 相册选择
          chooseImage('album', key);
          break;
        case 2: // 从微信聊天选择
          chooseWechatMessageFile(key);
          break;
      }
    },
    fail: (err) => {
      console.log('取消选择', err);
    }
  });
};
	// 从微信聊天记录(好友/群聊)选择文件
// 从微信聊天记录(好友/群聊)选择文件 - 修正API调用
const chooseWechatMessageFile = (key) => {
  uni.chooseMessageFile({
    count: 3 - (fileList.value[key]?.length || 0),
    type: 'file',
    success: (res) => {
      // 关键修复:微信聊天文件的路径字段是 path,而非 tempFilePath
      res.tempFiles.forEach(file => {
        const tempFilePath = file.path; // 正确字段名是 path
        if (tempFilePath) { // 增加校验,确保路径存在
          handleFileUpload(tempFilePath, key);
        } else {
          console.error('微信文件路径获取失败:', file);
          uni.showToast({ title: '文件路径错误', icon: 'none' });
        }
      });
    },
    fail: (err) => { /* ... */ }
  });
};
	// 1. 处理拍摄/相册选择(图片)
	const chooseImage = (sourceType, key) => {
	  uni.chooseImage({
	    count: 3 - (fileList.value[key]?.length || 0), // 最多选择3张(减去已上传数量)
	    sizeType: ['original', 'compressed'],
	    sourceType: [sourceType], // 'camera' 或 'album'
	    success: (res) => {
	      // 选择成功后调用上传
	      res.tempFilePaths.forEach(tempPath => {
	        handleFileUpload(tempPath, key);
	      });
	    }
	  });
	};
	
	
	// 3. 统一文件上传逻辑
	const handleFileUpload = (tempFilePath, key) => {
	  // 1. 先添加到文件列表(标记为上传中)
	  if (!fileList.value[key]) {
	    fileList.value[key] = [];
	  }
	  const fileIndex = fileList.value[key].length;
	  fileList.value[key].push({
	    url: tempFilePath,
	    status: 'uploading',
	    message: '',
	    id: ''
	  });
	  // 2. 调用上传接口
	  uploadFile(tempFilePath)
	    .then(result => {
	      // 上传成功:更新状态
	      fileList.value[key][fileIndex] = {
	        ...fileList.value[key][fileIndex],
	        url: result.url,
	        status: 'success',
	        id: result.id
	      };
		    console.log('PDF文件上传成功,后端返回URL:', result.url); // 关键:检查此URL是否带.pdf扩展名
	      // 同步到全局存储
	      allUploadedUrls.value.push({ url: result.url, key });
	      uni.setStorageSync('allUploadedUrls', allUploadedUrls.value);
	    })
	    .catch(error => {
	      // 上传失败:更新状态
	      fileList.value[key][fileIndex].status = 'fail';
	      fileList.value[key][fileIndex].message = error.message;
	    });
		
	};
	
	// 4. 辅助方法:判断是否为图片
// 4. 辅助方法:判断是否为图片
const isImage = (url) => {
  if (!url) return false; // 路径为空时视为非图片
  const imgExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'jfif']; // 覆盖常见图片格式
  const ext = url.split('.').pop().toLowerCase().split('?')[0]; // 去除URL参数影响(如xxx.png?123)
  return imgExts.includes(ext);
};

// 辅助方法:提取文件名(保持不变,确保正确获取扩展名)
const getFileName = (url) => {
  if (!url) return '未知文件';
  const urlWithoutParams = url.split('?')[0]; // 去除参数
  const fileName = urlWithoutParams.split('/').pop(); // 提取最后一段作为文件名
  return fileName || '未知文件';
};

const shore = () => {
  // 可添加点击确定后的逻辑
  // 检查是否有未上传的文件
  let allUploaded = true;
  // 检查 array 对应的上传项
  array.value.forEach(item => {
    if (item.key == 'id' && (!fileList.value[item.key] || fileList.value[item.key].length === 0)) {
      allUploaded = false;
    }
  });
  if (!allUploaded) {
    uni.showToast({
      title: '所有项都是必填项',
      icon: 'none'
    });
    return;
  } else {
    // 其他
    let filelasrt_other = []
    fileList_other.value.forEach(item => {
      filelasrt_other.push(item.url)
    })
    // 初始化文件数组
    const fileGroups = {
      id: [],
      contract: [],
      bill: [],
      boxing: [],
      form: [],
      other:[]
    };
    // 处理已上传的文件
    try {
      const allUploadedUrls = uni.getStorageSync('allUploadedUrls') || [];
      console.log(allUploadedUrls, '刪除后保存');
      if (Array.isArray(allUploadedUrls)) {
        allUploadedUrls.forEach(item => {
          if (item.key && item.url) {
            // 根据key将url分类到对应的数组
            switch (item.key) {
              case 'contract':
                fileGroups.contract.push(item.url);
                break;
              case 'bill':
                fileGroups.bill.push(item.url);
                break;
              case 'id':
              case 'idB': // 身份证正反面都归类到id
                fileGroups.id.push(item.url);
                break;
              case 'boxing':
                fileGroups.boxing.push(item.url);
                break;
              case 'form':
                fileGroups.form.push(item.url);
                break;
              case 'other':
                fileGroups.other.push(item.url);
                break;
              default:
                console.warn('未知文件类型:', item.key);
            }
          }
        });
      }
    } catch (error) {
      console.error('处理已上传文件时出错:', error);
    }

    // 构建最终信息对象
    const info = {
      ...fileGroups,
      text: '已上傳'
    };
    let declareclass = uni.getStorageSync('declare') || []; // 确保获取到数组,默认空数组

    // 提取 declareclass 中所有必填的 key(这些 key 必须在 filteredInfo 中存在)
    const requiredKeys = declareclass.map(item => item.key);

    // 过滤 info 对象,仅保留存在于 declareclass 中的 key
    const filteredInfo = Object.keys(info).reduce((acc, key) => {
      if (requiredKeys.includes(key)) {
        acc[key] = info[key];
      }
      return acc;
    }, {});
    filteredInfo.text = '已上傳';
    console.log(filteredInfo, '輸出');

    // 移除值为空数组的字段
    for (let key in filteredInfo) {
      if (Array.isArray(filteredInfo[key]) && filteredInfo[key].length === 0) {
        delete filteredInfo[key];
      }
    }

    // 新增:检查身份证图片数量是否为2
    if (requiredKeys.includes('id') && (!filteredInfo.id || filteredInfo.id.length !== 2)) {
      uni.showToast({
        title: '请上传身份证正反面照片',
        icon: 'none'
      });
      return;
    }

    // 核心检查:确保 declareclass 中的所有 key 都在 filteredInfo 中存在
    const allRequiredExist = requiredKeys.every(key => filteredInfo.hasOwnProperty(key));

    if (!allRequiredExist) {
      // 存在未上传的必填项
      uni.showToast({
        title: '所有项都是必填项1',
        icon: 'none'
      });
      return; // 阻止后续操作
    }

    // 所有必填项都存在,继续执行
    console.log(filteredInfo, 'so?');
    uni.setStorageSync('info_url', filteredInfo);
    uni.setStorageSync('info_content_url', filteredInfo);
    uni.setStorageSync('clsledir', '1');
    uni.navigateBack(1);
    uni.setStorageSync('info_urclassl', '1');
  }
};
const previewDemoImage = (imageUrl) => {
  // 校验图片URL是否有效
  if (!imageUrl) {
    uni.showToast({ title: '图片地址无效', icon: 'none' });
    return;
  }

  // 调用微信原生预览接口
  uni.previewImage({
    urls: [imageUrl], // 预览的图片URL数组(单张图片也需放在数组中)
    current: 0, // 默认显示第几张(这里只有一张,为0)
    success: () => {
      console.log('图片预览成功');
    },
    fail: (err) => {
      console.error('图片预览失败:', err);
      uni.showToast({ title: '预览失败,请检查图片地址', icon: 'none' });
    }
  });
};
	let array = ref([]);
	const towupload = ref(false);
	const onwupload = ref(false);
	const suipupload = ref(false);
	// 处理身份证上传的通用函数
const handleIdUpload = (event, key) => {
		const files = Array.isArray(event.file) ? event.file : [event.file];
		files.forEach((file) => {
			// 确保数组存在
			if (!fileList.value[key]) {
				fileList.value[key] = [];
			}

			// 清空现有数组(替换模式)
			if (key === 'id' && fileList.value[key].length > 0) {
				fileList.value[key] = [];
			} 
			if (key === 'idB' && fileList.value[key].length > 0) {
				fileList.value[key] = [];
			}

			// 添加新的上传项
			fileList.value[key].push({
				url: file.url,
				status: 'uploading',
				message: '',
				id: ''
			});

			uploadFile(file.url)
				.then((result) => {
					const index = fileList.value[key].findIndex((item) => item.url === file.url);
					if (index !== -1) {
						// 创建新对象替换旧对象,确保响应式更新
						const newItem = {
							...fileList.value[key][index],
							status: 'success',
							url: result.url,
							id: result.id
						};

						fileList.value[key].splice(index, 1, newItem);

						// 更新 allUploadedUrls
						const urlIndex = allUploadedUrls.value.findIndex(
							(item) => item.key === key
						);

						if (urlIndex !== -1) {
							allUploadedUrls.value.splice(urlIndex, 1, {
								url: result.url,
								key: key,
								type: key === 'id' ? 'id' : 'idB',
								fileName: file.name
							});
						} else {
							allUploadedUrls.value.push({
								url: result.url,
								key: key,
								type: key === 'id' ? 'id' : 'idB',
								fileName: file.name
							});
						}

						uni.setStorageSync('allUploadedUrls', allUploadedUrls.value);
						
						// 身份证上传成功提示日志
						const successMsg = key === 'id' 
							? '身份证人像页上传成功' 
							: '身份证国徽页上传成功';
						uni.showToast({ title: successMsg, icon: 'none' });
						console.log(successMsg, '文件ID:', result.id);
					}
				})
				.catch((error) => {
					const index = fileList.value[key].findIndex((item) => item.url === file.url);
					if (index !== -1) {
						fileList.value[key][index].status = 'fail';
						fileList.value[key][index].message = error.message;
					}
					
					// 身份证上传失败提示日志
					const failMsg = key === 'id' 
						? `身份证人像页上传失败: ${error.message}` 
						: `身份证国徽页上传失败: ${error.message}`;
					uni.showToast({ title: failMsg, icon: 'none' });
					console.error(failMsg, '错误详情:', error);
				});
		});
	};
	// const array = ref([]);
	const fileList = ref({});
	const fileList_other = ref([]);
	const allUploadedUrls = ref([]); // 用于存储所有上传成功的 URL
	// 删除图片
	const deletePic = (event, key) => {
		const deletedUrl = fileList.value[key][event.index].url;
		console.log(deletedUrl);
		fileList.value[key].splice(event.index, 1);
		console.log('After delete:', fileList.value[key]);
		console.log(allUploadedUrls.value);
		// 从 allUploadedUrls 中移除删除的 URL 及其对应的 key
		allUploadedUrls.value = allUploadedUrls.value.filter(item => !(item.url === deletedUrl && item.key === key));
		uni.setStorageSync('allUploadedUrls', allUploadedUrls.value);
	};

	// 删除其他图片
	const deletePic_other = (event) => {
		fileList_other.value.splice(event.index, 1);
	};

	// 上传文件方法
const uploadFile = (filePath) => {
  return new Promise((resolve, reject) => {
    const baseUrl = uni.getStorageSync('http');
    const token = uni.getStorageSync('token');
    const fullUrl = `${baseUrl}/api/public/uploadImage`;

    // 基础参数校验
    if (!baseUrl || !token) {
      reject(new Error('配置错误:服务器地址或Token缺失'));
      return;
    }

    uni.uploadFile({
      url: fullUrl,
      filePath: filePath,
      name: 'file',
      formData: { user: 'test' },
	  header: {
	  	'Authorization': `Bearer ${uni.getStorageSync('token')}` // 修正 Token 格式
	  },
      success: (res) => {
        console.log('上传接口响应状态:', res);

        // 1. 处理 500 服务器错误
        if (res.statusCode === 500) {
          // 记录错误详情(方便排查)
          console.error('服务器内部错误,响应内容:', res.data);
          reject(new Error('服务器繁忙,请稍后再试')); // 友好提示用户
          return;
        }

        // 2. 处理非 200/500 的其他状态码(如 404 接口不存在、403 权限不足)
        if (res.statusCode !== 200) {
          reject(new Error(`上传失败(状态码:${res.statusCode})`));
          return;
        }

        // 3. 处理 200 状态码(HTTP请求成功,需解析业务逻辑)
        try {
          const data = JSON.parse(res.data);
          if (data.code === 0) {
            // 业务成功:返回文件信息
            resolve({ url: data.data.url, id: data.data.id });
          } else {
            // 业务失败(如文件类型不支持、大小超限,后端明确返回错误信息)
            reject(new Error(data.message || '上传失败,请检查文件是否符合要求'));
          }
        } catch (error) {
          // 200状态码但响应格式错误(如后端返回HTML而非JSON)
          console.error('响应格式错误,原始数据:', res.data);
          reject(new Error('服务器返回数据格式错误'));
        }
      },
      fail: (err) => {
		  uni.showToast({ title: '上傳失敗', icon: 'none' });
        // 客户端调用失败(如网络问题、文件不存在)
        console.error('上传调用失败:', err.errMsg);
        reject(new Error(`上传失败:${err.errMsg}`));
      }
    });
  });
};
	// 处理文件上传后的逻辑
const afterRead = (event, key) => {
		console.log('Before upload:', fileList.value[key]);
		console.log(key);
		const files = Array.isArray(event.file) ? event.file : [event.file];
		files.forEach((file) => {
			if (!fileList.value[key]) {
				fileList.value[key] = [];
			}
			fileList.value[key].push({
				url: file.url,
				status: 'uploading',
				message: '',
				id: ''
			});

			uploadFile(file.url)
				.then((result) => {
					const index = fileList.value[key].findIndex((item) => item.url === file.url);
					if (index !== -1) {
						fileList.value[key][index] = {
							...fileList.value[key][index],
							status: 'success',
							url: result.url,
							id: result.id
						};
						allUploadedUrls.value.push({
							url: result.url,
							key: key
						});
						uni.setStorageSync('allUploadedUrls', allUploadedUrls.value);
						
						// 新增:通用文件上传成功提示
						const item = array.value.find(i => i.key === key);
						const fileName = item?.name || '文件';
						uni.showToast({ title: `${fileName}上传成功`, icon: 'none' });
						console.log(`${fileName}上传成功`, result.url);
					}
					console.log('After upload success:', fileList.value[key]);
				})
				.catch((error) => {
					const index = fileList.value[key].findIndex((item) => item.url === file.url);
					if (index !== -1) {
						fileList.value[key][index].status = 'fail';
						fileList.value[key][index].message = error.message;
					}
					
					// 新增:通用文件上传失败提示
					const item = array.value.find(i => i.key === key);
					const fileName = item?.name || '文件';
					uni.showToast({ title: `${fileName}上传失败: ${error.message}`, icon: 'none' });
					console.error(`${fileName}上传失败`, error);
				});
		});
	};
	// 根据 key 判断是否显示组件
	const shouldShowComponent = (key) => {
		// 这里可以添加更多逻辑,目前默认都显示
		return true;
	};

	function transformData(obj) {
		const result = [];

		// 遍历对象的每个属性
		Object.keys(obj).forEach(key => {
			// 处理特殊情况:id 字段需要拆分为 id 和 idB
			if (key === 'id' && Array.isArray(obj[key]) && obj[key].length > 0) {
				// 添加 id 字段
				result.push({
					key: 'id',
					url: obj[key][0]
				});

				// 添加 idB 字段(如果存在第二个 URL)
				if (obj[key].length > 1) {
					result.push({
						key: 'idB',
						url: obj[key][1]
					});
				}
			}
			// 处理其他字段
			else if (Array.isArray(obj[key]) && obj[key].length > 0) {
				// 每个 URL 创建一个对象
				obj[key].forEach(url => {
					result.push({
						key: key,
						url: url
					});
				});
			}
		});

		return result;
	}
	// 新增标记位,记录是否已初始化
	const isInitialized = ref(false);
	const classhow = ref(true)
	onShow(() => {
		if (!isInitialized.value) {
			// 首次进入:初始化并读取存储
			initializeFileList();
			isInitialized.value = true;
		} else {
			// 页面回流:跳过初始化,避免清空已上传内容
			console.log('页面重新显示,复用之前的文件状态');
		}
	});

	// 抽离初始化逻辑为独立函数
	function initializeFileList() {
		// 1. 初始化 fileList(仅首次)
		fileList.value = {
			id: [],
			idB: [],
			contract: [],
			bill: [],
			boxing: [],
			form: []
		};

		// 2. 初始化 other 文件列表
		fileList_other.value = [];
		const uni_order = uni.getStorageSync('Details');
		if (uni_order) {
			classhow.value = false;
		}
		// 3. 读取存储并回显
		const declareArr = uni.getStorageSync('declare');
		array.value = declareArr || [];

		const clasasppr = uni.getStorageSync('info_url');
		if (clasasppr) {
			handleOtherFiles(clasasppr); // 抽离的回显逻辑
		}

		const storedUrls = uni.getStorageSync('allUploadedUrls') || [];
		restoreUploadedUrls(storedUrls); // 抽离的回显逻辑
	}

	// 抽离:回显 other 类型文件
	function handleOtherFiles(clasasppr) {
		if (clasasppr.other && Array.isArray(clasasppr.other)) {
			clasasppr.other.forEach(url => {
				if (!fileList_other.value.some(item => item.url === url)) {
					fileList_other.value.push({
						url,
						status: 'success',
						message: ''
					});
				}
			});
		}
	}

	// 抽离:回显已上传的图片
	function restoreUploadedUrls(storedUrls) {
		allUploadedUrls.value = [];
		storedUrls.forEach((item) => {
			if (!fileList.value[item.key]) {
				fileList.value[item.key] = [];
			}
			fileList.value[item.key].push({
				url: item.url,
				status: 'success',
				id: item.id || '',
				message: ''
			});
			allUploadedUrls.value.push({
				url: item.url,
				key: item.key
			});
		});
		uni.setStorageSync('classupdate', allUploadedUrls.value);
	}


</script>
相关推荐
Near_Li3 小时前
uniapp-使用mumu模拟器调试安卓APP
android·uni-app
00后程序员张10 小时前
Charles中文版抓包工具功能解析,提升API调试与网络性能优化
android·ios·小程序·https·uni-app·iphone·webview
九点五亿少女的梦13 小时前
uniapp开发微信小程序遇到富文本内容大小变形问题v-html
微信小程序·uni-app·html
2501_916013741 天前
iOS混淆工具有哪些?跨平台 App 混淆与保护的实用方案
android·ios·小程序·https·uni-app·iphone·webview
2501_915909061 天前
iOS 文件管理实战指南,用户文件、安全访问与开发调试方案
android·ios·小程序·https·uni-app·iphone·webview
小小黑0071 天前
总结运行CRMEB标准版(uniapp)微信小程序的问题
微信小程序·小程序·uni-app
!win !2 天前
支付宝小程序IDE突然极不稳定
uni-app·支付宝小程序
2501_916007472 天前
Charles中文版抓包工具使用指南 提高API调试和网络优化效率
android·ios·小程序·https·uni-app·iphone·webview
Rudon滨海渔村2 天前
[失败记录] 使用HBuilderX创建的uniapp vue3项目添加tailwindcss3的完整过程
css·uni-app·tailwindcss