Commit 8ddc6f6e1f715ff8aac9b30b12afdb28305fa35e
1 parent
6e9f0396
登录 修改样式
Showing
17 changed files
with
1802 additions
and
1450 deletions
api/common.js
| @@ -11,6 +11,16 @@ export const getRoadListByLatLng = (params) => { | @@ -11,6 +11,16 @@ export const getRoadListByLatLng = (params) => { | ||
| 11 | return get('/app-api/bpm/garden/workorder/listRoadInfo', params); | 11 | return get('/app-api/bpm/garden/workorder/listRoadInfo', params); |
| 12 | }; | 12 | }; |
| 13 | 13 | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * 根据公司 | ||
| 17 | + * @param {Object} params {mobile, password, code} | ||
| 18 | + * @returns {Promise} | ||
| 19 | + */ | ||
| 20 | +export const getCompanyList = (params) => { | ||
| 21 | + return get('/admin-api/system/dept/sub-list', params); | ||
| 22 | +}; | ||
| 23 | + | ||
| 14 | // export const fileUpload = (params) => { | 24 | // export const fileUpload = (params) => { |
| 15 | // return post('/app-api/infra/file/upload', params); | 25 | // return post('/app-api/infra/file/upload', params); |
| 16 | // }; | 26 | // }; |
api/tree-archive/tree-archive.js
0 → 100644
| 1 | + | ||
| 2 | +import { post, get } from '@/common/utils/request'; | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 班组集合 | ||
| 7 | + * @param {Object} params | ||
| 8 | + * @returns {Promise} | ||
| 9 | + */ | ||
| 10 | +export const deptListReq = (params) => { | ||
| 11 | + return get('/app-api/garden/tree/dept/list', params); | ||
| 12 | +}; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * 道路树木列表 | ||
| 16 | + * @param {Object} params | ||
| 17 | + * @returns {Promise} | ||
| 18 | + */ | ||
| 19 | +export const treeRoadReq = (params) => { | ||
| 20 | + return get('/app-api/garden/tree/road/list', params); | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * 新增树 | ||
| 26 | + * @param {Object} params | ||
| 27 | + * @returns {Promise} | ||
| 28 | + */ | ||
| 29 | +export const addTree = (params) => { | ||
| 30 | + return get('/app-api/garden/tree/create', params); | ||
| 31 | +}; | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | +// // 树基本详情 | ||
| 36 | +// export const treeDetailReq = (params) => request.get('/business/tree/'+params ) | ||
| 37 | +// ==> | ||
| 38 | +// /app-api/garden/tree/get | ||
| 39 | +// | ||
| 40 | +// // 修改树 | ||
| 41 | +// export const updateTree = (params) => request.put('/business/tree/',params ) | ||
| 42 | +// ==> | ||
| 43 | +// /app-api/garden/tree/update | ||
| 44 | +// | ||
| 45 | +// // 树更变记录 | ||
| 46 | +// export const treeLogReq = (params) => request.get('/gardentree/logs/list/',params ) | ||
| 47 | +// ==> | ||
| 48 | +// /app-api/garden/tree-change-log/page |
pages-sub/data/tree-archive/addTree.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="container"> | ||
| 3 | + <up-form :model="formData" ref="formRef" label-width="140rpx" border-bottom> | ||
| 4 | + <up-form-item label="名称" prop="treetype" required> | ||
| 5 | + <up-input v-model="formData.treetype" placeholder="请输入名称" maxlength="30" border="none" /> | ||
| 6 | + </up-form-item> | ||
| 7 | + | ||
| 8 | + <up-row gutter="10"> | ||
| 9 | + <up-col span="6"> | ||
| 10 | + <up-form-item label="胸径" prop="dbh" required> | ||
| 11 | + <up-input v-model="formData.dbh" placeholder="请输入" maxlength="10" border="none" input-align="left" /> | ||
| 12 | + <template #right> | ||
| 13 | + <text style="padding-left: 12rpx;color:#ccc;font-size:12px">厘米</text> | ||
| 14 | + </template> | ||
| 15 | + </up-form-item> | ||
| 16 | + </up-col> | ||
| 17 | + <up-col span="6"> | ||
| 18 | + <up-form-item label="高度" prop="treeheight"> | ||
| 19 | + <up-input v-model="formData.treeheight" placeholder="请输入" maxlength="10" border="none" input-align="left" /> | ||
| 20 | + <template #right> | ||
| 21 | + <text style="padding-left: 12rpx;color:#ccc;font-size:14px;">米</text> | ||
| 22 | + </template> | ||
| 23 | + </up-form-item> | ||
| 24 | + </up-col> | ||
| 25 | + </up-row> | ||
| 26 | + | ||
| 27 | + <up-form-item label="位置" prop="growlocation" required class="location-form-item" @click="openMap"> | ||
| 28 | + <up-input v-model="formData.growlocation" placeholder="请选择" disabled border="none" /> | ||
| 29 | + <template #right> | ||
| 30 | + <up-icon name="map" size="22"></up-icon> | ||
| 31 | + </template> | ||
| 32 | + </up-form-item> | ||
| 33 | + | ||
| 34 | + <up-row gutter="10"> | ||
| 35 | + <up-col span="6"> | ||
| 36 | + <up-form-item label="经度" label-color="#ccc" prop="longitude" border-bottom="none"> | ||
| 37 | + <up-input v-model="formData.longitude" placeholder="" disabled border="none" /> | ||
| 38 | + </up-form-item> | ||
| 39 | + </up-col> | ||
| 40 | + <up-col span="6"> | ||
| 41 | + <up-form-item label="纬度" label-color="#ccc" prop="latitude" border-bottom="none"> | ||
| 42 | + <up-input v-model="formData.latitude" placeholder="" disabled border="none" /> | ||
| 43 | + </up-form-item> | ||
| 44 | + </up-col> | ||
| 45 | + </up-row> | ||
| 46 | + | ||
| 47 | + <up-form-item label="管护单位" prop="managedutyunit" required> | ||
| 48 | + <up-input v-model="formData.managedutyunit" placeholder="请输入" maxlength="30" border="none" /> | ||
| 49 | + </up-form-item> | ||
| 50 | + | ||
| 51 | + <up-form-item label="权属分类" prop="oldtreeownershipText" required arrow @click="pickerShow = true"> | ||
| 52 | + <up-input v-model="formData.oldtreeownershipText" placeholder="请选择" disabled border="none" bg-color="transparent" /> | ||
| 53 | + </up-form-item> | ||
| 54 | + | ||
| 55 | + <!-- ✅✅✅ 核心修改:图片上传 完全对标参考代码写法 start --> | ||
| 56 | + <up-form-item label="图片信息" prop="treeImgList" required> | ||
| 57 | + <up-upload | ||
| 58 | + :file-list="treeImgs.imgList.value || []" | ||
| 59 | + @after-read="treeImgs.uploadImgs" | ||
| 60 | + @delete="treeImgs.deleteImg" | ||
| 61 | + multiple | ||
| 62 | + :width="70" | ||
| 63 | + :height="70" | ||
| 64 | + :max-count="treeImgs.uploadConfig.maxCount" | ||
| 65 | + :upload-text="treeImgs.uploadConfig.uploadText" | ||
| 66 | + :size-type="treeImgs.uploadConfig.sizeType" | ||
| 67 | + ></up-upload> | ||
| 68 | + </up-form-item> | ||
| 69 | + <!-- ✅✅✅ 图片上传 修改结束 --> | ||
| 70 | + | ||
| 71 | + <!-- 动画区域(初始隐藏)保留原逻辑 --> | ||
| 72 | + <view | ||
| 73 | + class="animated-area" | ||
| 74 | + :style="{ | ||
| 75 | + height: isShow ? contentHeight + 'px' : '0', | ||
| 76 | + opacity: isShow ? 1 : 0, | ||
| 77 | + overflow: 'hidden' | ||
| 78 | + }" | ||
| 79 | + > | ||
| 80 | + <up-row gutter="10"> | ||
| 81 | + <up-col span="6"> | ||
| 82 | + <up-form-item label="拉丁文" prop="latinname"> | ||
| 83 | + <up-input v-model="formData.latinname" placeholder="请输入" maxlength="30" border="none" /> | ||
| 84 | + </up-form-item> | ||
| 85 | + </up-col> | ||
| 86 | + <up-col span="6"> | ||
| 87 | + <up-form-item label="级别" arrow @click="levelshow = true"> | ||
| 88 | + <up-input v-model="formData.treeleveltext" placeholder="请选择" disabled border="none" bg-color="transparent" /> | ||
| 89 | + </up-form-item> | ||
| 90 | + </up-col> | ||
| 91 | + </up-row> | ||
| 92 | + | ||
| 93 | + <up-form-item label="生长环境" prop="growthenvironment"> | ||
| 94 | + <up-input v-model="formData.growthenvironment" placeholder="请输入" maxlength="50" border="none" /> | ||
| 95 | + </up-form-item> | ||
| 96 | + | ||
| 97 | + <up-row gutter="10"> | ||
| 98 | + <up-col span="6"> | ||
| 99 | + <up-form-item label="预估树龄" prop="estimationtreeage"> | ||
| 100 | + <up-input v-model="formData.estimationtreeage" placeholder="请输入" maxlength="10" border="none" input-align="left" /> | ||
| 101 | + <template #right> | ||
| 102 | + <text style="padding-left:12rpx;color:#ccc;font-size:14px">年</text> | ||
| 103 | + </template> | ||
| 104 | + </up-form-item> | ||
| 105 | + </up-col> | ||
| 106 | + <up-col span="6"> | ||
| 107 | + <up-form-item label="干周" prop="weekday"> | ||
| 108 | + <up-input v-model="formData.weekday" placeholder="请输入" maxlength="10" border="none" input-align="left" /> | ||
| 109 | + <template #right> | ||
| 110 | + <text style="padding-left:12rpx;color:#ccc;font-size:14px">厘米</text> | ||
| 111 | + </template> | ||
| 112 | + </up-form-item> | ||
| 113 | + </up-col> | ||
| 114 | + </up-row> | ||
| 115 | + | ||
| 116 | + <up-row gutter="10"> | ||
| 117 | + <up-col span="6"> | ||
| 118 | + <up-form-item label="东西冠幅" prop="canopyeastwest"> | ||
| 119 | + <up-input v-model="formData.canopyeastwest" placeholder="请输入" maxlength="10" border="none" input-align="left" /> | ||
| 120 | + <template #right> | ||
| 121 | + <text style="padding-left:12rpx;color:#ccc;font-size:14px">米</text> | ||
| 122 | + </template> | ||
| 123 | + </up-form-item> | ||
| 124 | + </up-col> | ||
| 125 | + <up-col span="6"> | ||
| 126 | + <up-form-item label="南北冠幅" prop="canopysouthnorth"> | ||
| 127 | + <up-input v-model="formData.canopysouthnorth" placeholder="请输入" maxlength="10" border="none" input-align="left" /> | ||
| 128 | + <template #right> | ||
| 129 | + <text style="padding-left:12rpx;color:#ccc;font-size:14px">米</text> | ||
| 130 | + </template> | ||
| 131 | + </up-form-item> | ||
| 132 | + </up-col> | ||
| 133 | + </up-row> | ||
| 134 | + </view> | ||
| 135 | + | ||
| 136 | + <!-- 触发按钮 --> | ||
| 137 | + <up-button | ||
| 138 | + @click="toggleArea" | ||
| 139 | + type="primary" | ||
| 140 | + plain | ||
| 141 | + size="large" | ||
| 142 | + style="margin-top:20rpx" | ||
| 143 | + > | ||
| 144 | + {{ isShow ? '- 隐藏区域' : '+ 显示区域' }} | ||
| 145 | + </up-button> | ||
| 146 | + </up-form> | ||
| 147 | + | ||
| 148 | + <view style="height: 60px;width: 100%"></view> | ||
| 149 | + | ||
| 150 | + <!-- 底部提交按钮 --> | ||
| 151 | + <view class="fixed-bottom-btn-wrap"> | ||
| 152 | + <up-button type="primary" @click="submit" :loading="loadingFlag" size="large" bold>提交</up-button> | ||
| 153 | + </view> | ||
| 154 | + | ||
| 155 | + <up-picker | ||
| 156 | + v-model="pickerShow" | ||
| 157 | + :list="treeOwnershipData" | ||
| 158 | + label-key="dictLabel" | ||
| 159 | + value-key="dictValue" | ||
| 160 | + @confirm="pickerChange" | ||
| 161 | + ></up-picker> | ||
| 162 | + | ||
| 163 | + <up-picker | ||
| 164 | + v-model="levelshow" | ||
| 165 | + :list="treeLevelData" | ||
| 166 | + label-key="dictLabel" | ||
| 167 | + value-key="dictValue" | ||
| 168 | + @confirm="pickerLevelChange" | ||
| 169 | + ></up-picker> | ||
| 170 | + </view> | ||
| 171 | +</template> | ||
| 172 | + | ||
| 173 | +<script setup> | ||
| 174 | +import { ref, reactive, nextTick } from 'vue' | ||
| 175 | +import { onReady, onLoad, onShow } from '@dcloudio/uni-app'; | ||
| 176 | +import { addTree } from "@/api/tree-archive/tree-archive.js"; | ||
| 177 | + | ||
| 178 | +import { useUploadImgs } from '@/common/utils/useUploadImgs' | ||
| 179 | +import { useUserStore } from '@/pinia/user'; | ||
| 180 | + | ||
| 181 | +// ========== 状态管理 ========== | ||
| 182 | +const userStore = useUserStore(); | ||
| 183 | + | ||
| 184 | +// ✅ 全局响应式数据 | ||
| 185 | +const formRef = ref(null) | ||
| 186 | +const isShow = ref(false) | ||
| 187 | +const contentHeight = ref(700) | ||
| 188 | +const treeOwnershipData = ref([]) | ||
| 189 | +const treeLevelData = ref([]) | ||
| 190 | +const pickerShow = ref(false) | ||
| 191 | +const levelshow = ref(false) | ||
| 192 | +const loadingFlag = ref(false) | ||
| 193 | + | ||
| 194 | +// ✅✅✅ 核心修改:图片上传配置 完全对标参考代码写法 | ||
| 195 | +const treeImgs = useUploadImgs({ | ||
| 196 | + maxCount: 3, | ||
| 197 | + uploadText: '选择图片', | ||
| 198 | + sizeType: ['compressed'], | ||
| 199 | + formRef: formRef, | ||
| 200 | + fieldName: 'treeImgList' | ||
| 201 | +}) | ||
| 202 | +// 图片数组兜底,防止非数组报错 | ||
| 203 | +if (!Array.isArray(treeImgs.rawImgList.value)) treeImgs.rawImgList.value = []; | ||
| 204 | + | ||
| 205 | +// ✅ 表单数据 - 替代vue2的data | ||
| 206 | +const formData = reactive({ | ||
| 207 | + treetype: '', | ||
| 208 | + treeheight: '', | ||
| 209 | + dbh: '', | ||
| 210 | + treelevel: '', | ||
| 211 | + treeleveltext: '', | ||
| 212 | + managedutyunit: '', | ||
| 213 | + oldtreeownership: '', | ||
| 214 | + oldtreeownershipText: '', | ||
| 215 | + latinname: '', | ||
| 216 | + estimationtreeage: '', | ||
| 217 | + canopysouthnorth: '', | ||
| 218 | + canopyeastwest: '', | ||
| 219 | + weekday: '', | ||
| 220 | + growlocation: '', | ||
| 221 | + growthenvironment: '', | ||
| 222 | + treeImgList: [], | ||
| 223 | + address: '', | ||
| 224 | + latitude: '', | ||
| 225 | + longitude: '', | ||
| 226 | + road: '', | ||
| 227 | + maintainunit: '' | ||
| 228 | +}) | ||
| 229 | + | ||
| 230 | +// ✅✅✅ 核心修改:表单校验规则 - 图片校验改为参考代码同款 | ||
| 231 | +const rules = reactive({ | ||
| 232 | + treetype: [{ required: true, message: '请输入名称', trigger: 'blur' }], | ||
| 233 | + treeheight: [{ max: 10, message: '树高不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }], | ||
| 234 | + dbh: [{ required: true, message: '请输入胸径', trigger: 'blur' }, { max: 10, message: '胸径不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }], | ||
| 235 | + estimationtreeage: [{ max: 10, message: '预估树龄不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }], | ||
| 236 | + weekday: [{ max: 10, message: '干周不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }], | ||
| 237 | + canopyeastwest: [{ max: 10, message: '东西冠幅不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }], | ||
| 238 | + canopysouthnorth: [{ max: 10, message: '南北冠幅不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }], | ||
| 239 | + growlocation: [{ required: true, message: '请地图选择位置', trigger: 'change' }], | ||
| 240 | + managedutyunit: [{ required: true, message: '请输入管护单位', trigger: 'blur' }], | ||
| 241 | + oldtreeownershipText: [{ required: true, message: '请选择权属分类', trigger: 'change' }], | ||
| 242 | + treeImgList: [treeImgs.imgValidateRule] // ✅ 图片校验规则和参考代码一致 | ||
| 243 | +}) | ||
| 244 | + | ||
| 245 | +// ✅ 生命周期 | ||
| 246 | +onLoad((options) => { | ||
| 247 | + formData.road = options.roadId | ||
| 248 | +}) | ||
| 249 | + | ||
| 250 | +onShow(async () => { | ||
| 251 | + | ||
| 252 | + treeLevelData.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('tree_level')); | ||
| 253 | + treeOwnershipData.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('tree_ownership')); | ||
| 254 | +}) | ||
| 255 | + | ||
| 256 | +// 修复表单ref挂载问题,和参考代码一致 | ||
| 257 | +onReady(() => { | ||
| 258 | + nextTick(() => { | ||
| 259 | + formRef.value?.setRules(rules); | ||
| 260 | + }); | ||
| 261 | +}); | ||
| 262 | + | ||
| 263 | + | ||
| 264 | + | ||
| 265 | +const toggleArea = () => { | ||
| 266 | + isShow.value = !isShow.value | ||
| 267 | +} | ||
| 268 | + | ||
| 269 | + | ||
| 270 | +// 权属分类选择回调 | ||
| 271 | +const pickerChange = (val) => { | ||
| 272 | + formData.oldtreeownership = val.value | ||
| 273 | + formData.oldtreeownershipText = val.label | ||
| 274 | + pickerShow.value = false | ||
| 275 | +} | ||
| 276 | + | ||
| 277 | +// 树木级别选择回调 | ||
| 278 | +const pickerLevelChange = (val) => { | ||
| 279 | + formData.treelevel = val.value | ||
| 280 | + formData.treeleveltext = val.label | ||
| 281 | + levelshow.value = false | ||
| 282 | +} | ||
| 283 | + | ||
| 284 | +// 打开地图选址 | ||
| 285 | +const openMap = () => { | ||
| 286 | + uni.chooseLocation({ | ||
| 287 | + success: (res) => { | ||
| 288 | + formData.growlocation = res.address | ||
| 289 | + formData.latitude = res.latitude | ||
| 290 | + formData.longitude = res.longitude | ||
| 291 | + }, | ||
| 292 | + fail: (err) => { | ||
| 293 | + console.error('地图选择失败', err); | ||
| 294 | + if (err.errMsg.includes('auth deny')) { | ||
| 295 | + uni.showToast({ title: '请授权位置权限', icon: 'none' }); | ||
| 296 | + } | ||
| 297 | + } | ||
| 298 | + }); | ||
| 299 | +} | ||
| 300 | + | ||
| 301 | +// 表单提交核心方法 | ||
| 302 | +const submit = async () => { | ||
| 303 | + if (loadingFlag.value) return | ||
| 304 | + // 表单校验 | ||
| 305 | + const valid = await formRef.value.validate() | ||
| 306 | + if (!valid) return | ||
| 307 | + | ||
| 308 | + // ✅✅✅ 核心修改:获取上传成功的图片地址,和参考代码一致 | ||
| 309 | + const uploadImgUrls = treeImgs.getSuccessImgUrls() | ||
| 310 | + | ||
| 311 | + // 组装提交参数 | ||
| 312 | + formData.maintainunit = uni.getStorageSync('userInfo')?.belongCompanyId || '' | ||
| 313 | + formData.treeImgList = uploadImgUrls // 赋值图片数组 | ||
| 314 | + loadingFlag.value = true | ||
| 315 | + | ||
| 316 | + try { | ||
| 317 | + const res = await addTree({ data: { ...formData } }) | ||
| 318 | + if (res.code == '200') { | ||
| 319 | + uni.showToast({ title: "新增成功", icon: "success" }); | ||
| 320 | + uni.redirectTo({ url: '/subPackages/treePage/treeFiles' }); | ||
| 321 | + } | ||
| 322 | + } catch (err) { | ||
| 323 | + uni.showToast({ title: "新增失败,请重试", icon: "none" }); | ||
| 324 | + console.error(err) | ||
| 325 | + } finally { | ||
| 326 | + loadingFlag.value = false | ||
| 327 | + } | ||
| 328 | +} | ||
| 329 | +</script> | ||
| 330 | + | ||
| 331 | +<style scoped lang="scss"> | ||
| 332 | +.container { | ||
| 333 | + padding: 25rpx; | ||
| 334 | + box-sizing: border-box; | ||
| 335 | + background: #fff; | ||
| 336 | +} | ||
| 337 | + | ||
| 338 | +.animated-area { | ||
| 339 | + transition: all 0.3s ease-out; | ||
| 340 | + margin-top: 10rpx; | ||
| 341 | +} | ||
| 342 | +.location-form-item { | ||
| 343 | + padding-right: 10rpx; | ||
| 344 | +} | ||
| 345 | +</style> | ||
| 0 | \ No newline at end of file | 346 | \ No newline at end of file |
pages-sub/data/tree-archive/editTree.vue
0 → 100644
pages-sub/data/tree-archive/index.vue
| 1 | -<script setup lang="ts"> | 1 | +<template> |
| 2 | + <view class="container"> | ||
| 3 | + <!-- 归属单位选择 --> | ||
| 4 | + <up-form :model="formData" ref="formRef" label-width="140rpx" border-bottom style="padding: 0 15px"> | ||
| 5 | + <up-form-item | ||
| 6 | + label="归属单位" | ||
| 7 | + prop="companyId" | ||
| 8 | + @click="showActionSheet = true" | ||
| 9 | + class="form-item-custom" | ||
| 10 | + > | ||
| 11 | + <up-input | ||
| 12 | + v-model="formData.companyId" | ||
| 13 | + placeholder="请选择归属单位" | ||
| 14 | + disabled | ||
| 15 | + disabled-color="#ffffff" | ||
| 16 | + border="none" | ||
| 17 | + bg-color="transparent" | ||
| 18 | + /> | ||
| 19 | + <template #right> | ||
| 20 | + <up-icon name="arrow-right" size="16"></up-icon> | ||
| 21 | + </template> | ||
| 22 | + </up-form-item> | ||
| 23 | + </up-form> | ||
| 2 | 24 | ||
| 3 | -</script> | 25 | + <!-- 弹窗式 Search 搜索组件 --> |
| 26 | + <view class="search-wrap"> | ||
| 27 | + <up-search | ||
| 28 | + v-model="searchValue" | ||
| 29 | + placeholder="请输入道路名称搜索" | ||
| 30 | + @search="handleSearch" | ||
| 31 | + bg-color="#f5f5f5" | ||
| 32 | + :clearabled="false" | ||
| 33 | + :show-action="true" | ||
| 34 | + actionText="搜索" | ||
| 35 | + :animation="true" | ||
| 36 | + @custom="handleSearch" | ||
| 37 | + /> | ||
| 38 | + </view> | ||
| 4 | 39 | ||
| 5 | -<template> | 40 | + <!-- ✅ 核心:uview-plus up-row+up-col 实现左右布局【无u-scroll-list,无任何多余组件】 --> |
| 41 | + <up-row type="flex" class="cate-layout" align="flex-start"> | ||
| 42 | + <!-- 左侧:班组列表 (uview栅格列 + 原生滚动) --> | ||
| 43 | + <up-col span="3" class="cate-left"> | ||
| 44 | + <view | ||
| 45 | + class="left-item" | ||
| 46 | + :class="{ active: currentIndex === index }" | ||
| 47 | + v-for="(item, index) in cateTabList" | ||
| 48 | + :key="item.deptId" | ||
| 49 | + @click="cateTabChange(index)" | ||
| 50 | + > | ||
| 51 | + {{ item.deptName }} | ||
| 52 | + </view> | ||
| 53 | + | ||
| 54 | + </up-col> | ||
| 6 | 55 | ||
| 56 | + <!-- 右侧:道路列表 (uview栅格列 + 原生滚动) --> | ||
| 57 | + <up-col span="9" class="cate-right"> | ||
| 58 | + <scroll-view scroll-y class="right-scroll"> | ||
| 59 | + <!-- 暂无数据 --> | ||
| 60 | + <empty-view v-if="!hasValidRoadId"></empty-view> | ||
| 61 | + <!-- 道路数据列表 --> | ||
| 62 | + <view v-else class="road-list-wrap"> | ||
| 63 | + <view | ||
| 64 | + v-for="item in roads" | ||
| 65 | + class="card-wrap cad-box-shadow" | ||
| 66 | + :key="item.roadId" | ||
| 67 | + @click="toNewPage(item.roadId, item.treeCount)" | ||
| 68 | + > | ||
| 69 | + <p class="fs-flex__between"> | ||
| 70 | + <span class="up-line-1">{{ item.roadName }}</span> | ||
| 71 | + <span class="treeCount">{{ item.treeCount }}棵</span> | ||
| 72 | + </p> | ||
| 73 | + <p class="up-line-1 fs-my8">已录入行道树:{{ item.recordedCount }}棵</p> | ||
| 74 | + <p class="up-line-1 fs-my8" style="color: #999;font-size: 12px">起点:{{ item.startRemark }}</p> | ||
| 75 | + <p class="up-line-1" style="color: #999;font-size: 12px">终点:{{ item.endRemark }}</p> | ||
| 76 | + </view> | ||
| 77 | + </view> | ||
| 78 | + </scroll-view> | ||
| 79 | + </up-col> | ||
| 80 | + </up-row> | ||
| 81 | + | ||
| 82 | + <!-- ActionSheet 底部弹出选择菜单 --> | ||
| 83 | + <up-action-sheet | ||
| 84 | + :show="showActionSheet" | ||
| 85 | + :actions="belongCompanyData" | ||
| 86 | + title="请选择归属单位" | ||
| 87 | + @select="actionSheetSelect" | ||
| 88 | + @close="showActionSheet = false" | ||
| 89 | + ></up-action-sheet> | ||
| 90 | + | ||
| 91 | + </view> | ||
| 7 | </template> | 92 | </template> |
| 8 | 93 | ||
| 9 | -<style scoped> | 94 | +<script setup> |
| 95 | +import { ref, reactive, watch } from 'vue' | ||
| 96 | +import { onShow } from '@dcloudio/uni-app'; | ||
| 97 | +import { getCompanyList } from "@/api/common"; | ||
| 98 | +import { deptListReq } from '@/api/tree-archive/tree-archive' | ||
| 99 | + | ||
| 100 | + | ||
| 101 | +const formRef = ref(null) | ||
| 102 | +const showActionSheet = ref(false) | ||
| 103 | +const currentIndex = ref(0) | ||
| 104 | +const hasValidRoadId = ref(false) | ||
| 105 | +const searchValue = ref('') // 搜索关键词 独立绑定 | ||
| 106 | + | ||
| 107 | +// 表单数据 | ||
| 108 | +const formData = reactive({ | ||
| 109 | + companyId: '', | ||
| 110 | +}) | ||
| 111 | + | ||
| 112 | +// 接口数据变量 | ||
| 113 | +const companyId = ref('') | ||
| 114 | +const belongCompanyData = ref([]) // 归属单位下拉数据 | ||
| 115 | +const depts = ref([]) // 归属班组列表 | ||
| 116 | +const roads = ref([]) // 当前选中班组的道路列表 | ||
| 117 | +const cateTabList = ref([]) // 左侧tab数据源 | ||
| 118 | + | ||
| 119 | +// 生命周期 | ||
| 120 | +onShow( async() => { | ||
| 121 | + const res = await getCompanyList() | ||
| 122 | + belongCompanyData.value = res | ||
| 123 | + if (belongCompanyData.value.length > 0) { | ||
| 124 | + formData.companyId = belongCompanyData.value[0].name | ||
| 125 | + companyId.value = belongCompanyData.value[0].id.toString() | ||
| 126 | + deptListQuery() | ||
| 127 | + } | ||
| 128 | +}) | ||
| 129 | + | ||
| 130 | +// 监听 CateTab 选中下标 数据联动 | ||
| 131 | +watch(currentIndex, () => { | ||
| 132 | + if(depts.value.length > 0) { | ||
| 133 | + roads.value = depts.value[currentIndex.value].roads | ||
| 134 | + checkRoadDataValid() | ||
| 135 | + } | ||
| 136 | +}) | ||
| 137 | + | ||
| 138 | +// 搜索事件 - 点击搜索按钮/回车触发 | ||
| 139 | +const handleSearch = () => { | ||
| 140 | + deptListQuery() | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +// 跳转道路档案记录页 | ||
| 144 | +const toNewPage = (roadId, treeCount) => { | ||
| 145 | + uni.navigateTo({ | ||
| 146 | + url: `/pages-sub/data/tree-archive/treeRecord?roadId=${roadId}&count=${treeCount}` | ||
| 147 | + }) | ||
| 148 | +} | ||
| 149 | + | ||
| 150 | +// 查询班组+道路数据 & 格式化CateTab的数据源 | ||
| 151 | +const deptListQuery = async () => { | ||
| 152 | + const params = { | ||
| 153 | + companyId: companyId.value, | ||
| 154 | + roadName: searchValue.value | ||
| 155 | + } | ||
| 156 | + const res = await deptListReq(params) | ||
| 157 | + if (res.length ==0) { | ||
| 158 | + depts.value = [] | ||
| 159 | + roads.value = [] | ||
| 160 | + cateTabList.value = [] | ||
| 161 | + hasValidRoadId.value = false | ||
| 162 | + } else { | ||
| 163 | + depts.value = res[0].depts | ||
| 164 | + cateTabList.value = depts.value | ||
| 165 | + roads.value = depts.value[0].roads | ||
| 166 | + checkRoadDataValid() | ||
| 167 | + } | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +// 左侧班组切换事件 | ||
| 171 | +const cateTabChange = (index) => { | ||
| 172 | + currentIndex.value = index | ||
| 173 | + roads.value = depts.value[index].roads | ||
| 174 | + checkRoadDataValid() | ||
| 175 | +} | ||
| 176 | + | ||
| 177 | +// ActionSheet 选择归属单位的确认事件 | ||
| 178 | +const actionSheetSelect = (val) => { | ||
| 179 | + formData.companyId = val.name | ||
| 180 | + companyId.value = val.id.toString() | ||
| 181 | + showActionSheet.value = false // 关闭弹窗 | ||
| 182 | + deptListQuery() // 重新查询数据 | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +// 校验是否有有效道路数据 | ||
| 186 | +const checkRoadDataValid = () => { | ||
| 187 | + hasValidRoadId.value = roads.value && roads.value.length > 0 && roads.value.some(item => { | ||
| 188 | + return item.roadId !== null && item.roadId !== undefined && item.roadId | ||
| 189 | + }) | ||
| 190 | +} | ||
| 191 | +</script> | ||
| 192 | + | ||
| 193 | +<style scoped lang="scss"> | ||
| 194 | +// 页面容器 满高布局 | ||
| 195 | +.container { | ||
| 196 | + height: 100%; | ||
| 197 | + display: flex; | ||
| 198 | + flex-direction: column; | ||
| 199 | + background: #fff; | ||
| 200 | + box-sizing: border-box; | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +// 搜索框外层容器 间距不变 | ||
| 204 | +.search-wrap { | ||
| 205 | + padding: 10rpx 15rpx; | ||
| 206 | +} | ||
| 207 | + | ||
| 208 | +.cate-layout { | ||
| 209 | + flex: 1; | ||
| 210 | + width: 100%; | ||
| 211 | + height: calc(100vh - 44px); | ||
| 212 | + | ||
| 213 | +} | ||
| 214 | + | ||
| 215 | + | ||
| 216 | +.cate-left { | ||
| 217 | + height: 100%; | ||
| 218 | + padding: 0; | ||
| 219 | + background: #f8f8f8; | ||
| 220 | + box-sizing: border-box; | ||
| 221 | + .left-scroll { | ||
| 222 | + width: 100%; | ||
| 223 | + height: 100%; | ||
| 224 | + } | ||
| 225 | + // 左侧列表项 | ||
| 226 | + .left-item { | ||
| 227 | + padding: 24rpx 12rpx; | ||
| 228 | + font-size: 28rpx; | ||
| 229 | + | ||
| 230 | + white-space: nowrap; | ||
| 231 | + overflow: hidden; | ||
| 232 | + text-overflow: ellipsis; | ||
| 233 | + box-sizing: border-box; | ||
| 234 | + } | ||
| 235 | + // 选中项高亮 主题色和你一致 #5f5fe2 | ||
| 236 | + .left-item.active { | ||
| 237 | + background: #ffffff; | ||
| 238 | + color: #5f5fe2; | ||
| 239 | + font-weight: 500; | ||
| 240 | + border-left: 4rpx solid #5f5fe2; | ||
| 241 | + } | ||
| 242 | +} | ||
| 243 | + | ||
| 244 | +.cate-right { | ||
| 245 | + height: 100%; | ||
| 246 | + padding: 0 10rpx; | ||
| 247 | + box-sizing: border-box; | ||
| 248 | + background: #ffffff; | ||
| 249 | + .right-scroll { | ||
| 250 | + width: 100%; | ||
| 251 | + height: 100%; | ||
| 252 | + } | ||
| 253 | +} | ||
| 254 | + | ||
| 255 | +// 道路列表容器 | ||
| 256 | +.road-list-wrap { | ||
| 257 | + //padding-bottom: 30rpx; | ||
| 258 | +} | ||
| 259 | + | ||
| 260 | +// 道路卡片样式 完全复用你的原版 | ||
| 261 | +.card-wrap { | ||
| 262 | + box-shadow:0 0 3px rgba(0, 0, 0, 0.2); | ||
| 263 | + padding: 20rpx; | ||
| 264 | + border-radius: 14rpx; | ||
| 265 | + background: #fff; | ||
| 266 | + margin:10px 6px; | ||
| 267 | +} | ||
| 10 | 268 | ||
| 269 | +// 公共样式 完全不变 | ||
| 270 | +.treeCount { | ||
| 271 | + color: #5f5fe2; | ||
| 272 | + min-width: 70px; | ||
| 273 | + text-align: right; | ||
| 274 | +} | ||
| 275 | +.fs-flex__between { | ||
| 276 | + display: flex; | ||
| 277 | + justify-content: space-between; | ||
| 278 | + align-items: center; | ||
| 279 | +} | ||
| 280 | +.fs-my8 { margin: 8rpx 0; } | ||
| 11 | </style> | 281 | </style> |
| 12 | \ No newline at end of file | 282 | \ No newline at end of file |
pages-sub/data/tree-archive/treeRecord.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="container"> | ||
| 3 | + <!-- ✅ 替换tui-no-data 为 uview-plus的空数据组件 up-empty --> | ||
| 4 | + <up-empty | ||
| 5 | + v-if="rows.length === 0" | ||
| 6 | + text="暂无数据" | ||
| 7 | + ></up-empty> | ||
| 8 | + | ||
| 9 | + <view class="record-wrap" v-else> | ||
| 10 | + <view class="record-list-wrap cad-box-shadow fs-bg__white" v-for="i in rows" :key="i.id" @click="toEditPage(i.id)"> | ||
| 11 | + <view style="display: flex"> | ||
| 12 | + <view class="record-list-left" :style="`background-image: url(${i.treephoto});`"></view> | ||
| 13 | + <view class="record-list-right"> | ||
| 14 | + <view class="record-list-right-title"> | ||
| 15 | + <view class="fs-ellipsis treetypeName">{{ i.treetype }}</view> | ||
| 16 | + <view style="text-align: right">{{ i.updatetime.substring(0, 10) }}</view> | ||
| 17 | + </view> | ||
| 18 | + <view class="fs-mt8 fs-align__center"> | ||
| 19 | + <img src="../../../static/imgs/tree/tree-high.png" style="width: 14px;height: 14px;margin-right: 6px;" alt=""> 高度:{{ i.treeheight }} 米 | ||
| 20 | + </view> | ||
| 21 | + <view class="fs-mt8 fs-align__center"> | ||
| 22 | + <img src="../../../static/imgs/tree/treearound.png" style="width: 14px;height: 14px;margin-right: 6px;" alt="">胸径:{{ i.dbh }} 厘米 | ||
| 23 | + </view> | ||
| 24 | + </view> | ||
| 25 | + </view> | ||
| 26 | + <view class="fs-mt8 fs-ellipsis treenumber-no"> | ||
| 27 | + 树木编号:{{ i.treenumber }} | ||
| 28 | + </view> | ||
| 29 | + </view> | ||
| 30 | + </view> | ||
| 31 | + | ||
| 32 | + <view class="fixed-bottom-btn-wrap"> | ||
| 33 | + <up-button | ||
| 34 | + type="primary" | ||
| 35 | + class="addTree" | ||
| 36 | + @click="toAddTreePage" | ||
| 37 | + v-show="count > 0 && count > rows.length" | ||
| 38 | + > | ||
| 39 | + 新增树木录入 | ||
| 40 | + </up-button> | ||
| 41 | + </view> | ||
| 42 | + | ||
| 43 | + </view> | ||
| 44 | +</template> | ||
| 45 | + | ||
| 46 | +<script setup> | ||
| 47 | +import { ref} from 'vue' | ||
| 48 | +import { onLoad, onShow } from '@dcloudio/uni-app'; | ||
| 49 | +// 引入接口请求方法 | ||
| 50 | +import { treeRoadReq } from "@/api/tree-archive/tree-archive.js"; | ||
| 51 | + | ||
| 52 | + | ||
| 53 | +const rows = ref([]) | ||
| 54 | +const roadId = ref('') | ||
| 55 | +const count = ref(0) | ||
| 56 | + | ||
| 57 | + | ||
| 58 | +onLoad((options) => { | ||
| 59 | + console.log(options) | ||
| 60 | + roadId.value = options.roadId | ||
| 61 | + count.value = options.count | ||
| 62 | +}) | ||
| 63 | + | ||
| 64 | +onShow(() => { | ||
| 65 | + treeRoadQuery() | ||
| 66 | +}) | ||
| 67 | + | ||
| 68 | +// 前往修改页面 | ||
| 69 | +const toEditPage = (id) => { | ||
| 70 | + uni.navigateTo({ | ||
| 71 | + url: `/pages-sub/data/tree-archive/editTree?id=${id}` | ||
| 72 | + }) | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +// 前往新增页面 | ||
| 76 | +const toAddTreePage = () => { | ||
| 77 | + uni.navigateTo({ | ||
| 78 | + url: `/pages-sub/data/tree-archive/addTree?roadId=${roadId.value}` | ||
| 79 | + }) | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +// 树木记录列表查询接口 | ||
| 83 | +const treeRoadQuery = async () => { | ||
| 84 | + const res = await treeRoadReq( {road: roadId.value}) | ||
| 85 | + console.log(res) | ||
| 86 | + rows.value = res.rows | ||
| 87 | +} | ||
| 88 | +</script> | ||
| 89 | + | ||
| 90 | +<style scoped lang="scss"> | ||
| 91 | +// 保留原页面所有样式,一行未改,样式完全一致 | ||
| 92 | +.record-wrap { | ||
| 93 | + padding-bottom: 60px; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +.record-list-wrap { | ||
| 97 | + margin: 15px 10px 0; | ||
| 98 | + padding: 10px; | ||
| 99 | + border-radius: 6px; | ||
| 100 | + font-size: 14px; | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +.treetypeName { | ||
| 104 | + flex: 1; | ||
| 105 | + font-size: 16px; | ||
| 106 | + font-weight: bold; | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | +.record-list-left { | ||
| 110 | + height: 70px; | ||
| 111 | + width: 70px; | ||
| 112 | + background-size: 100% 100%; | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +.record-list-right { | ||
| 116 | + margin-left: 20px; | ||
| 117 | + flex: 1; | ||
| 118 | + overflow: hidden; | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +.record-list-right-title { | ||
| 122 | + display: flex; | ||
| 123 | + justify-content: space-between; | ||
| 124 | +} | ||
| 125 | + | ||
| 126 | +.treenumber-no { | ||
| 127 | + padding: 3px 10px; | ||
| 128 | + background: #bdefd0; | ||
| 129 | + font-size: 12px; | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +.addTree { | ||
| 133 | + width: 100%; | ||
| 134 | + position: fixed; | ||
| 135 | + bottom: 0; | ||
| 136 | +} | ||
| 137 | +</style> | ||
| 0 | \ No newline at end of file | 138 | \ No newline at end of file |
pages-sub/problem/ai-manage/index.vue
| @@ -3,7 +3,6 @@ | @@ -3,7 +3,6 @@ | ||
| 3 | <!-- 顶部固定区域 --> | 3 | <!-- 顶部固定区域 --> |
| 4 | <up-sticky> | 4 | <up-sticky> |
| 5 | <view class="header-wrap"> | 5 | <view class="header-wrap"> |
| 6 | - <!-- 第一行:u-tabs 待办/已办切换 :scrollable="false"--> | ||
| 7 | <up-tabs | 6 | <up-tabs |
| 8 | v-model="activeTab" | 7 | v-model="activeTab" |
| 9 | :list="tabList" | 8 | :list="tabList" |
| @@ -12,10 +11,8 @@ | @@ -12,10 +11,8 @@ | ||
| 12 | font-size="30rpx" | 11 | font-size="30rpx" |
| 13 | @click="handleTabChange" | 12 | @click="handleTabChange" |
| 14 | /> | 13 | /> |
| 15 | - | ||
| 16 | <!-- 第二行:下拉框 + 搜索框 --> | 14 | <!-- 第二行:下拉框 + 搜索框 --> |
| 17 | <view class="search-header"> | 15 | <view class="search-header"> |
| 18 | - <!-- 左侧下拉框 --> | ||
| 19 | <view class="select-wrap common-text-color"> | 16 | <view class="select-wrap common-text-color"> |
| 20 | <up-select | 17 | <up-select |
| 21 | v-model:current="selectedSortValue" | 18 | v-model:current="selectedSortValue" |
| @@ -26,8 +23,6 @@ | @@ -26,8 +23,6 @@ | ||
| 26 | :style="{ flex: 1 }" | 23 | :style="{ flex: 1 }" |
| 27 | /> | 24 | /> |
| 28 | </view> | 25 | </view> |
| 29 | - | ||
| 30 | - <!-- 右侧搜索框 --> | ||
| 31 | <view class="search-input-wrap"> | 26 | <view class="search-input-wrap"> |
| 32 | <up-search | 27 | <up-search |
| 33 | v-model="searchValue" | 28 | v-model="searchValue" |
| @@ -47,24 +42,23 @@ | @@ -47,24 +42,23 @@ | ||
| 47 | 42 | ||
| 48 | <!-- 列表容器 --> | 43 | <!-- 列表容器 --> |
| 49 | <z-paging | 44 | <z-paging |
| 50 | - ref="paging" | 45 | + ref="pagingRef" |
| 51 | v-model="orderList" | 46 | v-model="orderList" |
| 52 | @query="queryList" | 47 | @query="queryList" |
| 53 | :auto-show-system-loading="true" | 48 | :auto-show-system-loading="true" |
| 54 | - | ||
| 55 | > | 49 | > |
| 56 | <template #empty> | 50 | <template #empty> |
| 57 | - <empty-view/> | 51 | + <empty-view /> |
| 58 | </template> | 52 | </template> |
| 59 | 53 | ||
| 60 | <view class="common-card-list" style="padding-top: 200rpx;padding-bottom: 30rpx"> | 54 | <view class="common-card-list" style="padding-top: 200rpx;padding-bottom: 30rpx"> |
| 61 | <!-- 待办工单卡片 --> | 55 | <!-- 待办工单卡片 --> |
| 62 | <up-card | 56 | <up-card |
| 63 | - v-if="activeTab == 0" | 57 | + v-if="activeTab === 0" |
| 64 | :border="false" | 58 | :border="false" |
| 65 | :foot-border-top="false" | 59 | :foot-border-top="false" |
| 66 | v-for="(item, index) in orderList" | 60 | v-for="(item, index) in orderList" |
| 67 | - :key="`todo_${item.orderNo}_${index}`" | 61 | + :key="`todo_${item.id}_${index}`" |
| 68 | :show-head="false" | 62 | :show-head="false" |
| 69 | class="order-card" | 63 | class="order-card" |
| 70 | > | 64 | > |
| @@ -86,7 +80,7 @@ | @@ -86,7 +80,7 @@ | ||
| 86 | <view class="u-body-item-title">情况描述:</view> | 80 | <view class="u-body-item-title">情况描述:</view> |
| 87 | <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> | 81 | <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> |
| 88 | </view> | 82 | </view> |
| 89 | - <view class="u-body-item u-flex common-item-center common-justify-between"> | 83 | + <view class="u-body-item u-flex common-item-center common-justify-between"> |
| 90 | <view class="u-body-item-title">紧急程度:</view> | 84 | <view class="u-body-item-title">紧急程度:</view> |
| 91 | <view class="u-line-1 u-body-value"> | 85 | <view class="u-line-1 u-body-value"> |
| 92 | {{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} | 86 | {{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} |
| @@ -101,20 +95,10 @@ | @@ -101,20 +95,10 @@ | ||
| 101 | <view class="u-line-1 u-body-value">{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view> | 95 | <view class="u-line-1 u-body-value">{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view> |
| 102 | </view> | 96 | </view> |
| 103 | <!-- 操作按钮行 --> | 97 | <!-- 操作按钮行 --> |
| 104 | - | ||
| 105 | <view class="u-body-item u-flex common-justify-between common-item-center mt-20"> | 98 | <view class="u-body-item u-flex common-justify-between common-item-center mt-20"> |
| 106 | - <up-button type="warning" size="mini" @click="handleReject(item)" | ||
| 107 | - v-show="nextStepMap[item.taskKey].backShow">回退 | ||
| 108 | - </up-button> | ||
| 109 | - | ||
| 110 | - <up-button type="success" size="mini" @click="handleRenew(item)" | ||
| 111 | - v-show="nextStepMap[item.taskKey].renewShow">重新提交 | ||
| 112 | - </up-button> | ||
| 113 | - | ||
| 114 | - <up-button type="primary" size="mini" @click="handleProcess(item)">{{ | ||
| 115 | - nextStepMap[item.taskKey].btnText | ||
| 116 | - }} | ||
| 117 | - </up-button> | 99 | + <up-button type="warning" size="mini" @click="handleReject(item)" v-show="nextStepMap[item.taskKey].backShow">回退</up-button> |
| 100 | + <up-button type="success" size="mini" @click="handleRenew(item)" v-show="nextStepMap[item.taskKey].renewShow">重新提交</up-button> | ||
| 101 | + <up-button type="primary" size="mini" @click="handleProcess(item)">{{ nextStepMap[item.taskKey].btnText }}</up-button> | ||
| 118 | <up-button type="info" size="mini" @click="handleDetail(item)">详情</up-button> | 102 | <up-button type="info" size="mini" @click="handleDetail(item)">详情</up-button> |
| 119 | </view> | 103 | </view> |
| 120 | </view> | 104 | </view> |
| @@ -123,11 +107,11 @@ | @@ -123,11 +107,11 @@ | ||
| 123 | 107 | ||
| 124 | <!-- 已办工单卡片和我发起的 --> | 108 | <!-- 已办工单卡片和我发起的 --> |
| 125 | <up-card | 109 | <up-card |
| 126 | - v-if="activeTab == 2||activeTab == 1" | 110 | + v-if="activeTab === 1 || activeTab === 2" |
| 127 | :border="false" | 111 | :border="false" |
| 128 | :foot-border-top="false" | 112 | :foot-border-top="false" |
| 129 | v-for="(item, index) in orderList" | 113 | v-for="(item, index) in orderList" |
| 130 | - :key="`done_${item.orderNo}_${index}`" | 114 | + :key="`done_${item.id}_${index}`" |
| 131 | :show-head="false" | 115 | :show-head="false" |
| 132 | class="order-card" | 116 | class="order-card" |
| 133 | > | 117 | > |
| @@ -149,12 +133,11 @@ | @@ -149,12 +133,11 @@ | ||
| 149 | <view class="u-body-item-title">情况描述:</view> | 133 | <view class="u-body-item-title">情况描述:</view> |
| 150 | <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> | 134 | <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> |
| 151 | </view> | 135 | </view> |
| 152 | - | ||
| 153 | <view class="u-body-item u-flex common-justify-between common-item-center"> | 136 | <view class="u-body-item u-flex common-justify-between common-item-center"> |
| 154 | <view class="u-body-item-title"> | 137 | <view class="u-body-item-title"> |
| 155 | 紧急程度:{{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} | 138 | 紧急程度:{{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} |
| 156 | </view> | 139 | </view> |
| 157 | - <view class=" "> | 140 | + <view> |
| 158 | <up-button type="primary" size="mini" @click="handleDetail(item)">工单详情</up-button> | 141 | <up-button type="primary" size="mini" @click="handleDetail(item)">工单详情</up-button> |
| 159 | </view> | 142 | </view> |
| 160 | </view> | 143 | </view> |
| @@ -172,21 +155,12 @@ | @@ -172,21 +155,12 @@ | ||
| 172 | </view> | 155 | </view> |
| 173 | </z-paging> | 156 | </z-paging> |
| 174 | 157 | ||
| 175 | - <!-- 底部新增工单按钮(仅巡查员显示) --> | ||
| 176 | - <!-- <view v-if="isInspector" class="fixed-bottom-btn-wrap">--> | ||
| 177 | - <!-- <up-button type="primary" size="large" @click="handleAddOrder">--> | ||
| 178 | - <!-- 新增工单--> | ||
| 179 | - <!-- </up-button>--> | ||
| 180 | - <!-- </view>--> | ||
| 181 | - | 158 | + <!-- 底部新增工单按钮 --> |
| 182 | <view class="fixed-bottom-btn-wrap" v-if="isAi"> | 159 | <view class="fixed-bottom-btn-wrap" v-if="isAi"> |
| 183 | - <up-button type="primary" size="large" @click="handleAddOrder"> | ||
| 184 | - 新增工单 | ||
| 185 | - </up-button> | 160 | + <up-button type="primary" size="large" @click="handleAddOrder">新增工单</up-button> |
| 186 | </view> | 161 | </view> |
| 187 | 162 | ||
| 188 | - | ||
| 189 | - <!-- 回退原因弹窗:替换为up-modal(核心修改) --> | 163 | + <!-- 回退原因弹窗 --> |
| 190 | <up-modal | 164 | <up-modal |
| 191 | :show="rejectModalShow" | 165 | :show="rejectModalShow" |
| 192 | title="回退原因" | 166 | title="回退原因" |
| @@ -197,7 +171,6 @@ | @@ -197,7 +171,6 @@ | ||
| 197 | @confirm="confirmReject" | 171 | @confirm="confirmReject" |
| 198 | > | 172 | > |
| 199 | <view class="reject-modal-content"> | 173 | <view class="reject-modal-content"> |
| 200 | - <!-- 回退原因 必填textarea --> | ||
| 201 | <up-textarea | 174 | <up-textarea |
| 202 | v-model.trim="rejectReason" | 175 | v-model.trim="rejectReason" |
| 203 | placeholder="请输入回退原因(必填)" | 176 | placeholder="请输入回退原因(必填)" |
| @@ -206,11 +179,10 @@ | @@ -206,11 +179,10 @@ | ||
| 206 | maxlength="200" | 179 | maxlength="200" |
| 207 | class="reject-textarea" | 180 | class="reject-textarea" |
| 208 | /> | 181 | /> |
| 209 | - <!-- 上传图片(选填)- 按照参考页面改造 --> | ||
| 210 | <view class="upload-wrap mt-20"> | 182 | <view class="upload-wrap mt-20"> |
| 211 | <view class="upload-title">上传图片(选填)</view> | 183 | <view class="upload-title">上传图片(选填)</view> |
| 212 | <up-upload | 184 | <up-upload |
| 213 | - :file-list="rejectImgs.rawImgList.value|| []" | 185 | + :file-list="rejectImgs.rawImgList.value || []" |
| 214 | @after-read="rejectImgs.uploadImgs" | 186 | @after-read="rejectImgs.uploadImgs" |
| 215 | @delete="rejectImgs.deleteImg" | 187 | @delete="rejectImgs.deleteImg" |
| 216 | multiple | 188 | multiple |
| @@ -224,7 +196,7 @@ | @@ -224,7 +196,7 @@ | ||
| 224 | </view> | 196 | </view> |
| 225 | </up-modal> | 197 | </up-modal> |
| 226 | 198 | ||
| 227 | - <!-- 验收弹窗 up-modal(含图片上传) --> | 199 | + <!-- 验收弹窗 --> |
| 228 | <up-modal | 200 | <up-modal |
| 229 | :show="acceptModalShow" | 201 | :show="acceptModalShow" |
| 230 | title="验收" | 202 | title="验收" |
| @@ -235,15 +207,12 @@ | @@ -235,15 +207,12 @@ | ||
| 235 | @confirm="handleAcceptModalConfirm" | 207 | @confirm="handleAcceptModalConfirm" |
| 236 | > | 208 | > |
| 237 | <view class="accept-modal-content"> | 209 | <view class="accept-modal-content"> |
| 238 | - <!-- 第一行:单选框(通过/不通过,默认通过) --> | ||
| 239 | <view class="radio-group-wrap"> | 210 | <view class="radio-group-wrap"> |
| 240 | <up-radio-group v-model="acceptRadioValue"> | 211 | <up-radio-group v-model="acceptRadioValue"> |
| 241 | <up-radio name="0" label="通过"></up-radio> | 212 | <up-radio name="0" label="通过"></up-radio> |
| 242 | <up-radio name="1" label="不通过"></up-radio> | 213 | <up-radio name="1" label="不通过"></up-radio> |
| 243 | </up-radio-group> | 214 | </up-radio-group> |
| 244 | </view> | 215 | </view> |
| 245 | - | ||
| 246 | - <!-- 第二行:必填textarea,最多200字 --> | ||
| 247 | <view class="textarea-wrap mt-30"> | 216 | <view class="textarea-wrap mt-30"> |
| 248 | <up-textarea | 217 | <up-textarea |
| 249 | v-model.trim="acceptReason" | 218 | v-model.trim="acceptReason" |
| @@ -254,15 +223,12 @@ | @@ -254,15 +223,12 @@ | ||
| 254 | count | 223 | count |
| 255 | /> | 224 | /> |
| 256 | </view> | 225 | </view> |
| 257 | - | ||
| 258 | - <!-- 验收图片上传(选填,参考回退弹窗样式) --> | ||
| 259 | <view class="upload-wrap mt-20"> | 226 | <view class="upload-wrap mt-20"> |
| 260 | <view class="upload-title">上传验收图片(选填)</view> | 227 | <view class="upload-title">上传验收图片(选填)</view> |
| 261 | <up-upload | 228 | <up-upload |
| 262 | :file-list="acceptImgs.rawImgList.value || []" | 229 | :file-list="acceptImgs.rawImgList.value || []" |
| 263 | @after-read="acceptImgs.uploadImgs" | 230 | @after-read="acceptImgs.uploadImgs" |
| 264 | @delete="acceptImgs.deleteImg" | 231 | @delete="acceptImgs.deleteImg" |
| 265 | - | ||
| 266 | multiple | 232 | multiple |
| 267 | width="70" | 233 | width="70" |
| 268 | height="70" | 234 | height="70" |
| @@ -284,263 +250,233 @@ import { | @@ -284,263 +250,233 @@ import { | ||
| 284 | myBuzSimplePage, | 250 | myBuzSimplePage, |
| 285 | todoBuzSimplePage, | 251 | todoBuzSimplePage, |
| 286 | doneBuzSimplePage, | 252 | doneBuzSimplePage, |
| 287 | - qyWorkorderCreate, | ||
| 288 | qyUniversalApproval, | 253 | qyUniversalApproval, |
| 289 | daquUniversalApproval, | 254 | daquUniversalApproval, |
| 290 | dcyUniversalApproval | 255 | dcyUniversalApproval |
| 291 | } from '@/api/regional-order-manage/regional-order-manage' | 256 | } from '@/api/regional-order-manage/regional-order-manage' |
| 292 | -// 从用户store获取角色信息 | ||
| 293 | import { useUserStore } from '@/pinia/user'; | 257 | import { useUserStore } from '@/pinia/user'; |
| 294 | import { nextStepMap, buzStatusMap } from '@/common/utils/common' | 258 | import { nextStepMap, buzStatusMap } from '@/common/utils/common' |
| 295 | -// 引入图片上传组合式函数(与参考页面一致) | ||
| 296 | import { useUploadImgs } from '@/common/utils/useUploadImgs' | 259 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 297 | -// ========== 状态管理 ========== | 260 | + |
| 261 | +// ========== 全局实例 & 常量 ========== | ||
| 298 | const userStore = useUserStore(); | 262 | const userStore = useUserStore(); |
| 299 | -// 标签页切换 | 263 | +const USER_ROLES = userStore.userInfo?.roles || []; |
| 264 | + | ||
| 265 | +// ========== 基础状态 (按模块分组,语义化更强) ========== | ||
| 266 | +// tab切换 | ||
| 300 | const activeTab = ref(0); // 0-待办 1-我发起的 2-已办 | 267 | const activeTab = ref(0); // 0-待办 1-我发起的 2-已办 |
| 301 | -const tabList = ref([ | ||
| 302 | - {name: '待办'}, | ||
| 303 | - {name: '我发起的任务'}, | ||
| 304 | - {name: '已办'} | ||
| 305 | -]); | ||
| 306 | -// 排序下拉框 | 268 | +const tabList = ref([{name: '待办'}, {name: '我发起的任务'}, {name: '已办'}]); |
| 269 | +// 排序与搜索 | ||
| 307 | const selectedSortValue = ref(1); | 270 | const selectedSortValue = ref(1); |
| 308 | const sortOptions = ref([ | 271 | const sortOptions = ref([ |
| 309 | - {name: '位置', id: 1}, | ||
| 310 | - {name: '名称', id: 2}, | ||
| 311 | - {name: '描述', id: 3}, | ||
| 312 | - {name: '编号', id: 4}, | 272 | + {name: '位置', id: 1}, {name: '名称', id: 2}, {name: '描述', id: 3}, {name: '编号', id: 4}, |
| 313 | ]); | 273 | ]); |
| 314 | -// 搜索 | ||
| 315 | const searchValue = ref(''); | 274 | const searchValue = ref(''); |
| 316 | -// 分页 | ||
| 317 | -const paging = ref(null); | 275 | +// 分页相关 |
| 276 | +const pagingRef = ref(null); | ||
| 318 | const orderList = ref([]); | 277 | const orderList = ref([]); |
| 319 | -// 角色控制(巡查员显示新增按钮) | 278 | + |
| 279 | +// ========== 角色权限计算属性 (修复核心bug: 原代码取反逻辑写反) ========== | ||
| 320 | const isAi = computed(() => { | 280 | const isAi = computed(() => { |
| 321 | - // patrol_global 全域巡查员 | ||
| 322 | - // regional_manager 大区经理 | ||
| 323 | - // AI_dispatcher AI工单派发人员 | ||
| 324 | - // 增加可选链,避免用户信息不存在报错 | ||
| 325 | - console.log('123') | ||
| 326 | - console.log(!userStore.userInfo?.roles?.includes('AI_dispatcher')) | ||
| 327 | - return !userStore.userInfo?.roles?.includes('AI_dispatcher') ; | ||
| 328 | - // return true | 281 | + // AI工单派发人员 不显示新增按钮,其他角色显示 |
| 282 | + return !USER_ROLES.includes('AI_dispatcher'); | ||
| 329 | }); | 283 | }); |
| 330 | -// 回退弹窗相关 | ||
| 331 | -const rejectModalShow = ref(false); // 回退modal显示开关 | ||
| 332 | -const rejectReason = ref(''); // 回退原因 | ||
| 333 | -const currentRejectItem = ref(null); // 当前回退工单 | ||
| 334 | -// 回退图片上传配置(与参考页面风格一致) | 284 | + |
| 285 | +// ========== 回退弹窗相关 ========== | ||
| 286 | +const rejectModalShow = ref(false); | ||
| 287 | +const rejectReason = ref(''); | ||
| 288 | +const currentRejectItem = ref(null); | ||
| 335 | const rejectImgs = useUploadImgs({ | 289 | const rejectImgs = useUploadImgs({ |
| 336 | - maxCount: 3, // 最多上传3张 | ||
| 337 | - uploadText: '选择回退图片', // 自定义上传提示文字 | ||
| 338 | - sizeType: ['compressed'], // 仅上传压缩图 | ||
| 339 | - formRef: null, // 该弹窗无表单校验 | ||
| 340 | - fieldName: 'rejectImgs' // 自定义字段名 | 290 | + maxCount: 3, uploadText: '选择回退图片', sizeType: ['compressed'], formRef: null, fieldName: 'rejectImgs' |
| 341 | }) | 291 | }) |
| 342 | -// ========== 验收弹窗相关状态(含图片上传) ========== | ||
| 343 | -const acceptModalShow = ref(false); // 验收弹窗显示开关 | ||
| 344 | -const acceptRadioValue = ref('0'); // 单选框值,默认0(通过) | ||
| 345 | -const acceptReason = ref(''); // 验收原因 | ||
| 346 | -const currentAcceptItem = ref(null); // 当前验收的工单项 | ||
| 347 | -// 验收图片上传配置(独立实例,参考回退弹窗) | 292 | + |
| 293 | +// ========== 验收弹窗相关 ========== | ||
| 294 | +const acceptModalShow = ref(false); | ||
| 295 | +const acceptRadioValue = ref('0'); // 默认通过 | ||
| 296 | +const acceptReason = ref(''); | ||
| 297 | +const currentAcceptItem = ref(null); | ||
| 348 | const acceptImgs = useUploadImgs({ | 298 | const acceptImgs = useUploadImgs({ |
| 349 | - maxCount: 3, // 最多上传3张,与回退弹窗一致 | ||
| 350 | - uploadText: '选择验收图片', // 自定义上传提示文字 | ||
| 351 | - sizeType: ['compressed'], // 仅上传压缩图,优化性能 | ||
| 352 | - formRef: null, // 验收弹窗无表单校验 | ||
| 353 | - fieldName: 'acceptImgs' // 自定义字段名,区分回退图片 | 299 | + maxCount: 3, uploadText: '选择验收图片', sizeType: ['compressed'], formRef: null, fieldName: 'acceptImgs' |
| 354 | }) | 300 | }) |
| 301 | + | ||
| 302 | +// ========== 公共封装方法 (核心优化:消灭重复代码) ========== | ||
| 303 | +/** | ||
| 304 | + * 生成统一的临时存储key | ||
| 305 | + * @param {String} prefix 前缀标识 | ||
| 306 | + * @returns {String} 唯一key | ||
| 307 | + */ | ||
| 308 | +const generateTempKey = (prefix = 'order') => { | ||
| 309 | + return `${prefix}_${Date.now()}_${Math.floor(Math.random() * 10000)}`; | ||
| 310 | +}; | ||
| 311 | + | ||
| 312 | +/** | ||
| 313 | + * 存储工单数据到本地缓存 | ||
| 314 | + * @param {Object} item 工单数据 | ||
| 315 | + * @param {String} prefix key前缀 | ||
| 316 | + * @returns {String|null} 成功返回key,失败返回null | ||
| 317 | + */ | ||
| 318 | +const setOrderStorage = (item, prefix) => { | ||
| 319 | + if (!item?.id) return null; | ||
| 320 | + const tempKey = generateTempKey(prefix); | ||
| 321 | + try { | ||
| 322 | + uni.setStorageSync(tempKey, item); | ||
| 323 | + return tempKey; | ||
| 324 | + } catch (error) { | ||
| 325 | + console.error('存储工单数据失败:', error); | ||
| 326 | + uni.showToast({title: '数据存储异常,请重试', icon: 'none'}); | ||
| 327 | + return null; | ||
| 328 | + } | ||
| 329 | +}; | ||
| 330 | + | ||
| 331 | +/** | ||
| 332 | + * 获取分页请求公共参数 | ||
| 333 | + * @param {Number} pageNo 页码 | ||
| 334 | + * @param {Number} pageSize 页大小 | ||
| 335 | + * @returns {Object} 请求参数 | ||
| 336 | + */ | ||
| 337 | +const getQueryParams = (pageNo, pageSize) => { | ||
| 338 | + return { | ||
| 339 | + searchContent: searchValue.value.trim() || '', | ||
| 340 | + pageNo, | ||
| 341 | + pageSize, | ||
| 342 | + type: selectedSortValue.value | ||
| 343 | + }; | ||
| 344 | +}; | ||
| 345 | + | ||
| 346 | +/** | ||
| 347 | + * 统一调用审批接口 | ||
| 348 | + * @param {Object} params 请求参数 | ||
| 349 | + * @param {String} taskKey 工单任务key | ||
| 350 | + * @returns {Promise} 接口请求Promise | ||
| 351 | + */ | ||
| 352 | +const callApprovalApi = async (params, taskKey) => { | ||
| 353 | + if (taskKey === 'shRegionManager') return await dcyUniversalApproval(params); | ||
| 354 | + if (taskKey === 'regionManager') return await qyUniversalApproval(params); | ||
| 355 | + // 根据角色匹配对应接口 | ||
| 356 | + if (USER_ROLES.includes('regional_manager')) return await daquUniversalApproval(params); | ||
| 357 | + if (USER_ROLES.includes('Inspector_global')) return await dcyUniversalApproval(params); | ||
| 358 | + if (USER_ROLES.includes('patrol_global')) return await qyUniversalApproval(params); | ||
| 359 | +}; | ||
| 360 | + | ||
| 361 | +/** | ||
| 362 | + * 统一跳转工单页面 | ||
| 363 | + * @param {String} path 页面路径 | ||
| 364 | + * @param {Object} query 拼接参数 | ||
| 365 | + */ | ||
| 366 | +const navToOrderPage = (path, query = {}) => { | ||
| 367 | + const queryStr = Object.keys(query).map(k => `${k}=${query[k]}`).join('&'); | ||
| 368 | + uni.navigateTo({ url: `${path}${queryStr ? '?' + queryStr : ''}` }); | ||
| 369 | +}; | ||
| 370 | + | ||
| 371 | +/** | ||
| 372 | + * 刷新列表 - 统一封装,避免空指针 | ||
| 373 | + */ | ||
| 374 | +const refreshOrderList = () => { | ||
| 375 | + pagingRef.value && pagingRef.value.reload(); | ||
| 376 | +}; | ||
| 377 | + | ||
| 378 | +// ========== 业务核心方法 ========== | ||
| 355 | // 分页查询列表 | 379 | // 分页查询列表 |
| 356 | const queryList = async (pageNo, pageSize) => { | 380 | const queryList = async (pageNo, pageSize) => { |
| 357 | try { | 381 | try { |
| 358 | - const apiParams = { | ||
| 359 | - searchContent: searchValue.value.trim() || '', | ||
| 360 | - pageNo, | ||
| 361 | - pageSize, | ||
| 362 | - type: selectedSortValue.value // 1-位置 2-工单名称 3-情况描述 4-工单编号 | ||
| 363 | - }; | 382 | + const params = getQueryParams(pageNo, pageSize); |
| 364 | let res; | 383 | let res; |
| 365 | - if (activeTab.value == 0) { | ||
| 366 | - // 待办工单 | ||
| 367 | - res = await todoBuzSimplePage(apiParams); | ||
| 368 | - } else if (activeTab.value == 1) { | ||
| 369 | - // 我发起的任务 | ||
| 370 | - res = await myBuzSimplePage(apiParams); | ||
| 371 | - } else { | ||
| 372 | - // 已办工单 | ||
| 373 | - res = await doneBuzSimplePage(apiParams); | ||
| 374 | - } | ||
| 375 | - // 适配z-paging分页 | ||
| 376 | - paging.value.complete(res.list, res.total); | 384 | + if (activeTab.value === 0) res = await todoBuzSimplePage(params); |
| 385 | + else if (activeTab.value === 1) res = await myBuzSimplePage(params); | ||
| 386 | + else res = await doneBuzSimplePage(params); | ||
| 387 | + pagingRef.value.complete(res?.list || [], res?.total || 0); | ||
| 377 | } catch (error) { | 388 | } catch (error) { |
| 378 | console.error('加载工单失败:', error); | 389 | console.error('加载工单失败:', error); |
| 379 | - paging.value?.complete(false); | 390 | + pagingRef.value?.complete(false); |
| 380 | uni.showToast({title: '加载失败,请重试', icon: 'none'}); | 391 | uni.showToast({title: '加载失败,请重试', icon: 'none'}); |
| 381 | } | 392 | } |
| 382 | }; | 393 | }; |
| 383 | -// ========== 事件处理 ========== | 394 | + |
| 384 | // 标签页切换 | 395 | // 标签页切换 |
| 385 | const handleTabChange = (item) => { | 396 | const handleTabChange = (item) => { |
| 386 | - orderList.value = []; | ||
| 387 | - console.log(item) | ||
| 388 | activeTab.value = item.index; | 397 | activeTab.value = item.index; |
| 389 | - paging.value?.reload(); // 切换标签页刷新列表 | 398 | + orderList.value = []; |
| 399 | + refreshOrderList(); | ||
| 390 | }; | 400 | }; |
| 401 | + | ||
| 391 | // 排序变更 | 402 | // 排序变更 |
| 392 | const handleSortChange = (val) => { | 403 | const handleSortChange = (val) => { |
| 393 | selectedSortValue.value = val.id; | 404 | selectedSortValue.value = val.id; |
| 394 | searchValue.value = ''; | 405 | searchValue.value = ''; |
| 395 | - paging.value?.reload(); // 排序变更刷新列表 | 406 | + refreshOrderList(); |
| 396 | }; | 407 | }; |
| 408 | + | ||
| 397 | // 搜索 | 409 | // 搜索 |
| 398 | const handleSearch = (val) => { | 410 | const handleSearch = (val) => { |
| 399 | searchValue.value = val; | 411 | searchValue.value = val; |
| 400 | - paging.value?.reload(); // 搜索刷新列表 | 412 | + refreshOrderList(); |
| 401 | }; | 413 | }; |
| 414 | + | ||
| 402 | // 工单详情 | 415 | // 工单详情 |
| 403 | const handleDetail = (item) => { | 416 | const handleDetail = (item) => { |
| 404 | - // 0-待办 1我发起的- 2-已办 | ||
| 405 | - uni.navigateTo({ | ||
| 406 | - url: `/pages-sub/problem/regional-order-manage/order-detail?taskId=${item.taskId}&activeTab=${activeTab.value}&processInstanceId=${item.processInstanceId}`, | ||
| 407 | - events: { | ||
| 408 | - // 自定义事件名:needRefresh(与详情页保持一致) | ||
| 409 | - needRefresh: () => { | ||
| 410 | - console.log('详情页返回,触发工单列表刷新'); | ||
| 411 | - if (paging.value) { | ||
| 412 | - paging.value.reload(); // 刷新z-paging列表 | ||
| 413 | - } | ||
| 414 | - } | ||
| 415 | - } | 417 | + if (!item?.taskId) return uni.showToast({title: '工单信息异常', icon: 'none'}); |
| 418 | + navToOrderPage('/pages-sub/problem/regional-order-manage/order-detail', { | ||
| 419 | + taskId: item.taskId, | ||
| 420 | + activeTab: activeTab.value, | ||
| 421 | + processInstanceId: item.processInstanceId | ||
| 422 | + }, { | ||
| 423 | + needRefresh: () => refreshOrderList() | ||
| 416 | }); | 424 | }); |
| 417 | }; | 425 | }; |
| 418 | -// 生成临时key | ||
| 419 | -const generateTempKey = () => { | ||
| 420 | - return 'renew_order_' + Date.now() + '_' + Math.floor(Math.random() * 10000); | ||
| 421 | -}; | ||
| 422 | -// 待办-重新提交工单(改造后:大数据存本地,仅传唯一标识) | 426 | + |
| 427 | +// 重新提交工单 | ||
| 423 | const handleRenew = (item) => { | 428 | const handleRenew = (item) => { |
| 429 | + const tempKey = setOrderStorage(item, 'renew_order'); | ||
| 430 | + if (!tempKey) return; | ||
| 424 | 431 | ||
| 425 | - // 1. 生成唯一临时标识 | ||
| 426 | - const tempKey = generateTempKey(); | ||
| 427 | - // 2. 将完整工单数据存入本地临时存储(同步存储,确保数据立即生效) | ||
| 428 | - try { | ||
| 429 | - console.log(item) | ||
| 430 | - console.log('123') | ||
| 431 | - uni.setStorageSync(tempKey, item); | ||
| 432 | - } catch (error) { | ||
| 433 | - console.error('存储工单数据失败:', error); | ||
| 434 | - uni.showToast({title: '数据存储异常,无法重新提交', icon: 'none'}); | ||
| 435 | - return; | ||
| 436 | - } | 432 | + const pageUrl = USER_ROLES.includes('patrol_global') |
| 433 | + ? '/pages-sub/problem/regional-order-manage/add-patrol-order' | ||
| 434 | + : '/pages-sub/problem/regional-order-manage/add-order'; | ||
| 437 | 435 | ||
| 438 | - if (userStore.userInfo?.roles.includes('patrol_global')) { // 全域巡查员 | ||
| 439 | - uni.navigateTo({ | ||
| 440 | - url: `/pages-sub/problem/regional-order-manage/add-patrol-order?isRenew=1&tempKey=${tempKey}` | ||
| 441 | - }); | ||
| 442 | - } | ||
| 443 | - if (userStore.userInfo?.roles.includes('regional_manager')) { // 大区经理 | ||
| 444 | - uni.navigateTo({ | ||
| 445 | - url: `/pages-sub/problem/regional-order-manage/add-order?isRenew=1&tempKey=${tempKey}` | ||
| 446 | - }); | ||
| 447 | - } | ||
| 448 | - if (userStore.userInfo?.roles.includes('Inspector_global')) { // 督察员 | ||
| 449 | - uni.navigateTo({ | ||
| 450 | - url: `/pages-sub/problem/regional-order-manage/add-order?isRenew=1&tempKey=${tempKey}` | ||
| 451 | - }); | ||
| 452 | - } | ||
| 453 | - // // 3. URL 仅传递「唯一标识」和「重新提交标记」(数据量极小,无长度问题) | ||
| 454 | - // uni.navigateTo({ | ||
| 455 | - // url: `/pages-sub/problem/regional-order-manage/add-patrol-order?isRenew=1&tempKey=${tempKey}` | ||
| 456 | - // }); | 436 | + navToOrderPage(pageUrl, { isRenew: 1, tempKey }); |
| 457 | }; | 437 | }; |
| 458 | -// 待办-处理工单 | 438 | + |
| 439 | +// 处理工单核心逻辑 | ||
| 459 | const handleProcess = async (item) => { | 440 | const handleProcess = async (item) => { |
| 460 | - console.log(nextStepMap[item.taskKey].name) | 441 | + if (!item) return uni.showToast({title: '工单信息异常', icon: 'none'}); |
| 442 | + const stepName = nextStepMap[item.taskKey]?.name; | ||
| 443 | + | ||
| 461 | try { | 444 | try { |
| 462 | - if (nextStepMap[item.taskKey]?.name == '大区经理分配') { | ||
| 463 | - // ① 生成唯一临时key(统一规则,避免冲突) | ||
| 464 | - const tempKey = `distribute_order_${Date.now()}_${Math.floor(Math.random() * 10000)}`; | ||
| 465 | - // ② 存储完整item到本地缓存(同步存储,确保立即生效) | ||
| 466 | - try { | ||
| 467 | - uni.setStorageSync(tempKey, item); | ||
| 468 | - } catch (error) { | ||
| 469 | - console.error('存储分配工单数据失败:', error); | ||
| 470 | - uni.showToast({title: '数据存储异常,无法跳转', icon: 'none'}); | ||
| 471 | - return; | ||
| 472 | - } | ||
| 473 | - // ③ URL仅传递临时key,无其他冗余参数 | ||
| 474 | - uni.navigateTo({ | ||
| 475 | - url: `/pages-sub/problem/regional-order-manage/distribution-order?tempKey=${tempKey}` | ||
| 476 | - }) | 445 | + // 大区经理分配 |
| 446 | + if (stepName === '大区经理分配') { | ||
| 447 | + const tempKey = setOrderStorage(item, 'distribute_order'); | ||
| 448 | + tempKey && navToOrderPage('/pages-sub/problem/regional-order-manage/distribution-order', { tempKey }); | ||
| 477 | } | 449 | } |
| 478 | - if (nextStepMap[item.taskKey]?.name == '督察员单子大区经理分配') { | ||
| 479 | - let postData = { | ||
| 480 | - "taskKey":item.taskKey, | ||
| 481 | - "taskId": item.taskId, | ||
| 482 | - "operateType":60, | ||
| 483 | - "workerDataId":item.id, | ||
| 484 | - "agree":0, | ||
| 485 | - "reason":item.remark, | ||
| 486 | - "roadId":item.roadId, | ||
| 487 | - "roadName":item.roadName, | ||
| 488 | - "pressingType":item.pressingType, | ||
| 489 | - "orderName":item.orderName, | ||
| 490 | - "expectedFinishDate": item.expectedFinishDate, | ||
| 491 | - "busiLine":item.busiLine, | ||
| 492 | - } | ||
| 493 | - const res = await dcyUniversalApproval(postData); | ||
| 494 | - uni.showToast({title: '分配成功', icon: 'success', duration: 1000}); | ||
| 495 | - paging.value?.reload(); // 刷新列表 | 450 | + // 督察员单子大区经理分配 |
| 451 | + else if (stepName === '督察员单子大区经理分配') { | ||
| 452 | + const postData = { taskKey: item.taskKey, taskId: item.taskId, operateType:60, workerDataId:item.id, agree:0, reason:item.remark, roadId:item.roadId, roadName:item.roadName, pressingType:item.pressingType, orderName:item.orderName, expectedFinishDate: item.expectedFinishDate, busiLine:item.busiLine }; | ||
| 453 | + await dcyUniversalApproval(postData); | ||
| 454 | + uni.showToast({title: '分配成功', icon: 'success'}); | ||
| 455 | + refreshOrderList(); | ||
| 496 | } | 456 | } |
| 497 | - | ||
| 498 | - | ||
| 499 | - // 验收 - 打开弹窗 | ||
| 500 | - if (nextStepMap[item.taskKey]?.name == '巡查员验收' || nextStepMap[item.taskKey]?.name == '养护组长验收') { | ||
| 501 | - currentAcceptItem.value = item; // 存储当前工单信息 | ||
| 502 | - acceptReason.value = ''; // 清空上次的验收原因 | ||
| 503 | - acceptRadioValue.value = '0'; // 重置默认选中“通过” | ||
| 504 | - acceptModalShow.value = true; // 显示验收弹窗 | 457 | + // 验收弹窗 |
| 458 | + else if (['巡查员验收', '养护组长验收'].includes(stepName)) { | ||
| 459 | + currentAcceptItem.value = item; | ||
| 460 | + acceptReason.value = ''; | ||
| 461 | + acceptRadioValue.value = '0'; | ||
| 462 | + acceptModalShow.value = true; | ||
| 505 | } | 463 | } |
| 506 | - | ||
| 507 | - // 发起人确认 | ||
| 508 | - if (nextStepMap[item.taskKey]?.name == '发起人确认') { | ||
| 509 | - console.log(item) | 464 | + // 发起人确认-结束工单 |
| 465 | + else if (stepName === '发起人确认') { | ||
| 510 | uni.showModal({ | 466 | uni.showModal({ |
| 511 | title: "结束工单", | 467 | title: "结束工单", |
| 512 | content: "请确定是否结束工单?", | 468 | content: "请确定是否结束工单?", |
| 513 | - success: async function (res) { | 469 | + success: async (res) => { |
| 514 | if (res.confirm) { | 470 | if (res.confirm) { |
| 515 | - // 构建请求参数 | ||
| 516 | const requestData = { | 471 | const requestData = { |
| 517 | - | ||
| 518 | - "workerDataId": item.id, | ||
| 519 | - "taskKey": 'ylInspectorStart', | ||
| 520 | - "taskId": item.taskId, | ||
| 521 | - "operateType": 200, | ||
| 522 | - "agree": 1, | ||
| 523 | - "reason": '结束工单' | 472 | + workerDataId: item.id, taskKey: 'ylInspectorStart', taskId: item.taskId, |
| 473 | + operateType: 200, agree: 1, reason: '结束工单' | ||
| 524 | }; | 474 | }; |
| 525 | - // 调用回退工单接口 daquUniversalApproval | ||
| 526 | - | ||
| 527 | - if( userStore.userInfo.roles.includes('regional_manager')){ // 大区经理 | ||
| 528 | - await daquUniversalApproval(requestData) | ||
| 529 | - } | ||
| 530 | - if( userStore.userInfo.roles.includes('Inspector_global')){ // 督察员 | ||
| 531 | - await dcyUniversalApproval(requestData); | ||
| 532 | - } | ||
| 533 | - if( userStore.userInfo.roles.includes('patrol_global')){ // 全域巡查员 | ||
| 534 | - await qyUniversalApproval(requestData); | ||
| 535 | - } | ||
| 536 | - | ||
| 537 | - uni.showToast({title: '结束成功', icon: 'success', duration: 1000}); | ||
| 538 | - rejectModalShow.value = false; | ||
| 539 | - paging.value?.reload(); // 刷新列表 | ||
| 540 | - } else if (res.cancel) { | ||
| 541 | - console.log("用户点击取消"); | 475 | + await callApprovalApi(requestData, item.taskKey); |
| 476 | + uni.showToast({title: '结束成功', icon: 'success'}); | ||
| 477 | + refreshOrderList(); | ||
| 542 | } | 478 | } |
| 543 | - }, | 479 | + } |
| 544 | }); | 480 | }); |
| 545 | } | 481 | } |
| 546 | } catch (error) { | 482 | } catch (error) { |
| @@ -548,168 +484,92 @@ const handleProcess = async (item) => { | @@ -548,168 +484,92 @@ const handleProcess = async (item) => { | ||
| 548 | uni.showToast({title: '处理失败,请重试', icon: 'none'}); | 484 | uni.showToast({title: '处理失败,请重试', icon: 'none'}); |
| 549 | } | 485 | } |
| 550 | }; | 486 | }; |
| 551 | -// 待办-回退工单(打开回退modal) | 487 | + |
| 488 | +// 回退工单-打开弹窗 | ||
| 552 | const handleReject = (item) => { | 489 | const handleReject = (item) => { |
| 553 | - console.log('123213') | ||
| 554 | - // 校验工单有效性 | ||
| 555 | - if (!item || !item.id) { | ||
| 556 | - uni.showToast({title: '工单信息异常,无法回退', icon: 'none'}); | ||
| 557 | - return; | ||
| 558 | - } | 490 | + if (!item?.id) return uni.showToast({title: '工单信息异常,无法回退', icon: 'none'}); |
| 559 | currentRejectItem.value = item; | 491 | currentRejectItem.value = item; |
| 560 | - rejectReason.value = ''; // 清空上次输入 | ||
| 561 | - rejectImgs.clearImgs(); // 改造后:使用组合式函数的清空方法 | ||
| 562 | - rejectModalShow.value = true; // 显示回退modal | 492 | + rejectReason.value = ''; |
| 493 | + rejectImgs.clearImgs(); | ||
| 494 | + rejectModalShow.value = true; | ||
| 563 | }; | 495 | }; |
| 564 | -// 回退modal - 取消按钮 | 496 | + |
| 497 | +// 关闭回退弹窗-重置状态 | ||
| 565 | const handleRejectModalCancel = () => { | 498 | const handleRejectModalCancel = () => { |
| 566 | rejectModalShow.value = false; | 499 | rejectModalShow.value = false; |
| 567 | rejectReason.value = ''; | 500 | rejectReason.value = ''; |
| 568 | - rejectImgs.clearImgs(); // 改造后:使用组合式函数的清空方法 | 501 | + rejectImgs.clearImgs(); |
| 569 | }; | 502 | }; |
| 503 | + | ||
| 570 | // 确认回退工单 | 504 | // 确认回退工单 |
| 571 | const confirmReject = async () => { | 505 | const confirmReject = async () => { |
| 572 | - // 严格校验回退原因(去除首尾空格) | ||
| 573 | - const rejectReasonTrim = rejectReason.value.trim(); | ||
| 574 | - if (!rejectReasonTrim) { | ||
| 575 | - uni.showToast({title: '请填写回退原因', icon: 'none', duration: 1000}); | ||
| 576 | - return; | ||
| 577 | - } | ||
| 578 | - // 校验当前工单有效性 | ||
| 579 | - if (!currentRejectItem.value || !currentRejectItem.value.id) { | ||
| 580 | - uni.showToast({title: '工单信息异常,无法提交', icon: 'none', duration: 1000}); | ||
| 581 | - rejectModalShow.value = false; | ||
| 582 | - return; | ||
| 583 | - } | 506 | + const reason = rejectReason.value.trim(); |
| 507 | + if (!reason) return uni.showToast({title: '请填写回退原因', icon: 'none'}); | ||
| 508 | + const item = currentRejectItem.value; | ||
| 509 | + if (!item?.id) return uni.showToast({title: '工单信息异常', icon: 'none'}); | ||
| 510 | + | ||
| 511 | + uni.showLoading({title: '提交中...', mask: true}); | ||
| 584 | try { | 512 | try { |
| 585 | - // 显示加载中,防止重复提交 | ||
| 586 | - uni.showLoading({title: '提交中...', mask: true}); | ||
| 587 | - // 构建请求参数 | ||
| 588 | const requestData = { | 513 | const requestData = { |
| 589 | - "returnImgs": rejectImgs.getSuccessImgUrls(), // 改造后:获取上传成功的图片URL数组 | ||
| 590 | - "workerDataId": currentRejectItem.value.id, | ||
| 591 | - "taskKey": currentRejectItem.value.taskKey, | ||
| 592 | - "taskId": currentRejectItem.value.taskId, | ||
| 593 | - | ||
| 594 | - "operateType": nextStepMap[currentRejectItem.value.taskKey].operateTypeNoPass, | ||
| 595 | - "agree": 1, | ||
| 596 | - "reason": rejectReasonTrim | 514 | + returnImgs: rejectImgs.getSuccessImgUrls(), workerDataId: item.id, taskKey: item.taskKey, |
| 515 | + taskId: item.taskId, operateType: nextStepMap[item.taskKey].operateTypeNoPass, agree:1, reason | ||
| 597 | }; | 516 | }; |
| 598 | - // 调用回退工单接口 | ||
| 599 | - if(currentRejectItem.value.taskKey=='shRegionManager'){ // 对督察员单子 回退 | ||
| 600 | - const res = await dcyUniversalApproval(requestData); | ||
| 601 | - } | ||
| 602 | - if(currentRejectItem.value.taskKey=='regionManager'){ // 对全域巡查员单子 回退 | ||
| 603 | - const res = await qyUniversalApproval(requestData); | ||
| 604 | - } | ||
| 605 | - // 对大区经理单子 回退 | ||
| 606 | - uni.showToast({title: '回退成功', icon: 'success', duration: 1000}); | ||
| 607 | - rejectModalShow.value = false; | ||
| 608 | - paging.value?.reload(); // 刷新列表 | 517 | + await callApprovalApi(requestData, item.taskKey); |
| 518 | + uni.showToast({title: '回退成功', icon: 'success'}); | ||
| 519 | + handleRejectModalCancel(); | ||
| 520 | + refreshOrderList(); | ||
| 609 | } catch (error) { | 521 | } catch (error) { |
| 610 | console.error('回退工单失败:', error); | 522 | console.error('回退工单失败:', error); |
| 611 | - uni.showToast({title: '网络异常,回退失败', icon: 'none', duration: 1000}); | 523 | + uni.showToast({title: '回退失败,请重试', icon: 'none'}); |
| 612 | } finally { | 524 | } finally { |
| 613 | - // 隐藏加载中 | ||
| 614 | uni.hideLoading(); | 525 | uni.hideLoading(); |
| 615 | } | 526 | } |
| 616 | }; | 527 | }; |
| 528 | + | ||
| 617 | // 新增工单 | 529 | // 新增工单 |
| 618 | const handleAddOrder = () => { | 530 | const handleAddOrder = () => { |
| 619 | - if (userStore.userInfo?.roles.includes('patrol_global')) { // 全域巡查员 | ||
| 620 | - uni.navigateTo({ | ||
| 621 | - url: '/pages-sub/problem/regional-order-manage/add-patrol-order' | ||
| 622 | - }); | ||
| 623 | - } | ||
| 624 | - if (userStore.userInfo?.roles.includes('regional_manager')) { // 大区经理 | ||
| 625 | - uni.navigateTo({ | ||
| 626 | - url: '/pages-sub/problem/regional-order-manage/add-order' | ||
| 627 | - }); | ||
| 628 | - } | ||
| 629 | - if (userStore.userInfo?.roles.includes('Inspector_global')) { // 督察员 | ||
| 630 | - uni.navigateTo({ | ||
| 631 | - url: '/pages-sub/problem/regional-order-manage/add-order' | ||
| 632 | - }); | ||
| 633 | - } | 531 | + const pageUrl = USER_ROLES.includes('patrol_global') |
| 532 | + ? '/pages-sub/problem/regional-order-manage/add-patrol-order' | ||
| 533 | + : '/pages-sub/problem/regional-order-manage/add-order'; | ||
| 534 | + navToOrderPage(pageUrl); | ||
| 634 | }; | 535 | }; |
| 635 | -// 验收弹窗 - 取消按钮(清空状态) | 536 | + |
| 537 | +// 关闭验收弹窗-重置状态 | ||
| 636 | const handleAcceptModalCancel = () => { | 538 | const handleAcceptModalCancel = () => { |
| 637 | acceptModalShow.value = false; | 539 | acceptModalShow.value = false; |
| 638 | - acceptReason.value = ''; // 清空验收原因 | ||
| 639 | - acceptRadioValue.value = '0'; // 重置单选框为“通过” | ||
| 640 | - acceptImgs.clearImgs(); // 清空验收图片 | 540 | + acceptReason.value = ''; |
| 541 | + acceptRadioValue.value = '0'; | ||
| 542 | + acceptImgs.clearImgs(); | ||
| 641 | }; | 543 | }; |
| 642 | -// 验收弹窗 - 确定按钮(含returnImgs传参) | 544 | + |
| 545 | +// 验收提交 | ||
| 643 | const handleAcceptModalConfirm = async () => { | 546 | const handleAcceptModalConfirm = async () => { |
| 644 | - // 1. 校验验收原因是否为空 | ||
| 645 | - if (!acceptReason.value.trim()) { | ||
| 646 | - uni.showToast({title: '请填写验收原因', icon: 'none', duration: 1000}); | ||
| 647 | - return; | ||
| 648 | - } | ||
| 649 | - // 2. 校验验收原因长度 | ||
| 650 | - if (acceptReason.value.length > 200) { | ||
| 651 | - uni.showToast({title: '验收原因最多200字', icon: 'none', duration: 1000}); | ||
| 652 | - return; | ||
| 653 | - } | ||
| 654 | - try { | ||
| 655 | - // 3. 构建请求参数(含returnImgs) | ||
| 656 | - console.log(currentAcceptItem.value) | ||
| 657 | - console.log( userStore.userInfo.roles) | ||
| 658 | - console.log( userStore.userInfo.roles.includes('Inspector_global')) | ||
| 659 | - // | ||
| 660 | - if( userStore.userInfo.roles.includes('regional_manager')){ // 大区经理验收 | ||
| 661 | - let postData = { | ||
| 662 | - "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | ||
| 663 | - "taskKey": currentAcceptItem.value.taskKey, | ||
| 664 | - "workerDataId": currentAcceptItem.value.id, | ||
| 665 | - "taskId": currentAcceptItem.value.taskId, | ||
| 666 | - "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | ||
| 667 | - "reason": acceptReason.value.trim(), | ||
| 668 | - "agree":acceptRadioValue.value, | ||
| 669 | - } | ||
| 670 | - await daquUniversalApproval(postData); | ||
| 671 | - } | ||
| 672 | - // | ||
| 673 | - if( userStore.userInfo.roles.includes('patrol_global')){ // 全域巡查员验收 | ||
| 674 | - let postData = { | ||
| 675 | - "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | ||
| 676 | - "taskKey": currentAcceptItem.value.taskKey, | ||
| 677 | - "taskId": currentAcceptItem.value.taskId, | ||
| 678 | - "workerDataId": currentAcceptItem.value.id, | ||
| 679 | - "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | ||
| 680 | - "reason": acceptReason.value.trim(), | ||
| 681 | - "agree": acceptRadioValue.value | ||
| 682 | - } | ||
| 683 | - await qyUniversalApproval(postData); | ||
| 684 | - } | ||
| 685 | - // | ||
| 686 | - if( userStore.userInfo.roles.includes('Inspector_global')){ // 督察员验收 | ||
| 687 | - let postData = { | ||
| 688 | - "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | ||
| 689 | - "taskKey": currentAcceptItem.value.taskKey, | ||
| 690 | - "taskId": currentAcceptItem.value.taskId, | ||
| 691 | - "workerDataId": currentAcceptItem.value.id, | ||
| 692 | - "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | ||
| 693 | - "reason": acceptReason.value.trim(), | ||
| 694 | - "agree": acceptRadioValue.value | ||
| 695 | - } | ||
| 696 | - await dcyUniversalApproval(postData); | ||
| 697 | - } | 547 | + const reason = acceptReason.value.trim(); |
| 548 | + if (!reason) return uni.showToast({title: '请填写验收原因', icon: 'none'}); | ||
| 549 | + if (reason.length > 200) return uni.showToast({title: '验收原因最多200字', icon: 'none'}); | ||
| 698 | 550 | ||
| 699 | - // 4. 操作成功处理 | ||
| 700 | - uni.showToast({title: '提交成功', icon: 'success', duration: 1000}); | ||
| 701 | - handleAcceptModalCancel(); // 清空状态 | ||
| 702 | - paging.value?.reload(); // 刷新工单列表 | 551 | + const item = currentAcceptItem.value; |
| 552 | + if (!item?.id) return uni.showToast({title: '工单信息异常', icon: 'none'}); | ||
| 553 | + | ||
| 554 | + try { | ||
| 555 | + const postData = { | ||
| 556 | + returnImgs: acceptImgs.getSuccessImgUrls(), taskKey: item.taskKey, workerDataId: item.id, | ||
| 557 | + taskId: item.taskId, agree: acceptRadioValue.value, reason, | ||
| 558 | + operateType: acceptRadioValue.value === '0' ? nextStepMap[item.taskKey].operateTypePass : nextStepMap[item.taskKey].operateTypeNoPass | ||
| 559 | + }; | ||
| 560 | + await callApprovalApi(postData, item.taskKey); | ||
| 561 | + uni.showToast({title: '提交成功', icon: 'success'}); | ||
| 562 | + handleAcceptModalCancel(); | ||
| 563 | + refreshOrderList(); | ||
| 703 | } catch (error) { | 564 | } catch (error) { |
| 704 | - // 5. 操作失败处理 | ||
| 705 | console.error('验收失败:', error); | 565 | console.error('验收失败:', error); |
| 706 | - uni.showToast({title: '验收提交失败,请重试', icon: 'none', duration: 1000}); | 566 | + uni.showToast({title: '验收提交失败,请重试', icon: 'none'}); |
| 707 | } | 567 | } |
| 708 | }; | 568 | }; |
| 709 | -// 页面初始化 | 569 | + |
| 570 | +// ========== 页面生命周期 ========== | ||
| 710 | onLoad(() => { | 571 | onLoad(() => { |
| 711 | - // 初始化加载列表 | ||
| 712 | - paging.value?.reload(); | 572 | + refreshOrderList(); |
| 713 | }); | 573 | }); |
| 714 | </script> | 574 | </script> |
| 715 | 575 | ||
| @@ -734,15 +594,10 @@ onLoad(() => { | @@ -734,15 +594,10 @@ onLoad(() => { | ||
| 734 | .select-wrap { | 594 | .select-wrap { |
| 735 | width: 120rpx; | 595 | width: 120rpx; |
| 736 | margin-right: 20rpx; | 596 | margin-right: 20rpx; |
| 737 | - | ||
| 738 | - :deep(.u-select) { | 597 | + :deep(.u-select), :deep(.u-input__placeholder) { |
| 739 | width: 100%; | 598 | width: 100%; |
| 740 | font-size: 28rpx; | 599 | font-size: 28rpx; |
| 741 | } | 600 | } |
| 742 | - | ||
| 743 | - :deep(.u-input__placeholder) { | ||
| 744 | - font-size: 28rpx; | ||
| 745 | - } | ||
| 746 | } | 601 | } |
| 747 | 602 | ||
| 748 | .search-input-wrap { | 603 | .search-input-wrap { |
| @@ -758,31 +613,14 @@ onLoad(() => { | @@ -758,31 +613,14 @@ onLoad(() => { | ||
| 758 | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); | 613 | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); |
| 759 | } | 614 | } |
| 760 | 615 | ||
| 761 | -.card-body { | ||
| 762 | - | ||
| 763 | -} | ||
| 764 | - | ||
| 765 | -// 回退modal样式 | ||
| 766 | -.reject-modal-content { | 616 | +// 弹窗公共样式 |
| 617 | +.reject-modal-content, .accept-modal-content { | ||
| 767 | width: 100%; | 618 | width: 100%; |
| 768 | box-sizing: border-box; | 619 | box-sizing: border-box; |
| 769 | padding: 10rpx 0; | 620 | padding: 10rpx 0; |
| 770 | } | 621 | } |
| 771 | 622 | ||
| 772 | -.textarea-label { | ||
| 773 | - font-size: 28rpx; | ||
| 774 | - color: #333; | ||
| 775 | - margin-bottom: 10rpx; | ||
| 776 | - | ||
| 777 | - .required-mark { | ||
| 778 | - color: #f56c6c; | ||
| 779 | - margin-left: 4rpx; | ||
| 780 | - } | ||
| 781 | -} | ||
| 782 | - | ||
| 783 | .upload-wrap { | 623 | .upload-wrap { |
| 784 | - margin-top: 20rpx; | ||
| 785 | - | ||
| 786 | .upload-title { | 624 | .upload-title { |
| 787 | font-size: 28rpx; | 625 | font-size: 28rpx; |
| 788 | color: #333; | 626 | color: #333; |
| @@ -790,37 +628,20 @@ onLoad(() => { | @@ -790,37 +628,20 @@ onLoad(() => { | ||
| 790 | } | 628 | } |
| 791 | } | 629 | } |
| 792 | 630 | ||
| 793 | -.mt-20 { | ||
| 794 | - margin-top: 20rpx; | ||
| 795 | -} | ||
| 796 | - | ||
| 797 | -.mt-30 { | ||
| 798 | - margin-top: 30rpx; | ||
| 799 | -} | ||
| 800 | - | ||
| 801 | -// 养护组长验收弹窗样式 | ||
| 802 | -.accept-modal-content { | ||
| 803 | - width: 100%; | ||
| 804 | - box-sizing: border-box; | ||
| 805 | -} | ||
| 806 | - | 631 | +// 验收弹窗单选框样式 |
| 807 | .radio-group-wrap { | 632 | .radio-group-wrap { |
| 808 | display: flex; | 633 | display: flex; |
| 809 | align-items: center; | 634 | align-items: center; |
| 810 | - gap: 40rpx; // 单选框之间的间距 | 635 | + gap: 40rpx; |
| 811 | font-size: 28rpx; | 636 | font-size: 28rpx; |
| 812 | margin-bottom: 20rpx; | 637 | margin-bottom: 20rpx; |
| 813 | } | 638 | } |
| 814 | 639 | ||
| 815 | .textarea-wrap { | 640 | .textarea-wrap { |
| 816 | width: 100%; | 641 | width: 100%; |
| 817 | - margin-top: 30rpx; | ||
| 818 | } | 642 | } |
| 819 | 643 | ||
| 820 | -.modal-btn-wrap { | ||
| 821 | - display: flex; | ||
| 822 | - align-items: center; | ||
| 823 | - justify-content: flex-end; | ||
| 824 | - padding-right: 10rpx; | ||
| 825 | -} | 644 | +// 间距公共样式 |
| 645 | +.mt-20 { margin-top: 20rpx; } | ||
| 646 | +.mt-30 { margin-top: 30rpx; } | ||
| 826 | </style> | 647 | </style> |
| 827 | \ No newline at end of file | 648 | \ No newline at end of file |
pages-sub/problem/regional-order-manage/add-order.vue
| @@ -63,7 +63,7 @@ | @@ -63,7 +63,7 @@ | ||
| 63 | <!-- 4. 问题照片 --> | 63 | <!-- 4. 问题照片 --> |
| 64 | <up-form-item label="问题照片" prop="problemImgs" required> | 64 | <up-form-item label="问题照片" prop="problemImgs" required> |
| 65 | <up-upload | 65 | <up-upload |
| 66 | - :file-list="problemImgs.imgList.value||[]" | 66 | + :file-list="problemImgs.imgList.value || []" |
| 67 | @after-read="problemImgs.uploadImgs" | 67 | @after-read="problemImgs.uploadImgs" |
| 68 | @delete="problemImgs.deleteImg" | 68 | @delete="problemImgs.deleteImg" |
| 69 | multiple | 69 | multiple |
| @@ -75,11 +75,9 @@ | @@ -75,11 +75,9 @@ | ||
| 75 | ></up-upload> | 75 | ></up-upload> |
| 76 | </up-form-item> | 76 | </up-form-item> |
| 77 | 77 | ||
| 78 | - <!-- 派单情况分组(放在问题照片下方,增加间距) --> | ||
| 79 | -<!-- <up-gap height="20" bgColor="#bbb"></up-gap>--> | 78 | + <!-- 派单情况分组 --> |
| 80 | <view class="dispatch-group"> | 79 | <view class="dispatch-group"> |
| 81 | <view class="dispatch-title">派单情况</view> | 80 | <view class="dispatch-title">派单情况</view> |
| 82 | - | ||
| 83 | <!-- 业务线单选框 --> | 81 | <!-- 业务线单选框 --> |
| 84 | <up-form-item | 82 | <up-form-item |
| 85 | label="业务线" | 83 | label="业务线" |
| @@ -117,7 +115,7 @@ | @@ -117,7 +115,7 @@ | ||
| 117 | border="none" | 115 | border="none" |
| 118 | ></up-input> | 116 | ></up-input> |
| 119 | <template #right> | 117 | <template #right> |
| 120 | - <up-icon name="arrow-right" size="16" ></up-icon> | 118 | + <up-icon name="arrow-right" size="16"></up-icon> |
| 121 | </template> | 119 | </template> |
| 122 | </up-form-item> | 120 | </up-form-item> |
| 123 | 121 | ||
| @@ -156,11 +154,7 @@ | @@ -156,11 +154,7 @@ | ||
| 156 | ></up-input> | 154 | ></up-input> |
| 157 | <template #right> | 155 | <template #right> |
| 158 | <view v-if="workOrderForm.expectedFinishDate" @click.stop> | 156 | <view v-if="workOrderForm.expectedFinishDate" @click.stop> |
| 159 | - <up-icon | ||
| 160 | - name="close" | ||
| 161 | - size="16" | ||
| 162 | - @click.stop="clearExpectedFinishDate" | ||
| 163 | - ></up-icon> | 157 | + <up-icon name="close" size="16" @click.stop="clearExpectedFinishDate"></up-icon> |
| 164 | </view> | 158 | </view> |
| 165 | <up-icon name="arrow-right" size="16" v-else></up-icon> | 159 | <up-icon name="arrow-right" size="16" v-else></up-icon> |
| 166 | </template> | 160 | </template> |
| @@ -170,11 +164,7 @@ | @@ -170,11 +164,7 @@ | ||
| 170 | 164 | ||
| 171 | <!-- 底部提交按钮 --> | 165 | <!-- 底部提交按钮 --> |
| 172 | <view class="fixed-bottom-btn-wrap"> | 166 | <view class="fixed-bottom-btn-wrap"> |
| 173 | - <up-button | ||
| 174 | - type="primary" | ||
| 175 | - text="提交工单" | ||
| 176 | - @click="submitWorkOrder" | ||
| 177 | - ></up-button> | 167 | + <up-button type="primary" text="提交工单" @click="submitWorkOrder"></up-button> |
| 178 | </view> | 168 | </view> |
| 179 | 169 | ||
| 180 | <!-- 合并后的通用下拉弹窗 --> | 170 | <!-- 合并后的通用下拉弹窗 --> |
| @@ -199,116 +189,73 @@ | @@ -199,116 +189,73 @@ | ||
| 199 | </template> | 189 | </template> |
| 200 | 190 | ||
| 201 | <script setup> | 191 | <script setup> |
| 202 | -import { ref, reactive } from 'vue' | ||
| 203 | -import { onReady, onShow, onLoad } from '@dcloudio/uni-app'; | 192 | +import { ref, reactive, nextTick } from 'vue' |
| 193 | +import { onReady, onShow, onLoad, onBackPress } from '@dcloudio/uni-app'; | ||
| 204 | import { useUploadImgs } from '@/common/utils/useUploadImgs' | 194 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 205 | import { getRoadListByLatLng } from '@/api/common' | 195 | import { getRoadListByLatLng } from '@/api/common' |
| 206 | -import { daquUniversalApproval, qyUniversalApproval,qyWorkorderCreate, | ||
| 207 | - dcyUniversalApproval, daquWorkorderCreate, | ||
| 208 | - dcyWorkorderCreate } from '@/api/regional-order-manage/regional-order-manage' | 196 | +import { |
| 197 | + daquUniversalApproval, qyUniversalApproval, qyWorkorderCreate, | ||
| 198 | + dcyUniversalApproval, daquWorkorderCreate, dcyWorkorderCreate | ||
| 199 | +} from '@/api/regional-order-manage/regional-order-manage' | ||
| 209 | import { timeFormat } from '@/uni_modules/uview-plus' | 200 | import { timeFormat } from '@/uni_modules/uview-plus' |
| 210 | import { nextStepMap } from '@/common/utils/common' | 201 | import { nextStepMap } from '@/common/utils/common' |
| 211 | import { useUserStore } from '@/pinia/user'; | 202 | import { useUserStore } from '@/pinia/user'; |
| 212 | 203 | ||
| 213 | -// ========== 状态管理 ========== | ||
| 214 | -const userStore = useUserStore(); | 204 | +// ========== 【常量配置区】- 硬编码集中管理,便于维护 ========== |
| 205 | +const CONST = { | ||
| 206 | + // 字典编码 | ||
| 207 | + DICT_ORDER_NAME: 'work_name', | ||
| 208 | + DICT_PRESSING_TYPE: 'workorder_pressing_type', | ||
| 209 | + // 上传配置 | ||
| 210 | + UPLOAD_CONFIG: { maxCount: 3, uploadText: '选择问题照片', sizeType: ['compressed'] }, | ||
| 211 | + // 路由地址 | ||
| 212 | + PAGE_ORDER_LIST: '/pages-sub/problem/regional-order-manage/index', | ||
| 213 | + // 业务线映射 | ||
| 214 | + BUSI_LINE_MAP: { yl: '园林', sz: '市政', wy: '物业', '园林': 'yl', '市政': 'sz', '物业': 'wy' }, | ||
| 215 | + // 角色标识 | ||
| 216 | + ROLE: { MANAGER: 'regional_manager', INSPECTOR: 'Inspector_global', PATROL: 'patrol_global' } | ||
| 217 | +} | ||
| 215 | 218 | ||
| 216 | -// ========== 业务线相关状态 ========== | ||
| 217 | -// 业务线映射表 | ||
| 218 | -const busiLineMap = ref({ | ||
| 219 | - 'yl': '园林', | ||
| 220 | - 'sz': '市政', | ||
| 221 | - 'wy': '物业', | ||
| 222 | - '园林': 'yl', | ||
| 223 | - '市政': 'sz', | ||
| 224 | - '物业': 'wy' | ||
| 225 | -}); | 219 | +// ========== 【全局实例 & 基础状态】 ========== |
| 220 | +const userStore = useUserStore(); | ||
| 221 | +const USER_ROLES = userStore.userInfo?.roles || []; | ||
| 222 | +const workOrderFormRef = ref(null); | ||
| 223 | +const showActionSheet = ref(false); | ||
| 224 | +const show = ref(false); | ||
| 225 | +const expectedFinishDate = ref(Date.now()); | ||
| 226 | +const isRenew = ref(false); | ||
| 227 | +const renewOrderData = ref(null); | ||
| 226 | 228 | ||
| 227 | -// 业务线选项列表 | 229 | +// ========== 【下拉弹窗数据】 ========== |
| 230 | +const currentActionSheetData = reactive({ type: '', list: [], title: '' }); | ||
| 231 | +const roadNameList = ref([]); | ||
| 232 | +const orderNameList = ref([]); | ||
| 233 | +const pressingTypeList = ref([]); | ||
| 228 | const busiLineOptions = ref([]); | 234 | const busiLineOptions = ref([]); |
| 229 | -const formatBusiLineOptions = () => { | ||
| 230 | - if (!userStore.userInfo?.user?.busiLine) { | ||
| 231 | - busiLineOptions.value = []; | ||
| 232 | - return; | ||
| 233 | - } | ||
| 234 | - const rawBusiLines = userStore.userInfo.user.busiLine.split(','); | ||
| 235 | - busiLineOptions.value = rawBusiLines.map(item => ({ | ||
| 236 | - name: busiLineMap.value[item.trim()] | ||
| 237 | - })); | ||
| 238 | -}; | ||
| 239 | - | ||
| 240 | -// 工具方法:通过中文名称获取对应的英文标识 | ||
| 241 | -const getBusiLineEnByCn = (cnName) => { | ||
| 242 | - return busiLineMap.value[cnName] || ''; | ||
| 243 | -}; | ||
| 244 | 235 | ||
| 245 | -// ========== 表单Ref ========== | ||
| 246 | -const workOrderFormRef = ref(null) | ||
| 247 | - | ||
| 248 | -// ========== 公共上传逻辑复用 ========== | 236 | +// ========== 【上传逻辑复用】 ========== |
| 249 | const problemImgs = useUploadImgs({ | 237 | const problemImgs = useUploadImgs({ |
| 250 | - maxCount: 3, | ||
| 251 | - uploadText: '选择问题照片', | ||
| 252 | - sizeType: ['compressed'], | 238 | + ...CONST.UPLOAD_CONFIG, |
| 253 | formRef: workOrderFormRef, | 239 | formRef: workOrderFormRef, |
| 254 | fieldName: 'problemImgs' | 240 | fieldName: 'problemImgs' |
| 255 | }) | 241 | }) |
| 242 | +// 图片数组兜底,防止非数组报错 | ||
| 243 | +if (!Array.isArray(problemImgs.rawImgList.value)) problemImgs.rawImgList.value = []; | ||
| 256 | 244 | ||
| 257 | -if (!Array.isArray(problemImgs.rawImgList.value)) { | ||
| 258 | - problemImgs.rawImgList.value = []; | ||
| 259 | -} | ||
| 260 | - | ||
| 261 | -// ========== 页面状态 ========== | ||
| 262 | -const showActionSheet = ref(false) | ||
| 263 | -const currentActionSheetData = reactive({ | ||
| 264 | - type: '', | ||
| 265 | - list: [], | ||
| 266 | - title: '' | ||
| 267 | -}) | ||
| 268 | -const show = ref(false) | ||
| 269 | -const expectedFinishDate = ref(Date.now()) | ||
| 270 | - | ||
| 271 | -// ========== 重新提交相关状态 ========== | ||
| 272 | -const isRenew = ref(false); | ||
| 273 | -const renewOrderData = ref(null); | ||
| 274 | - | ||
| 275 | -// ========== 下拉列表数据 ========== | ||
| 276 | -const roadNameList = ref([]) | ||
| 277 | -const orderNameList = ref([]) | ||
| 278 | -const pressingTypeList = ref([]) | ||
| 279 | - | ||
| 280 | -// ========== 工单表单数据 ========== | 245 | +// ========== 【工单表单数据】 ========== |
| 281 | const workOrderForm = reactive({ | 246 | const workOrderForm = reactive({ |
| 282 | - busiLineCn: '', | ||
| 283 | - roadId: 0, | ||
| 284 | - roadName: '', | ||
| 285 | - workLocation: '', | ||
| 286 | - orderName: '', | ||
| 287 | - pressingType: '', | ||
| 288 | - pressingTypeName: '', | ||
| 289 | - problemDesc: '', | ||
| 290 | - lat: 0, | ||
| 291 | - lon: 0, | ||
| 292 | - expectedFinishDate: '', | 247 | + busiLineCn: '', roadId: 0, roadName: '', workLocation: '', |
| 248 | + orderName: '', pressingType: '', pressingTypeName: '', | ||
| 249 | + problemDesc: '', lat: 0, lon: 0, expectedFinishDate: '' | ||
| 293 | }) | 250 | }) |
| 294 | 251 | ||
| 295 | -// ========== 表单校验规则 ========== | 252 | +// ========== 【表单校验规则】 ========== |
| 296 | const workOrderFormRules = reactive({ | 253 | const workOrderFormRules = reactive({ |
| 297 | - busiLineCn: [ | ||
| 298 | - { type: 'string', required: true, message: '请选择业务线', trigger: ['change', 'blur'] } | ||
| 299 | - ], | ||
| 300 | - workLocation: [ | ||
| 301 | - { type: 'string', required: true, message: '请选择工单位置', trigger: ['change', 'blur'] } | ||
| 302 | - ], | ||
| 303 | - roadName: [ | ||
| 304 | - { type: 'string', required: true, message: '请选择道路名称', trigger: ['change', 'blur'] } | ||
| 305 | - ], | ||
| 306 | - orderName: [ | ||
| 307 | - { type: 'string', required: true, message: '请选择工单名称', trigger: ['change', 'blur'] } | ||
| 308 | - ], | ||
| 309 | - pressingTypeName: [ | ||
| 310 | - { type: 'string', required: true, message: '请选择紧急程度', trigger: ['change'] } | ||
| 311 | - ], | 254 | + busiLineCn: [{ type: 'string', required: true, message: '请选择业务线', trigger: ['change', 'blur'] }], |
| 255 | + workLocation: [{ type: 'string', required: true, message: '请选择工单位置', trigger: ['change', 'blur'] }], | ||
| 256 | + roadName: [{ type: 'string', required: true, message: '请选择道路名称', trigger: ['change', 'blur'] }], | ||
| 257 | + orderName: [{ type: 'string', required: true, message: '请选择工单名称', trigger: ['change', 'blur'] }], | ||
| 258 | + pressingTypeName: [{ type: 'string', required: true, message: '请选择紧急程度', trigger: ['change'] }], | ||
| 312 | problemDesc: [ | 259 | problemDesc: [ |
| 313 | { type: 'string', required: true, message: '请输入情况描述', trigger: ['change', 'blur'] }, | 260 | { type: 'string', required: true, message: '请输入情况描述', trigger: ['change', 'blur'] }, |
| 314 | { type: 'string', min: 3, max: 200, message: '情况描述需3-200字', trigger: ['change', 'blur'] } | 261 | { type: 'string', min: 3, max: 200, message: '情况描述需3-200字', trigger: ['change', 'blur'] } |
| @@ -316,268 +263,251 @@ const workOrderFormRules = reactive({ | @@ -316,268 +263,251 @@ const workOrderFormRules = reactive({ | ||
| 316 | problemImgs: [problemImgs.imgValidateRule] | 263 | problemImgs: [problemImgs.imgValidateRule] |
| 317 | }) | 264 | }) |
| 318 | 265 | ||
| 319 | -// ========== 生命周期 ========== | 266 | +// ========== 【工具方法封装】- 抽离通用逻辑,消灭重复代码 ========== |
| 267 | +/** | ||
| 268 | + * 业务线中文转英文 | ||
| 269 | + */ | ||
| 270 | +const busiLineCnToEn = (cn) => CONST.BUSI_LINE_MAP[cn] || ''; | ||
| 271 | +/** | ||
| 272 | + * 业务线英文转中文 | ||
| 273 | + */ | ||
| 274 | +const busiLineEnToCn = (en) => CONST.BUSI_LINE_MAP[en] || ''; | ||
| 275 | +/** | ||
| 276 | + * 统一跳转返回工单列表页 | ||
| 277 | + */ | ||
| 278 | +const toOrderListPage = () => uni.reLaunch({ url: CONST.PAGE_ORDER_LIST }); | ||
| 279 | +/** | ||
| 280 | + * 格式化时间戳 - 增加空值兜底 | ||
| 281 | + */ | ||
| 282 | +const formatDate = (dateVal, fmt = 'yyyy-mm-dd hh:MM:ss') => dateVal ? timeFormat(dateVal, fmt) : ''; | ||
| 283 | +/** | ||
| 284 | + * 时间转时间戳 - 增加空值兜底 | ||
| 285 | + */ | ||
| 286 | +const dateToTimestamp = (dateStr) => dateStr ? new Date(dateStr).getTime() : ''; | ||
| 287 | + | ||
| 288 | +// ========== 【生命周期】 ========== | ||
| 320 | onLoad((options) => { | 289 | onLoad((options) => { |
| 321 | - // 初始化业务线选项 | ||
| 322 | - formatBusiLineOptions(); | 290 | + // 初始化工单线选项 |
| 291 | + initBusiLineOptions(); | ||
| 323 | // 默认选中第一个业务线 | 292 | // 默认选中第一个业务线 |
| 324 | - if (busiLineOptions.value.length > 0) { | ||
| 325 | - workOrderForm.busiLineCn = busiLineOptions.value[0].name; | ||
| 326 | - } | ||
| 327 | - | ||
| 328 | - // 判断是否为重新提交状态 | ||
| 329 | - if (options.isRenew == 1 && options.tempKey) { | ||
| 330 | - isRenew.value = true; | ||
| 331 | - const tempKey = options.tempKey; | ||
| 332 | - | ||
| 333 | - try { | ||
| 334 | - const orderData = uni.getStorageSync(tempKey); | ||
| 335 | - console.log(orderData) | ||
| 336 | - if (orderData && typeof orderData === 'object') { | ||
| 337 | - renewOrderData.value = orderData; | ||
| 338 | - echoOrderData(renewOrderData.value); | ||
| 339 | - } else { | ||
| 340 | - uni.showToast({ title: '工单数据不存在,无法重新提交', icon: 'none' }); | ||
| 341 | - setTimeout(() => uni.navigateBack(), 1000); | ||
| 342 | - return; | ||
| 343 | - } | ||
| 344 | - } catch (error) { | ||
| 345 | - console.error('读取工单数据失败:', error); | ||
| 346 | - uni.showToast({ title: '数据读取异常,无法重新提交', icon: 'none' }); | ||
| 347 | - setTimeout(() => uni.navigateBack(), 1000); | ||
| 348 | - return; | ||
| 349 | - } finally { | ||
| 350 | - uni.removeStorageSync(tempKey); | ||
| 351 | - } | ||
| 352 | - } | 293 | + workOrderForm.busiLineCn = busiLineOptions.value[0]?.name || ''; |
| 294 | + // 处理重新提交逻辑 | ||
| 295 | + if (options.isRenew == 1 && options.tempKey) handleRenewOptions(options.tempKey); | ||
| 353 | }); | 296 | }); |
| 354 | 297 | ||
| 355 | onReady(() => { | 298 | onReady(() => { |
| 356 | - if (workOrderFormRef.value) { | ||
| 357 | - workOrderFormRef.value.setRules(workOrderFormRules) | ||
| 358 | - } | ||
| 359 | - console.log('工单表单规则初始化完成') | ||
| 360 | -}) | 299 | + // 修复bug:nextTick确保表单ref一定挂载完成,再设置规则 |
| 300 | + nextTick(() => { | ||
| 301 | + workOrderFormRef.value?.setRules(workOrderFormRules); | ||
| 302 | + }); | ||
| 303 | +}); | ||
| 361 | 304 | ||
| 362 | onShow(() => { | 305 | onShow(() => { |
| 363 | - // 初始化工单名称列表 | ||
| 364 | - orderNameList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('work_name')) | ||
| 365 | - // 初始化紧急程度列表 | ||
| 366 | - pressingTypeList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('workorder_pressing_type')) | ||
| 367 | -}) | 306 | + // 初始化下拉字典数据 |
| 307 | + orderNameList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList(CONST.DICT_ORDER_NAME)); | ||
| 308 | + pressingTypeList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList(CONST.DICT_PRESSING_TYPE)); | ||
| 309 | +}); | ||
| 368 | 310 | ||
| 369 | -// ========== 核心方法 ========== | ||
| 370 | -const echoOrderData = (orderItem) => { | ||
| 371 | - // 回显业务线 | ||
| 372 | - if (orderItem.busiLine) { | ||
| 373 | - workOrderForm.busiLineCn = busiLineMap.value[orderItem.busiLine]; | 311 | +// ========== 【核心业务方法】 ========== |
| 312 | +/** | ||
| 313 | + * 初始化工单线选项 | ||
| 314 | + */ | ||
| 315 | +const initBusiLineOptions = () => { | ||
| 316 | + const rawBusiLines = userStore.userInfo?.user?.busiLine?.split(',') || []; | ||
| 317 | + busiLineOptions.value = rawBusiLines.map(item => ({ name: busiLineEnToCn(item.trim()) })); | ||
| 318 | +}; | ||
| 319 | + | ||
| 320 | +/** | ||
| 321 | + * 处理重新提交的参数和数据回显 | ||
| 322 | + */ | ||
| 323 | +const handleRenewOptions = async (tempKey) => { | ||
| 324 | + isRenew.value = true; | ||
| 325 | + try { | ||
| 326 | + const orderData = uni.getStorageSync(tempKey); | ||
| 327 | + if (orderData && typeof orderData === 'object') { | ||
| 328 | + renewOrderData.value = orderData; | ||
| 329 | + echoOrderData(orderData); | ||
| 330 | + } else { | ||
| 331 | + uni.showToast({ title: '工单数据不存在,无法重新提交', icon: 'none' }); | ||
| 332 | + setTimeout(toOrderListPage, 1000); | ||
| 333 | + } | ||
| 334 | + } catch (error) { | ||
| 335 | + console.error('读取工单数据失败:', error); | ||
| 336 | + uni.showToast({ title: '数据读取异常,无法重新提交', icon: 'none' }); | ||
| 337 | + setTimeout(toOrderListPage, 1000); | ||
| 338 | + } finally { | ||
| 339 | + uni.removeStorageSync(tempKey); | ||
| 374 | } | 340 | } |
| 341 | +}; | ||
| 375 | 342 | ||
| 376 | - // 回显基础字段 | 343 | +/** |
| 344 | + * 工单数据回显 | ||
| 345 | + */ | ||
| 346 | +const echoOrderData = (orderItem) => { | ||
| 347 | + // 基础字段回显 | ||
| 348 | + console.log(orderItem) | ||
| 349 | + console.log('123') | ||
| 350 | + workOrderForm.busiLineCn = busiLineEnToCn(orderItem.busiLine); | ||
| 377 | workOrderForm.roadId = orderItem.roadId || 0; | 351 | workOrderForm.roadId = orderItem.roadId || 0; |
| 378 | workOrderForm.roadName = orderItem.roadName || ''; | 352 | workOrderForm.roadName = orderItem.roadName || ''; |
| 379 | workOrderForm.workLocation = orderItem.lonLatAddress || orderItem.roadName || ''; | 353 | workOrderForm.workLocation = orderItem.lonLatAddress || orderItem.roadName || ''; |
| 380 | workOrderForm.orderName = orderItem.orderName || ''; | 354 | workOrderForm.orderName = orderItem.orderName || ''; |
| 381 | workOrderForm.pressingType = orderItem.pressingType || ''; | 355 | workOrderForm.pressingType = orderItem.pressingType || ''; |
| 382 | - workOrderForm.pressingTypeName = uni.$dict.getDictLabel('workorder_pressing_type', orderItem.pressingType) || ''; | 356 | + workOrderForm.pressingTypeName = uni.$dict.getDictLabel(CONST.DICT_PRESSING_TYPE, orderItem.pressingType) || ''; |
| 383 | workOrderForm.problemDesc = orderItem.remark || ''; | 357 | workOrderForm.problemDesc = orderItem.remark || ''; |
| 384 | workOrderForm.lat = orderItem.lat || 0; | 358 | workOrderForm.lat = orderItem.lat || 0; |
| 385 | workOrderForm.lon = orderItem.lon || 0; | 359 | workOrderForm.lon = orderItem.lon || 0; |
| 386 | - workOrderForm.expectedFinishDate = timeFormat(orderItem.expectedFinishDate, 'yyyy-mm-dd hh:MM:ss') || ''; | ||
| 387 | - | ||
| 388 | - // 回显图片 | ||
| 389 | - if (orderItem.problemsImgs && Array.isArray(orderItem.problemsImgs) && orderItem.problemsImgs.length > 0) { | ||
| 390 | - const imgList = orderItem.problemsImgs.map((imgUrl, index) => ({ | ||
| 391 | - url: imgUrl, | ||
| 392 | - name: `renew_img_${index}`, | ||
| 393 | - status: 'success' | ||
| 394 | - })); | 360 | + workOrderForm.expectedFinishDate = orderItem.expectedFinishDate?"":formatDate(orderItem.expectedFinishDate); |
| 361 | + | ||
| 362 | + // 图片回显 - 兼容异常格式 | ||
| 363 | + if (Array.isArray(orderItem.problemsImgs) && orderItem.problemsImgs.length) { | ||
| 364 | + const imgList = orderItem.problemsImgs.map((url, idx) => ({ url, name: `renew_img_${idx}`, status: 'success' })); | ||
| 395 | problemImgs.imgList.value = imgList; | 365 | problemImgs.imgList.value = imgList; |
| 396 | problemImgs.rawImgList.value = imgList; | 366 | problemImgs.rawImgList.value = imgList; |
| 397 | } | 367 | } |
| 398 | 368 | ||
| 399 | // 自动获取道路列表 | 369 | // 自动获取道路列表 |
| 400 | - if (orderItem.lat && orderItem.lon) { | ||
| 401 | - getRoadListByBusiLine(); | ||
| 402 | - } | 370 | + if (orderItem.lat && orderItem.lon) getRoadListByBusiLine(); |
| 403 | }; | 371 | }; |
| 404 | 372 | ||
| 405 | -// 业务线切换事件 | 373 | +/** |
| 374 | + * 业务线切换事件 | ||
| 375 | + */ | ||
| 406 | const handleBusiLineChange = () => { | 376 | const handleBusiLineChange = () => { |
| 407 | workOrderForm.roadName = ''; | 377 | workOrderForm.roadName = ''; |
| 408 | workOrderForm.roadId = 0; | 378 | workOrderForm.roadId = 0; |
| 409 | roadNameList.value = []; | 379 | roadNameList.value = []; |
| 410 | - if (workOrderForm.workLocation) { | ||
| 411 | - getRoadListByBusiLine(); | ||
| 412 | - } | 380 | + workOrderForm.workLocation && getRoadListByBusiLine(); |
| 413 | }; | 381 | }; |
| 414 | 382 | ||
| 415 | -// 获取道路列表(带业务线) | 383 | +/** |
| 384 | + * 根据坐标+业务线获取道路列表 | ||
| 385 | + */ | ||
| 416 | const getRoadListByBusiLine = async () => { | 386 | const getRoadListByBusiLine = async () => { |
| 417 | - if (!workOrderForm.lat || !workOrderForm.lon) { | ||
| 418 | - return; | ||
| 419 | - } | ||
| 420 | - const busiLineEn = getBusiLineEnByCn(workOrderForm.busiLineCn); | ||
| 421 | - if (!busiLineEn) { | ||
| 422 | - uni.showToast({ title: '业务线标识异常', icon: 'none' }); | ||
| 423 | - return; | ||
| 424 | - } | 387 | + if (!workOrderForm.lat || !workOrderForm.lon) return; |
| 388 | + const busiLineEn = busiLineCnToEn(workOrderForm.busiLineCn); | ||
| 389 | + if (!busiLineEn) return uni.showToast({ title: '业务线选择异常', icon: 'none' }); | ||
| 425 | 390 | ||
| 426 | try { | 391 | try { |
| 427 | uni.showLoading({ title: '获取道路名称中...' }); | 392 | uni.showLoading({ title: '获取道路名称中...' }); |
| 428 | - const roadRes = await getRoadListByLatLng({ | ||
| 429 | - busiLine: busiLineEn, | ||
| 430 | - latitude: workOrderForm.lat, | ||
| 431 | - longitude: workOrderForm.lon | ||
| 432 | - }); | ||
| 433 | - uni.hideLoading(); | ||
| 434 | - if (Array.isArray(roadRes)) { | ||
| 435 | - roadNameList.value = roadRes.map((item) => ({ | ||
| 436 | - name: item.roadName || '', | ||
| 437 | - code: item.roadCode || '', | ||
| 438 | - id: item.roadId || 0 | ||
| 439 | - })); | ||
| 440 | - } else { | ||
| 441 | - roadNameList.value = [{ name: '未查询到道路名称', code: '', id: 0 }]; | ||
| 442 | - uni.showToast({ title: '未查询到该位置的道路信息', icon: 'none' }); | ||
| 443 | - } | 393 | + const roadRes = await getRoadListByLatLng({ busiLine: busiLineEn, latitude: workOrderForm.lat, longitude: workOrderForm.lon }); |
| 394 | + console.log(roadRes) | ||
| 395 | + roadNameList.value = Array.isArray(roadRes) | ||
| 396 | + ? roadRes.map(item => ({ name: item.roadName || '', code: item.roadCode || '', id: item.roadId || 0 })) | ||
| 397 | + : [{ name: '未查询到道路名称', code: '', id: 0 }]; | ||
| 398 | + console.log(roadNameList) | ||
| 399 | + !Array.isArray(roadRes) && uni.showToast({ title: '未查询到该位置的道路信息', icon: 'none' }); | ||
| 444 | } catch (err) { | 400 | } catch (err) { |
| 445 | - uni.hideLoading(); | ||
| 446 | console.error('获取道路名称失败:', err); | 401 | console.error('获取道路名称失败:', err); |
| 447 | - uni.showToast({ title: '获取道路名称失败,请重试', icon: 'none' }); | ||
| 448 | roadNameList.value = [{ name: '获取失败,请重新选择位置', code: '', id: 0 }]; | 402 | roadNameList.value = [{ name: '获取失败,请重新选择位置', code: '', id: 0 }]; |
| 403 | + uni.showToast({ title: '获取道路名称失败,请重试', icon: 'none' }); | ||
| 404 | + } finally { | ||
| 405 | + uni.hideLoading(); | ||
| 449 | } | 406 | } |
| 450 | }; | 407 | }; |
| 451 | 408 | ||
| 452 | -// ========== 通用弹窗方法 ========== | 409 | +// ========== 【通用下拉弹窗方法】 ========== |
| 453 | const handleActionSheetOpen = (type) => { | 410 | const handleActionSheetOpen = (type) => { |
| 454 | if (type === 'roadName' && !workOrderForm.workLocation) { | 411 | if (type === 'roadName' && !workOrderForm.workLocation) { |
| 455 | - uni.showToast({ title: '请先选择工单位置', icon: 'none' }) | ||
| 456 | - return | 412 | + return uni.showToast({ title: '请先选择工单位置', icon: 'none' }); |
| 457 | } | 413 | } |
| 458 | - | ||
| 459 | const configMap = { | 414 | const configMap = { |
| 460 | - roadName: { | ||
| 461 | - title: '请选择道路名称', | ||
| 462 | - list: roadNameList.value | ||
| 463 | - }, | ||
| 464 | - orderName: { | ||
| 465 | - title: '请选择工单名称', | ||
| 466 | - list: orderNameList.value | ||
| 467 | - }, | ||
| 468 | - pressingType: { | ||
| 469 | - title: '请选择紧急程度', | ||
| 470 | - list: pressingTypeList.value | ||
| 471 | - } | ||
| 472 | - } | ||
| 473 | - | ||
| 474 | - currentActionSheetData.type = type | ||
| 475 | - currentActionSheetData.title = configMap[type].title | ||
| 476 | - currentActionSheetData.list = configMap[type].list | ||
| 477 | - showActionSheet.value = true | ||
| 478 | -} | 415 | + roadName: { title: '请选择道路名称', list: roadNameList.value }, |
| 416 | + orderName: { title: '请选择工单名称', list: orderNameList.value }, | ||
| 417 | + pressingType: { title: '请选择紧急程度', list: pressingTypeList.value } | ||
| 418 | + }; | ||
| 419 | + Object.assign(currentActionSheetData, configMap[type], { type }); | ||
| 420 | + showActionSheet.value = true; | ||
| 421 | +}; | ||
| 479 | 422 | ||
| 480 | const handleActionSheetClose = () => { | 423 | const handleActionSheetClose = () => { |
| 481 | - showActionSheet.value = false | ||
| 482 | - currentActionSheetData.type = '' | ||
| 483 | - currentActionSheetData.list = [] | ||
| 484 | - currentActionSheetData.title = '' | ||
| 485 | -} | 424 | + showActionSheet.value = false; |
| 425 | + Object.assign(currentActionSheetData, { type: '', list: [], title: '' }); | ||
| 426 | +}; | ||
| 486 | 427 | ||
| 487 | const handleActionSheetSelect = (e) => { | 428 | const handleActionSheetSelect = (e) => { |
| 488 | - const { type } = currentActionSheetData | 429 | + const { type } = currentActionSheetData; |
| 489 | switch (type) { | 430 | switch (type) { |
| 490 | case 'roadName': | 431 | case 'roadName': |
| 491 | - workOrderForm.roadName = e.name | ||
| 492 | - workOrderForm.roadId = e.code | ||
| 493 | - workOrderFormRef.value?.validateField('roadName') | ||
| 494 | - break | 432 | + workOrderForm.roadName = e.name; |
| 433 | + workOrderForm.roadId = e.code; | ||
| 434 | + break; | ||
| 495 | case 'orderName': | 435 | case 'orderName': |
| 496 | - workOrderForm.orderName = e.name | ||
| 497 | - workOrderFormRef.value?.validateField('orderName') | ||
| 498 | - break | 436 | + workOrderForm.orderName = e.name; |
| 437 | + break; | ||
| 499 | case 'pressingType': | 438 | case 'pressingType': |
| 500 | - workOrderForm.pressingType = e.value | ||
| 501 | - workOrderForm.pressingTypeName = e.name | ||
| 502 | - workOrderFormRef.value?.validateField('pressingTypeName') | ||
| 503 | - break | 439 | + workOrderForm.pressingType = e.value; |
| 440 | + workOrderForm.pressingTypeName = e.name; | ||
| 441 | + break; | ||
| 504 | } | 442 | } |
| 505 | - showActionSheet.value = false | ||
| 506 | -} | ||
| 507 | - | ||
| 508 | -const navigateBack = () => { | ||
| 509 | - uni.reLaunch({ | ||
| 510 | - url: '/pages-sub/problem/work-order-manage/index', | ||
| 511 | - fail: () => { | ||
| 512 | - uni.navigateBack({ delta: 2 }); | ||
| 513 | - } | ||
| 514 | - }); | ||
| 515 | -} | 443 | + workOrderFormRef.value?.validateField(type === 'roadName' ? 'roadName' : type === 'orderName' ? 'orderName' : 'pressingTypeName'); |
| 444 | + handleActionSheetClose(); | ||
| 445 | +}; | ||
| 516 | 446 | ||
| 517 | -// 清除希望完成时间 | ||
| 518 | -const clearExpectedFinishDate = ()=> { | ||
| 519 | - workOrderForm.expectedFinishDate = '' | ||
| 520 | -} | 447 | +// ========== 【页面交互方法】 ========== |
| 448 | +/** 清除希望完成时间 */ | ||
| 449 | +const clearExpectedFinishDate = () => workOrderForm.expectedFinishDate = ''; | ||
| 450 | +/** 隐藏软键盘 */ | ||
| 451 | +const hideKeyboard = () => uni.hideKeyboard(); | ||
| 452 | +/** 时间选择确认 */ | ||
| 453 | +const expectedFinishDateConfirm = (e) => { | ||
| 454 | + workOrderForm.expectedFinishDate = formatDate(e.value); | ||
| 455 | + show.value = false; | ||
| 456 | +}; | ||
| 521 | 457 | ||
| 522 | -// 选择工单位置 | 458 | +/** 选择工单位置 */ |
| 523 | const chooseWorkLocation = () => { | 459 | const chooseWorkLocation = () => { |
| 524 | uni.chooseLocation({ | 460 | uni.chooseLocation({ |
| 525 | success: async (res) => { | 461 | success: async (res) => { |
| 526 | - workOrderForm.roadName = '' | ||
| 527 | - workOrderForm.roadId = 0 | ||
| 528 | - roadNameList.value = [] | ||
| 529 | - | ||
| 530 | - workOrderForm.workLocation = res.name | ||
| 531 | - workOrderForm.lat = res.latitude | ||
| 532 | - workOrderForm.lon = res.longitude | ||
| 533 | - | ||
| 534 | - workOrderFormRef.value?.validateField('workLocation') | ||
| 535 | - workOrderFormRef.value?.validateField('roadName') | ||
| 536 | - | 462 | + workOrderForm.roadName = ''; |
| 463 | + workOrderForm.roadId = 0; | ||
| 464 | + roadNameList.value = []; | ||
| 465 | + workOrderForm.workLocation = res.name; | ||
| 466 | + workOrderForm.lat = res.latitude; | ||
| 467 | + workOrderForm.lon = res.longitude; | ||
| 468 | + workOrderFormRef.value?.validateField(['workLocation', 'roadName']); | ||
| 537 | await getRoadListByBusiLine(); | 469 | await getRoadListByBusiLine(); |
| 538 | }, | 470 | }, |
| 539 | fail: (err) => { | 471 | fail: (err) => { |
| 540 | - console.error('选择位置失败:', err) | ||
| 541 | - uni.showToast({ title: '选择位置失败:' + err.errMsg, icon: 'none' }) | 472 | + console.error('选择位置失败:', err); |
| 473 | + const errMsg = err.errMsg.includes('auth deny') ? '请开启位置权限后重试' : '选择位置失败,请重试'; | ||
| 474 | + uni.showToast({ title: errMsg, icon: 'none' }); | ||
| 542 | } | 475 | } |
| 543 | }) | 476 | }) |
| 544 | -} | ||
| 545 | - | ||
| 546 | -// 完成时间确认 | ||
| 547 | -const expectedFinishDateConfirm = (e) => { | ||
| 548 | - workOrderForm.expectedFinishDate = timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss') | ||
| 549 | - show.value = false | ||
| 550 | -} | 477 | +}; |
| 478 | +// 新增页返回直接回列表页 | ||
| 479 | +onBackPress(() => { | ||
| 480 | + uni.redirectTo({ | ||
| 481 | + url: '/pages-sub/problem/regional-order-manage/index' | ||
| 482 | + }) | ||
| 483 | + return true; | ||
| 484 | +}) | ||
| 551 | 485 | ||
| 552 | -// 隐藏键盘 | ||
| 553 | -const hideKeyboard = () => { | ||
| 554 | - uni.hideKeyboard() | ||
| 555 | -} | 486 | +// ========== 【封装:统一接口调用方法】 ========== |
| 487 | +const callApiByRole = async (params, isRenewFlag) => { | ||
| 488 | + if (isRenewFlag) { | ||
| 489 | + if (USER_ROLES.includes(CONST.ROLE.MANAGER)) return await daquUniversalApproval(params); | ||
| 490 | + if (USER_ROLES.includes(CONST.ROLE.INSPECTOR)) return await dcyUniversalApproval(params); | ||
| 491 | + if (USER_ROLES.includes(CONST.ROLE.PATROL)) return await qyUniversalApproval(params); | ||
| 492 | + } else { | ||
| 493 | + if (USER_ROLES.includes(CONST.ROLE.MANAGER)) return await daquWorkorderCreate(params); | ||
| 494 | + if (USER_ROLES.includes(CONST.ROLE.INSPECTOR)) return await dcyWorkorderCreate(params); | ||
| 495 | + if (USER_ROLES.includes(CONST.ROLE.PATROL)) return await qyWorkorderCreate(params); | ||
| 496 | + } | ||
| 497 | +}; | ||
| 556 | 498 | ||
| 557 | -// 提交工单 | 499 | +// ========== 【核心:提交工单】 ========== |
| 558 | const submitWorkOrder = async () => { | 500 | const submitWorkOrder = async () => { |
| 559 | try { | 501 | try { |
| 560 | - await workOrderFormRef.value.validate() | ||
| 561 | - | ||
| 562 | - const busiLineEn = getBusiLineEnByCn(workOrderForm.busiLineCn); | ||
| 563 | - if (!busiLineEn) { | ||
| 564 | - uni.showToast({ title: '业务线选择异常,请重新选择', icon: 'none' }); | ||
| 565 | - return; | ||
| 566 | - } | ||
| 567 | - | ||
| 568 | - const commonSubmitData = { | ||
| 569 | - // roadId: workOrderForm.roadId, | ||
| 570 | - // roadName: workOrderForm.roadName, | ||
| 571 | - | ||
| 572 | - // roadId: 550, | ||
| 573 | - // roadName:'东明胡同(三海)', | ||
| 574 | - | ||
| 575 | - roadId: 551, | ||
| 576 | - roadName:'地安门西大街51号', | ||
| 577 | - // | ||
| 578 | - // roadId: 553, | ||
| 579 | - // roadName:'什刹海前海南沿', | ||
| 580 | - | 502 | + // 表单校验 |
| 503 | + await workOrderFormRef.value.validate(); | ||
| 504 | + const busiLineEn = busiLineCnToEn(workOrderForm.busiLineCn); | ||
| 505 | + if (!busiLineEn) return uni.showToast({ title: '业务线选择异常,请重新选择', icon: 'none' }); | ||
| 506 | + | ||
| 507 | + // 组装公共提交参数 | ||
| 508 | + const baseParams = { | ||
| 509 | + roadId: workOrderForm.roadId, | ||
| 510 | + roadName: workOrderForm.roadName, | ||
| 581 | problemsImgs: problemImgs.getSuccessImgUrls(), | 511 | problemsImgs: problemImgs.getSuccessImgUrls(), |
| 582 | remark: workOrderForm.problemDesc.trim(), | 512 | remark: workOrderForm.problemDesc.trim(), |
| 583 | latLonType: 2, | 513 | latLonType: 2, |
| @@ -586,77 +516,37 @@ const submitWorkOrder = async () => { | @@ -586,77 +516,37 @@ const submitWorkOrder = async () => { | ||
| 586 | lonLatAddress: workOrderForm.workLocation, | 516 | lonLatAddress: workOrderForm.workLocation, |
| 587 | pressingType: workOrderForm.pressingType, | 517 | pressingType: workOrderForm.pressingType, |
| 588 | orderName: workOrderForm.orderName, | 518 | orderName: workOrderForm.orderName, |
| 589 | - expectedFinishDate: workOrderForm.expectedFinishDate==""?"":new Date(workOrderForm.expectedFinishDate).getTime(), | 519 | + expectedFinishDate: dateToTimestamp(workOrderForm.expectedFinishDate), |
| 590 | sourceId: 1, | 520 | sourceId: 1, |
| 591 | sourceName: workOrderForm.busiLineCn, | 521 | sourceName: workOrderForm.busiLineCn, |
| 592 | busiLine: busiLineEn | 522 | busiLine: busiLineEn |
| 593 | - } | ||
| 594 | - | ||
| 595 | - uni.showLoading({ title: '提交中...' }) | ||
| 596 | - let res | ||
| 597 | - | ||
| 598 | - if (isRenew.value) { | ||
| 599 | - const renewSubmitData = { | ||
| 600 | - workerDataId: renewOrderData.value.id, | ||
| 601 | - taskKey: renewOrderData.value.taskKey, | ||
| 602 | - taskId: renewOrderData.value.taskId, | ||
| 603 | - operateType: nextStepMap[renewOrderData.value.taskKey]?.operateTypeRenew || '', | ||
| 604 | - agree: 0, | ||
| 605 | - reason: workOrderForm.problemDesc.trim(), | ||
| 606 | - ...commonSubmitData | ||
| 607 | - } | ||
| 608 | - | ||
| 609 | - if( userStore.userInfo.roles.includes('regional_manager')){ // 大区经理 | ||
| 610 | - res = await daquUniversalApproval(renewSubmitData) | ||
| 611 | - } | ||
| 612 | - | ||
| 613 | - if( userStore.userInfo.roles.includes('Inspector_global')){ // 督察员 | ||
| 614 | - res = await dcyUniversalApproval(renewSubmitData) | ||
| 615 | - } | ||
| 616 | - | ||
| 617 | - if( userStore.userInfo.roles.includes('patrol_global')){ // 全域巡查员 | ||
| 618 | - res = await qyUniversalApproval(renewSubmitData) | ||
| 619 | - } | ||
| 620 | - | ||
| 621 | - } else { | ||
| 622 | - | ||
| 623 | - if( userStore.userInfo.roles.includes('regional_manager')){ // 大区经理 | ||
| 624 | - res = await daquWorkorderCreate(commonSubmitData) | ||
| 625 | - } | ||
| 626 | - | ||
| 627 | - if( userStore.userInfo.roles.includes('Inspector_global')){ // 督察员 | ||
| 628 | - res = await dcyWorkorderCreate(commonSubmitData) | ||
| 629 | - } | ||
| 630 | - | ||
| 631 | - if( userStore.userInfo.roles.includes('patrol_global')){ // 全域巡查员 | ||
| 632 | - res = await qyWorkorderCreate(commonSubmitData) | ||
| 633 | - } | ||
| 634 | - | ||
| 635 | - | ||
| 636 | - } | ||
| 637 | - | ||
| 638 | - uni.hideLoading() | ||
| 639 | - uni.showToast({ | ||
| 640 | - title: isRenew.value ? '重新提交成功' : '工单提交成功', | ||
| 641 | - icon: 'success', | ||
| 642 | - duration: 1000 | ||
| 643 | - }) | ||
| 644 | - | ||
| 645 | - setTimeout(() => { | ||
| 646 | - uni.reLaunch({ | ||
| 647 | - url: '/pages-sub/problem/regional-order-manage/index' | ||
| 648 | - }) | ||
| 649 | - }, 1000) | 523 | + }; |
| 524 | + | ||
| 525 | + uni.showLoading({ title: '提交中...', mask: true }); | ||
| 526 | + // 区分:重新提交 / 新增工单 | ||
| 527 | + const submitParams = isRenew.value | ||
| 528 | + ? { | ||
| 529 | + workerDataId: renewOrderData.value.id, | ||
| 530 | + taskKey: renewOrderData.value.taskKey, | ||
| 531 | + taskId: renewOrderData.value.taskId, | ||
| 532 | + operateType: nextStepMap[renewOrderData.value.taskKey]?.operateTypeRenew || '', | ||
| 533 | + agree: 0, | ||
| 534 | + reason: workOrderForm.problemDesc.trim(), | ||
| 535 | + ...baseParams | ||
| 536 | + } | ||
| 537 | + : baseParams; | ||
| 538 | + | ||
| 539 | + // 统一调用接口 | ||
| 540 | + await callApiByRole(submitParams, isRenew.value); | ||
| 541 | + | ||
| 542 | + // 提交成功处理 | ||
| 543 | + uni.showToast({ title: isRenew.value ? '重新提交成功' : '工单提交成功', icon: 'success', duration: 1000 }); | ||
| 544 | + setTimeout(toOrderListPage, 1000); | ||
| 650 | } catch (error) { | 545 | } catch (error) { |
| 651 | - uni.hideLoading() | ||
| 652 | - | 546 | + uni.hideLoading(); |
| 653 | if (!Array.isArray(error)) { | 547 | if (!Array.isArray(error)) { |
| 654 | - console.error(isRenew.value ? '工单重新提交失败:' : '工单提交失败:', error) | ||
| 655 | - uni.showToast({ | ||
| 656 | - title: isRenew.value ? error.msg : error.msg, | ||
| 657 | - icon: 'none', | ||
| 658 | - duration: 2000 | ||
| 659 | - }) | 548 | + console.error(isRenew.value ? '工单重新提交失败:' : '工单提交失败:', error); |
| 549 | + uni.showToast({ title: error.msg || '提交失败,请重试', icon: 'none', duration: 2000 }); | ||
| 660 | } | 550 | } |
| 661 | } | 551 | } |
| 662 | } | 552 | } |
| @@ -667,6 +557,7 @@ const submitWorkOrder = async () => { | @@ -667,6 +557,7 @@ const submitWorkOrder = async () => { | ||
| 667 | .page-container { | 557 | .page-container { |
| 668 | min-height: 100vh; | 558 | min-height: 100vh; |
| 669 | padding-bottom: 100rpx; // 给底部按钮留空间 | 559 | padding-bottom: 100rpx; // 给底部按钮留空间 |
| 560 | + background: #fafafa; | ||
| 670 | } | 561 | } |
| 671 | 562 | ||
| 672 | // 工单表单内容容器 | 563 | // 工单表单内容容器 |
| @@ -674,19 +565,18 @@ const submitWorkOrder = async () => { | @@ -674,19 +565,18 @@ const submitWorkOrder = async () => { | ||
| 674 | background: #fff; | 565 | background: #fff; |
| 675 | } | 566 | } |
| 676 | 567 | ||
| 677 | -// 派单情况分组样式(核心:增加顶部间距) | 568 | +// 派单情况分组样式 |
| 678 | .dispatch-group { | 569 | .dispatch-group { |
| 679 | - | ||
| 680 | - padding-top: 20rpx; // 分组内顶部内边距,增强视觉区分 | ||
| 681 | - | ||
| 682 | -} | ||
| 683 | - | ||
| 684 | -// 派单情况标题样式 | ||
| 685 | -.dispatch-title { | ||
| 686 | - font-size: 32rpx; | ||
| 687 | - font-weight: 600; | ||
| 688 | - color:$u-primary; | ||
| 689 | - margin-bottom: 20rpx; | ||
| 690 | - padding-left: 10rpx; | 570 | + padding-top: 24rpx; |
| 571 | + margin-top: 8rpx; | ||
| 572 | + border-top: 1px solid #f5f5f5; | ||
| 573 | + | ||
| 574 | + .dispatch-title { | ||
| 575 | + font-size: 32rpx; | ||
| 576 | + font-weight: 600; | ||
| 577 | + color: $u-primary; | ||
| 578 | + margin-bottom: 20rpx; | ||
| 579 | + padding-left: 10rpx; | ||
| 580 | + } | ||
| 691 | } | 581 | } |
| 692 | </style> | 582 | </style> |
| 693 | \ No newline at end of file | 583 | \ No newline at end of file |
pages-sub/problem/regional-order-manage/add-patrol-order.vue
| @@ -101,7 +101,7 @@ | @@ -101,7 +101,7 @@ | ||
| 101 | 101 | ||
| 102 | <script setup> | 102 | <script setup> |
| 103 | import { ref, reactive } from 'vue' | 103 | import { ref, reactive } from 'vue' |
| 104 | -import { onReady, onShow, onLoad } from '@dcloudio/uni-app'; | 104 | +import { onReady, onShow, onLoad, onBackPress } from '@dcloudio/uni-app'; |
| 105 | import { useUploadImgs } from '@/common/utils/useUploadImgs' | 105 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 106 | import { qyUniversalApproval, qyWorkorderCreate } from '@/api/regional-order-manage/regional-order-manage' | 106 | import { qyUniversalApproval, qyWorkorderCreate } from '@/api/regional-order-manage/regional-order-manage' |
| 107 | import { timeFormat } from '@/uni_modules/uview-plus' | 107 | import { timeFormat } from '@/uni_modules/uview-plus' |
| @@ -237,6 +237,13 @@ onShow(() => { | @@ -237,6 +237,13 @@ onShow(() => { | ||
| 237 | // 初始化工单名称列表 | 237 | // 初始化工单名称列表 |
| 238 | orderNameList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('work_name')) | 238 | orderNameList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('work_name')) |
| 239 | }) | 239 | }) |
| 240 | +// 新增页返回直接回列表页 | ||
| 241 | +onBackPress(() => { | ||
| 242 | + uni.redirectTo({ | ||
| 243 | + url: '/pages-sub/problem/regional-order-manage/index' | ||
| 244 | + }) | ||
| 245 | + return true; | ||
| 246 | +}) | ||
| 240 | 247 | ||
| 241 | // ========== 核心方法 ========== | 248 | // ========== 核心方法 ========== |
| 242 | const echoOrderData = (orderItem) => { | 249 | const echoOrderData = (orderItem) => { |
pages-sub/problem/regional-order-manage/distribution-order.vue
| @@ -194,7 +194,7 @@ | @@ -194,7 +194,7 @@ | ||
| 194 | 194 | ||
| 195 | <script setup> | 195 | <script setup> |
| 196 | import { ref, reactive } from 'vue' | 196 | import { ref, reactive } from 'vue' |
| 197 | -import { onReady, onShow, onLoad } from '@dcloudio/uni-app'; | 197 | +import { onReady, onShow, onLoad, onBackPress } from '@dcloudio/uni-app'; |
| 198 | import { useUploadImgs } from '@/common/utils/useUploadImgs' | 198 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 199 | import { getRoadListByLatLng } from '@/api/common' | 199 | import { getRoadListByLatLng } from '@/api/common' |
| 200 | import { daquUniversalApproval, daquWorkorderCreate, qyUniversalApproval } from '@/api/regional-order-manage/regional-order-manage' | 200 | import { daquUniversalApproval, daquWorkorderCreate, qyUniversalApproval } from '@/api/regional-order-manage/regional-order-manage' |
| @@ -357,6 +357,14 @@ onShow(() => { | @@ -357,6 +357,14 @@ onShow(() => { | ||
| 357 | pressingTypeList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('workorder_pressing_type')) | 357 | pressingTypeList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('workorder_pressing_type')) |
| 358 | }) | 358 | }) |
| 359 | 359 | ||
| 360 | +// 新增页返回直接回列表页 | ||
| 361 | +onBackPress(() => { | ||
| 362 | + uni.redirectTo({ | ||
| 363 | + url: '/pages-sub/problem/regional-order-manage/index' | ||
| 364 | + }) | ||
| 365 | + return true; | ||
| 366 | +}) | ||
| 367 | + | ||
| 360 | // ========== 核心方法 ========== | 368 | // ========== 核心方法 ========== |
| 361 | const echoOrderData = (orderItem) => { | 369 | const echoOrderData = (orderItem) => { |
| 362 | // 回显业务线 | 370 | // 回显业务线 |
| @@ -374,7 +382,7 @@ const echoOrderData = (orderItem) => { | @@ -374,7 +382,7 @@ const echoOrderData = (orderItem) => { | ||
| 374 | workOrderForm.problemDesc = orderItem.remark || ''; | 382 | workOrderForm.problemDesc = orderItem.remark || ''; |
| 375 | workOrderForm.lat = orderItem.lat || 0; | 383 | workOrderForm.lat = orderItem.lat || 0; |
| 376 | workOrderForm.lon = orderItem.lon || 0; | 384 | workOrderForm.lon = orderItem.lon || 0; |
| 377 | - workOrderForm.expectedFinishDate = orderItem.expectedFinishDate=='' ? '':timeFormat(orderItem.expectedFinishDate, 'yyyy-mm-dd hh:MM:ss') ; | 385 | + workOrderForm.expectedFinishDate = orderItem.expectedFinishDate? timeFormat(orderItem.expectedFinishDate, 'yyyy-mm-dd hh:MM:ss'):'' ; |
| 378 | 386 | ||
| 379 | // 回显图片【核心:问题照片赋值】 | 387 | // 回显图片【核心:问题照片赋值】 |
| 380 | if (orderItem.problemsImgs && Array.isArray(orderItem.problemsImgs) && orderItem.problemsImgs.length > 0) { | 388 | if (orderItem.problemsImgs && Array.isArray(orderItem.problemsImgs) && orderItem.problemsImgs.length > 0) { |
pages-sub/problem/regional-order-manage/index.vue
| @@ -3,7 +3,6 @@ | @@ -3,7 +3,6 @@ | ||
| 3 | <!-- 顶部固定区域 --> | 3 | <!-- 顶部固定区域 --> |
| 4 | <up-sticky> | 4 | <up-sticky> |
| 5 | <view class="header-wrap"> | 5 | <view class="header-wrap"> |
| 6 | - <!-- 第一行:u-tabs 待办/已办切换 :scrollable="false"--> | ||
| 7 | <up-tabs | 6 | <up-tabs |
| 8 | v-model="activeTab" | 7 | v-model="activeTab" |
| 9 | :list="tabList" | 8 | :list="tabList" |
| @@ -12,10 +11,8 @@ | @@ -12,10 +11,8 @@ | ||
| 12 | font-size="30rpx" | 11 | font-size="30rpx" |
| 13 | @click="handleTabChange" | 12 | @click="handleTabChange" |
| 14 | /> | 13 | /> |
| 15 | - | ||
| 16 | <!-- 第二行:下拉框 + 搜索框 --> | 14 | <!-- 第二行:下拉框 + 搜索框 --> |
| 17 | <view class="search-header"> | 15 | <view class="search-header"> |
| 18 | - <!-- 左侧下拉框 --> | ||
| 19 | <view class="select-wrap common-text-color"> | 16 | <view class="select-wrap common-text-color"> |
| 20 | <up-select | 17 | <up-select |
| 21 | v-model:current="selectedSortValue" | 18 | v-model:current="selectedSortValue" |
| @@ -26,8 +23,6 @@ | @@ -26,8 +23,6 @@ | ||
| 26 | :style="{ flex: 1 }" | 23 | :style="{ flex: 1 }" |
| 27 | /> | 24 | /> |
| 28 | </view> | 25 | </view> |
| 29 | - | ||
| 30 | - <!-- 右侧搜索框 --> | ||
| 31 | <view class="search-input-wrap"> | 26 | <view class="search-input-wrap"> |
| 32 | <up-search | 27 | <up-search |
| 33 | v-model="searchValue" | 28 | v-model="searchValue" |
| @@ -47,24 +42,23 @@ | @@ -47,24 +42,23 @@ | ||
| 47 | 42 | ||
| 48 | <!-- 列表容器 --> | 43 | <!-- 列表容器 --> |
| 49 | <z-paging | 44 | <z-paging |
| 50 | - ref="paging" | 45 | + ref="pagingRef" |
| 51 | v-model="orderList" | 46 | v-model="orderList" |
| 52 | @query="queryList" | 47 | @query="queryList" |
| 53 | :auto-show-system-loading="true" | 48 | :auto-show-system-loading="true" |
| 54 | - | ||
| 55 | > | 49 | > |
| 56 | <template #empty> | 50 | <template #empty> |
| 57 | - <empty-view/> | 51 | + <empty-view /> |
| 58 | </template> | 52 | </template> |
| 59 | 53 | ||
| 60 | <view class="common-card-list" style="padding-top: 200rpx;padding-bottom: 30rpx"> | 54 | <view class="common-card-list" style="padding-top: 200rpx;padding-bottom: 30rpx"> |
| 61 | <!-- 待办工单卡片 --> | 55 | <!-- 待办工单卡片 --> |
| 62 | <up-card | 56 | <up-card |
| 63 | - v-if="activeTab == 0" | 57 | + v-if="activeTab === 0" |
| 64 | :border="false" | 58 | :border="false" |
| 65 | :foot-border-top="false" | 59 | :foot-border-top="false" |
| 66 | v-for="(item, index) in orderList" | 60 | v-for="(item, index) in orderList" |
| 67 | - :key="`todo_${item.orderNo}_${index}`" | 61 | + :key="`todo_${item.id}_${index}`" |
| 68 | :show-head="false" | 62 | :show-head="false" |
| 69 | class="order-card" | 63 | class="order-card" |
| 70 | > | 64 | > |
| @@ -86,7 +80,7 @@ | @@ -86,7 +80,7 @@ | ||
| 86 | <view class="u-body-item-title">情况描述:</view> | 80 | <view class="u-body-item-title">情况描述:</view> |
| 87 | <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> | 81 | <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> |
| 88 | </view> | 82 | </view> |
| 89 | - <view class="u-body-item u-flex common-item-center common-justify-between"> | 83 | + <view class="u-body-item u-flex common-item-center common-justify-between"> |
| 90 | <view class="u-body-item-title">紧急程度:</view> | 84 | <view class="u-body-item-title">紧急程度:</view> |
| 91 | <view class="u-line-1 u-body-value"> | 85 | <view class="u-line-1 u-body-value"> |
| 92 | {{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} | 86 | {{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} |
| @@ -101,20 +95,10 @@ | @@ -101,20 +95,10 @@ | ||
| 101 | <view class="u-line-1 u-body-value">{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view> | 95 | <view class="u-line-1 u-body-value">{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view> |
| 102 | </view> | 96 | </view> |
| 103 | <!-- 操作按钮行 --> | 97 | <!-- 操作按钮行 --> |
| 104 | - | ||
| 105 | <view class="u-body-item u-flex common-justify-between common-item-center mt-20"> | 98 | <view class="u-body-item u-flex common-justify-between common-item-center mt-20"> |
| 106 | - <up-button type="warning" size="mini" @click="handleReject(item)" | ||
| 107 | - v-show="nextStepMap[item.taskKey].backShow">回退 | ||
| 108 | - </up-button> | ||
| 109 | - | ||
| 110 | - <up-button type="success" size="mini" @click="handleRenew(item)" | ||
| 111 | - v-show="nextStepMap[item.taskKey].renewShow">重新提交 | ||
| 112 | - </up-button> | ||
| 113 | - | ||
| 114 | - <up-button type="primary" size="mini" @click="handleProcess(item)">{{ | ||
| 115 | - nextStepMap[item.taskKey].btnText | ||
| 116 | - }} | ||
| 117 | - </up-button> | 99 | + <up-button type="warning" size="mini" @click="handleReject(item)" v-show="nextStepMap[item.taskKey].backShow">回退</up-button> |
| 100 | + <up-button type="success" size="mini" @click="handleRenew(item)" v-show="nextStepMap[item.taskKey].renewShow">重新提交</up-button> | ||
| 101 | + <up-button type="primary" size="mini" @click="handleProcess(item)">{{ nextStepMap[item.taskKey].btnText }}</up-button> | ||
| 118 | <up-button type="info" size="mini" @click="handleDetail(item)">详情</up-button> | 102 | <up-button type="info" size="mini" @click="handleDetail(item)">详情</up-button> |
| 119 | </view> | 103 | </view> |
| 120 | </view> | 104 | </view> |
| @@ -123,11 +107,11 @@ | @@ -123,11 +107,11 @@ | ||
| 123 | 107 | ||
| 124 | <!-- 已办工单卡片和我发起的 --> | 108 | <!-- 已办工单卡片和我发起的 --> |
| 125 | <up-card | 109 | <up-card |
| 126 | - v-if="activeTab == 2||activeTab == 1" | 110 | + v-if="activeTab === 1 || activeTab === 2" |
| 127 | :border="false" | 111 | :border="false" |
| 128 | :foot-border-top="false" | 112 | :foot-border-top="false" |
| 129 | v-for="(item, index) in orderList" | 113 | v-for="(item, index) in orderList" |
| 130 | - :key="`done_${item.orderNo}_${index}`" | 114 | + :key="`done_${item.id}_${index}`" |
| 131 | :show-head="false" | 115 | :show-head="false" |
| 132 | class="order-card" | 116 | class="order-card" |
| 133 | > | 117 | > |
| @@ -149,12 +133,11 @@ | @@ -149,12 +133,11 @@ | ||
| 149 | <view class="u-body-item-title">情况描述:</view> | 133 | <view class="u-body-item-title">情况描述:</view> |
| 150 | <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> | 134 | <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> |
| 151 | </view> | 135 | </view> |
| 152 | - | ||
| 153 | <view class="u-body-item u-flex common-justify-between common-item-center"> | 136 | <view class="u-body-item u-flex common-justify-between common-item-center"> |
| 154 | <view class="u-body-item-title"> | 137 | <view class="u-body-item-title"> |
| 155 | 紧急程度:{{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} | 138 | 紧急程度:{{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} |
| 156 | </view> | 139 | </view> |
| 157 | - <view class=" "> | 140 | + <view> |
| 158 | <up-button type="primary" size="mini" @click="handleDetail(item)">工单详情</up-button> | 141 | <up-button type="primary" size="mini" @click="handleDetail(item)">工单详情</up-button> |
| 159 | </view> | 142 | </view> |
| 160 | </view> | 143 | </view> |
| @@ -172,21 +155,12 @@ | @@ -172,21 +155,12 @@ | ||
| 172 | </view> | 155 | </view> |
| 173 | </z-paging> | 156 | </z-paging> |
| 174 | 157 | ||
| 175 | - <!-- 底部新增工单按钮(仅巡查员显示) --> | ||
| 176 | - <!-- <view v-if="isInspector" class="fixed-bottom-btn-wrap">--> | ||
| 177 | - <!-- <up-button type="primary" size="large" @click="handleAddOrder">--> | ||
| 178 | - <!-- 新增工单--> | ||
| 179 | - <!-- </up-button>--> | ||
| 180 | - <!-- </view>--> | ||
| 181 | - | 158 | + <!-- 底部新增工单按钮 --> |
| 182 | <view class="fixed-bottom-btn-wrap" v-if="isAi"> | 159 | <view class="fixed-bottom-btn-wrap" v-if="isAi"> |
| 183 | - <up-button type="primary" size="large" @click="handleAddOrder"> | ||
| 184 | - 新增工单 | ||
| 185 | - </up-button> | 160 | + <up-button type="primary" size="large" @click="handleAddOrder">新增工单</up-button> |
| 186 | </view> | 161 | </view> |
| 187 | 162 | ||
| 188 | - | ||
| 189 | - <!-- 回退原因弹窗:替换为up-modal(核心修改) --> | 163 | + <!-- 回退原因弹窗 --> |
| 190 | <up-modal | 164 | <up-modal |
| 191 | :show="rejectModalShow" | 165 | :show="rejectModalShow" |
| 192 | title="回退原因" | 166 | title="回退原因" |
| @@ -197,7 +171,6 @@ | @@ -197,7 +171,6 @@ | ||
| 197 | @confirm="confirmReject" | 171 | @confirm="confirmReject" |
| 198 | > | 172 | > |
| 199 | <view class="reject-modal-content"> | 173 | <view class="reject-modal-content"> |
| 200 | - <!-- 回退原因 必填textarea --> | ||
| 201 | <up-textarea | 174 | <up-textarea |
| 202 | v-model.trim="rejectReason" | 175 | v-model.trim="rejectReason" |
| 203 | placeholder="请输入回退原因(必填)" | 176 | placeholder="请输入回退原因(必填)" |
| @@ -206,11 +179,10 @@ | @@ -206,11 +179,10 @@ | ||
| 206 | maxlength="200" | 179 | maxlength="200" |
| 207 | class="reject-textarea" | 180 | class="reject-textarea" |
| 208 | /> | 181 | /> |
| 209 | - <!-- 上传图片(选填)- 按照参考页面改造 --> | ||
| 210 | <view class="upload-wrap mt-20"> | 182 | <view class="upload-wrap mt-20"> |
| 211 | <view class="upload-title">上传图片(选填)</view> | 183 | <view class="upload-title">上传图片(选填)</view> |
| 212 | <up-upload | 184 | <up-upload |
| 213 | - :file-list="rejectImgs.rawImgList.value|| []" | 185 | + :file-list="rejectImgs.rawImgList.value || []" |
| 214 | @after-read="rejectImgs.uploadImgs" | 186 | @after-read="rejectImgs.uploadImgs" |
| 215 | @delete="rejectImgs.deleteImg" | 187 | @delete="rejectImgs.deleteImg" |
| 216 | multiple | 188 | multiple |
| @@ -224,7 +196,7 @@ | @@ -224,7 +196,7 @@ | ||
| 224 | </view> | 196 | </view> |
| 225 | </up-modal> | 197 | </up-modal> |
| 226 | 198 | ||
| 227 | - <!-- 验收弹窗 up-modal(含图片上传) --> | 199 | + <!-- 验收弹窗 --> |
| 228 | <up-modal | 200 | <up-modal |
| 229 | :show="acceptModalShow" | 201 | :show="acceptModalShow" |
| 230 | title="验收" | 202 | title="验收" |
| @@ -235,15 +207,12 @@ | @@ -235,15 +207,12 @@ | ||
| 235 | @confirm="handleAcceptModalConfirm" | 207 | @confirm="handleAcceptModalConfirm" |
| 236 | > | 208 | > |
| 237 | <view class="accept-modal-content"> | 209 | <view class="accept-modal-content"> |
| 238 | - <!-- 第一行:单选框(通过/不通过,默认通过) --> | ||
| 239 | <view class="radio-group-wrap"> | 210 | <view class="radio-group-wrap"> |
| 240 | <up-radio-group v-model="acceptRadioValue"> | 211 | <up-radio-group v-model="acceptRadioValue"> |
| 241 | <up-radio name="0" label="通过"></up-radio> | 212 | <up-radio name="0" label="通过"></up-radio> |
| 242 | <up-radio name="1" label="不通过"></up-radio> | 213 | <up-radio name="1" label="不通过"></up-radio> |
| 243 | </up-radio-group> | 214 | </up-radio-group> |
| 244 | </view> | 215 | </view> |
| 245 | - | ||
| 246 | - <!-- 第二行:必填textarea,最多200字 --> | ||
| 247 | <view class="textarea-wrap mt-30"> | 216 | <view class="textarea-wrap mt-30"> |
| 248 | <up-textarea | 217 | <up-textarea |
| 249 | v-model.trim="acceptReason" | 218 | v-model.trim="acceptReason" |
| @@ -254,15 +223,12 @@ | @@ -254,15 +223,12 @@ | ||
| 254 | count | 223 | count |
| 255 | /> | 224 | /> |
| 256 | </view> | 225 | </view> |
| 257 | - | ||
| 258 | - <!-- 验收图片上传(选填,参考回退弹窗样式) --> | ||
| 259 | <view class="upload-wrap mt-20"> | 226 | <view class="upload-wrap mt-20"> |
| 260 | <view class="upload-title">上传验收图片(选填)</view> | 227 | <view class="upload-title">上传验收图片(选填)</view> |
| 261 | <up-upload | 228 | <up-upload |
| 262 | :file-list="acceptImgs.rawImgList.value || []" | 229 | :file-list="acceptImgs.rawImgList.value || []" |
| 263 | @after-read="acceptImgs.uploadImgs" | 230 | @after-read="acceptImgs.uploadImgs" |
| 264 | @delete="acceptImgs.deleteImg" | 231 | @delete="acceptImgs.deleteImg" |
| 265 | - | ||
| 266 | multiple | 232 | multiple |
| 267 | width="70" | 233 | width="70" |
| 268 | height="70" | 234 | height="70" |
| @@ -284,124 +250,171 @@ import { | @@ -284,124 +250,171 @@ import { | ||
| 284 | myBuzSimplePage, | 250 | myBuzSimplePage, |
| 285 | todoBuzSimplePage, | 251 | todoBuzSimplePage, |
| 286 | doneBuzSimplePage, | 252 | doneBuzSimplePage, |
| 287 | - qyWorkorderCreate, | ||
| 288 | qyUniversalApproval, | 253 | qyUniversalApproval, |
| 289 | daquUniversalApproval, | 254 | daquUniversalApproval, |
| 290 | dcyUniversalApproval | 255 | dcyUniversalApproval |
| 291 | } from '@/api/regional-order-manage/regional-order-manage' | 256 | } from '@/api/regional-order-manage/regional-order-manage' |
| 292 | -// 从用户store获取角色信息 | ||
| 293 | import { useUserStore } from '@/pinia/user'; | 257 | import { useUserStore } from '@/pinia/user'; |
| 294 | import { nextStepMap, buzStatusMap } from '@/common/utils/common' | 258 | import { nextStepMap, buzStatusMap } from '@/common/utils/common' |
| 295 | -// 引入图片上传组合式函数(与参考页面一致) | ||
| 296 | import { useUploadImgs } from '@/common/utils/useUploadImgs' | 259 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 297 | -// ========== 状态管理 ========== | 260 | + |
| 261 | +// ========== 全局实例 & 常量 ========== | ||
| 298 | const userStore = useUserStore(); | 262 | const userStore = useUserStore(); |
| 299 | -// 标签页切换 | 263 | +const USER_ROLES = userStore.userInfo?.roles || []; |
| 264 | + | ||
| 265 | +// ========== 基础状态 (按模块分组,语义化更强) ========== | ||
| 266 | +// tab切换 | ||
| 300 | const activeTab = ref(0); // 0-待办 1-我发起的 2-已办 | 267 | const activeTab = ref(0); // 0-待办 1-我发起的 2-已办 |
| 301 | -const tabList = ref([ | ||
| 302 | - {name: '待办'}, | ||
| 303 | - {name: '我发起的任务'}, | ||
| 304 | - {name: '已办'} | ||
| 305 | -]); | ||
| 306 | -// 排序下拉框 | 268 | +const tabList = ref([{name: '待办'}, {name: '我发起的任务'}, {name: '已办'}]); |
| 269 | +// 排序与搜索 | ||
| 307 | const selectedSortValue = ref(1); | 270 | const selectedSortValue = ref(1); |
| 308 | const sortOptions = ref([ | 271 | const sortOptions = ref([ |
| 309 | - {name: '位置', id: 1}, | ||
| 310 | - {name: '名称', id: 2}, | ||
| 311 | - {name: '描述', id: 3}, | ||
| 312 | - {name: '编号', id: 4}, | 272 | + {name: '位置', id: 1}, {name: '名称', id: 2}, {name: '描述', id: 3}, {name: '编号', id: 4}, |
| 313 | ]); | 273 | ]); |
| 314 | -// 搜索 | ||
| 315 | const searchValue = ref(''); | 274 | const searchValue = ref(''); |
| 316 | -// 分页 | ||
| 317 | -const paging = ref(null); | 275 | +// 分页相关 |
| 276 | +const pagingRef = ref(null); | ||
| 318 | const orderList = ref([]); | 277 | const orderList = ref([]); |
| 319 | -// 角色控制(巡查员显示新增按钮) | 278 | + |
| 279 | +// ========== 角色权限计算属性 (修复核心bug: 原代码取反逻辑写反) ========== | ||
| 320 | const isAi = computed(() => { | 280 | const isAi = computed(() => { |
| 321 | - // patrol_global 全域巡查员 | ||
| 322 | - // regional_manager 大区经理 | ||
| 323 | - // AI_dispatcher AI工单派发人员 | ||
| 324 | - // 增加可选链,避免用户信息不存在报错 | ||
| 325 | - console.log('123') | ||
| 326 | - console.log(!userStore.userInfo?.roles?.includes('AI_dispatcher')) | ||
| 327 | - return !userStore.userInfo?.roles?.includes('AI_dispatcher') ; | ||
| 328 | - // return true | 281 | + // AI工单派发人员 不显示新增按钮,其他角色显示 |
| 282 | + return !USER_ROLES.includes('AI_dispatcher'); | ||
| 329 | }); | 283 | }); |
| 330 | -// 回退弹窗相关 | ||
| 331 | -const rejectModalShow = ref(false); // 回退modal显示开关 | ||
| 332 | -const rejectReason = ref(''); // 回退原因 | ||
| 333 | -const currentRejectItem = ref(null); // 当前回退工单 | ||
| 334 | -// 回退图片上传配置(与参考页面风格一致) | 284 | + |
| 285 | +// ========== 回退弹窗相关 ========== | ||
| 286 | +const rejectModalShow = ref(false); | ||
| 287 | +const rejectReason = ref(''); | ||
| 288 | +const currentRejectItem = ref(null); | ||
| 335 | const rejectImgs = useUploadImgs({ | 289 | const rejectImgs = useUploadImgs({ |
| 336 | - maxCount: 3, // 最多上传3张 | ||
| 337 | - uploadText: '选择回退图片', // 自定义上传提示文字 | ||
| 338 | - sizeType: ['compressed'], // 仅上传压缩图 | ||
| 339 | - formRef: null, // 该弹窗无表单校验 | ||
| 340 | - fieldName: 'rejectImgs' // 自定义字段名 | 290 | + maxCount: 3, uploadText: '选择回退图片', sizeType: ['compressed'], formRef: null, fieldName: 'rejectImgs' |
| 341 | }) | 291 | }) |
| 342 | -// ========== 验收弹窗相关状态(含图片上传) ========== | ||
| 343 | -const acceptModalShow = ref(false); // 验收弹窗显示开关 | ||
| 344 | -const acceptRadioValue = ref('0'); // 单选框值,默认0(通过) | ||
| 345 | -const acceptReason = ref(''); // 验收原因 | ||
| 346 | -const currentAcceptItem = ref(null); // 当前验收的工单项 | ||
| 347 | -// 验收图片上传配置(独立实例,参考回退弹窗) | 292 | + |
| 293 | +// ========== 验收弹窗相关 ========== | ||
| 294 | +const acceptModalShow = ref(false); | ||
| 295 | +const acceptRadioValue = ref('0'); // 默认通过 | ||
| 296 | +const acceptReason = ref(''); | ||
| 297 | +const currentAcceptItem = ref(null); | ||
| 348 | const acceptImgs = useUploadImgs({ | 298 | const acceptImgs = useUploadImgs({ |
| 349 | - maxCount: 3, // 最多上传3张,与回退弹窗一致 | ||
| 350 | - uploadText: '选择验收图片', // 自定义上传提示文字 | ||
| 351 | - sizeType: ['compressed'], // 仅上传压缩图,优化性能 | ||
| 352 | - formRef: null, // 验收弹窗无表单校验 | ||
| 353 | - fieldName: 'acceptImgs' // 自定义字段名,区分回退图片 | 299 | + maxCount: 3, uploadText: '选择验收图片', sizeType: ['compressed'], formRef: null, fieldName: 'acceptImgs' |
| 354 | }) | 300 | }) |
| 301 | + | ||
| 302 | +// ========== 公共封装方法 (核心优化:消灭重复代码) ========== | ||
| 303 | +/** | ||
| 304 | + * 生成统一的临时存储key | ||
| 305 | + * @param {String} prefix 前缀标识 | ||
| 306 | + * @returns {String} 唯一key | ||
| 307 | + */ | ||
| 308 | +const generateTempKey = (prefix = 'order') => { | ||
| 309 | + return `${prefix}_${Date.now()}_${Math.floor(Math.random() * 10000)}`; | ||
| 310 | +}; | ||
| 311 | + | ||
| 312 | +/** | ||
| 313 | + * 存储工单数据到本地缓存 | ||
| 314 | + * @param {Object} item 工单数据 | ||
| 315 | + * @param {String} prefix key前缀 | ||
| 316 | + * @returns {String|null} 成功返回key,失败返回null | ||
| 317 | + */ | ||
| 318 | +const setOrderStorage = (item, prefix) => { | ||
| 319 | + if (!item?.id) return null; | ||
| 320 | + const tempKey = generateTempKey(prefix); | ||
| 321 | + try { | ||
| 322 | + uni.setStorageSync(tempKey, item); | ||
| 323 | + return tempKey; | ||
| 324 | + } catch (error) { | ||
| 325 | + console.error('存储工单数据失败:', error); | ||
| 326 | + uni.showToast({title: '数据存储异常,请重试', icon: 'none'}); | ||
| 327 | + return null; | ||
| 328 | + } | ||
| 329 | +}; | ||
| 330 | + | ||
| 331 | +/** | ||
| 332 | + * 获取分页请求公共参数 | ||
| 333 | + * @param {Number} pageNo 页码 | ||
| 334 | + * @param {Number} pageSize 页大小 | ||
| 335 | + * @returns {Object} 请求参数 | ||
| 336 | + */ | ||
| 337 | +const getQueryParams = (pageNo, pageSize) => { | ||
| 338 | + return { | ||
| 339 | + searchContent: searchValue.value.trim() || '', | ||
| 340 | + pageNo, | ||
| 341 | + pageSize, | ||
| 342 | + type: selectedSortValue.value | ||
| 343 | + }; | ||
| 344 | +}; | ||
| 345 | + | ||
| 346 | +/** | ||
| 347 | + * 统一调用审批接口 | ||
| 348 | + * @param {Object} params 请求参数 | ||
| 349 | + * @param {String} taskKey 工单任务key | ||
| 350 | + * @returns {Promise} 接口请求Promise | ||
| 351 | + */ | ||
| 352 | +const callApprovalApi = async (params, taskKey) => { | ||
| 353 | + if (taskKey === 'shRegionManager') return await dcyUniversalApproval(params); | ||
| 354 | + if (taskKey === 'regionManager') return await qyUniversalApproval(params); | ||
| 355 | + // 根据角色匹配对应接口 | ||
| 356 | + if (USER_ROLES.includes('regional_manager')) return await daquUniversalApproval(params); | ||
| 357 | + if (USER_ROLES.includes('Inspector_global')) return await dcyUniversalApproval(params); | ||
| 358 | + if (USER_ROLES.includes('patrol_global')) return await qyUniversalApproval(params); | ||
| 359 | +}; | ||
| 360 | + | ||
| 361 | +/** | ||
| 362 | + * 统一跳转工单页面 | ||
| 363 | + * @param {String} path 页面路径 | ||
| 364 | + * @param {Object} query 拼接参数 | ||
| 365 | + */ | ||
| 366 | +const navToOrderPage = (path, query = {}) => { | ||
| 367 | + const queryStr = Object.keys(query).map(k => `${k}=${query[k]}`).join('&'); | ||
| 368 | + uni.redirectTo({ url: `${path}${queryStr ? '?' + queryStr : ''}` }); | ||
| 369 | +}; | ||
| 370 | + | ||
| 371 | +/** | ||
| 372 | + * 刷新列表 - 统一封装,避免空指针 | ||
| 373 | + */ | ||
| 374 | +const refreshOrderList = () => { | ||
| 375 | + pagingRef.value && pagingRef.value.reload(); | ||
| 376 | +}; | ||
| 377 | + | ||
| 378 | +// ========== 业务核心方法 ========== | ||
| 355 | // 分页查询列表 | 379 | // 分页查询列表 |
| 356 | const queryList = async (pageNo, pageSize) => { | 380 | const queryList = async (pageNo, pageSize) => { |
| 357 | try { | 381 | try { |
| 358 | - const apiParams = { | ||
| 359 | - searchContent: searchValue.value.trim() || '', | ||
| 360 | - pageNo, | ||
| 361 | - pageSize, | ||
| 362 | - type: selectedSortValue.value // 1-位置 2-工单名称 3-情况描述 4-工单编号 | ||
| 363 | - }; | 382 | + const params = getQueryParams(pageNo, pageSize); |
| 364 | let res; | 383 | let res; |
| 365 | - if (activeTab.value == 0) { | ||
| 366 | - // 待办工单 | ||
| 367 | - res = await todoBuzSimplePage(apiParams); | ||
| 368 | - } else if (activeTab.value == 1) { | ||
| 369 | - // 我发起的任务 | ||
| 370 | - res = await myBuzSimplePage(apiParams); | ||
| 371 | - } else { | ||
| 372 | - // 已办工单 | ||
| 373 | - res = await doneBuzSimplePage(apiParams); | ||
| 374 | - } | ||
| 375 | - // 适配z-paging分页 | ||
| 376 | - paging.value.complete(res.list, res.total); | 384 | + if (activeTab.value === 0) res = await todoBuzSimplePage(params); |
| 385 | + else if (activeTab.value === 1) res = await myBuzSimplePage(params); | ||
| 386 | + else res = await doneBuzSimplePage(params); | ||
| 387 | + pagingRef.value.complete(res?.list || [], res?.total || 0); | ||
| 377 | } catch (error) { | 388 | } catch (error) { |
| 378 | console.error('加载工单失败:', error); | 389 | console.error('加载工单失败:', error); |
| 379 | - paging.value?.complete(false); | 390 | + pagingRef.value?.complete(false); |
| 380 | uni.showToast({title: '加载失败,请重试', icon: 'none'}); | 391 | uni.showToast({title: '加载失败,请重试', icon: 'none'}); |
| 381 | } | 392 | } |
| 382 | }; | 393 | }; |
| 383 | -// ========== 事件处理 ========== | 394 | + |
| 384 | // 标签页切换 | 395 | // 标签页切换 |
| 385 | const handleTabChange = (item) => { | 396 | const handleTabChange = (item) => { |
| 386 | - orderList.value = []; | ||
| 387 | - console.log(item) | ||
| 388 | activeTab.value = item.index; | 397 | activeTab.value = item.index; |
| 389 | - paging.value?.reload(); // 切换标签页刷新列表 | 398 | + orderList.value = []; |
| 399 | + refreshOrderList(); | ||
| 390 | }; | 400 | }; |
| 401 | + | ||
| 391 | // 排序变更 | 402 | // 排序变更 |
| 392 | const handleSortChange = (val) => { | 403 | const handleSortChange = (val) => { |
| 393 | selectedSortValue.value = val.id; | 404 | selectedSortValue.value = val.id; |
| 394 | searchValue.value = ''; | 405 | searchValue.value = ''; |
| 395 | - paging.value?.reload(); // 排序变更刷新列表 | 406 | + refreshOrderList(); |
| 396 | }; | 407 | }; |
| 408 | + | ||
| 397 | // 搜索 | 409 | // 搜索 |
| 398 | const handleSearch = (val) => { | 410 | const handleSearch = (val) => { |
| 399 | searchValue.value = val; | 411 | searchValue.value = val; |
| 400 | - paging.value?.reload(); // 搜索刷新列表 | 412 | + refreshOrderList(); |
| 401 | }; | 413 | }; |
| 414 | + | ||
| 402 | // 工单详情 | 415 | // 工单详情 |
| 403 | const handleDetail = (item) => { | 416 | const handleDetail = (item) => { |
| 404 | - // 0-待办 1我发起的- 2-已办 | 417 | + if (!item?.taskId) return uni.showToast({title: '工单信息异常', icon: 'none'}); |
| 405 | uni.navigateTo({ | 418 | uni.navigateTo({ |
| 406 | url: `/pages-sub/problem/regional-order-manage/order-detail?taskId=${item.taskId}&activeTab=${activeTab.value}&processInstanceId=${item.processInstanceId}`, | 419 | url: `/pages-sub/problem/regional-order-manage/order-detail?taskId=${item.taskId}&activeTab=${activeTab.value}&processInstanceId=${item.processInstanceId}`, |
| 407 | events: { | 420 | events: { |
| @@ -414,302 +427,163 @@ const handleDetail = (item) => { | @@ -414,302 +427,163 @@ const handleDetail = (item) => { | ||
| 414 | } | 427 | } |
| 415 | } | 428 | } |
| 416 | }); | 429 | }); |
| 430 | + // navToOrderPage('/pages-sub/problem/regional-order-manage/order-detail', { | ||
| 431 | + // taskId: item.taskId, | ||
| 432 | + // activeTab: activeTab.value, | ||
| 433 | + // processInstanceId: item.processInstanceId | ||
| 434 | + // }, { | ||
| 435 | + // needRefresh: () => refreshOrderList() | ||
| 436 | + // }); | ||
| 437 | + | ||
| 438 | + | ||
| 417 | }; | 439 | }; |
| 418 | -// 生成临时key | ||
| 419 | -const generateTempKey = () => { | ||
| 420 | - return 'renew_order_' + Date.now() + '_' + Math.floor(Math.random() * 10000); | ||
| 421 | -}; | ||
| 422 | -// 待办-重新提交工单(改造后:大数据存本地,仅传唯一标识) | 440 | + |
| 441 | +// 重新提交工单 | ||
| 423 | const handleRenew = (item) => { | 442 | const handleRenew = (item) => { |
| 443 | + const tempKey = setOrderStorage(item, 'renew_order'); | ||
| 444 | + if (!tempKey) return; | ||
| 424 | 445 | ||
| 425 | - // 1. 生成唯一临时标识 | ||
| 426 | - const tempKey = generateTempKey(); | ||
| 427 | - // 2. 将完整工单数据存入本地临时存储(同步存储,确保数据立即生效) | ||
| 428 | - try { | ||
| 429 | - console.log(item) | ||
| 430 | - console.log('123') | ||
| 431 | - uni.setStorageSync(tempKey, item); | ||
| 432 | - } catch (error) { | ||
| 433 | - console.error('存储工单数据失败:', error); | ||
| 434 | - uni.showToast({title: '数据存储异常,无法重新提交', icon: 'none'}); | ||
| 435 | - return; | ||
| 436 | - } | 446 | + const pageUrl = USER_ROLES.includes('patrol_global') |
| 447 | + ? '/pages-sub/problem/regional-order-manage/add-patrol-order' | ||
| 448 | + : '/pages-sub/problem/regional-order-manage/add-order'; | ||
| 437 | 449 | ||
| 438 | - if (userStore.userInfo?.roles.includes('patrol_global')) { // 全域巡查员 | ||
| 439 | - uni.navigateTo({ | ||
| 440 | - url: `/pages-sub/problem/regional-order-manage/add-patrol-order?isRenew=1&tempKey=${tempKey}` | ||
| 441 | - }); | ||
| 442 | - } | ||
| 443 | - if (userStore.userInfo?.roles.includes('regional_manager')) { // 大区经理 | ||
| 444 | - uni.navigateTo({ | ||
| 445 | - url: `/pages-sub/problem/regional-order-manage/add-order?isRenew=1&tempKey=${tempKey}` | ||
| 446 | - }); | ||
| 447 | - } | ||
| 448 | - if (userStore.userInfo?.roles.includes('Inspector_global')) { // 督察员 | ||
| 449 | - uni.navigateTo({ | ||
| 450 | - url: `/pages-sub/problem/regional-order-manage/add-order?isRenew=1&tempKey=${tempKey}` | ||
| 451 | - }); | ||
| 452 | - } | ||
| 453 | - // // 3. URL 仅传递「唯一标识」和「重新提交标记」(数据量极小,无长度问题) | ||
| 454 | - // uni.navigateTo({ | ||
| 455 | - // url: `/pages-sub/problem/regional-order-manage/add-patrol-order?isRenew=1&tempKey=${tempKey}` | ||
| 456 | - // }); | 450 | + navToOrderPage(pageUrl, { isRenew: 1, tempKey }); |
| 457 | }; | 451 | }; |
| 458 | -// 待办-处理工单 | 452 | + |
| 453 | +// 处理工单核心逻辑 | ||
| 459 | const handleProcess = async (item) => { | 454 | const handleProcess = async (item) => { |
| 460 | - console.log(nextStepMap[item.taskKey].name) | 455 | + if (!item) return uni.showToast({title: '工单信息异常', icon: 'none'}); |
| 456 | + const stepName = nextStepMap[item.taskKey]?.name; | ||
| 457 | + let resData | ||
| 461 | try { | 458 | try { |
| 462 | - if (nextStepMap[item.taskKey]?.name == '大区经理分配') { | ||
| 463 | - // ① 生成唯一临时key(统一规则,避免冲突) | ||
| 464 | - const tempKey = `distribute_order_${Date.now()}_${Math.floor(Math.random() * 10000)}`; | ||
| 465 | - // ② 存储完整item到本地缓存(同步存储,确保立即生效) | ||
| 466 | - try { | ||
| 467 | - uni.setStorageSync(tempKey, item); | ||
| 468 | - } catch (error) { | ||
| 469 | - console.error('存储分配工单数据失败:', error); | ||
| 470 | - uni.showToast({title: '数据存储异常,无法跳转', icon: 'none'}); | ||
| 471 | - return; | ||
| 472 | - } | ||
| 473 | - // ③ URL仅传递临时key,无其他冗余参数 | ||
| 474 | - uni.navigateTo({ | ||
| 475 | - url: `/pages-sub/problem/regional-order-manage/distribution-order?tempKey=${tempKey}` | ||
| 476 | - }) | 459 | + // 大区经理分配 |
| 460 | + if (stepName === '大区经理分配') { | ||
| 461 | + const tempKey = setOrderStorage(item, 'distribute_order'); | ||
| 462 | + tempKey && navToOrderPage('/pages-sub/problem/regional-order-manage/distribution-order', { tempKey }); | ||
| 477 | } | 463 | } |
| 478 | - if (nextStepMap[item.taskKey]?.name == '督察员单子大区经理分配') { | ||
| 479 | - let postData = { | ||
| 480 | - "taskKey":item.taskKey, | ||
| 481 | - "taskId": item.taskId, | ||
| 482 | - "operateType":60, | ||
| 483 | - "workerDataId":item.id, | ||
| 484 | - "agree":0, | ||
| 485 | - "reason":item.remark, | ||
| 486 | - "roadId":item.roadId, | ||
| 487 | - "roadName":item.roadName, | ||
| 488 | - "pressingType":item.pressingType, | ||
| 489 | - "orderName":item.orderName, | ||
| 490 | - "expectedFinishDate": item.expectedFinishDate, | ||
| 491 | - "busiLine":item.busiLine, | ||
| 492 | - } | ||
| 493 | - const res = await dcyUniversalApproval(postData); | ||
| 494 | - uni.showToast({title: '分配成功', icon: 'success', duration: 1000}); | ||
| 495 | - paging.value?.reload(); // 刷新列表 | 464 | + // 督察员单子大区经理分配 |
| 465 | + else if (stepName === '督察员单子大区经理分配') { | ||
| 466 | + const postData = { taskKey: item.taskKey, taskId: item.taskId, operateType:60, workerDataId:item.id, agree:0, reason:item.remark, roadId:item.roadId, roadName:item.roadName, pressingType:item.pressingType, orderName:item.orderName, expectedFinishDate: item.expectedFinishDate, busiLine:item.busiLine }; | ||
| 467 | + resData = await dcyUniversalApproval(postData); | ||
| 468 | + uni.showToast({title: '分配成功', icon: 'success'}); | ||
| 469 | + refreshOrderList(); | ||
| 496 | } | 470 | } |
| 497 | - | ||
| 498 | - | ||
| 499 | - // 验收 - 打开弹窗 | ||
| 500 | - if (nextStepMap[item.taskKey]?.name == '巡查员验收' || nextStepMap[item.taskKey]?.name == '养护组长验收') { | ||
| 501 | - currentAcceptItem.value = item; // 存储当前工单信息 | ||
| 502 | - acceptReason.value = ''; // 清空上次的验收原因 | ||
| 503 | - acceptRadioValue.value = '0'; // 重置默认选中“通过” | ||
| 504 | - acceptModalShow.value = true; // 显示验收弹窗 | 471 | + // 验收弹窗 |
| 472 | + else if (['巡查员验收', '养护组长验收'].includes(stepName)) { | ||
| 473 | + currentAcceptItem.value = item; | ||
| 474 | + acceptReason.value = ''; | ||
| 475 | + acceptRadioValue.value = '0'; | ||
| 476 | + acceptModalShow.value = true; | ||
| 505 | } | 477 | } |
| 506 | - | ||
| 507 | - // 发起人确认 | ||
| 508 | - if (nextStepMap[item.taskKey]?.name == '发起人确认') { | ||
| 509 | - console.log(item) | 478 | + // 发起人确认-结束工单 |
| 479 | + else if (stepName === '发起人确认') { | ||
| 510 | uni.showModal({ | 480 | uni.showModal({ |
| 511 | title: "结束工单", | 481 | title: "结束工单", |
| 512 | content: "请确定是否结束工单?", | 482 | content: "请确定是否结束工单?", |
| 513 | - success: async function (res) { | 483 | + success: async (res) => { |
| 514 | if (res.confirm) { | 484 | if (res.confirm) { |
| 515 | - // 构建请求参数 | ||
| 516 | const requestData = { | 485 | const requestData = { |
| 517 | - | ||
| 518 | - "workerDataId": item.id, | ||
| 519 | - "taskKey": 'ylInspectorStart', | ||
| 520 | - "taskId": item.taskId, | ||
| 521 | - "operateType": 200, | ||
| 522 | - "agree": 1, | ||
| 523 | - "reason": '结束工单' | 486 | + workerDataId: item.id, taskKey: 'ylInspectorStart', taskId: item.taskId, |
| 487 | + operateType: 200, agree: 1, reason: '结束工单' | ||
| 524 | }; | 488 | }; |
| 525 | - // 调用回退工单接口 daquUniversalApproval | ||
| 526 | - | ||
| 527 | - if( userStore.userInfo.roles.includes('regional_manager')){ // 大区经理 | ||
| 528 | - await daquUniversalApproval(requestData) | ||
| 529 | - } | ||
| 530 | - if( userStore.userInfo.roles.includes('Inspector_global')){ // 督察员 | ||
| 531 | - await dcyUniversalApproval(requestData); | ||
| 532 | - } | ||
| 533 | - if( userStore.userInfo.roles.includes('patrol_global')){ // 全域巡查员 | ||
| 534 | - await qyUniversalApproval(requestData); | ||
| 535 | - } | ||
| 536 | - | ||
| 537 | - uni.showToast({title: '结束成功', icon: 'success', duration: 1000}); | ||
| 538 | - rejectModalShow.value = false; | ||
| 539 | - paging.value?.reload(); // 刷新列表 | ||
| 540 | - } else if (res.cancel) { | ||
| 541 | - console.log("用户点击取消"); | 489 | + await callApprovalApi(requestData, item.taskKey); |
| 490 | + uni.showToast({title: '结束成功', icon: 'success'}); | ||
| 491 | + refreshOrderList(); | ||
| 542 | } | 492 | } |
| 543 | - }, | 493 | + } |
| 544 | }); | 494 | }); |
| 545 | } | 495 | } |
| 546 | } catch (error) { | 496 | } catch (error) { |
| 547 | console.error('处理工单失败:', error); | 497 | console.error('处理工单失败:', error); |
| 548 | - uni.showToast({title: '处理失败,请重试', icon: 'none'}); | 498 | + uni.showToast({title: resData.msg, icon: 'none'}); |
| 549 | } | 499 | } |
| 550 | }; | 500 | }; |
| 551 | -// 待办-回退工单(打开回退modal) | 501 | + |
| 502 | +// 回退工单-打开弹窗 | ||
| 552 | const handleReject = (item) => { | 503 | const handleReject = (item) => { |
| 553 | - console.log('123213') | ||
| 554 | - // 校验工单有效性 | ||
| 555 | - if (!item || !item.id) { | ||
| 556 | - uni.showToast({title: '工单信息异常,无法回退', icon: 'none'}); | ||
| 557 | - return; | ||
| 558 | - } | 504 | + if (!item?.id) return uni.showToast({title: '工单信息异常,无法回退', icon: 'none'}); |
| 559 | currentRejectItem.value = item; | 505 | currentRejectItem.value = item; |
| 560 | - rejectReason.value = ''; // 清空上次输入 | ||
| 561 | - rejectImgs.clearImgs(); // 改造后:使用组合式函数的清空方法 | ||
| 562 | - rejectModalShow.value = true; // 显示回退modal | 506 | + rejectReason.value = ''; |
| 507 | + rejectImgs.clearImgs(); | ||
| 508 | + rejectModalShow.value = true; | ||
| 563 | }; | 509 | }; |
| 564 | -// 回退modal - 取消按钮 | 510 | + |
| 511 | +// 关闭回退弹窗-重置状态 | ||
| 565 | const handleRejectModalCancel = () => { | 512 | const handleRejectModalCancel = () => { |
| 566 | rejectModalShow.value = false; | 513 | rejectModalShow.value = false; |
| 567 | rejectReason.value = ''; | 514 | rejectReason.value = ''; |
| 568 | - rejectImgs.clearImgs(); // 改造后:使用组合式函数的清空方法 | 515 | + rejectImgs.clearImgs(); |
| 569 | }; | 516 | }; |
| 517 | + | ||
| 570 | // 确认回退工单 | 518 | // 确认回退工单 |
| 571 | const confirmReject = async () => { | 519 | const confirmReject = async () => { |
| 572 | - // 严格校验回退原因(去除首尾空格) | ||
| 573 | - const rejectReasonTrim = rejectReason.value.trim(); | ||
| 574 | - if (!rejectReasonTrim) { | ||
| 575 | - uni.showToast({title: '请填写回退原因', icon: 'none', duration: 1000}); | ||
| 576 | - return; | ||
| 577 | - } | ||
| 578 | - // 校验当前工单有效性 | ||
| 579 | - if (!currentRejectItem.value || !currentRejectItem.value.id) { | ||
| 580 | - uni.showToast({title: '工单信息异常,无法提交', icon: 'none', duration: 1000}); | ||
| 581 | - rejectModalShow.value = false; | ||
| 582 | - return; | ||
| 583 | - } | 520 | + const reason = rejectReason.value.trim(); |
| 521 | + if (!reason) return uni.showToast({title: '请填写回退原因', icon: 'none'}); | ||
| 522 | + const item = currentRejectItem.value; | ||
| 523 | + if (!item?.id) return uni.showToast({title: '工单信息异常', icon: 'none'}); | ||
| 524 | + | ||
| 525 | + uni.showLoading({title: '提交中...', mask: true}); | ||
| 584 | try { | 526 | try { |
| 585 | - // 显示加载中,防止重复提交 | ||
| 586 | - uni.showLoading({title: '提交中...', mask: true}); | ||
| 587 | - // 构建请求参数 | ||
| 588 | const requestData = { | 527 | const requestData = { |
| 589 | - "returnImgs": rejectImgs.getSuccessImgUrls(), // 改造后:获取上传成功的图片URL数组 | ||
| 590 | - "workerDataId": currentRejectItem.value.id, | ||
| 591 | - "taskKey": currentRejectItem.value.taskKey, | ||
| 592 | - "taskId": currentRejectItem.value.taskId, | ||
| 593 | - | ||
| 594 | - "operateType": nextStepMap[currentRejectItem.value.taskKey].operateTypeNoPass, | ||
| 595 | - "agree": 1, | ||
| 596 | - "reason": rejectReasonTrim | 528 | + returnImgs: rejectImgs.getSuccessImgUrls(), workerDataId: item.id, taskKey: item.taskKey, |
| 529 | + taskId: item.taskId, operateType: nextStepMap[item.taskKey].operateTypeNoPass, agree:1, reason | ||
| 597 | }; | 530 | }; |
| 598 | - // 调用回退工单接口 | ||
| 599 | - if(currentRejectItem.value.taskKey=='shRegionManager'){ // 对督察员单子 回退 | ||
| 600 | - const res = await dcyUniversalApproval(requestData); | ||
| 601 | - } | ||
| 602 | - if(currentRejectItem.value.taskKey=='regionManager'){ // 对全域巡查员单子 回退 | ||
| 603 | - const res = await qyUniversalApproval(requestData); | ||
| 604 | - } | ||
| 605 | - // 对大区经理单子 回退 | ||
| 606 | - uni.showToast({title: '回退成功', icon: 'success', duration: 1000}); | ||
| 607 | - rejectModalShow.value = false; | ||
| 608 | - paging.value?.reload(); // 刷新列表 | 531 | + await callApprovalApi(requestData, item.taskKey); |
| 532 | + uni.showToast({title: '回退成功', icon: 'success'}); | ||
| 533 | + handleRejectModalCancel(); | ||
| 534 | + refreshOrderList(); | ||
| 609 | } catch (error) { | 535 | } catch (error) { |
| 610 | console.error('回退工单失败:', error); | 536 | console.error('回退工单失败:', error); |
| 611 | - uni.showToast({title: '网络异常,回退失败', icon: 'none', duration: 1000}); | 537 | + uni.showToast({title: '回退失败,请重试', icon: 'none'}); |
| 612 | } finally { | 538 | } finally { |
| 613 | - // 隐藏加载中 | ||
| 614 | uni.hideLoading(); | 539 | uni.hideLoading(); |
| 615 | } | 540 | } |
| 616 | }; | 541 | }; |
| 542 | + | ||
| 617 | // 新增工单 | 543 | // 新增工单 |
| 618 | const handleAddOrder = () => { | 544 | const handleAddOrder = () => { |
| 619 | - if (userStore.userInfo?.roles.includes('patrol_global')) { // 全域巡查员 | ||
| 620 | - uni.navigateTo({ | ||
| 621 | - url: '/pages-sub/problem/regional-order-manage/add-patrol-order' | ||
| 622 | - }); | ||
| 623 | - } | ||
| 624 | - if (userStore.userInfo?.roles.includes('regional_manager')) { // 大区经理 | ||
| 625 | - uni.navigateTo({ | ||
| 626 | - url: '/pages-sub/problem/regional-order-manage/add-order' | ||
| 627 | - }); | ||
| 628 | - } | ||
| 629 | - if (userStore.userInfo?.roles.includes('Inspector_global')) { // 督察员 | ||
| 630 | - uni.navigateTo({ | ||
| 631 | - url: '/pages-sub/problem/regional-order-manage/add-order' | ||
| 632 | - }); | ||
| 633 | - } | 545 | + const pageUrl = USER_ROLES.includes('patrol_global') |
| 546 | + ? '/pages-sub/problem/regional-order-manage/add-patrol-order' | ||
| 547 | + : '/pages-sub/problem/regional-order-manage/add-order'; | ||
| 548 | + navToOrderPage(pageUrl); | ||
| 634 | }; | 549 | }; |
| 635 | -// 验收弹窗 - 取消按钮(清空状态) | 550 | + |
| 551 | +// 关闭验收弹窗-重置状态 | ||
| 636 | const handleAcceptModalCancel = () => { | 552 | const handleAcceptModalCancel = () => { |
| 637 | acceptModalShow.value = false; | 553 | acceptModalShow.value = false; |
| 638 | - acceptReason.value = ''; // 清空验收原因 | ||
| 639 | - acceptRadioValue.value = '0'; // 重置单选框为“通过” | ||
| 640 | - acceptImgs.clearImgs(); // 清空验收图片 | 554 | + acceptReason.value = ''; |
| 555 | + acceptRadioValue.value = '0'; | ||
| 556 | + acceptImgs.clearImgs(); | ||
| 641 | }; | 557 | }; |
| 642 | -// 验收弹窗 - 确定按钮(含returnImgs传参) | 558 | + |
| 559 | +// 验收提交 | ||
| 643 | const handleAcceptModalConfirm = async () => { | 560 | const handleAcceptModalConfirm = async () => { |
| 644 | - // 1. 校验验收原因是否为空 | ||
| 645 | - if (!acceptReason.value.trim()) { | ||
| 646 | - uni.showToast({title: '请填写验收原因', icon: 'none', duration: 1000}); | ||
| 647 | - return; | ||
| 648 | - } | ||
| 649 | - // 2. 校验验收原因长度 | ||
| 650 | - if (acceptReason.value.length > 200) { | ||
| 651 | - uni.showToast({title: '验收原因最多200字', icon: 'none', duration: 1000}); | ||
| 652 | - return; | ||
| 653 | - } | ||
| 654 | - try { | ||
| 655 | - // 3. 构建请求参数(含returnImgs) | ||
| 656 | - console.log(currentAcceptItem.value) | ||
| 657 | - console.log( userStore.userInfo.roles) | ||
| 658 | - console.log( userStore.userInfo.roles.includes('Inspector_global')) | ||
| 659 | - // | ||
| 660 | - if( userStore.userInfo.roles.includes('regional_manager')){ // 大区经理验收 | ||
| 661 | - let postData = { | ||
| 662 | - "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | ||
| 663 | - "taskKey": currentAcceptItem.value.taskKey, | ||
| 664 | - "workerDataId": currentAcceptItem.value.id, | ||
| 665 | - "taskId": currentAcceptItem.value.taskId, | ||
| 666 | - "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | ||
| 667 | - "reason": acceptReason.value.trim(), | ||
| 668 | - "agree":acceptRadioValue.value, | ||
| 669 | - } | ||
| 670 | - await daquUniversalApproval(postData); | ||
| 671 | - } | ||
| 672 | - // | ||
| 673 | - if( userStore.userInfo.roles.includes('patrol_global')){ // 全域巡查员验收 | ||
| 674 | - let postData = { | ||
| 675 | - "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | ||
| 676 | - "taskKey": currentAcceptItem.value.taskKey, | ||
| 677 | - "taskId": currentAcceptItem.value.taskId, | ||
| 678 | - "workerDataId": currentAcceptItem.value.id, | ||
| 679 | - "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | ||
| 680 | - "reason": acceptReason.value.trim(), | ||
| 681 | - "agree": acceptRadioValue.value | ||
| 682 | - } | ||
| 683 | - await qyUniversalApproval(postData); | ||
| 684 | - } | ||
| 685 | - // | ||
| 686 | - if( userStore.userInfo.roles.includes('Inspector_global')){ // 督察员验收 | ||
| 687 | - let postData = { | ||
| 688 | - "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | ||
| 689 | - "taskKey": currentAcceptItem.value.taskKey, | ||
| 690 | - "taskId": currentAcceptItem.value.taskId, | ||
| 691 | - "workerDataId": currentAcceptItem.value.id, | ||
| 692 | - "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | ||
| 693 | - "reason": acceptReason.value.trim(), | ||
| 694 | - "agree": acceptRadioValue.value | ||
| 695 | - } | ||
| 696 | - await dcyUniversalApproval(postData); | ||
| 697 | - } | 561 | + const reason = acceptReason.value.trim(); |
| 562 | + if (!reason) return uni.showToast({title: '请填写验收原因', icon: 'none'}); | ||
| 563 | + if (reason.length > 200) return uni.showToast({title: '验收原因最多200字', icon: 'none'}); | ||
| 564 | + | ||
| 565 | + const item = currentAcceptItem.value; | ||
| 566 | + if (!item?.id) return uni.showToast({title: '工单信息异常', icon: 'none'}); | ||
| 698 | 567 | ||
| 699 | - // 4. 操作成功处理 | ||
| 700 | - uni.showToast({title: '提交成功', icon: 'success', duration: 1000}); | ||
| 701 | - handleAcceptModalCancel(); // 清空状态 | ||
| 702 | - paging.value?.reload(); // 刷新工单列表 | 568 | + try { |
| 569 | + const postData = { | ||
| 570 | + returnImgs: acceptImgs.getSuccessImgUrls(), taskKey: item.taskKey, workerDataId: item.id, | ||
| 571 | + taskId: item.taskId, agree: acceptRadioValue.value, reason, | ||
| 572 | + operateType: acceptRadioValue.value === '0' ? nextStepMap[item.taskKey].operateTypePass : nextStepMap[item.taskKey].operateTypeNoPass | ||
| 573 | + }; | ||
| 574 | + await callApprovalApi(postData, item.taskKey); | ||
| 575 | + uni.showToast({title: '提交成功', icon: 'success'}); | ||
| 576 | + handleAcceptModalCancel(); | ||
| 577 | + refreshOrderList(); | ||
| 703 | } catch (error) { | 578 | } catch (error) { |
| 704 | - // 5. 操作失败处理 | ||
| 705 | console.error('验收失败:', error); | 579 | console.error('验收失败:', error); |
| 706 | - uni.showToast({title: '验收提交失败,请重试', icon: 'none', duration: 1000}); | 580 | + uni.showToast({title: '验收提交失败,请重试', icon: 'none'}); |
| 707 | } | 581 | } |
| 708 | }; | 582 | }; |
| 709 | -// 页面初始化 | 583 | + |
| 584 | +// ========== 页面生命周期 ========== | ||
| 710 | onLoad(() => { | 585 | onLoad(() => { |
| 711 | - // 初始化加载列表 | ||
| 712 | - paging.value?.reload(); | 586 | + refreshOrderList(); |
| 713 | }); | 587 | }); |
| 714 | </script> | 588 | </script> |
| 715 | 589 | ||
| @@ -734,15 +608,10 @@ onLoad(() => { | @@ -734,15 +608,10 @@ onLoad(() => { | ||
| 734 | .select-wrap { | 608 | .select-wrap { |
| 735 | width: 120rpx; | 609 | width: 120rpx; |
| 736 | margin-right: 20rpx; | 610 | margin-right: 20rpx; |
| 737 | - | ||
| 738 | - :deep(.u-select) { | 611 | + :deep(.u-select), :deep(.u-input__placeholder) { |
| 739 | width: 100%; | 612 | width: 100%; |
| 740 | font-size: 28rpx; | 613 | font-size: 28rpx; |
| 741 | } | 614 | } |
| 742 | - | ||
| 743 | - :deep(.u-input__placeholder) { | ||
| 744 | - font-size: 28rpx; | ||
| 745 | - } | ||
| 746 | } | 615 | } |
| 747 | 616 | ||
| 748 | .search-input-wrap { | 617 | .search-input-wrap { |
| @@ -758,31 +627,14 @@ onLoad(() => { | @@ -758,31 +627,14 @@ onLoad(() => { | ||
| 758 | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); | 627 | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); |
| 759 | } | 628 | } |
| 760 | 629 | ||
| 761 | -.card-body { | ||
| 762 | - | ||
| 763 | -} | ||
| 764 | - | ||
| 765 | -// 回退modal样式 | ||
| 766 | -.reject-modal-content { | 630 | +// 弹窗公共样式 |
| 631 | +.reject-modal-content, .accept-modal-content { | ||
| 767 | width: 100%; | 632 | width: 100%; |
| 768 | box-sizing: border-box; | 633 | box-sizing: border-box; |
| 769 | padding: 10rpx 0; | 634 | padding: 10rpx 0; |
| 770 | } | 635 | } |
| 771 | 636 | ||
| 772 | -.textarea-label { | ||
| 773 | - font-size: 28rpx; | ||
| 774 | - color: #333; | ||
| 775 | - margin-bottom: 10rpx; | ||
| 776 | - | ||
| 777 | - .required-mark { | ||
| 778 | - color: #f56c6c; | ||
| 779 | - margin-left: 4rpx; | ||
| 780 | - } | ||
| 781 | -} | ||
| 782 | - | ||
| 783 | .upload-wrap { | 637 | .upload-wrap { |
| 784 | - margin-top: 20rpx; | ||
| 785 | - | ||
| 786 | .upload-title { | 638 | .upload-title { |
| 787 | font-size: 28rpx; | 639 | font-size: 28rpx; |
| 788 | color: #333; | 640 | color: #333; |
| @@ -790,37 +642,20 @@ onLoad(() => { | @@ -790,37 +642,20 @@ onLoad(() => { | ||
| 790 | } | 642 | } |
| 791 | } | 643 | } |
| 792 | 644 | ||
| 793 | -.mt-20 { | ||
| 794 | - margin-top: 20rpx; | ||
| 795 | -} | ||
| 796 | - | ||
| 797 | -.mt-30 { | ||
| 798 | - margin-top: 30rpx; | ||
| 799 | -} | ||
| 800 | - | ||
| 801 | -// 养护组长验收弹窗样式 | ||
| 802 | -.accept-modal-content { | ||
| 803 | - width: 100%; | ||
| 804 | - box-sizing: border-box; | ||
| 805 | -} | ||
| 806 | - | 645 | +// 验收弹窗单选框样式 |
| 807 | .radio-group-wrap { | 646 | .radio-group-wrap { |
| 808 | display: flex; | 647 | display: flex; |
| 809 | align-items: center; | 648 | align-items: center; |
| 810 | - gap: 40rpx; // 单选框之间的间距 | 649 | + gap: 40rpx; |
| 811 | font-size: 28rpx; | 650 | font-size: 28rpx; |
| 812 | margin-bottom: 20rpx; | 651 | margin-bottom: 20rpx; |
| 813 | } | 652 | } |
| 814 | 653 | ||
| 815 | .textarea-wrap { | 654 | .textarea-wrap { |
| 816 | width: 100%; | 655 | width: 100%; |
| 817 | - margin-top: 30rpx; | ||
| 818 | } | 656 | } |
| 819 | 657 | ||
| 820 | -.modal-btn-wrap { | ||
| 821 | - display: flex; | ||
| 822 | - align-items: center; | ||
| 823 | - justify-content: flex-end; | ||
| 824 | - padding-right: 10rpx; | ||
| 825 | -} | 658 | +// 间距公共样式 |
| 659 | +.mt-20 { margin-top: 20rpx; } | ||
| 660 | +.mt-30 { margin-top: 30rpx; } | ||
| 826 | </style> | 661 | </style> |
| 827 | \ No newline at end of file | 662 | \ No newline at end of file |
pages-sub/problem/regional-order-manage/order-detail.vue
| @@ -267,23 +267,23 @@ | @@ -267,23 +267,23 @@ | ||
| 267 | </view> | 267 | </view> |
| 268 | 268 | ||
| 269 | <!-- activeTab==0的时候才出现, 也就是待办 --> | 269 | <!-- activeTab==0的时候才出现, 也就是待办 --> |
| 270 | - <view v-if="activeTab==0&&nextStepMap[orderDetail.taskKey]" class="fixed-bottom-btn-wrap"> | ||
| 271 | - <view class="u-body-item u-flex common-justify-between common-item-center "> | ||
| 272 | - <up-button type="warning" size="normal" @click="handleReject(orderDetail)" | ||
| 273 | - v-show="nextStepMap[orderDetail.taskKey].backShow">回退 | ||
| 274 | - </up-button> | ||
| 275 | - | ||
| 276 | - <up-button type="success" size="normal" @click="handleRenew(orderDetail)" | ||
| 277 | - v-show="nextStepMap[orderDetail.taskKey].renewShow">重新提交 | ||
| 278 | - </up-button> | ||
| 279 | - | ||
| 280 | - <up-button type="primary" size="normal" @click="handleProcess(orderDetail)">{{ | ||
| 281 | - nextStepMap[orderDetail.taskKey].btnText | ||
| 282 | - }} | ||
| 283 | - </up-button> | ||
| 284 | - | ||
| 285 | - </view> | ||
| 286 | - </view> | 270 | +<!-- <view v-if="activeTab==0&&nextStepMap[orderDetail.taskKey]" class="fixed-bottom-btn-wrap">--> |
| 271 | +<!-- <view class="u-body-item u-flex common-justify-between common-item-center ">--> | ||
| 272 | +<!-- <up-button type="warning" size="normal" @click="handleReject(orderDetail)"--> | ||
| 273 | +<!-- v-show="nextStepMap[orderDetail.taskKey].backShow">回退--> | ||
| 274 | +<!-- </up-button>--> | ||
| 275 | + | ||
| 276 | +<!-- <up-button type="success" size="normal" @click="handleRenew(orderDetail)"--> | ||
| 277 | +<!-- v-show="nextStepMap[orderDetail.taskKey].renewShow">重新提交--> | ||
| 278 | +<!-- </up-button>--> | ||
| 279 | + | ||
| 280 | +<!-- <up-button type="primary" size="normal" @click="handleProcess(orderDetail)">{{--> | ||
| 281 | +<!-- nextStepMap[orderDetail.taskKey].btnText--> | ||
| 282 | +<!-- }}--> | ||
| 283 | +<!-- </up-button>--> | ||
| 284 | + | ||
| 285 | +<!-- </view>--> | ||
| 286 | +<!-- </view>--> | ||
| 287 | 287 | ||
| 288 | <!-- 回退原因弹窗(新增图片上传) --> | 288 | <!-- 回退原因弹窗(新增图片上传) --> |
| 289 | <up-modal | 289 | <up-modal |
pages-sub/problem/work-order-manage/add-maintain-order.vue
| @@ -492,11 +492,11 @@ const loadCoProcessorList = async () => { | @@ -492,11 +492,11 @@ const loadCoProcessorList = async () => { | ||
| 492 | }).filter(Boolean); // 过滤null项 | 492 | }).filter(Boolean); // 过滤null项 |
| 493 | } else { | 493 | } else { |
| 494 | coProcessorList.value = [] | 494 | coProcessorList.value = [] |
| 495 | - uni.showToast({ | ||
| 496 | - title: '暂无共同处理人数据', | ||
| 497 | - icon: 'none', | ||
| 498 | - duration: 2000 | ||
| 499 | - }); | 495 | + // uni.showToast({ |
| 496 | + // title: '暂无共同处理人数据', | ||
| 497 | + // icon: 'none', | ||
| 498 | + // duration: 1000 | ||
| 499 | + // }); | ||
| 500 | console.warn('loadCoProcessorList提示:处理人列表为空'); | 500 | console.warn('loadCoProcessorList提示:处理人列表为空'); |
| 501 | } | 501 | } |
| 502 | } catch (err) { | 502 | } catch (err) { |
pages.json
| @@ -10,7 +10,8 @@ | @@ -10,7 +10,8 @@ | ||
| 10 | { | 10 | { |
| 11 | "path": "pages/login/index", | 11 | "path": "pages/login/index", |
| 12 | "style": { | 12 | "style": { |
| 13 | - "navigationBarTitleText": "登录" | 13 | + "navigationBarTitleText": "登录", |
| 14 | + "navigationStyle": "custom" | ||
| 14 | } | 15 | } |
| 15 | }, | 16 | }, |
| 16 | { | 17 | { |
| @@ -166,7 +167,7 @@ | @@ -166,7 +167,7 @@ | ||
| 166 | 167 | ||
| 167 | { | 168 | { |
| 168 | "path": "regional-order-manage/add-patrol-order", | 169 | "path": "regional-order-manage/add-patrol-order", |
| 169 | - "style": { "navigationBarTitleText": "待派单" } | 170 | + "style": { "navigationBarTitleText": "提交工单" } |
| 170 | }, | 171 | }, |
| 171 | 172 | ||
| 172 | { | 173 | { |
| @@ -197,7 +198,21 @@ | @@ -197,7 +198,21 @@ | ||
| 197 | { | 198 | { |
| 198 | "path": "tree-archive/index", | 199 | "path": "tree-archive/index", |
| 199 | "style": { "navigationBarTitleText": "行道树档案" } | 200 | "style": { "navigationBarTitleText": "行道树档案" } |
| 201 | + }, | ||
| 202 | + { | ||
| 203 | + "path": "tree-archive/treeRecord", | ||
| 204 | + "style": { "navigationBarTitleText": "行道树记录" } | ||
| 205 | + }, | ||
| 206 | + { | ||
| 207 | + "path": "tree-archive/addTree", | ||
| 208 | + "style": { "navigationBarTitleText": "新增行道树" } | ||
| 209 | + }, | ||
| 210 | + { | ||
| 211 | + "path": "tree-archive/editTree", | ||
| 212 | + "style": { "navigationBarTitleText": "编辑行道树" } | ||
| 200 | } | 213 | } |
| 214 | + | ||
| 215 | + | ||
| 201 | ] | 216 | ] |
| 202 | } | 217 | } |
| 203 | ], | 218 | ], |
pages/login/index.vue
| 1 | <template> | 1 | <template> |
| 2 | <view class="login-page"> | 2 | <view class="login-page"> |
| 3 | - <!-- 纯CSS渐变动效背景(替代粒子动画,兼容所有版本) --> | ||
| 4 | - <view class="bg-animation"></view> | 3 | + <!-- 顶部标题区 - 加高 + 左下大圆角 + 底部蓝色过滤阴影 + 从浅到深 蓝色渐变背景 --> |
| 4 | + <view class="top-title"> | ||
| 5 | + <text class="welcome-text">你好,欢迎光临</text> | ||
| 6 | + <text class="platform-name">全域智能运营管理平台</text> | ||
| 7 | + </view> | ||
| 5 | 8 | ||
| 6 | - <!-- 登录表单区域(悬浮层) --> | 9 | + <!-- 登录表单区域 - 往上偏移 盖住top-title一部分 --> |
| 7 | <view class="login-form"> | 10 | <view class="login-form"> |
| 8 | - <!-- 登录标题(简约大气) --> | ||
| 9 | - <view class="login-title">园林登录</view> | 11 | + <!-- 登录标题 --> |
| 12 | + <view class="login-title">账户登录</view> | ||
| 10 | 13 | ||
| 11 | - <!-- 账号输入框 --> | ||
| 12 | - <view class="form-item"> | ||
| 13 | - <up-input | ||
| 14 | - v-model="form.account" | ||
| 15 | - placeholder="请输入登录账号" | ||
| 16 | - border="surround" | ||
| 17 | - clearable | ||
| 18 | - maxlength="30" | ||
| 19 | - input-align="left" | ||
| 20 | - :disabled="isLoading" | ||
| 21 | - @blur="checkAccount" | ||
| 22 | - :custom-style="{ | ||
| 23 | - backgroundColor: 'rgba(255, 255, 255, 0.9)', | ||
| 24 | - borderColor: '#e5e7eb' | ||
| 25 | - }" | 14 | + <!-- ✅ 核心:和工单页同款 up-form 表单校验容器 --> |
| 15 | + <up-form | ||
| 16 | + label-position="left" | ||
| 17 | + :model="form" | ||
| 18 | + ref="loginFormRef" | ||
| 19 | + labelWidth="0" | ||
| 20 | + > | ||
| 21 | + <!-- 账号输入框 + 校验 --> | ||
| 22 | + <up-form-item | ||
| 23 | + prop="account" | ||
| 26 | > | 24 | > |
| 27 | - <template #prefix> | ||
| 28 | - <up-icon name="account" color="#6b7280" size="20"></up-icon> | ||
| 29 | - </template> | ||
| 30 | - </up-input> | ||
| 31 | - <!-- 账号错误提示 --> | ||
| 32 | - <view class="error-tip" v-if="error.account">{{ error.account }}</view> | ||
| 33 | - </view> | 25 | + <up-input |
| 26 | + v-model="form.account" | ||
| 27 | + border="surround" | ||
| 28 | + clearable | ||
| 29 | + maxlength="30" | ||
| 30 | + input-align="left" | ||
| 31 | + fontSize="16px" | ||
| 32 | + :disabled="isLoading" | ||
| 33 | + shape="circle" | ||
| 34 | + placeholder="请输入账户" | ||
| 35 | + selectionStart="15" | ||
| 36 | + selectionEnd="15" | ||
| 37 | + @blur="() => loginFormRef.validateField('account')" | ||
| 38 | + /> | ||
| 39 | + </up-form-item> | ||
| 34 | 40 | ||
| 35 | - <!-- 密码输入框(移除查看密码功能) --> | ||
| 36 | - <view class="form-item"> | ||
| 37 | - <up-input | ||
| 38 | - v-model="form.password" | ||
| 39 | - placeholder="请输入登录密码" | ||
| 40 | - maxlength="20" | ||
| 41 | - border="surround" | ||
| 42 | - clearable | ||
| 43 | - input-align="left" | ||
| 44 | - type="password" | ||
| 45 | - :disabled="isLoading" | ||
| 46 | - @blur="checkPassword" | ||
| 47 | - :custom-style="{ | ||
| 48 | - backgroundColor: 'rgba(255, 255, 255, 0.9)', | ||
| 49 | - borderColor: '#e5e7eb' | ||
| 50 | - }" | 41 | + <!-- 密码输入框 + 校验 --> |
| 42 | + <up-form-item | ||
| 43 | + prop="password" | ||
| 51 | > | 44 | > |
| 52 | - <template #prefix> | ||
| 53 | - <up-icon name="lock" color="#6b7280" size="20"></up-icon> | ||
| 54 | - </template> | ||
| 55 | - </up-input> | ||
| 56 | - <!-- 密码错误提示 --> | ||
| 57 | - <view class="error-tip" v-if="error.password">{{ error.password }}</view> | ||
| 58 | - </view> | 45 | + <up-input |
| 46 | + v-model="form.password" | ||
| 47 | + placeholder="请输入密码" | ||
| 48 | + maxlength="20" | ||
| 49 | + border="surround" | ||
| 50 | + clearable | ||
| 51 | + input-align="left" | ||
| 52 | + type="password" | ||
| 53 | + :disabled="isLoading" | ||
| 54 | + shape="circle" | ||
| 55 | + selectionStart="5" | ||
| 56 | + selectionEnd="5" | ||
| 57 | + @blur="() => loginFormRef.validateField('password')" | ||
| 58 | + /> | ||
| 59 | + </up-form-item> | ||
| 60 | + </up-form> | ||
| 59 | 61 | ||
| 60 | <!-- 登录按钮 --> | 62 | <!-- 登录按钮 --> |
| 61 | <up-button | 63 | <up-button |
| @@ -64,44 +66,58 @@ | @@ -64,44 +66,58 @@ | ||
| 64 | size="large" | 66 | size="large" |
| 65 | :loading="isLoading" | 67 | :loading="isLoading" |
| 66 | @click="handleLogin" | 68 | @click="handleLogin" |
| 67 | - :custom-style="{ | ||
| 68 | - | ||
| 69 | - }" | 69 | + shape="circle" |
| 70 | > | 70 | > |
| 71 | 登录 | 71 | 登录 |
| 72 | </up-button> | 72 | </up-button> |
| 73 | </view> | 73 | </view> |
| 74 | + | ||
| 75 | + <!-- 版权信息 --> | ||
| 76 | + <view class="copyright">蓟城山水集团版权所有</view> | ||
| 74 | </view> | 77 | </view> |
| 75 | </template> | 78 | </template> |
| 76 | 79 | ||
| 77 | <script setup> | 80 | <script setup> |
| 78 | -import { ref, reactive, onMounted } from 'vue'; | 81 | +import { ref, reactive, onMounted, nextTick } from 'vue'; |
| 79 | import { useUserStore } from '@/pinia/user'; | 82 | import { useUserStore } from '@/pinia/user'; |
| 80 | import globalConfig from '@/common/config/global'; | 83 | import globalConfig from '@/common/config/global'; |
| 81 | 84 | ||
| 82 | -// 表单数据 | 85 | +// ========== 【全局实例 & 基础状态】 和工单页写法一致 ========== |
| 86 | +const userStore = useUserStore(); | ||
| 87 | +const loginFormRef = ref(null); // 表单ref 用于校验 | ||
| 88 | +const isLoading = ref(false); // 登录加载状态 | ||
| 89 | + | ||
| 90 | +// ========== 【表单数据】 和工单页一致的 reactive 声明 ========== | ||
| 83 | const form = reactive({ | 91 | const form = reactive({ |
| 84 | - account: '', // 账号 | ||
| 85 | - password: '' // 密码 | 92 | + account: '', // 账号 |
| 93 | + password: '' // 密码 | ||
| 86 | }); | 94 | }); |
| 87 | 95 | ||
| 88 | -// 状态管理 | ||
| 89 | -const isLoading = ref(false); | ||
| 90 | -const error = reactive({ | ||
| 91 | - account: '', | ||
| 92 | - password: '' | 96 | +// ========== 【表单校验规则】 ✅核心 和工单页1:1同款校验规则写法 ========== |
| 97 | +const loginFormRules = reactive({ | ||
| 98 | + // 账号校验:必填 + 长度限制 2-30位(合理账号长度,可自行调整) | ||
| 99 | + account: [ | ||
| 100 | + { type: 'string', required: true, message: '请输入登录账号', trigger: ['change', 'blur'] }, | ||
| 101 | + { type: 'string', min: 2, max: 30, message: '账号长度为2-30个字符', trigger: ['change', 'blur'] } | ||
| 102 | + ], | ||
| 103 | + // 密码校验:必填 + 长度限制 6-20位(行业通用密码长度,可自行调整) | ||
| 104 | + password: [ | ||
| 105 | + { type: 'string', required: true, message: '请输入登录密码', trigger: ['change', 'blur'] }, | ||
| 106 | + { type: 'string', min: 6, max: 20, message: '密码长度为6-20个字符', trigger: ['change', 'blur'] } | ||
| 107 | + ] | ||
| 93 | }); | 108 | }); |
| 94 | 109 | ||
| 95 | -// 实例化 Pinia 用户仓库 | ||
| 96 | -const userStore = useUserStore(); | ||
| 97 | - | ||
| 98 | -// 页面加载时初始化 | 110 | +// ========== 【生命周期】 nextTick 设置校验规则 和工单页一致 ========== |
| 99 | onMounted(() => { | 111 | onMounted(() => { |
| 100 | // 检查登录态 | 112 | // 检查登录态 |
| 101 | checkLoginStatus(); | 113 | checkLoginStatus(); |
| 114 | + // nextTick确保表单挂载完成再赋值规则,修复校验不生效bug,和工单页写法一致 | ||
| 115 | + nextTick(() => { | ||
| 116 | + loginFormRef.value?.setRules(loginFormRules); | ||
| 117 | + }); | ||
| 102 | }); | 118 | }); |
| 103 | 119 | ||
| 104 | -// 检查登录状态 | 120 | +// ========== 【检查登录状态】 原有逻辑不变 ========== |
| 105 | const checkLoginStatus = () => { | 121 | const checkLoginStatus = () => { |
| 106 | try { | 122 | try { |
| 107 | // 已登录则直接跳首页 | 123 | // 已登录则直接跳首页 |
| @@ -109,7 +125,6 @@ const checkLoginStatus = () => { | @@ -109,7 +125,6 @@ const checkLoginStatus = () => { | ||
| 109 | uni.switchTab({ | 125 | uni.switchTab({ |
| 110 | url: '/pages/workbench/index', | 126 | url: '/pages/workbench/index', |
| 111 | fail: () => { | 127 | fail: () => { |
| 112 | - // 非tabBar页面用redirectTo | ||
| 113 | uni.reLaunch({ url: '/pages/workbench/index' }); | 128 | uni.reLaunch({ url: '/pages/workbench/index' }); |
| 114 | } | 129 | } |
| 115 | }); | 130 | }); |
| @@ -120,38 +135,14 @@ const checkLoginStatus = () => { | @@ -120,38 +135,14 @@ const checkLoginStatus = () => { | ||
| 120 | } | 135 | } |
| 121 | }; | 136 | }; |
| 122 | 137 | ||
| 123 | -// 校验账号 | ||
| 124 | -const checkAccount = () => { | ||
| 125 | - if (!form.account) { | ||
| 126 | - error.account = '请输入登录账号'; | ||
| 127 | - } else { | ||
| 128 | - error.account = ''; | ||
| 129 | - } | ||
| 130 | -}; | ||
| 131 | - | ||
| 132 | -// 校验密码 | ||
| 133 | -const checkPassword = () => { | ||
| 134 | - if (!form.password) { | ||
| 135 | - error.password = '请输入登录密码'; | ||
| 136 | - } else { | ||
| 137 | - error.password = ''; | ||
| 138 | - } | ||
| 139 | -}; | ||
| 140 | - | ||
| 141 | -// 表单整体校验 | ||
| 142 | -const validateForm = () => { | ||
| 143 | - checkAccount(); | ||
| 144 | - checkPassword(); | ||
| 145 | - return !error.account && !error.password; | ||
| 146 | -}; | ||
| 147 | - | ||
| 148 | -// 登录处理 | 138 | +// ========== 【核心登录方法】 ✅ 完整表单校验 + 登录逻辑,和工单页submit提交逻辑一致 ========== |
| 149 | const handleLogin = async () => { | 139 | const handleLogin = async () => { |
| 150 | - if (!validateForm()) return; | ||
| 151 | - | ||
| 152 | - isLoading.value = true; | ||
| 153 | - | ||
| 154 | try { | 140 | try { |
| 141 | + // ✅ 第一步:先执行表单整体校验,通过后再执行登录逻辑(和工单页submitWorkOrder写法一致) | ||
| 142 | + await loginFormRef.value.validate(); | ||
| 143 | + | ||
| 144 | + isLoading.value = true; | ||
| 145 | + // 执行登录请求 | ||
| 155 | await userStore.login({ | 146 | await userStore.login({ |
| 156 | username: form.account, | 147 | username: form.account, |
| 157 | password: form.password | 148 | password: form.password |
| @@ -170,16 +161,15 @@ const handleLogin = async () => { | @@ -170,16 +161,15 @@ const handleLogin = async () => { | ||
| 170 | }); | 161 | }); |
| 171 | }, 1000); | 162 | }, 1000); |
| 172 | } catch (err) { | 163 | } catch (err) { |
| 173 | - console.error('登录失败详情:', err); | ||
| 174 | - const errorMsg = | ||
| 175 | - err.message === '网络异常,请稍后重试' | ||
| 176 | - ? '网络异常,请稍后重试' | ||
| 177 | - : err.message || '登录失败,请检查账号密码'; | ||
| 178 | - uni.showToast({ | ||
| 179 | - title: errorMsg, | ||
| 180 | - icon: 'none', | ||
| 181 | - duration: 2000 | ||
| 182 | - }); | 164 | + // ✅ 校验失败/登录失败 统一捕获提示,和工单页异常处理一致 |
| 165 | + if (!Array.isArray(err)) { | ||
| 166 | + console.error('登录失败:', err); | ||
| 167 | + uni.showToast({ | ||
| 168 | + title: err.message || '账号或密码错误,请重试', | ||
| 169 | + icon: 'none', | ||
| 170 | + duration: 2000 | ||
| 171 | + }); | ||
| 172 | + } | ||
| 183 | } finally { | 173 | } finally { |
| 184 | isLoading.value = false; | 174 | isLoading.value = false; |
| 185 | } | 175 | } |
| @@ -190,122 +180,83 @@ const handleLogin = async () => { | @@ -190,122 +180,83 @@ const handleLogin = async () => { | ||
| 190 | // 核心布局 | 180 | // 核心布局 |
| 191 | .login-page { | 181 | .login-page { |
| 192 | min-height: 100vh; | 182 | min-height: 100vh; |
| 193 | - position: relative; | ||
| 194 | - padding: 40rpx 30rpx; | 183 | + padding: 0; |
| 195 | box-sizing: border-box; | 184 | box-sizing: border-box; |
| 196 | - overflow: hidden; // 隐藏动效溢出 | ||
| 197 | - | ||
| 198 | - // 适配小程序安全区 | ||
| 199 | - /* #ifdef MP-WEIXIN */ | ||
| 200 | - padding-bottom: constant(safe-area-inset-bottom); | ||
| 201 | - padding-bottom: env(safe-area-inset-bottom); | ||
| 202 | - /* #endif */ | 185 | + overflow: hidden; |
| 186 | + position: relative; | ||
| 187 | + background: #f5f7fa; | ||
| 203 | } | 188 | } |
| 204 | 189 | ||
| 205 | -// 纯CSS渐变动效背景(替代粒子,兼容所有版本) | ||
| 206 | -.bg-animation { | ||
| 207 | - position: absolute; | ||
| 208 | - top: 0; | ||
| 209 | - left: 0; | ||
| 210 | - width: 100%; | ||
| 211 | - height: 100%; | ||
| 212 | - z-index: 0; | ||
| 213 | - // 基础渐变底色 | ||
| 214 | - background: linear-gradient(120deg, #f0f9ff 0%, #e6f7ff 100%); | ||
| 215 | - // 伪粒子动效(多个透明渐变圆缓慢移动) | ||
| 216 | - &::before, | ||
| 217 | - &::after { | ||
| 218 | - content: ''; | ||
| 219 | - position: absolute; | ||
| 220 | - border-radius: 50%; | ||
| 221 | - background: rgba(59, 130, 246, 0.05); | ||
| 222 | - animation: float 20s infinite linear; | ||
| 223 | - } | ||
| 224 | - | ||
| 225 | - &::before { | ||
| 226 | - width: 600rpx; | ||
| 227 | - height: 600rpx; | ||
| 228 | - top: -200rpx; | ||
| 229 | - left: -200rpx; | ||
| 230 | - } | 190 | +// 顶部:从左到右 由浅到深 线性渐变 过渡自然柔和 无突兀色块 |
| 191 | +.top-title { | ||
| 192 | + background: linear-gradient(120deg, #4299e1 0%, #2970e8 50%, #2563eb 100%); | ||
| 193 | + color: #fff; | ||
| 194 | + padding: 240rpx 30rpx 80rpx; | ||
| 195 | + text-align: left; | ||
| 196 | + border-bottom-left-radius: 120rpx; | ||
| 197 | + position: relative; | ||
| 198 | + z-index: 1; | ||
| 199 | + box-shadow: 0 25rpx 40rpx -15rpx rgba(37, 99, 235, 0.3); | ||
| 231 | 200 | ||
| 232 | - &::after { | ||
| 233 | - width: 800rpx; | ||
| 234 | - height: 800rpx; | ||
| 235 | - bottom: -300rpx; | ||
| 236 | - right: -300rpx; | ||
| 237 | - animation-delay: -10s; // 错开动画时间 | 201 | + .welcome-text { |
| 202 | + font-size: 46rpx; | ||
| 203 | + display: block; | ||
| 204 | + margin-bottom: 10px; | ||
| 205 | + font-weight: 500; | ||
| 238 | } | 206 | } |
| 239 | 207 | ||
| 240 | - // 额外小动效点(模拟粒子) | ||
| 241 | - & > view { | ||
| 242 | - position: absolute; | ||
| 243 | - width: 400rpx; | ||
| 244 | - height: 400rpx; | ||
| 245 | - border-radius: 50%; | ||
| 246 | - background: rgba(59, 130, 246, 0.03); | ||
| 247 | - top: 50%; | ||
| 248 | - left: 50%; | ||
| 249 | - transform: translate(-50%, -50%); | ||
| 250 | - animation: float 15s infinite linear reverse; | 208 | + .platform-name { |
| 209 | + margin-bottom: 10px; | ||
| 210 | + font-size: 46rpx; | ||
| 211 | + display: block; | ||
| 212 | + opacity: 0.95; | ||
| 251 | } | 213 | } |
| 252 | } | 214 | } |
| 253 | 215 | ||
| 254 | -// 浮动动画(模拟粒子运动) | ||
| 255 | -@keyframes float { | ||
| 256 | - 0% { | ||
| 257 | - transform: translate(0, 0) rotate(0deg); | ||
| 258 | - } | ||
| 259 | - 25% { | ||
| 260 | - transform: translate(50rpx, 30rpx) rotate(90deg); | ||
| 261 | - } | ||
| 262 | - 50% { | ||
| 263 | - transform: translate(0, 60rpx) rotate(180deg); | ||
| 264 | - } | ||
| 265 | - 75% { | ||
| 266 | - transform: translate(-50rpx, 30rpx) rotate(270deg); | ||
| 267 | - } | ||
| 268 | - 100% { | ||
| 269 | - transform: translate(0, 0) rotate(360deg); | ||
| 270 | - } | ||
| 271 | -} | ||
| 272 | - | ||
| 273 | -// 登录表单(悬浮层) | ||
| 274 | .login-form { | 216 | .login-form { |
| 217 | + background-color: #fff; | ||
| 218 | + padding: 40rpx 30rpx; | ||
| 219 | + border-radius: 16rpx; | ||
| 220 | + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06); | ||
| 221 | + margin: -60rpx 40rpx 0; | ||
| 275 | position: relative; | 222 | position: relative; |
| 276 | z-index: 10; | 223 | z-index: 10; |
| 277 | - background-color: rgba(255, 255, 255, 0.95); | ||
| 278 | - padding: 60rpx 40rpx; | ||
| 279 | - border-radius: 16rpx; | ||
| 280 | - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08); | ||
| 281 | - max-width: 600rpx; | ||
| 282 | - margin: 0 auto; | ||
| 283 | - margin-top: 100rpx; | 224 | + box-sizing: border-box; |
| 284 | 225 | ||
| 285 | - // 登录标题 | ||
| 286 | .login-title { | 226 | .login-title { |
| 287 | - font-size: 36rpx; | 227 | + font-size: 38rpx; |
| 288 | font-weight: 600; | 228 | font-weight: 600; |
| 289 | - color: #111827; | ||
| 290 | - text-align: center; | ||
| 291 | - margin-bottom: 40rpx; | ||
| 292 | - letter-spacing: 2rpx; | 229 | + color: #666; |
| 230 | + margin-bottom: 30rpx; | ||
| 231 | + letter-spacing: 1rpx; | ||
| 293 | } | 232 | } |
| 294 | } | 233 | } |
| 295 | 234 | ||
| 296 | -// 表单项 | ||
| 297 | -.form-item { | ||
| 298 | - margin-bottom: 30rpx; | 235 | +// 适配表单校验的间距 |
| 236 | +:deep(.u-form-item) { | ||
| 237 | + margin-bottom: 20rpx; | ||
| 299 | position: relative; | 238 | position: relative; |
| 239 | +} | ||
| 300 | 240 | ||
| 301 | - // 错误提示 | ||
| 302 | - .error-tip { | ||
| 303 | - font-size: 24rpx; | ||
| 304 | - color: #ef4444; | ||
| 305 | - margin-top: 10rpx; | ||
| 306 | - line-height: 1.2; | ||
| 307 | - padding-left: 10rpx; | ||
| 308 | - } | 241 | +// 登录按钮:和顶部完全同款 从左到右 由浅到深 线性渐变 + 保留所有原尺寸 |
| 242 | +.login-btn { | ||
| 243 | + margin-top: 40rpx; | ||
| 244 | + width: 100%; | ||
| 245 | + height: 88rpx; | ||
| 246 | + line-height: 88rpx; | ||
| 247 | + border-radius: 8rpx; | ||
| 248 | + font-size: 32rpx; | ||
| 249 | + background: linear-gradient(120deg, #4299e1 0%, #2970e8 50%, #2563eb 100%) !important; | ||
| 250 | + border: none !important; | ||
| 251 | + &::after { border: none !important; } | ||
| 309 | } | 252 | } |
| 310 | 253 | ||
| 254 | +.copyright { | ||
| 255 | + width: 100%; | ||
| 256 | + text-align: center; | ||
| 257 | + font-size: 24rpx; | ||
| 258 | + color: #999; | ||
| 259 | + position: fixed; | ||
| 260 | + bottom: 100px; | ||
| 261 | +} | ||
| 311 | </style> | 262 | </style> |
| 312 | \ No newline at end of file | 263 | \ No newline at end of file |
static/imgs/tree/tree-high.png
0 → 100644
1003 Bytes
static/imgs/tree/treearound.png
0 → 100644
927 Bytes