Commit 420cb4439c03229b0e9ed1686d0cc34753fca459
1 parent
0d1a4181
快速工单列表
Showing
4 changed files
with
430 additions
and
306 deletions
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
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 = () => {}; |
| 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 = () => {}; |
| 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 = () => {}; |
| 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) => { |
| 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) => { |
| 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) => { |
| 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) => { |
| 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) => { |
| 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) => { |
| 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 | } | ... | ... |