Commit 420cb4439c03229b0e9ed1686d0cc34753fca459

Authored by 刘淇
1 parent 0d1a4181

快速工单列表

pages-sub/daily/patrol-manage/add-patrol-record/index.vue
1 <template> 1 <template>
2 <view class="u-page"> 2 <view class="u-page">
3 - <!-- 表单容器:统一label单位为rpx -->  
4 - <up-form  
5 - :model="form"  
6 - ref="uFormRef"  
7 - :rules="rules"  
8 - label-position="left"  
9 - >  
10 - <!-- 1. 文本域(必填,无label但保留必填验证) -->  
11 - <up-form-item  
12 - prop="content"  
13 - class="form-item" 3 + <!-- 核心:将所有 up-form-item 包裹在同一个 up-form 内 -->
  4 + <view class="inspect-form-content commonPageLRpadding">
  5 + <up-form
  6 + label-position="left"
  7 + :model="inspectForm"
  8 + ref="inspectFormRef"
  9 + labelWidth="140rpx"
14 > 10 >
15 - <up-textarea  
16 - v-model="form.content"  
17 - placeholder="请输入巡查描述"  
18 - maxlength="200"  
19 - :show-word-limit="true"  
20 - border  
21 - :count="true"  
22 - class="textarea"  
23 - ></up-textarea>  
24 - </up-form-item>  
25 -  
26 - <!-- 2. 上传图片:修复labelWidth单位为rpx -->  
27 - <up-form-item  
28 - prop="images"  
29 - class="form-item"  
30 - required  
31 - label="上传图片"  
32 - label-width="140rpx"  
33 - >  
34 - <up-upload  
35 - v-model="form.images"  
36 - :action="uploadUrl"  
37 - :max-count="3"  
38 - :multiple="true"  
39 - @after-read="handleAfterRead"  
40 - @delete="handleDelete"  
41 - @on-exceed="handleExceed"  
42 - upload-text="选择图片"  
43 - del-color="#ff4d4f"  
44 - class="upload-wrap"  
45 - ></up-upload>  
46 - <view class="tips">(最少1张,最多3张)</view>  
47 - </up-form-item>  
48 -  
49 - <!-- 3. 转为工单:修复radio绑定 + labelWidth单位 -->  
50 - <up-form-item  
51 - prop="isWorkOrder"  
52 - class="form-item"  
53 - required  
54 - label="转为工单"  
55 - label-width="140rpx"  
56 - >  
57 - <up-radio-group  
58 - v-model="form.isWorkOrder"  
59 - active-color="#1989fa"  
60 - direction="row"  
61 - class="radio-group" 11 + <!-- 1. 巡查描述(文本域) -->
  12 + <up-form-item
  13 + prop="content"
  14 + class="form-item"
  15 + >
  16 + <up-textarea
  17 + v-model="inspectForm.content"
  18 + placeholder="请输入巡查描述"
  19 + maxlength="200"
  20 + count
  21 + ></up-textarea>
  22 + </up-form-item>
  23 +
  24 + <!-- 2. 上传图片 -->
  25 + <up-form-item
  26 + label="上传图片"
  27 + prop="images"
  28 + required
  29 + border-bottom
  30 + class="form-item"
  31 + >
  32 + <up-upload
  33 + :file-list="imagesList"
  34 + @after-read="(event) => uploadImgs(event)"
  35 + @delete="(event) => deleteImg(event)"
  36 + @on-exceed="handleExceed"
  37 + multiple
  38 + :max-count="3"
  39 + upload-text="选择图片"
  40 + del-color="#ff4d4f"
  41 + class="upload-wrap"
  42 + ></up-upload>
  43 + <view class="tips">(最少1张,最多3张)</view>
  44 + </up-form-item>
  45 +
  46 + <!-- 3. 转为工单(单选框) -->
  47 + <up-form-item
  48 + label="转为工单"
  49 + prop="isWorkOrder"
  50 + required
  51 + class="form-item"
62 > 52 >
63 - <!-- 修复:radio绑定value而非name -->  
64 - <up-radio  
65 - :custom-style="{marginRight: '40rpx'}"  
66 - v-for="(item, index) in radioList"  
67 - :label="item.label"  
68 - :name="item.value" 53 + <up-radio-group
  54 + v-model="inspectForm.isWorkOrder"
  55 + active-color="#1989fa"
  56 + direction="row"
  57 + class="radio-group"
69 > 58 >
70 - {{ item.label }}  
71 - </up-radio>  
72 - </up-radio-group>  
73 - </up-form-item>  
74 - </up-form> 59 + <up-radio
  60 + :custom-style="{marginRight: '40rpx'}"
  61 + v-for="(item, index) in radioList"
  62 + :key="index"
  63 + :label="item.label"
  64 + :name="item.value"
  65 + >
  66 + {{ item.label }}
  67 + </up-radio>
  68 + </up-radio-group>
  69 + </up-form-item>
  70 +
  71 + </up-form>
  72 + </view>
75 73
76 <!-- 底部提交按钮 --> 74 <!-- 底部提交按钮 -->
77 <view class="fixed-bottom-btn-wrap"> 75 <view class="fixed-bottom-btn-wrap">
78 <up-button 76 <up-button
79 type="primary" 77 type="primary"
80 - size="default"  
81 - @click="submit" 78 + text="提交"
  79 + @click="submitInspect"
82 :style="{ width: '100%', height: '88rpx', fontSize: '32rpx', borderRadius: 0 }" 80 :style="{ width: '100%', height: '88rpx', fontSize: '32rpx', borderRadius: 0 }"
83 - >  
84 - 提交  
85 - </up-button> 81 + ></up-button>
86 </view> 82 </view>
87 </view> 83 </view>
88 </template> 84 </template>
89 85
90 -<script setup>  
91 -import { ref, reactive } from 'vue';  
92 -// 表单数据  
93 -const form = reactive({  
94 - content: '', // 文本域内容  
95 - images: [], // 上传图片列表  
96 - isWorkOrder: '1' // 是否转为工单 1:是 2:否  
97 -});  
98 -// 图片上传地址  
99 -const uploadUrl = ref('');  
100 -// 单选列表  
101 -const radioList = ref([  
102 - {label: '是', value: '1'},  
103 - {label: '否', value: '2'}  
104 -]);  
105 -// 校验规则  
106 -const rules = reactive({  
107 - content: [  
108 - {required: true, message: '请输入巡查描述', trigger: ['blur', 'change']},  
109 - {max: 200, message: '内容不能超过200字', trigger: ['blur', 'change']}  
110 - ],  
111 - images: [  
112 - {  
113 - validator: (rule, value, callback) => {  
114 - if (value.length < 1) callback(new Error('最少需要上传1张图片'));  
115 - else if (value.length > 3) callback(new Error('最多只能上传3张图片'));  
116 - else callback(); 86 +<script setup lang="ts">
  87 +import { ref } from 'vue'
  88 +import type { UniFormRef } from '@/uni_modules/uview-plus/types'
  89 +// 定义ref供选项式API使用
  90 +const inspectFormRef = ref<UniFormRef>(null)
  91 +</script>
  92 +
  93 +<script lang="ts">
  94 +import { uploadImages } from '@/common/utils/upload';
  95 +
  96 +export default {
  97 + data() {
  98 + return {
  99 + // 图片列表
  100 + imagesList: [],
  101 + // 单选列表
  102 + radioList: [
  103 + { label: '是', value: '1' },
  104 + { label: '否', value: '2' }
  105 + ],
  106 + // 巡查表单数据
  107 + inspectForm: {
  108 + content: '', // 巡查描述
  109 + isWorkOrder: '1' // 是否转为工单 1:是(默认) 2:否
117 }, 110 },
118 - trigger: ['change']  
119 - }  
120 - ],  
121 - isWorkOrder: [  
122 - {required: true, message: '请选择是否转为工单', trigger: ['change']}  
123 - ]  
124 -});  
125 -// 表单引用  
126 -const uFormRef = ref(null);  
127 -// 图片上传/删除/超出处理  
128 -const handleAfterRead = (event) => {  
129 - const {file} = event;  
130 - setTimeout(() => {  
131 - form.images.push({url: file.url, name: file.name || 'image.png', status: 'success'});  
132 - uFormRef.value.validateField('images');  
133 - }, 500);  
134 -};  
135 -const handleDelete = (index) => {  
136 - form.images.splice(index, 1);  
137 - uFormRef.value.validateField('images');  
138 -};  
139 -const handleExceed = () => uni.$u.toast('最多只能上传3张图片', 'none');  
140 -// 提交方法  
141 -const submit = () => {  
142 - uFormRef.value.validate().then(valid => {  
143 - if (valid) {  
144 - uni.showLoading({title: '提交中...'});  
145 - setTimeout(() => {  
146 - uni.hideLoading();  
147 - uni.$u.toast('提交成功');  
148 - uFormRef.value.resetFields();  
149 - form.images = [];  
150 - }, 1500); 111 + // 表单校验规则
  112 + inspectFormRules: {
  113 + images: [
  114 + {
  115 + required: true,
  116 + message: '请上传图片',
  117 + trigger: 'change',
  118 + validator: (rule, value, callback) => {
  119 + // 自定义校验规则:检查是否有成功上传的图片
  120 + const hasSuccessImg = this.imagesList.some(item => item.status === 'success')
  121 + const imgCount = this.imagesList.filter(item => item.status === 'success').length
  122 +
  123 + if (!hasSuccessImg || imgCount < 1) {
  124 + callback(new Error('最少需要上传1张图片'))
  125 + } else if (imgCount > 3) {
  126 + callback(new Error('最多只能上传3张图片'))
  127 + } else {
  128 + callback()
  129 + }
  130 + }
  131 + }
  132 + ],
  133 + isWorkOrder: [
  134 + { type: 'string', required: true, message: '请选择是否转为工单', trigger: ['change'] }
  135 + ]
  136 + }
151 } 137 }
152 - }).catch(() => uni.$u.toast('表单验证失败,请检查必填项', 'none'));  
153 -};  
154 -</script> 138 + },
  139 + onReady() {
  140 + // 兼容微信小程序,通过setRules设置校验规则
  141 + this.$refs.inspectFormRef.setRules(this.inspectFormRules)
  142 + console.log('巡查表单规则初始化完成')
  143 + },
  144 + methods: {
  145 + /**
  146 + * 删除图片
  147 + */
  148 + deleteImg(event) {
  149 + console.log('删除图片事件:', event)
  150 + this.imagesList.splice(event.index, 1)
  151 + // 删除图片后重新校验图片字段
  152 + this.$refs.inspectFormRef.validateField('images')
  153 + uni.showToast({ title: '图片删除成功', icon: 'success' })
  154 + },
155 155
156 -<style scoped lang="scss">  
157 -// 基础布局:避免内容重叠  
158 -.u-page {  
159 - padding: 20rpx;  
160 -} 156 + /**
  157 + * 上传图片
  158 + */
  159 + async uploadImgs(event) {
  160 + console.log('上传图片事件:', event)
  161 + const fileList = Array.isArray(event.file) ? event.file : [event.file]
  162 + const targetImgList = this.imagesList
161 163
162 -// 表单项样式:分隔区域,避免label和内容重叠  
163 -.form-item {  
164 - background-color: #fff;  
165 - border-radius: 12rpx;  
166 - padding:0 30rpx;  
167 - margin-bottom: 20rpx;  
168 - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);  
169 - position: relative; // 为文本域必填*号定位  
170 -} 164 + const filePaths = fileList.map(item => item.url)
  165 + const tempItems = fileList.map(item => ({
  166 + ...item,
  167 + status: 'uploading',
  168 + message: '上传中'
  169 + }))
  170 + const startIndex = targetImgList.length
  171 + targetImgList.push(...tempItems)
171 172
172 -// 文本域样式  
173 -.textarea {  
174 - margin-bottom: 10rpx;  
175 -} 173 + try {
  174 + const uploadResultUrls = await uploadImages({
  175 + filePaths: filePaths,
  176 + ignoreError: true
  177 + })
  178 + console.log('上传成功的URL列表:', uploadResultUrls)
176 179
177 -// 上传区域样式  
178 -.upload-wrap {  
179 - margin-top: 10rpx;  
180 -} 180 + uploadResultUrls.forEach((url, index) => {
  181 + if (targetImgList[startIndex + index]) {
  182 + targetImgList.splice(startIndex + index, 1, {
  183 + ...fileList[index],
  184 + status: 'success',
  185 + message: '',
  186 + url: url
  187 + })
  188 + }
  189 + })
181 190
182 -.tips {  
183 - font-size: 24rpx;  
184 - color: #999;  
185 - margin-top: 10rpx;  
186 -} 191 + if (uploadResultUrls.length < fileList.length) {
  192 + const failCount = fileList.length - uploadResultUrls.length
  193 + for (let i = uploadResultUrls.length; i < fileList.length; i++) {
  194 + if (targetImgList[startIndex + i]) {
  195 + targetImgList.splice(startIndex + i, 1, {
  196 + ...fileList[i],
  197 + status: 'failed',
  198 + message: '上传失败'
  199 + })
  200 + }
  201 + }
  202 + uni.showToast({ title: `成功上传${uploadResultUrls.length}张,失败${failCount}张`, icon: 'none' })
  203 + } else {
  204 + uni.showToast({ title: `成功上传${fileList.length}张图片`, icon: 'success' })
  205 + }
187 206
188 -// ========== 核心:修复必填*号显示 ==========  
189 -// 1. 放大+高亮uView默认必填*号  
190 -:deep(.up-form-item__required) {  
191 - color: #ff4d4f !important; // 醒目红色  
192 - font-size: 28rpx !important; // 放大字号  
193 - font-weight: bold !important; // 加粗  
194 - margin-left: 5rpx !important; // 与label保持间距  
195 -} 207 + // 上传完成后重新校验图片字段
  208 + this.$refs.inspectFormRef.validateField('images')
  209 + } catch (err) {
  210 + console.error('图片上传失败:', err)
  211 + for (let i = 0; i < fileList.length; i++) {
  212 + if (targetImgList[startIndex + i]) {
  213 + targetImgList.splice(startIndex + i, 1, {
  214 + ...fileList[i],
  215 + status: 'failed',
  216 + message: '上传失败'
  217 + })
  218 + }
  219 + }
  220 + uni.showToast({ title: '图片上传失败,请重试', icon: 'none' })
  221 +
  222 + // 上传失败后重新校验图片字段
  223 + this.$refs.inspectFormRef.validateField('images')
  224 + }
  225 + },
  226 +
  227 + /**
  228 + * 处理图片超出数量限制
  229 + */
  230 + handleExceed() {
  231 + uni.showToast({ title: '最多只能上传3张图片', icon: 'none' })
  232 + },
  233 +
  234 + /**
  235 + * 提取图片URL数组
  236 + */
  237 + getImgUrlList(imgList) {
  238 + return imgList.filter(item => item.status === 'success').map(item => item.url)
  239 + },
  240 +
  241 + /**
  242 + * 提交巡查表单
  243 + */
  244 + async submitInspect() {
  245 + console.log('当前选择是否转为工单:', this.inspectForm.isWorkOrder)
  246 + try {
  247 + // 先执行表单校验
  248 + await this.$refs.inspectFormRef.validate()
  249 +
  250 + // 构造提交数据
  251 + const submitData = {
  252 + content: this.inspectForm.content,
  253 + images: this.getImgUrlList(this.imagesList),
  254 + isWorkOrder: this.inspectForm.isWorkOrder // 1=是,2=否
  255 + }
  256 +
  257 + // 显示加载中
  258 + uni.showLoading({ title: '提交中...' })
  259 +
  260 + // 这里替换为实际的接口调用
  261 + // const res = await yourSubmitApi(submitData)
  262 +
  263 + // 模拟接口调用延迟
  264 + await new Promise(resolve => setTimeout(resolve, 1500))
196 265
  266 + uni.hideLoading()
  267 + uni.showToast({
  268 + title: '提交成功',
  269 + icon: 'success',
  270 + duration: 1500
  271 + })
197 272
  273 + // 重置表单(保留默认值:转为工单=是)
  274 + setTimeout(() => {
  275 + this.$refs.inspectFormRef.resetFields()
  276 + this.imagesList = []
  277 + this.inspectForm = {
  278 + content: '',
  279 + isWorkOrder: '1' // 重置后仍默认选中“是”
  280 + }
  281 + }, 1500)
198 282
  283 + } catch (error) {
  284 + // 隐藏加载框
  285 + uni.hideLoading()
  286 +
  287 + // 区分是表单校验失败还是接口调用失败
  288 + if (Array.isArray(error)) {
  289 + // 表单校验失败 - 静默处理(uView会自动提示)
  290 + } else {
  291 + // 接口调用失败
  292 + console.error('巡查表单提交失败:', error)
  293 + uni.showToast({
  294 + title: '提交失败,请重试',
  295 + icon: 'none',
  296 + duration: 2000
  297 + })
  298 + }
  299 + }
  300 + }
  301 + }
  302 +}
  303 +</script>
  304 +
  305 +<style lang="scss" scoped>
  306 +// 全局页面样式
  307 +.u-page {
  308 +}
  309 +
  310 +// 巡查表单内容容器
  311 +.inspect-form-content {
  312 + background: #fff;
  313 + padding: 20rpx;
  314 +}
199 315
200 </style> 316 </style>
201 \ No newline at end of file 317 \ No newline at end of file
pages-sub/daily/quick-order/add-order.vue
@@ -230,10 +230,7 @@ export default { @@ -230,10 +230,7 @@ export default {
230 } 230 }
231 } 231 }
232 ], 232 ],
233 - handleResultDesc: [  
234 - // 移除required,改为可选字段  
235 - {type: 'string', min: 3, max: 200, message: '处理结果需3-200字', trigger: ['change', 'blur']}  
236 - ] 233 +
237 } 234 }
238 } 235 }
239 }, 236 },
pages-sub/daily/quick-order/index.vue
1 <template> 1 <template>
2 - <view class="work-order-page"> 2 + <view class="u-page">
3 <!-- 顶部固定搜索栏 --> 3 <!-- 顶部固定搜索栏 -->
4 <up-sticky> 4 <up-sticky>
5 <view class="search-header"> 5 <view class="search-header">
6 - <!-- 左侧下拉框 -->  
7 - <view class="dropdown-wrap">  
8 - <up-dropdown ref="uDropdownRef" @open="open" @close="close">  
9 - <up-dropdown-item  
10 - v-model="selectedSortValue"  
11 - title="距离"  
12 - :options="sortOptions"  
13 - @change="handleSortChange"  
14 - />  
15 - </up-dropdown> 6 + <!-- 左侧下拉框:替换为uView Plus的Select组件 -->
  7 + <view class="select-wrap">
  8 + <up-select
  9 + v-model:current="selectedSortValue"
  10 + :options="sortOptions"
  11 + :showOptionsLabel="true"
  12 + @select="handleSortChange"
  13 + border="surround"
  14 + :style="{ flex: 1 }"
  15 + />
16 </view> 16 </view>
17 17
18 <!-- 右侧搜索框 --> 18 <!-- 右侧搜索框 -->
@@ -38,32 +38,32 @@ @@ -38,32 +38,32 @@
38 v-model="orderList" 38 v-model="orderList"
39 @query="queryList" 39 @query="queryList"
40 :top="100" 40 :top="100"
41 - :bottom="120" 41 + :bottom="120"
42 > 42 >
43 - <template #empty>  
44 - <view class="empty-tip">暂无工单数据</view>  
45 - </template>  
46 -  
47 - <!-- 修复:新增列表容器,配置顶部内边距 -->  
48 - <view class="order-list">  
49 - <view class="order-card" v-for="item in orderList" :key="item.orderNo">  
50 - <view class="order-item up-line-1">工单编号:{{ item.orderNo }}</view>  
51 - <view class="order-item up-line-1">工单位置:{{ item.roadName || '未填写' }}</view>  
52 - <view class="order-item up-line-1">工单名称:{{ item.orderName || '未填写' }}</view>  
53 - <view class="order-item up-line-1">情况描述:{{ item.remark || '无' }}</view>  
54 - <view class="order-footer">  
55 - <view class="submit-time up-line-1">提交时间:{{ timeFormat(item.createTime,'yyyy-mm-dd') }}</view>  
56 - <up-button  
57 - type="primary"  
58 - size="mini"  
59 - @click="handleDetail(item)"  
60 - :style="{ width: '80px', height: '28px', fontSize: '14px', borderRadius: 4 }"  
61 - >  
62 - 工单详情  
63 - </up-button> 43 + <template #empty>
  44 + <empty-view/>
  45 + </template>
  46 +
  47 + <!-- 修复:新增列表容器,配置顶部内边距 -->
  48 + <view class="order-list">
  49 + <view class="order-card" v-for="item in orderList" :key="item.orderNo">
  50 + <view class="order-item up-line-1">工单编号:{{ item.orderNo }}</view>
  51 + <view class="order-item up-line-1">工单位置:{{ item.roadName || '未填写' }}</view>
  52 + <view class="order-item up-line-1">工单名称:{{ item.orderName || '未填写' }}</view>
  53 + <view class="order-item up-line-1">情况描述:{{ item.remark || '无' }}</view>
  54 + <view class="order-footer">
  55 + <view class="submit-time up-line-1">提交时间:{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view>
  56 + <up-button
  57 + type="primary"
  58 + size="mini"
  59 + @click="handleDetail(item)"
  60 + :style="{ width: '80px', height: '28px', fontSize: '14px', borderRadius: 4 }"
  61 + >
  62 + 工单详情
  63 + </up-button>
  64 + </view>
64 </view> 65 </view>
65 </view> 66 </view>
66 - </view>  
67 </z-paging> 67 </z-paging>
68 68
69 <!-- 修复:补充底部按钮样式层级 --> 69 <!-- 修复:补充底部按钮样式层级 -->
@@ -76,18 +76,19 @@ @@ -76,18 +76,19 @@
76 </template> 76 </template>
77 77
78 <script setup> 78 <script setup>
79 -import { ref } from 'vue'; 79 +import { ref, computed } from 'vue';
80 import { workorderPage } from "@/api/quick-order/quick-order"; 80 import { workorderPage } from "@/api/quick-order/quick-order";
81 import { timeFormat } from '@/uni_modules/uview-plus'; 81 import { timeFormat } from '@/uni_modules/uview-plus';
82 // ========== 修复1:声明所有核心响应式变量 ========== 82 // ========== 修复1:声明所有核心响应式变量 ==========
83 // 顶部/底部高度(rpx) 83 // 顶部/底部高度(rpx)
84 -const headerHeight = 100;  
85 -const bottomBtnHeight = 120;  
86 -// 排序相关 84 +// 排序相关:适配up-select的格式
87 const selectedSortValue = ref(1); 85 const selectedSortValue = ref(1);
  86 +// 1 位置 2 工单名称 3 情况描述 4 工单编号
88 const sortOptions = ref([ 87 const sortOptions = ref([
89 - { label: '默认排序', value: 1 },  
90 - { label: '距离优先', value: 2 } 88 + {name: '位置', id: 1},
  89 + {name: '名称', id: 2},
  90 + {name: '描述', id: 3},
  91 + {name: '编号', id: 4},
91 ]); 92 ]);
92 // 分页相关(核心:声明orderList) 93 // 分页相关(核心:声明orderList)
93 const pageNo = ref(1); 94 const pageNo = ref(1);
@@ -96,70 +97,53 @@ const paging = ref(null); @@ -96,70 +97,53 @@ const paging = ref(null);
96 const orderList = ref([]); // 修复:新增列表变量 97 const orderList = ref([]); // 修复:新增列表变量
97 // 搜索相关 98 // 搜索相关
98 const searchValue = ref(''); 99 const searchValue = ref('');
99 -  
100 -  
101 -  
102 // ========== 修复3:适配z-paging回调参数 ========== 100 // ========== 修复3:适配z-paging回调参数 ==========
103 -const queryList = async (pageNo,pageSize) => { 101 +const queryList = async (pageNo, pageSize) => {
104 try { 102 try {
105 // 修复:z-paging的query回调参数是对象 {pageNo, pageSize} 103 // 修复:z-paging的query回调参数是对象 {pageNo, pageSize}
106 const apiParams = { 104 const apiParams = {
107 searchContent: searchValue.value.trim() || '', 105 searchContent: searchValue.value.trim() || '',
108 pageNo: pageNo, 106 pageNo: pageNo,
109 pageSize: pageSize, 107 pageSize: pageSize,
110 - type:1 // 1 位置 2 工单名称 3 情况描述 4 工单编号 108 + type: selectedSortValue.value // 1 位置 2 工单名称 3 情况描述 4 工单编号
111 }; 109 };
112 console.log('请求参数:', apiParams); 110 console.log('请求参数:', apiParams);
113 const res = await workorderPage(apiParams); 111 const res = await workorderPage(apiParams);
114 console.log('接口返回:', res); 112 console.log('接口返回:', res);
115 -  
116 -  
117 paging.value.complete(res.list); 113 paging.value.complete(res.list);
118 } catch (error) { 114 } catch (error) {
119 console.error('加载失败:', error); 115 console.error('加载失败:', error);
120 paging.value?.complete(false); 116 paging.value?.complete(false);
121 - uni.showToast({ title: '加载失败,请重试', icon: 'none' }); 117 + uni.showToast({title: '加载失败,请重试', icon: 'none'});
122 } 118 }
123 }; 119 };
124 -  
125 // ========== 其他方法补充 ========== 120 // ========== 其他方法补充 ==========
126 const handleSortChange = (val) => { 121 const handleSortChange = (val) => {
127 console.log('排序变更:', val); 122 console.log('排序变更:', val);
  123 + searchValue.value = ''
  124 + selectedSortValue.value = val.id; // 更新选中值
128 paging.value?.reload(); // 排序后刷新列表 125 paging.value?.reload(); // 排序后刷新列表
129 }; 126 };
130 -  
131 const handleSearch = (val) => { 127 const handleSearch = (val) => {
132 console.log('搜索内容:', val); 128 console.log('搜索内容:', val);
133 searchValue.value = val; 129 searchValue.value = val;
134 paging.value?.reload(); // 搜索后刷新列表 130 paging.value?.reload(); // 搜索后刷新列表
135 }; 131 };
136 -  
137 const handleDetail = (item) => { 132 const handleDetail = (item) => {
138 console.log('工单详情:', item); 133 console.log('工单详情:', item);
139 uni.navigateTo({ 134 uni.navigateTo({
140 url: `/pages-sub/daily/quick-order/order-detail?id=${item.id}` 135 url: `/pages-sub/daily/quick-order/order-detail?id=${item.id}`
141 }); 136 });
142 }; 137 };
143 -  
144 const handleAddOrder = () => { 138 const handleAddOrder = () => {
145 uni.navigateTo({ 139 uni.navigateTo({
146 url: '/pages-sub/daily/quick-order/add-order' 140 url: '/pages-sub/daily/quick-order/add-order'
147 }); 141 });
148 }; 142 };
149 -  
150 -// 空方法(避免下拉框报错)  
151 -const open = () => {};  
152 -const close = () => {};  
153 </script> 143 </script>
154 144
155 <style scoped lang="scss"> 145 <style scoped lang="scss">
156 -// 修复:页面基础样式  
157 -.work-order-page {  
158 - min-height: 100vh;  
159 - background-color: #f5f5f5;  
160 - padding-bottom: env(safe-area-inset-bottom);  
161 - box-sizing: border-box;  
162 -} 146 +
163 147
164 // 顶部搜索栏 148 // 顶部搜索栏
165 .search-header { 149 .search-header {
@@ -167,17 +151,26 @@ const close = () =&gt; {}; @@ -167,17 +151,26 @@ const close = () =&gt; {};
167 align-items: center; 151 align-items: center;
168 padding: 20rpx; 152 padding: 20rpx;
169 background-color: #fff; 153 background-color: #fff;
170 - border-bottom: 1px solid #f0f0f0;  
171 - height: v-bind(headerHeight + 'rpx');  
172 box-sizing: border-box; 154 box-sizing: border-box;
173 155
174 - .dropdown-wrap {  
175 - flex: 1; 156 + // 下拉选择框容器
  157 + .select-wrap {
  158 + width: 80px;
  159 + color: #333;
176 margin-right: 20rpx; 160 margin-right: 20rpx;
  161 + // 适配up-select样式
  162 + :deep(.u-select) {
  163 + width: 100%;
  164 + font-size: 28rpx;
  165 + }
  166 +
  167 + :deep(.u-input__placeholder) {
  168 + font-size: 28rpx;
  169 + }
177 } 170 }
178 171
179 .search-input-wrap { 172 .search-input-wrap {
180 - flex: 2; 173 + flex: 3;
181 } 174 }
182 } 175 }
183 176
@@ -187,14 +180,6 @@ const close = () =&gt; {}; @@ -187,14 +180,6 @@ const close = () =&gt; {};
187 box-sizing: border-box; 180 box-sizing: border-box;
188 } 181 }
189 182
190 -// 空状态样式  
191 -.empty-tip {  
192 - text-align: center;  
193 - padding: 100rpx 0;  
194 - color: #999;  
195 - font-size: 28rpx;  
196 -}  
197 -  
198 // 工单卡片样式 183 // 工单卡片样式
199 .order-card { 184 .order-card {
200 background-color: #fff; 185 background-color: #fff;
@@ -214,13 +199,16 @@ const close = () =&gt; {}; @@ -214,13 +199,16 @@ const close = () =&gt; {};
214 display: flex; 199 display: flex;
215 justify-content: space-between; 200 justify-content: space-between;
216 align-items: center; 201 align-items: center;
217 - margin-top: 12rpx;  
218 202
219 .submit-time { 203 .submit-time {
  204 + flex: 1;
  205 + overflow: hidden;
  206 + text-overflow: ellipsis;
  207 + white-space: nowrap;
220 font-size: 26rpx; 208 font-size: 26rpx;
221 color: #666; 209 color: #666;
222 - line-height: 40rpx;  
223 } 210 }
  211 +
224 } 212 }
225 } 213 }
226 214
pages-sub/daily/quick-order/order-detail.vue
1 <template> 1 <template>
2 <view class="u-page"> 2 <view class="u-page">
3 -  
4 -  
5 - <!-- 页面级加载组件(up-loading-page,uview-plus标准组件) --> 3 + <!-- 页面级加载组件 -->
6 <up-loading-page 4 <up-loading-page
7 v-if="loading" 5 v-if="loading"
8 :loading="true" 6 :loading="true"
@@ -10,10 +8,17 @@ @@ -10,10 +8,17 @@
10 color="#3c9cff" 8 color="#3c9cff"
11 ></up-loading-page> 9 ></up-loading-page>
12 10
13 - <!-- 内容容器(仅在非加载状态显示) --> 11 + <!-- 内容容器 -->
14 <view v-else class="content-wrap"> 12 <view v-else class="content-wrap">
15 - <!-- 单元格分组(核心uview组件) -->  
16 - <up-cell-group :border="false" inset style="margin: 20rpx;" > 13 + <!-- 空状态 -->
  14 + <view v-if="!Object.keys(orderDetail).length" class="empty-wrap">
  15 + <text class="empty-icon">📄</text>
  16 + <text class="empty-text">暂无工单详情</text>
  17 + <text class="empty-subtext">请检查工单ID是否正确</text>
  18 + </view>
  19 +
  20 + <!-- 工单详情内容 -->
  21 + <up-cell-group :border="false" inset style="margin: 20rpx;" v-else>
17 <!-- 1. 工单编号 --> 22 <!-- 1. 工单编号 -->
18 <up-cell 23 <up-cell
19 title="工单编号" 24 title="工单编号"
@@ -46,36 +51,38 @@ @@ -46,36 +51,38 @@
46 align="middle" 51 align="middle"
47 ></up-cell> 52 ></up-cell>
48 53
49 - <!-- 5. 问题照片 -->  
50 - <up-cell title="问题照片" align="top"> 54 + <!-- 5. 问题照片(核心修复:判断条件+空值处理) -->
  55 + <up-cell title="问题照片" >
  56 + <template #value>
51 <view class="cell-content-wrap"> 57 <view class="cell-content-wrap">
  58 +
  59 + <!-- 修复1:正确判断problemImgsList,补充空数组默认值 -->
52 <up-album 60 <up-album
53 - v-if="orderDetail.imgs && orderDetail.imgs.length"  
54 - :list="formatAlbumList(orderDetail.imgs)"  
55 - :column="3"  
56 - :max-count="9" 61 + v-if="!!orderDetail.problemImgsList?.length"
  62 + :urls="orderDetail.problemImgsList || []"
  63 + singleSize="70"
57 :preview-full-image="true" 64 :preview-full-image="true"
58 - disabled  
59 - style="width: 100%;" 65 +
60 ></up-album> 66 ></up-album>
61 <text v-else class="empty-text">暂无问题照片</text> 67 <text v-else class="empty-text">暂无问题照片</text>
62 </view> 68 </view>
  69 + </template>
63 </up-cell> 70 </up-cell>
64 71
65 - <!-- 6. 完成照片 --> 72 + <!-- 6. 完成照片(优化:空值处理+容错) -->
66 <up-cell title="完成照片" align="top"> 73 <up-cell title="完成照片" align="top">
  74 + <template #value>
67 <view class="cell-content-wrap"> 75 <view class="cell-content-wrap">
68 <up-album 76 <up-album
69 - v-if="orderDetail.longRangeImgList && orderDetail.longRangeImgList.length"  
70 - :list="formatAlbumList(orderDetail.longRangeImgList)"  
71 - :column="3"  
72 - :max-count="9" 77 + v-if="!!orderDetail.completeImgsList?.length"
  78 + :urls="orderDetail.completeImgsList || []"
  79 + singleSize="70"
73 :preview-full-image="true" 80 :preview-full-image="true"
74 - disabled  
75 - style="width: 100%;" 81 +
76 ></up-album> 82 ></up-album>
77 <text v-else class="empty-text">暂无完成照片</text> 83 <text v-else class="empty-text">暂无完成照片</text>
78 </view> 84 </view>
  85 + </template>
79 </up-cell> 86 </up-cell>
80 87
81 <!-- 7. 处理结果 --> 88 <!-- 7. 处理结果 -->
@@ -87,13 +94,6 @@ @@ -87,13 +94,6 @@
87 :border="false" 94 :border="false"
88 ></up-cell> 95 ></up-cell>
89 </up-cell-group> 96 </up-cell-group>
90 -  
91 - <!-- 空状态(原生样式,替代up-empty) -->  
92 - <view v-if="!Object.keys(orderDetail).length" class="empty-wrap">  
93 - <text class="empty-icon">📄</text>  
94 - <text class="empty-text">暂无工单详情</text>  
95 - <text class="empty-subtext">请检查工单ID是否正确</text>  
96 - </view>  
97 </view> 97 </view>
98 </view> 98 </view>
99 </template> 99 </template>
@@ -101,22 +101,12 @@ @@ -101,22 +101,12 @@
101 <script setup lang="ts"> 101 <script setup lang="ts">
102 import { ref, reactive } from 'vue'; 102 import { ref, reactive } from 'vue';
103 import { inspectionPlanDetail } from "@/api/quick-order/quick-order"; 103 import { inspectionPlanDetail } from "@/api/quick-order/quick-order";
104 -  
105 import { onLoad, onShow } from '@dcloudio/uni-app'; 104 import { onLoad, onShow } from '@dcloudio/uni-app';
  105 +
106 // 状态管理 106 // 状态管理
107 const loading = ref(true); 107 const loading = ref(true);
108 const orderDetail = ref({}); 108 const orderDetail = ref({});
109 109
110 -/**  
111 - * 格式化相册列表(适配up-album)  
112 - */  
113 -const formatAlbumList = (imgUrls: string[]) => {  
114 - return imgUrls.map(url => ({  
115 - url,  
116 - thumb: url,  
117 - name: `图片-${Date.now()}`  
118 - }));  
119 -};  
120 110
121 /** 111 /**
122 * 获取工单详情 112 * 获取工单详情
@@ -125,9 +115,13 @@ const getOrderDetail = async (id: string) =&gt; { @@ -125,9 +115,13 @@ const getOrderDetail = async (id: string) =&gt; {
125 try { 115 try {
126 loading.value = true; 116 loading.value = true;
127 const res = await inspectionPlanDetail({ id }); 117 const res = await inspectionPlanDetail({ id });
128 - console.log('接口返回:', res)  
129 - orderDetail.value = res  
130 - 118 + console.log('接口返回:', res);
  119 + // 优化:确保图片数组为数组类型,避免非数组导致渲染错误
  120 + orderDetail.value = {
  121 + ...res,
  122 + problemImgsList: Array.isArray(res.problemImgsList) ? res.problemImgsList : [],
  123 + completeImgsList: Array.isArray(res.completeImgsList) ? res.completeImgsList : []
  124 + };
131 } catch (error) { 125 } catch (error) {
132 console.error('获取工单详情失败:', error); 126 console.error('获取工单详情失败:', error);
133 uni.showToast({ title: '加载失败,请重试', icon: 'none' }); 127 uni.showToast({ title: '加载失败,请重试', icon: 'none' });
@@ -149,22 +143,23 @@ onLoad((options) =&gt; { @@ -149,22 +143,23 @@ onLoad((options) =&gt; {
149 </script> 143 </script>
150 144
151 <style scoped lang="scss"> 145 <style scoped lang="scss">
  146 +// 页面基础样式
  147 +.u-page {
  148 + min-height: 100vh;
  149 + background-color: #f5f5f5;
  150 + box-sizing: border-box;
  151 +}
152 152
153 -  
154 -// 内容容器(原生滚动) 153 +// 内容容器
155 .content-wrap { 154 .content-wrap {
156 background: #fff; 155 background: #fff;
157 width: 100%; 156 width: 100%;
158 box-sizing: border-box; 157 box-sizing: border-box;
159 overflow-y: auto; 158 overflow-y: auto;
  159 + min-height: calc(100vh - 40rpx);
160 } 160 }
161 161
162 -// 单元格内容包裹层  
163 -.cell-content-wrap {  
164 - width: 100%;  
165 - padding: 10rpx 0;  
166 - box-sizing: border-box;  
167 -} 162 +
168 163
169 // 空文本样式 164 // 空文本样式
170 .empty-text { 165 .empty-text {
@@ -181,6 +176,7 @@ onLoad((options) =&gt; { @@ -181,6 +176,7 @@ onLoad((options) =&gt; {
181 --u-cell-group-border-radius: 12rpx; 176 --u-cell-group-border-radius: 12rpx;
182 --u-cell-group-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); 177 --u-cell-group-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
183 } 178 }
  179 +
184 :deep(.up-cell) { 180 :deep(.up-cell) {
185 --u-cell-title-font-size: 28rpx; 181 --u-cell-title-font-size: 28rpx;
186 --u-cell-value-font-size: 28rpx; 182 --u-cell-value-font-size: 28rpx;
@@ -189,9 +185,33 @@ onLoad((options) =&gt; { @@ -189,9 +185,33 @@ onLoad((options) =&gt; {
189 --u-cell-padding: 20rpx 15rpx; 185 --u-cell-padding: 20rpx 15rpx;
190 --u-cell-border-color: #f5f5f5; 186 --u-cell-border-color: #f5f5f5;
191 } 187 }
  188 +
  189 +// 相册样式优化(关键:适配图片展示)
  190 +:deep(.up-album) {
  191 + width: 100%;
  192 + box-sizing: border-box;
  193 +}
  194 +
  195 +:deep(.up-album__list) {
  196 + display: flex;
  197 + flex-wrap: wrap;
  198 + padding: 0;
  199 + margin: 0;
  200 +}
  201 +
192 :deep(.up-album__item) { 202 :deep(.up-album__item) {
193 - margin: 10rpx 5rpx; 203 + width: calc(33.333% - 10rpx);
  204 + height: 200rpx; // 固定图片高度,避免变形
  205 + margin: 5rpx;
194 border-radius: 8rpx; 206 border-radius: 8rpx;
  207 + overflow: hidden;
  208 + background-color: #f8f8f8;
  209 +}
  210 +
  211 +:deep(.up-album__image) {
  212 + width: 100%;
  213 + height: 100%;
  214 + object-fit: cover; // 图片裁剪填充,避免拉伸
195 } 215 }
196 216
197 // 原生空状态样式 217 // 原生空状态样式
@@ -199,17 +219,20 @@ onLoad((options) =&gt; { @@ -199,17 +219,20 @@ onLoad((options) =&gt; {
199 margin-top: 200rpx; 219 margin-top: 200rpx;
200 text-align: center; 220 text-align: center;
201 } 221 }
  222 +
202 .empty-icon { 223 .empty-icon {
203 font-size: 80rpx; 224 font-size: 80rpx;
204 display: block; 225 display: block;
205 margin-bottom: 20rpx; 226 margin-bottom: 20rpx;
206 color: #ddd; 227 color: #ddd;
207 } 228 }
  229 +
208 .empty-text { 230 .empty-text {
209 font-size: 28rpx; 231 font-size: 28rpx;
210 color: #999; 232 color: #999;
211 display: block; 233 display: block;
212 } 234 }
  235 +
213 .empty-subtext { 236 .empty-subtext {
214 font-size: 24rpx; 237 font-size: 24rpx;
215 color: #ccc; 238 color: #ccc;
@@ -217,7 +240,7 @@ onLoad((options) =&gt; { @@ -217,7 +240,7 @@ onLoad((options) =&gt; {
217 display: block; 240 display: block;
218 } 241 }
219 242
220 -// 适配up-loading-page样式 243 +// 加载组件样式
221 :deep(.up-loading-page) { 244 :deep(.up-loading-page) {
222 margin-top: 100rpx; 245 margin-top: 100rpx;
223 } 246 }