Commit 420cb4439c03229b0e9ed1686d0cc34753fca459

Authored by 刘淇
1 parent 0d1a4181

快速工单列表

pages-sub/daily/patrol-manage/add-patrol-record/index.vue
1 1 <template>
2 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 75 <view class="fixed-bottom-btn-wrap">
78 76 <up-button
79 77 type="primary"
80   - size="default"
81   - @click="submit"
  78 + text="提交"
  79 + @click="submitInspect"
82 80 :style="{ width: '100%', height: '88rpx', fontSize: '32rpx', borderRadius: 0 }"
83   - >
84   - 提交
85   - </up-button>
  81 + ></up-button>
86 82 </view>
87 83 </view>
88 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 316 </style>
201 317 \ No newline at end of file
... ...
pages-sub/daily/quick-order/add-order.vue
... ... @@ -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 1 <template>
2   - <view class="work-order-page">
  2 + <view class="u-page">
3 3 <!-- 顶部固定搜索栏 -->
4 4 <up-sticky>
5 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 16 </view>
17 17  
18 18 <!-- 右侧搜索框 -->
... ... @@ -38,32 +38,32 @@
38 38 v-model="orderList"
39 39 @query="queryList"
40 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 65 </view>
65 66 </view>
66   - </view>
67 67 </z-paging>
68 68  
69 69 <!-- 修复:补充底部按钮样式层级 -->
... ... @@ -76,18 +76,19 @@
76 76 </template>
77 77  
78 78 <script setup>
79   -import { ref } from 'vue';
  79 +import { ref, computed } from 'vue';
80 80 import { workorderPage } from "@/api/quick-order/quick-order";
81 81 import { timeFormat } from '@/uni_modules/uview-plus';
82 82 // ========== 修复1:声明所有核心响应式变量 ==========
83 83 // 顶部/底部高度(rpx)
84   -const headerHeight = 100;
85   -const bottomBtnHeight = 120;
86   -// 排序相关
  84 +// 排序相关:适配up-select的格式
87 85 const selectedSortValue = ref(1);
  86 +// 1 位置 2 工单名称 3 情况描述 4 工单编号
88 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 93 // 分页相关(核心:声明orderList)
93 94 const pageNo = ref(1);
... ... @@ -96,70 +97,53 @@ const paging = ref(null);
96 97 const orderList = ref([]); // 修复:新增列表变量
97 98 // 搜索相关
98 99 const searchValue = ref('');
99   -
100   -
101   -
102 100 // ========== 修复3:适配z-paging回调参数 ==========
103   -const queryList = async (pageNo,pageSize) => {
  101 +const queryList = async (pageNo, pageSize) => {
104 102 try {
105 103 // 修复:z-paging的query回调参数是对象 {pageNo, pageSize}
106 104 const apiParams = {
107 105 searchContent: searchValue.value.trim() || '',
108 106 pageNo: pageNo,
109 107 pageSize: pageSize,
110   - type:1 // 1 位置 2 工单名称 3 情况描述 4 工单编号
  108 + type: selectedSortValue.value // 1 位置 2 工单名称 3 情况描述 4 工单编号
111 109 };
112 110 console.log('请求参数:', apiParams);
113 111 const res = await workorderPage(apiParams);
114 112 console.log('接口返回:', res);
115   -
116   -
117 113 paging.value.complete(res.list);
118 114 } catch (error) {
119 115 console.error('加载失败:', error);
120 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 121 const handleSortChange = (val) => {
127 122 console.log('排序变更:', val);
  123 + searchValue.value = ''
  124 + selectedSortValue.value = val.id; // 更新选中值
128 125 paging.value?.reload(); // 排序后刷新列表
129 126 };
130   -
131 127 const handleSearch = (val) => {
132 128 console.log('搜索内容:', val);
133 129 searchValue.value = val;
134 130 paging.value?.reload(); // 搜索后刷新列表
135 131 };
136   -
137 132 const handleDetail = (item) => {
138 133 console.log('工单详情:', item);
139 134 uni.navigateTo({
140 135 url: `/pages-sub/daily/quick-order/order-detail?id=${item.id}`
141 136 });
142 137 };
143   -
144 138 const handleAddOrder = () => {
145 139 uni.navigateTo({
146 140 url: '/pages-sub/daily/quick-order/add-order'
147 141 });
148 142 };
149   -
150   -// 空方法(避免下拉框报错)
151   -const open = () => {};
152   -const close = () => {};
153 143 </script>
154 144  
155 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 149 .search-header {
... ... @@ -167,17 +151,26 @@ const close = () =&gt; {};
167 151 align-items: center;
168 152 padding: 20rpx;
169 153 background-color: #fff;
170   - border-bottom: 1px solid #f0f0f0;
171   - height: v-bind(headerHeight + 'rpx');
172 154 box-sizing: border-box;
173 155  
174   - .dropdown-wrap {
175   - flex: 1;
  156 + // 下拉选择框容器
  157 + .select-wrap {
  158 + width: 80px;
  159 + color: #333;
176 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 172 .search-input-wrap {
180   - flex: 2;
  173 + flex: 3;
181 174 }
182 175 }
183 176  
... ... @@ -187,14 +180,6 @@ const close = () =&gt; {};
187 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 184 .order-card {
200 185 background-color: #fff;
... ... @@ -214,13 +199,16 @@ const close = () =&gt; {};
214 199 display: flex;
215 200 justify-content: space-between;
216 201 align-items: center;
217   - margin-top: 12rpx;
218 202  
219 203 .submit-time {
  204 + flex: 1;
  205 + overflow: hidden;
  206 + text-overflow: ellipsis;
  207 + white-space: nowrap;
220 208 font-size: 26rpx;
221 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 1 <template>
2 2 <view class="u-page">
3   -
4   -
5   - <!-- 页面级加载组件(up-loading-page,uview-plus标准组件) -->
  3 + <!-- 页面级加载组件 -->
6 4 <up-loading-page
7 5 v-if="loading"
8 6 :loading="true"
... ... @@ -10,10 +8,17 @@
10 8 color="#3c9cff"
11 9 ></up-loading-page>
12 10  
13   - <!-- 内容容器(仅在非加载状态显示) -->
  11 + <!-- 内容容器 -->
14 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 22 <!-- 1. 工单编号 -->
18 23 <up-cell
19 24 title="工单编号"
... ... @@ -46,36 +51,38 @@
46 51 align="middle"
47 52 ></up-cell>
48 53  
49   - <!-- 5. 问题照片 -->
50   - <up-cell title="问题照片" align="top">
  54 + <!-- 5. 问题照片(核心修复:判断条件+空值处理) -->
  55 + <up-cell title="问题照片" >
  56 + <template #value>
51 57 <view class="cell-content-wrap">
  58 +
  59 + <!-- 修复1:正确判断problemImgsList,补充空数组默认值 -->
52 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 64 :preview-full-image="true"
58   - disabled
59   - style="width: 100%;"
  65 +
60 66 ></up-album>
61 67 <text v-else class="empty-text">暂无问题照片</text>
62 68 </view>
  69 + </template>
63 70 </up-cell>
64 71  
65   - <!-- 6. 完成照片 -->
  72 + <!-- 6. 完成照片(优化:空值处理+容错) -->
66 73 <up-cell title="完成照片" align="top">
  74 + <template #value>
67 75 <view class="cell-content-wrap">
68 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 80 :preview-full-image="true"
74   - disabled
75   - style="width: 100%;"
  81 +
76 82 ></up-album>
77 83 <text v-else class="empty-text">暂无完成照片</text>
78 84 </view>
  85 + </template>
79 86 </up-cell>
80 87  
81 88 <!-- 7. 处理结果 -->
... ... @@ -87,13 +94,6 @@
87 94 :border="false"
88 95 ></up-cell>
89 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 97 </view>
98 98 </view>
99 99 </template>
... ... @@ -101,22 +101,12 @@
101 101 <script setup lang="ts">
102 102 import { ref, reactive } from 'vue';
103 103 import { inspectionPlanDetail } from "@/api/quick-order/quick-order";
104   -
105 104 import { onLoad, onShow } from '@dcloudio/uni-app';
  105 +
106 106 // 状态管理
107 107 const loading = ref(true);
108 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 115 try {
126 116 loading.value = true;
127 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 125 } catch (error) {
132 126 console.error('获取工单详情失败:', error);
133 127 uni.showToast({ title: '加载失败,请重试', icon: 'none' });
... ... @@ -149,22 +143,23 @@ onLoad((options) =&gt; {
149 143 </script>
150 144  
151 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 154 .content-wrap {
156 155 background: #fff;
157 156 width: 100%;
158 157 box-sizing: border-box;
159 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 165 .empty-text {
... ... @@ -181,6 +176,7 @@ onLoad((options) =&gt; {
181 176 --u-cell-group-border-radius: 12rpx;
182 177 --u-cell-group-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
183 178 }
  179 +
184 180 :deep(.up-cell) {
185 181 --u-cell-title-font-size: 28rpx;
186 182 --u-cell-value-font-size: 28rpx;
... ... @@ -189,9 +185,33 @@ onLoad((options) =&gt; {
189 185 --u-cell-padding: 20rpx 15rpx;
190 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 202 :deep(.up-album__item) {
193   - margin: 10rpx 5rpx;
  203 + width: calc(33.333% - 10rpx);
  204 + height: 200rpx; // 固定图片高度,避免变形
  205 + margin: 5rpx;
194 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 219 margin-top: 200rpx;
200 220 text-align: center;
201 221 }
  222 +
202 223 .empty-icon {
203 224 font-size: 80rpx;
204 225 display: block;
205 226 margin-bottom: 20rpx;
206 227 color: #ddd;
207 228 }
  229 +
208 230 .empty-text {
209 231 font-size: 28rpx;
210 232 color: #999;
211 233 display: block;
212 234 }
  235 +
213 236 .empty-subtext {
214 237 font-size: 24rpx;
215 238 color: #ccc;
... ... @@ -217,7 +240,7 @@ onLoad((options) =&gt; {
217 240 display: block;
218 241 }
219 242  
220   -// 适配up-loading-page样式
  243 +// 加载组件样式
221 244 :deep(.up-loading-page) {
222 245 margin-top: 100rpx;
223 246 }
... ...