Răsfoiți Sursa

feat: update work order pages and enhance upload functionality

- Modified the pages.json to include new navigation paths for "我的列表" and "提交工单".
- Enhanced the cy-upload component to support multiple file uploads and set a maximum count of files.
- Improved error handling in work order history and detail pages to provide more informative messages.
- Updated navigation URLs in work order creation and recycle pages to ensure proper encoding of parameters.
- Refactored image handling logic in various components for better performance and reliability.
ylong 1 lună în urmă
părinte
comite
8ad305b113
37 a modificat fișierele cu 407 adăugiri și 106 ștergeri
  1. 35 27
      components/cy-upload/index.vue
  2. 1 1
      config/request.js
  3. 14 2
      pages.json
  4. 18 14
      pages/index/work-order/history.vue
  5. 5 5
      pages/index/work-order/mall.vue
  6. 9 5
      pages/index/work-order/recycle.vue
  7. 20 10
      pages/order/components/info-card.vue
  8. 1 1
      pages/order/components/track-form.vue
  9. 38 5
      pages/order/components/track-record.vue
  10. 2 2
      pages/order/index.vue
  11. 48 16
      pages/order/mall/created.vue
  12. 5 3
      pages/order/mall/detail.vue
  13. 64 0
      pages/order/mall/my-list.vue
  14. 19 9
      pages/order/recycle/created.vue
  15. 7 4
      pages/order/recycle/detail.vue
  16. 115 0
      pages/order/recycle/my-list.vue
  17. 6 2
      pages/order/recycle/pending.vue
  18. 0 0
      unpackage/dist/build/app-plus/app-config-service.js
  19. 0 0
      unpackage/dist/build/app-plus/app-service.js
  20. 0 0
      unpackage/dist/build/app-plus/pages/book/index.css
  21. 0 0
      unpackage/dist/build/app-plus/pages/index/detail/book-audit.css
  22. 0 0
      unpackage/dist/build/app-plus/pages/index/detail/index.css
  23. 0 0
      unpackage/dist/build/app-plus/pages/index/detail/review-book.css
  24. 0 0
      unpackage/dist/build/app-plus/pages/index/detail/review-detail.css
  25. 0 0
      unpackage/dist/build/app-plus/pages/index/express/weight-modify.css
  26. 0 0
      unpackage/dist/build/app-plus/pages/index/wms/code-storage-add.css
  27. 0 0
      unpackage/dist/build/app-plus/pages/index/work-order/history.css
  28. 0 0
      unpackage/dist/build/app-plus/pages/index/work-order/mall.css
  29. 0 0
      unpackage/dist/build/app-plus/pages/index/work-order/recycle.css
  30. 0 0
      unpackage/dist/build/app-plus/pages/order/index.css
  31. 0 0
      unpackage/dist/build/app-plus/pages/order/mall/created.css
  32. 0 0
      unpackage/dist/build/app-plus/pages/order/mall/detail.css
  33. 0 0
      unpackage/dist/build/app-plus/pages/order/mall/my-list.css
  34. 0 0
      unpackage/dist/build/app-plus/pages/order/recycle/created.css
  35. 0 0
      unpackage/dist/build/app-plus/pages/order/recycle/detail.css
  36. 0 0
      unpackage/dist/build/app-plus/pages/order/recycle/my-list.css
  37. 0 0
      unpackage/dist/build/app-plus/pages/order/recycle/pending.css

+ 35 - 27
components/cy-upload/index.vue

@@ -1,6 +1,6 @@
 <template>
 	<u-upload v-bind="$attrs" :fileList="fileList" @afterRead="afterRead" @delete="deletePic" :notFile="notFile"
-		:disabled="disabled">
+		:disabled="disabled" :multiple="multiple" :maxCount="maxCount">
 	</u-upload>
 	<view class="tips" v-if="tips">{{tips}}</view>
 </template>
@@ -40,6 +40,14 @@
         loading:{
             type:Boolean,
             default:false
+        },
+        multiple: {
+            type: Boolean,
+            default: false
+        },
+        maxCount: {
+            type: [Number, String],
+            default: 9
         }
 	})
 	const fileList = ref([])
@@ -61,41 +69,40 @@
 	})
 
 	const afterRead = async (e) => {
-		const {
-			file
-		} = e
-		fileList.value.push({
-			...file,
-			status: 'uploading',
-			message: '上传中...',
-		});
-        emit('update:loading',true)
-		const result = await uploadFilePromise(file.url, props.url);
-		console.log(result, 'result')
-
-		fileList.value.forEach((v,index) => {
-			if(index == fileList.value.length - 1){
-				v.url = result.url
-				v.status = 'success'
-				v.message = ''
-			}
-		})
-		console.log(fileList.value, 'fileList.value')
-		//更新外部参数
-		emit('update:filename', fileList.value.map(v => v.url))
-		emit('success', result)
-        emit('update:loading',false)
+		const files = Array.isArray(e.file) ? e.file : [e.file]
+        emit('update:loading', true)
+        try {
+            for (const file of files) {
+                const idx = fileList.value.length
+                fileList.value.push({
+                    ...file,
+                    status: 'uploading',
+                    message: '上传中...',
+                })
+                const result = await uploadFilePromise(file.url, props.url)
+                if (fileList.value[idx]) {
+                    fileList.value[idx].url = result.url || result.data?.url || result.fileName || file.url
+                    fileList.value[idx].status = 'success'
+                    fileList.value[idx].message = ''
+                }
+                emit('success', result)
+            }
+            emit('update:filename', fileList.value.map(v => v.url).filter(Boolean))
+        } finally {
+            emit('update:loading', false)
+        }
 	}
 
 	const deletePic = (event) => {
 		fileList.value.splice(event.index, 1);
+		emit('update:filename', fileList.value.map(v => v.url).filter(Boolean))
 	}
 
 	const uploadFilePromise = (url, baseStr = '/app/common/upload') => {
 		let token = uni.getStorageSync('token')
 		return new Promise((resolve, reject) => {
 			let a = uni.uploadFile({
-				url: baseUrl + baseStr, // 图片上传地址
+				url: baseUrl + baseStr,
 				filePath: url,
 				name: 'file',
 				header: {
@@ -105,6 +112,7 @@
 					let respic = JSON.parse(res.data)
 					resolve(respic)
 				},
+                fail: reject
 			});
 		});
 	};
@@ -123,4 +131,4 @@
 	::v-deep .align-right .u-upload__wrap {
 		justify-content: flex-end;
 	}
-</style>
+</style>

+ 1 - 1
config/request.js

@@ -1,7 +1,7 @@
 /**
  * 文档地址:https://uiadmin.net/uview-plus/js/http.html
  */
-const baseUrl = "https://bpi.shuhi.com";
+const baseUrl = "https://bk.shuhi.com";
 export function initRequest() {
     console.log("初始化了 http 请求代码");
     // 初始化请求配置

+ 14 - 2
pages.json

@@ -453,11 +453,17 @@
 					}
 				},
 				{
-					"path": "created",
+					"path": "my-list",
 					"style": {
 						"navigationBarTitleText": "我创建的"
 					}
 				},
+				{
+					"path": "created",
+					"style": {
+						"navigationBarTitleText": "提交工单"
+					}
+				},
 				{
 					"path": "detail",
 					"style": {
@@ -476,11 +482,17 @@
 					}
 				},
 				{
-					"path": "created",
+					"path": "my-list",
 					"style": {
 						"navigationBarTitleText": "我创建的"
 					}
 				},
+				{
+					"path": "created",
+					"style": {
+						"navigationBarTitleText": "提交工单"
+					}
+				},
 				{
 					"path": "detail",
 					"style": {

+ 18 - 14
pages/index/work-order/history.vue

@@ -46,11 +46,11 @@
 
                 <view class="info-row">
                     <text class="label">指派人:</text>
-                    <text class="value">{{  workOrderDetail.handleUsers.map(item => item.userName).join(',') || '-' }}</text>
+                    <text class="value">{{  (workOrderDetail.handleUsers || []).map(item => item.userName).filter(Boolean).join(',') || '-' }}</text>
                 </view>
                 
                 <!-- 图片展示 -->
-                <view class="image-list" v-if="workOrderDetail.imgInfo && workOrderDetail.imgInfo.imgUrlList.length > 0">
+                <view class="image-list" v-if="workOrderDetail.imgInfo && workOrderDetail.imgInfo.imgUrlList && workOrderDetail.imgInfo.imgUrlList.length > 0">
                     <image 
                         v-for="(img, index) in workOrderDetail.imgInfo.imgUrlList" 
                         :key="index"
@@ -156,22 +156,26 @@ const getWorkOrderDetail = async () => {
         }
     } catch (error) {
         console.error(error)
-        uni.$u.toast('网络错误')
+        uni.$u.toast(error?.data?.msg || error?.msg || '网络错误')
     } finally {
         uni.hideLoading()
     }
 }
 
 // 预览图片
+const getImageUrlList = () => {
+    const info = workOrderDetail.value?.imgInfo
+    if (!info) return []
+    if (Array.isArray(info?.imgUrlList)) return info.imgUrlList.filter(Boolean)
+    if (Array.isArray(info)) return info.map(v => (typeof v === 'string' ? v : v?.url)).filter(Boolean)
+    if (typeof info === 'string') return info.split(',').map(s => s.trim()).filter(Boolean)
+    return []
+}
+
 const previewImage = (index) => {
-    if (workOrderDetail.value?.imgInfo) {
-        const urls = Array.isArray(workOrderDetail.value.imgInfo) ? workOrderDetail.value.imgInfo : workOrderDetail.value.imgInfo.split(',')
-        if (urls.length > 0) {
-            uni.previewImage({
-                urls: urls,
-                current: index
-            })
-        }
+    const urls = getImageUrlList()
+    if (urls.length > 0) {
+        uni.previewImage({ urls, current: index })
     }
 }
 
@@ -217,7 +221,7 @@ const handleFinish = async () => {
                     }
                 } catch (error) {
                     console.error(error)
-                    uni.$u.toast('网络错误')
+                    uni.$u.toast(error?.data?.msg || error?.msg || '网络错误')
                 } finally {
                     uni.hideLoading()
                 }
@@ -248,7 +252,7 @@ const handleCancel = async () => {
                     }
                 } catch (error) {
                     console.error(error)
-                    uni.$u.toast('网络错误')
+                    uni.$u.toast(error?.data?.msg || error?.msg || '网络错误')
                 } finally {
                     uni.hideLoading()
                 }
@@ -279,7 +283,7 @@ const handleReopen = async () => {
                     }
                 } catch (error) {
                     console.error(error)
-                    uni.$u.toast('网络错误')
+                    uni.$u.toast(error?.data?.msg || error?.msg || '网络错误')
                 } finally {
                     uni.hideLoading()
                 }

+ 5 - 5
pages/index/work-order/mall.vue

@@ -52,17 +52,17 @@ const handleSubmit = async () => {
         
         if (res.code === 200) {
             if (res.data && res.data.id) {
-                // 存在历史工单,跳转到历史工单页面
+                const waybillCode = res.data.waybillCode || formData.value.search || '';
+                const orderId = res.data.orderId || '';
                 uni.navigateTo({
-                    url: `/pages/index/work-order/history?workOrderId=${res.data.id}&type=1&waybillCode=${res.data.waybillCode || formData.value.search}&orderId=${res.data.orderId || ''}`,
+                    url: `/pages/index/work-order/history?workOrderId=${res.data.id}&type=1&waybillCode=${encodeURIComponent(waybillCode)}&orderId=${encodeURIComponent(orderId)}`,
                 });
             } else {
-                // 不存在历史工单,跳转到创建工单页面,携带回填信息
                 const orderId = res.data?.orderId || '';
                 const waybillCode = res.data?.waybillCode || formData.value.search;
-                const expressType = res.data?.expressType || '';
+                const expressType = res.data?.expressType ?? '';
                 uni.navigateTo({
-                    url: `/pages/order/mall/created?waybillCode=${waybillCode}&orderId=${orderId}&expressType=${expressType}&readonly=1`,
+                    url: `/pages/order/mall/created?waybillCode=${encodeURIComponent(waybillCode)}&orderId=${encodeURIComponent(orderId)}&expressType=${expressType}&readonly=1`,
                 });
             }
         } else {

+ 9 - 5
pages/index/work-order/recycle.vue

@@ -44,7 +44,7 @@ const formData = ref({
 // 处理查询
 const handleSubmit = async () => {
     if (!formData.value.search) {
-        uni.$u.toast("请扫描/输入物流单号");
+        uni.$u.toast(formData.value.searchType === '1' ? "请扫描/输入订单号" : "请扫描/输入物流单号");
         return;
     }
     
@@ -62,17 +62,21 @@ const handleSubmit = async () => {
             const reqOrderId = formData.value.searchType === '1' ? formData.value.search : '';
             
             if (res.data && res.data.id) {
-                // 存在历史工单,跳转到历史工单页面
+                const waybillCode = res.data.waybillCode || reqWaybillCode || '';
+                const orderId = res.data.orderId || reqOrderId || '';
                 uni.navigateTo({
-                    url: `/pages/index/work-order/history?workOrderId=${res.data.id}&type=2&waybillCode=${res.data.waybillCode}&orderId=${res.data.orderId}`,
+                    url: `/pages/index/work-order/history?workOrderId=${res.data.id}&type=2&waybillCode=${encodeURIComponent(waybillCode)}&orderId=${encodeURIComponent(orderId)}`,
                 });
             } else {
-                // 不存在历史工单,跳转到创建工单页面,携带回填信息
                 const orderId = res.data?.orderId || reqOrderId;
                 const waybillCode = res.data?.waybillCode || reqWaybillCode;
                 const expressType = res.data?.expressType || '';
+                if (!orderId && !waybillCode) {
+                    uni.$u.toast('未查询到关联订单/物流信息');
+                    return;
+                }
                 uni.navigateTo({
-                    url: `/pages/order/recycle/created?waybillCode=${waybillCode}&orderId=${orderId}&expressType=${expressType}&readonly=1`,
+                    url: `/pages/order/recycle/created?waybillCode=${encodeURIComponent(waybillCode)}&orderId=${encodeURIComponent(orderId)}&expressType=${expressType}&readonly=1`,
                 });
             }
         } else {

+ 20 - 10
pages/order/components/info-card.vue

@@ -33,9 +33,9 @@
             <text class="label">任务状态:</text>
             <text class="status" :class="{ danger: detail.taskStatusName === '待处理' }">{{ detail.taskStatusName }}</text>
         </view>
-        <view class="image-wrap" v-if="imgSrc">
-            <u-image :src="imgSrc" width="150rpx" height="150rpx" radius="8" mode="aspectFill"
-                @click="preview"></u-image>
+        <view class="image-wrap" v-if="imageList.length">
+            <u-image v-for="(src, idx) in imageList" :key="idx" :src="src" width="150rpx" height="150rpx" radius="8" mode="aspectFill"
+                @click="preview(idx)"></u-image>
         </view>
     </view>
 </template>
@@ -54,21 +54,28 @@ const props = defineProps({
     }
 })
 
-const imgSrc = computed(() => props.detail.imageUrl || props.detail.imgPath || '')
+const imageList = computed(() => {
+    if (Array.isArray(props.detail.imageUrls) && props.detail.imageUrls.length) {
+        return props.detail.imageUrls.filter(Boolean)
+    }
+    const info = props.detail.imgInfo
+    if (info?.imgUrlList?.length) return info.imgUrlList.filter(Boolean)
+    if (props.detail.imageUrl) return [props.detail.imageUrl]
+    if (props.detail.imgPath) return [props.detail.imgPath]
+    return []
+})
 
 const copy = (text) => {
     if (!text) return
     uni.setClipboardData({ data: String(text) })
 }
 
-const preview = () => {
-    if (props.detail.imageUrls && props.detail.imageUrls.length > 0) {
+const preview = (index = 0) => {
+    if (imageList.value.length > 0) {
         uni.previewImage({
-            urls: props.detail.imageUrls,
-            current: 0
+            urls: imageList.value,
+            current: index
         })
-    } else if (imgSrc.value) {
-        uni.previewImage({ urls: [imgSrc.value] })
     }
 }
 </script>
@@ -118,5 +125,8 @@ const preview = () => {
 
 .image-wrap {
     margin: 16rpx 0;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 12rpx;
 }
 </style>

+ 1 - 1
pages/order/components/track-form.vue

@@ -10,7 +10,7 @@
         </view>
         <view class="field">
             <text class="label">上传图片</text>
-            <cy-upload :filename="files" @update:filename="files = $event" @update:loading="uploading = $event" />
+            <cy-upload :filename="files" @update:filename="files = $event" @update:loading="uploading = $event" :multiple="true" :maxCount="9" />
         </view>
         <view class="actions">
             <u-button type="primary" :loading="uploading" :disabled="uploading || submitting"

+ 38 - 5
pages/order/components/track-record.vue

@@ -36,12 +36,45 @@ const props = defineProps({
     }
 })
 
-const getImgs = (item) => {
-    const arr = item?.images || item?.files || item?.fileList || item?.pictures || item?.newContent || []
+const isImageUrl = (v) => {
+    if (!v || typeof v !== 'string') return false
+    const s = v.trim()
+    if (!s) return false
+    if (/^https?:\/\//i.test(s) || s.startsWith('/') || s.startsWith('data:image')) return true
+    return /\.(png|jpe?g|gif|webp|bmp)(\?.*)?$/i.test(s)
+}
+
+const normalizeImgs = (arr) => {
     if (!arr) return []
-    return Array.isArray(arr)
-        ? arr.map(v => typeof v === 'string' ? v : (v?.url || '')).filter(Boolean)
-        : []
+    if (typeof arr === 'string') {
+        return arr.split(',').map(s => s.trim()).filter(isImageUrl)
+    }
+    if (Array.isArray(arr)) {
+        return arr.map(v => typeof v === 'string' ? v : (v?.url || v?.imgUrl || '')).filter(isImageUrl)
+    }
+    if (typeof arr === 'object') {
+        if (Array.isArray(arr.imgUrlList)) return normalizeImgs(arr.imgUrlList)
+        if (arr.url) return isImageUrl(arr.url) ? [arr.url] : []
+    }
+    return []
+}
+
+const getImgs = (item) => {
+    const candidates = [
+        item?.imgInfo,
+        item?.images,
+        item?.files,
+        item?.fileList,
+        item?.pictures,
+        item?.imgUrlList,
+        item?.imgUrls,
+    ]
+    for (const c of candidates) {
+        const imgs = normalizeImgs(c)
+        if (imgs.length) return imgs
+    }
+    // newContent 可能是纯文本,只有确认是图片 URL 才展示
+    return normalizeImgs(item?.newContent)
 }
 
 const preview = (urls, index) => {

+ 2 - 2
pages/order/index.vue

@@ -50,7 +50,7 @@
                                 workOrderStat.recycle.myPending || 0
                                 }}</text>
                         </view>
-                        <view @tap="navigateToDetail('/pages/order/recycle/created')">
+                        <view @tap="navigateToDetail('/pages/order/recycle/my-list')">
                             <text class="workorder-label">我创建的</text>
                             <text class="workorder-value">{{
                                 workOrderStat.recycle.myCreated || 0
@@ -71,7 +71,7 @@
                                 workOrderStat.mall.myPending || 0
                                 }}</text>
                         </view>
-                        <view @tap="navigateToDetail('/pages/order/mall/created')">
+                        <view @tap="navigateToDetail('/pages/order/mall/my-list')">
                             <text class="workorder-label">我创建的</text>
                             <text class="workorder-value">{{
                                 workOrderStat.mall.myCreated || 0

+ 48 - 16
pages/order/mall/created.vue

@@ -15,28 +15,32 @@
                     <u-input v-else v-model="form.orderId" placeholder="请输入订单编号" clearable></u-input>
                 </u-form-item> -->
                 <u-form-item label="承运商:" prop="carrier" required>
-                    <u-input v-model="carrierText" readonly suffixIcon="arrow-down" placeholder="请选择"
-                        @click="!isReadonly && (showCarrierPicker = true)"></u-input>
+                    <view class="picker-field" @click="openCarrierPicker" @tap="openCarrierPicker">
+                        <u-input v-model="carrierText" readonly suffixIcon="arrow-down" placeholder="请选择"></u-input>
+                    </view>
                 </u-form-item>
                 <u-form-item label="验货状态:" prop="verifyStatus" required>
-                    <u-input v-model="verifyText" readonly suffixIcon="arrow-down" placeholder="请选择"
-                        @click="showVerifyPicker = true"></u-input>
+                    <view class="picker-field" @tap="showVerifyPicker = true">
+                        <u-input v-model="verifyText" readonly suffixIcon="arrow-down" placeholder="请选择"></u-input>
+                    </view>
                 </u-form-item>
                 <u-form-item label="任务类型:" prop="taskType" required>
-                    <u-input v-model="taskTypeText" readonly suffixIcon="arrow-down" placeholder="请选择"
-                        @click="showTaskTypePicker = true"></u-input>
+                    <view class="picker-field" @tap="showTaskTypePicker = true">
+                        <u-input v-model="taskTypeText" readonly suffixIcon="arrow-down" placeholder="请选择"></u-input>
+                    </view>
                 </u-form-item>
                 <u-form-item label="任务详情:" prop="taskDetail" required>
                     <u-textarea v-model="form.taskDetail" placeholder="请输入" :height="120"
                         :autoHeight="true"></u-textarea>
                 </u-form-item>
                 <u-form-item label="上传图片:" prop="images" required>
-                    <cy-upload :filename="form.images" @update:filename="form.images = $event" />
+                    <cy-upload :filename="form.images" @update:filename="form.images = $event" :multiple="true" :maxCount="9" />
                 </u-form-item>
                 <view class="divider"></view>
                 <u-form-item label="指派给:" prop="assignTo">
-                    <u-input v-model="assignText" readonly suffixIcon="arrow-down" placeholder="请选择 (非必填)"
-                        @click="openAssignPicker"></u-input>
+                    <view class="picker-field" @tap="openAssignPicker">
+                        <u-input v-model="assignText" readonly suffixIcon="arrow-down" placeholder="请选择 (非必填)"></u-input>
+                    </view>
                 </u-form-item>
             </u-form>
         </view>
@@ -127,6 +131,10 @@ const getCarrierOptions = async () => {
                 text: item.dictLabel,
                 value: item.dictValue
             }))
+            if (form.value.expressType !== '' && form.value.expressType !== undefined && form.value.expressType !== null) {
+                const matchedCarrier = carrierOptions.value.find(item => String(item.value) === String(form.value.expressType))
+                if (matchedCarrier) carrierText.value = matchedCarrier.text
+            }
         }
     } catch (e) {
         console.error('获取快递公司失败', e)
@@ -202,8 +210,13 @@ const onPickTaskType = (e) => {
 }
 
 // 打开指派人选择器时,初始化临时选中状态
+const openCarrierPicker = () => {
+    if (isEdit.value) return
+    showCarrierPicker.value = true
+}
+
 const openAssignPicker = () => {
-    if (isReadonly.value) return
+    if (isEdit.value) return
     // 根据当前已选择的值,初始化 tempAssignIndexes
     tempAssignIndexes.value = []
     if (form.value.assignTo && form.value.assignTo.length > 0) {
@@ -332,7 +345,7 @@ const onSubmit = async () => {
 
     if (isEdit.value) {
         payload.id = workOrderId.value
-        payload.updateType = 1
+        payload.updateType = 2
     }
 
     const apiUrl = isEdit.value ? '/app/workOrder/update' : '/app/workOrder/createWorkOrder'
@@ -340,21 +353,26 @@ const onSubmit = async () => {
     try {
         const res = await uni.$u.http.post(apiUrl, payload)
         if (res?.code === 200) {
+            uni.$u.ttsModule?.speak?.('提交成功')
             uni.$u.toast('提交成功')
-            uni.navigateBack()
+            if (isEdit.value) {
+                uni.navigateBack()
+            } else {
+                uni.redirectTo({ url: '/pages/index/work-order/mall' })
+            }
         } else {
             uni.$u.toast(res?.msg || '提交失败')
         }
     } catch (err) {
-        uni.$u.toast('网络错误,已本地保存')
+        uni.$u.toast(err?.data?.msg || err?.msg || '网络错误')
     } finally {
         submitting.value = false
     }
 }
 
 onLoad((options) => {
-    form.value.waybillCode = options?.waybillCode || ''
-    form.value.orderId = options?.orderId || ''
+    form.value.waybillCode = options?.waybillCode ? decodeURIComponent(options.waybillCode) : ''
+    form.value.orderId = options?.orderId ? decodeURIComponent(options.orderId) : ''
 
     if (options?.readonly == 1) {
         isReadonly.value = true
@@ -362,9 +380,15 @@ onLoad((options) => {
         if (options?.expressType !== undefined && options?.expressType !== null) {
             form.value.expressType = parseInt(options.expressType)
             // 从字典中查找对应的文本
-            const matchedCarrier = carrierOptions.value.find(item => item.value === options.expressType)
+            const matchedCarrier = carrierOptions.value.find(item => String(item.value) === String(options.expressType))
             if (matchedCarrier) {
                 carrierText.value = matchedCarrier.text
+            } else {
+                // 字典异步加载后再回显
+                setTimeout(() => {
+                    const c = carrierOptions.value.find(item => String(item.value) === String(options.expressType))
+                    if (c) carrierText.value = c.text
+                }, 300)
             }
         }
     }
@@ -496,4 +520,12 @@ onLoad((options) => {
     color: #2979ff;
     line-height: 60rpx;
 }
+.picker-field {
+    width: 100%;
+    min-height: 60rpx;
+}
+.picker-field :deep(.u-input),
+.picker-field :deep(input) {
+    pointer-events: none;
+}
 </style>

+ 5 - 3
pages/order/mall/detail.vue

@@ -107,7 +107,7 @@ const onVoid = () => {
                 try {
                     const result = await uni.$u.http.post('/app/workOrder/cancel', { id: workOrderId.value })
                     if (result.code === 200) {
-                        uni.$u.toast('已作废')
+                        uni.$u.ttsModule?.speak?.('已作废'); uni.$u.toast('已作废')
                         setTimeout(() => {
                             uni.navigateBack()
                         }, 1000)
@@ -116,6 +116,7 @@ const onVoid = () => {
                     }
                 } catch (e) {
                     console.error(e)
+                    uni.$u.toast(e?.data?.msg || e?.msg || '网络错误')
                 }
             }
         }
@@ -131,7 +132,7 @@ const onFinish = () => {
                 try {
                     const result = await uni.$u.http.post('/app/workOrder/finish', { ids: [workOrderId.value] })
                     if (result.code === 200) {
-                        uni.$u.toast('已完成')
+                        uni.$u.ttsModule?.speak?.('已完成'); uni.$u.toast('已完成')
                         setTimeout(() => {
                             uni.navigateBack()
                         }, 1000)
@@ -140,6 +141,7 @@ const onFinish = () => {
                     }
                 } catch (e) {
                     console.error(e)
+                    uni.$u.toast(e?.data?.msg || e?.msg || '网络错误')
                 }
             }
         }
@@ -157,7 +159,7 @@ const onReopen = () => {
                     // 假设接口是 /app/workOrder/reopen
                     const result = await uni.$u.http.post('/app/workOrder/reopen', { id: workOrderId.value })
                     if (result.code === 200) {
-                        uni.$u.toast('已重开')
+                        uni.$u.ttsModule?.speak?.('已重开'); uni.$u.toast('已重开')
                         setTimeout(() => {
                             uni.navigateBack()
                         }, 1000)

+ 64 - 0
pages/order/mall/my-list.vue

@@ -0,0 +1,64 @@
+<template>
+    <view class="common-page" style="padding: 0;">
+        <PageScroll
+            requestStr="/app/workOrder/getMyWorkOrder"
+            @updateList="updateList"
+            ref="scrollRef"
+            :otherParams="otherParams"
+            method="get"
+        >
+            <view class="list-con" v-if="dataList.length">
+                <WorkorderItem
+                    v-for="(cell, idx) in dataList"
+                    :key="idx"
+                    :item="cell"
+                    :showDuration="false"
+                    @click="goDetail(cell)"
+                    class="mt-20"
+                />
+            </view>
+        </PageScroll>
+    </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
+import PageScroll from '@/components/pageScroll/index.vue'
+import WorkorderItem from '../components/workorder-item.vue'
+
+const dataList = ref([])
+const scrollRef = ref(null)
+
+const otherParams = ref({
+    type: 1
+})
+
+const updateList = (data) => {
+    const rows = data?.rows || data
+    dataList.value = Array.isArray(rows) && rows.length ? rows : []
+}
+
+const refreshList = () => {
+    scrollRef.value?.resetUpScroll()
+}
+
+const goDetail = (cell) => {
+    const id = cell?.id || ''
+    uni.navigateTo({
+        url: `/pages/order/mall/detail?id=${id}`
+    })
+}
+
+onShow(() => {
+    refreshList()
+})
+</script>
+
+<style lang="scss" scoped>
+.list-con {
+    padding: 10rpx 30rpx;
+    gap: 30rpx;
+}
+.mt-20 { margin-top: 20rpx; }
+</style>

+ 19 - 9
pages/order/recycle/created.vue

@@ -14,16 +14,18 @@
                     </template>
                     <u-input v-else v-model="form.orderId" placeholder="请输入订单编号" clearable></u-input>
                 </u-form-item>
-                <u-form-item label="任务类型:" prop="taskType" required>
-                    <u-input v-model="taskTypeText" readonly suffixIcon="arrow-down" placeholder="请选择"
-                        @click="showTaskTypePicker = true"></u-input>
+                <u-form-item label="任务类型:" prop="taskType" required @click="showTaskTypePicker = true">
+                    <view class="picker-field" @tap="showTaskTypePicker = true">
+                        <u-input v-model="taskTypeText" readonly suffixIcon="arrow-down" placeholder="请选择"
+                            :disabled="false"></u-input>
+                    </view>
                 </u-form-item>
                 <u-form-item label="任务详情:" prop="taskDetail" required>
                     <u-textarea v-model="form.taskDetail" placeholder="请输入" :height="120"
                         :autoHeight="true"></u-textarea>
                 </u-form-item>
                 <u-form-item label="上传图片:" prop="imgInfo" required>
-                    <cy-upload :filename="form.imgInfo" @update:filename="form.imgInfo = $event" />
+                    <cy-upload :filename="form.imgInfo" @update:filename="form.imgInfo = $event" :multiple="true" :maxCount="9" />
                 </u-form-item>
             </u-form>
         </view>
@@ -155,7 +157,7 @@ const onSubmit = async () => {
 
     if (isEdit.value) {
         payload.id = workOrderId.value
-        payload.updateType = 1
+        payload.updateType = 2
     }
 
     const apiUrl = isEdit.value ? '/app/workOrder/update' : '/app/workOrder/createWorkOrder'
@@ -163,21 +165,26 @@ const onSubmit = async () => {
     try {
         const res = await uni.$u.http.post(apiUrl, payload)
         if (res?.code === 200) {
+            uni.$u.ttsModule?.speak?.('提交成功')
             uni.$u.toast('提交成功')
-            uni.navigateBack()
+            if (isEdit.value) {
+                uni.navigateBack()
+            } else {
+                uni.redirectTo({ url: '/pages/index/work-order/recycle' })
+            }
         } else {
             uni.$u.toast(res?.msg || '提交失败')
         }
     } catch (err) {
-        uni.$u.toast('网络错误,已本地保存')
+        uni.$u.toast(err?.data?.msg || err?.msg || '网络错误')
     } finally {
         submitting.value = false
     }
 }
 
 onLoad((options) => {
-    form.value.waybillCode = options?.waybillCode || ''
-    form.value.orderId = options?.orderId || ''
+    form.value.waybillCode = options?.waybillCode ? decodeURIComponent(options.waybillCode) : ''
+    form.value.orderId = options?.orderId ? decodeURIComponent(options.orderId) : ''
     if (options?.expressType) {
         expressTypeFromScan.value = parseInt(options.expressType)
     }
@@ -224,4 +231,7 @@ onLoad((options) => {
     color: #2979ff;
     line-height: 60rpx;
 }
+.picker-field {
+    width: 100%;
+}
 </style>

+ 7 - 4
pages/order/recycle/detail.vue

@@ -117,7 +117,7 @@ const onSubmitTrack = async (payload) => {
         }
     } catch (e) {
         console.error(e)
-        uni.$u.toast('网络错误')
+        uni.$u.toast(e?.data?.msg || e?.msg || '网络错误')
     }
 }
 
@@ -136,7 +136,7 @@ const onVoid = () => {
                 try {
                     const result = await uni.$u.http.post('/app/workOrder/cancel', { id: workOrderId.value })
                     if (result.code === 200) {
-                        uni.$u.toast('已作废')
+                        uni.$u.ttsModule?.speak?.('已作废'); uni.$u.toast('已作废')
                         setTimeout(() => {
                             uni.navigateBack()
                         }, 1000)
@@ -145,6 +145,7 @@ const onVoid = () => {
                     }
                 } catch (e) {
                     console.error(e)
+                    uni.$u.toast(e?.data?.msg || e?.msg || '网络错误')
                 }
             }
         }
@@ -160,7 +161,7 @@ const onFinish = () => {
                 try {
                     const result = await uni.$u.http.post('/app/workOrder/finish', { ids: [workOrderId.value] })
                     if (result.code === 200) {
-                        uni.$u.toast('已完成')
+                        uni.$u.ttsModule?.speak?.('已完成'); uni.$u.toast('已完成')
                         setTimeout(() => {
                             uni.navigateBack()
                         }, 1000)
@@ -169,6 +170,7 @@ const onFinish = () => {
                     }
                 } catch (e) {
                     console.error(e)
+                    uni.$u.toast(e?.data?.msg || e?.msg || '网络错误')
                 }
             }
         }
@@ -186,7 +188,7 @@ const onReopen = () => {
                     // 假设接口是 /app/workOrder/reopen
                     const result = await uni.$u.http.post('/app/workOrder/reopen', { id: workOrderId.value })
                     if (result.code === 200) {
-                        uni.$u.toast('已重开')
+                        uni.$u.ttsModule?.speak?.('已重开'); uni.$u.toast('已重开')
                         setTimeout(() => {
                             uni.navigateBack()
                         }, 1000)
@@ -195,6 +197,7 @@ const onReopen = () => {
                     }
                 } catch (e) {
                     console.error(e)
+                    uni.$u.toast(e?.data?.msg || e?.msg || '网络错误')
                 }
             }
         }

+ 115 - 0
pages/order/recycle/my-list.vue

@@ -0,0 +1,115 @@
+<template>
+    <view class="common-page" style="padding: 0;">
+        <view class="filter-bar">
+            <view class="picker-trigger" @tap="pickerShow = true">
+                <text class="picker-label">{{ selectedTaskType?.text || '任务类型' }}</text>
+                <u-icon name="arrow-down" size="16" color="#666"></u-icon>
+            </view>
+            <u-button class="ml-10" type="primary" size="small" @click="onQuery">查询</u-button>
+            <u-button class="ml-10" size="small" @click="onReset">重置</u-button>
+        </view>
+
+        <u-picker :show="pickerShow" :columns="[taskTypeOptions]" title="选择任务类型" @confirm="onPickConfirm"
+            @cancel="pickerShow = false" @close="pickerShow = false"></u-picker>
+
+        <PageScroll requestStr="/app/workOrder/getMyWorkOrder" @updateList="updateList" ref="scrollRef"
+            :otherParams="otherParams" method="get" :diffHeight="150">
+            <WorkorderItem v-for="(cell, idx) in dataList" :key="idx" :item="cell" :showDuration="false"
+                @click="goDetail(cell)" class="mt-20" />
+        </PageScroll>
+    </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
+import PageScroll from '@/components/pageScroll/index.vue'
+import WorkorderItem from '../components/workorder-item.vue'
+
+const dataList = ref([])
+const scrollRef = ref(null)
+const pickerShow = ref(false)
+const selectedTaskType = ref(null)
+const taskTypeOptions = ref([])
+
+const getTaskTypeOptions = async () => {
+    try {
+        const res = await uni.$u.http.get('/system/dict/data/type/task_type')
+        if (res.code === 200 && res.data) {
+            taskTypeOptions.value = [{ text: '全部', value: '' }].concat(res.data.map(item => ({
+                text: item.dictLabel,
+                value: parseInt(item.dictValue)
+            })))
+        }
+    } catch (e) {
+        console.error('获取任务类型失败', e)
+    }
+}
+
+const otherParams = ref({
+    type: 2,
+    taskType: ''
+})
+
+const updateList = (data) => {
+    dataList.value = data
+}
+
+const refreshList = () => {
+    scrollRef.value?.resetUpScroll()
+}
+
+const onPickConfirm = (e) => {
+    const val = e?.value?.[0]
+    selectedTaskType.value = val
+    otherParams.value.taskType = val?.value || ''
+    pickerShow.value = false
+}
+
+const onQuery = () => {
+    refreshList()
+}
+const onReset = () => {
+    selectedTaskType.value = null
+    otherParams.value.taskType = ''
+    refreshList()
+}
+
+const goDetail = (cell) => {
+    const id = cell?.id || ''
+    uni.navigateTo({
+        url: `/pages/order/recycle/detail?id=${id}`
+    })
+}
+
+onShow(() => {
+    getTaskTypeOptions()
+    refreshList()
+})
+</script>
+
+<style lang="scss" scoped>
+.filter-bar {
+    display: flex;
+    align-items: center;
+    padding: 20rpx;
+    background-color: #ffffff;
+    gap: 16rpx;
+}
+.picker-trigger {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 10rpx 20rpx;
+    border: 1rpx solid #e6e8eb;
+    border-radius: 8rpx;
+    min-width: 200px;
+}
+.picker-label {
+    font-size: 28rpx;
+    color: #333;
+}
+.ml-10 { margin-left: 10rpx; }
+.mt-20 { margin-top: 20rpx; }
+</style>

+ 6 - 2
pages/order/recycle/pending.vue

@@ -1,7 +1,7 @@
 <template>
     <view class="common-page" style="padding: 0;">
         <view class="filter-bar">
-            <view class="picker-trigger" @tap="pickerShow = true">
+            <view class="picker-trigger" @tap.stop="pickerShow = true">
                 <text class="picker-label">{{ selectedTaskType?.text || '任务类型' }}</text>
                 <u-icon name="arrow-down" size="16" color="#666"></u-icon>
             </view>
@@ -69,8 +69,12 @@ const refreshList = () => {
 const onPickConfirm = (e) => {
     const val = e?.value?.[0]
     selectedTaskType.value = val
-    otherParams.value.taskType = val?.value || ''
+    otherParams.value = {
+        ...otherParams.value,
+        taskType: val?.value === '' || val?.value === undefined ? '' : val.value
+    }
     pickerShow.value = false
+    refreshList()
 }
 
 const onQuery = () => {

Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/app-config-service.js


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/app-service.js


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/book/index.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/detail/book-audit.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/detail/index.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/detail/review-book.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/detail/review-detail.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/express/weight-modify.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/wms/code-storage-add.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/work-order/history.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/work-order/mall.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/index/work-order/recycle.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/order/index.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/order/mall/created.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/order/mall/detail.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/order/mall/my-list.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/order/recycle/created.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/order/recycle/detail.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/order/recycle/my-list.css


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
unpackage/dist/build/app-plus/pages/order/recycle/pending.css


Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff