Commit 28e3b4f3d4f5db106f43e22235fce841d8e71c6f

Authored by 王彪总
1 parent 98689726

业务线 小程序不用写死,从后端接口获取

api/common.js
@@ -57,6 +57,16 @@ export const getByType = (params) => { @@ -57,6 +57,16 @@ export const getByType = (params) => {
57 }; 57 };
58 58
59 /** 59 /**
  60 + * 拉取「已配置填报项」的作业类型
  61 + * 填报页进入时若该业务线只配了一个作业类型,直接选中并加载动态字段,避免用户不知道要先选作业类型。
  62 + * @param {Object} params {`businessType`、`bizType`}
  63 + * @returns {Promise} List<{workTypeId, workTypeName}>
  64 + */
  65 +export const getConfiguredWorkTypes = (params) => {
  66 + return get('/app-api/app/garden/work-field-config/work-types', params);
  67 +};
  68 +
  69 +/**
60 * 拉取选项 用于 fieldType 3(枚举)/6(多选)/9(关联记录) 且 field.options 为空(即非静态来源)时获取可选项。 70 * 拉取选项 用于 fieldType 3(枚举)/6(多选)/9(关联记录) 且 field.options 为空(即非静态来源)时获取可选项。
61 * @param {Object} params {} 71 * @param {Object} params {}
62 * @returns {Promise} 72 * @returns {Promise}
common/config/env.js
@@ -2,12 +2,12 @@ @@ -2,12 +2,12 @@
2 const env = { 2 const env = {
3 // 开发环境 3 // 开发环境
4 development: { 4 development: {
5 - baseUrl: 'https://test.jichengshanshui.com.cn:28302', 5 + baseUrl: 'http://192.168.1.55:48081',
6 // https://test.jichengshanshui.com.cn:28302 6 // https://test.jichengshanshui.com.cn:28302
7 7
8 // baseUrl: 'http://192.168.1.111:48081', 8 // baseUrl: 'http://192.168.1.111:48081',
9 9
10 - uploadUrl: 'https://test.jichengshanshui.com.cn:28302', 10 + uploadUrl: 'http://192.168.1.55:48081',
11 // baseApi:'admin-api', 11 // baseApi:'admin-api',
12 // appApi:'app-api' 12 // appApi:'app-api'
13 }, 13 },
common/utils/common.js
@@ -286,6 +286,9 @@ export const translateRoles = (roles = []) =&gt; { @@ -286,6 +286,9 @@ export const translateRoles = (roles = []) =&gt; {
286 .join(','); 286 .join(',');
287 } 287 }
288 288
  289 +/** 配置了工单(biz_type=1)动态字段的业务线;其他业务线走统一动作弹窗 */
  290 +const WORKER_IMPLEMENT_BIZ_LINES = ['yl', 'hj'];
  291 +
289 /** 292 /**
290 * 跳转「作业填报」页(养护员实施) 293 * 跳转「作业填报」页(养护员实施)
291 * 294 *
@@ -293,11 +296,20 @@ export const translateRoles = (roles = []) =&gt; { @@ -293,11 +296,20 @@ export const translateRoles = (roles = []) =&gt; {
293 * 上传开始/进行中/结束/人员/材料五组照片,统一动作弹窗只有原因+单个附件,承载不了, 296 * 上传开始/进行中/结束/人员/材料五组照片,统一动作弹窗只有原因+单个附件,承载不了,
294 * 因此实施动作固定进「作业填报」页。 297 * 因此实施动作固定进「作业填报」页。
295 * 298 *
  299 + * 只有养护(yl)、环卫(hj)配置了工单动态字段,秩序(zx)/市政(sz)/物业(wy)没有配置,
  300 + * 这类工单仍走统一动作弹窗,保持原有处理流程。
  301 + *
296 * 工单数据存本地缓存,URL 只带临时 key,避免参数过长。 302 * 工单数据存本地缓存,URL 只带临时 key,避免参数过长。
297 * @param {Object} item 待办行数据,需包含 id(工单ID)与 taskId(流程任务ID) 303 * @param {Object} item 待办行数据,需包含 id(工单ID)与 taskId(流程任务ID)
298 - * @returns {Boolean} 是否成功跳转 304 + * @param {String} from 来源列表页标识:work-order / regional / ai,提交后回到对应列表
  305 + * @returns {Boolean} 是否已跳转;返回 false 时由调用方继续走统一动作弹窗
299 */ 306 */
300 -export const toWorkerImplementPage = (item) => { 307 +export const toWorkerImplementPage = (item, from = 'work-order') => {
  308 + // 业务线可能多选(逗号分隔),任一命中即视为养护类工单
  309 + const bizLines = String(item?.busiLine || '').split(',').map(v => v.trim()).filter(Boolean);
  310 + if (!bizLines.some(v => WORKER_IMPLEMENT_BIZ_LINES.includes(v))) {
  311 + return false;
  312 + }
301 if (!item || !item.id || !item.taskId) { 313 if (!item || !item.id || !item.taskId) {
302 uni.showToast({ title: '工单信息异常,无法实施', icon: 'none' }); 314 uni.showToast({ title: '工单信息异常,无法实施', icon: 'none' });
303 return false; 315 return false;
@@ -311,7 +323,7 @@ export const toWorkerImplementPage = (item) =&gt; { @@ -311,7 +323,7 @@ export const toWorkerImplementPage = (item) =&gt; {
311 return false; 323 return false;
312 } 324 }
313 uni.navigateTo({ 325 uni.navigateTo({
314 - url: `/pages-sub/problem/work-order-manage/add-maintain-order?tempKey=${tempKey}` 326 + url: `/pages-sub/problem/work-order-manage/add-maintain-order?tempKey=${tempKey}&from=${from}`
315 }); 327 });
316 return true; 328 return true;
317 } 329 }
318 \ No newline at end of file 330 \ No newline at end of file
pages-sub/problem/ai-manage/index.vue
@@ -517,9 +517,9 @@ const handleUnifiedProcess = async (item, action = null) =&gt; { @@ -517,9 +517,9 @@ const handleUnifiedProcess = async (item, action = null) =&gt; {
517 : await queryUnifiedActions(item) 517 : await queryUnifiedActions(item)
518 if (actions) { 518 if (actions) {
519 const target = action || actions[0] 519 const target = action || actions[0]
520 - // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页  
521 - if (target?.code === 'HANDLE') {  
522 - toWorkerImplementPage(item) 520 + // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页;
  521 + // 该业务线未配置工单动态字段时返回 false,继续走统一动作弹窗
  522 + if (target?.code === 'HANDLE' && toWorkerImplementPage(item, 'ai')) {
523 return 523 return
524 } 524 }
525 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 525 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择
pages-sub/problem/regional-order-manage/index.vue
@@ -498,9 +498,9 @@ const handleUnifiedProcess = async (item, action = null) =&gt; { @@ -498,9 +498,9 @@ const handleUnifiedProcess = async (item, action = null) =&gt; {
498 : await queryUnifiedActions(item) 498 : await queryUnifiedActions(item)
499 if (actions) { 499 if (actions) {
500 const target = action || actions[0] 500 const target = action || actions[0]
501 - // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页  
502 - if (target?.code === 'HANDLE') {  
503 - toWorkerImplementPage(item) 501 + // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页;
  502 + // 该业务线未配置工单动态字段时返回 false,继续走统一动作弹窗
  503 + if (target?.code === 'HANDLE' && toWorkerImplementPage(item, 'regional')) {
504 return 504 return
505 } 505 }
506 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 506 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择
pages-sub/problem/regional-order-manage/list-detail.vue
@@ -553,9 +553,9 @@ const handleUnifiedProcess = async (item: any, action: any = null) =&gt; { @@ -553,9 +553,9 @@ const handleUnifiedProcess = async (item: any, action: any = null) =&gt; {
553 : await queryUnifiedActions(item?.taskId) 553 : await queryUnifiedActions(item?.taskId)
554 if (actions) { 554 if (actions) {
555 const target = action || actions[0] 555 const target = action || actions[0]
556 - // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页  
557 - if (target?.code === 'HANDLE') {  
558 - toWorkerImplementPage(item) 556 + // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页;
  557 + // 该业务线未配置工单动态字段时返回 false,继续走统一动作弹窗
  558 + if (target?.code === 'HANDLE' && toWorkerImplementPage(item, 'regional')) {
559 return 559 return
560 } 560 }
561 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 561 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择
pages-sub/problem/regional-order-manage/order-detail.vue
@@ -623,9 +623,9 @@ const handleUnifiedProcess = async (item: any, action: any = null) =&gt; { @@ -623,9 +623,9 @@ const handleUnifiedProcess = async (item: any, action: any = null) =&gt; {
623 : await queryUnifiedActions(item?.taskId) 623 : await queryUnifiedActions(item?.taskId)
624 if (actions) { 624 if (actions) {
625 const target = action || actions[0] 625 const target = action || actions[0]
626 - // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页  
627 - if (target?.code === 'HANDLE') {  
628 - toWorkerImplementPage(item) 626 + // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页;
  627 + // 该业务线未配置工单动态字段时返回 false,继续走统一动作弹窗
  628 + if (target?.code === 'HANDLE' && toWorkerImplementPage(item, 'regional')) {
629 return 629 return
630 } 630 }
631 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 631 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择
pages-sub/problem/work-order-manage/add-maintain-order.vue
@@ -221,7 +221,7 @@ import { ref, reactive, watch } from &#39;vue&#39; @@ -221,7 +221,7 @@ import { ref, reactive, watch } from &#39;vue&#39;
221 import { onLoad, onReady, onShow } from '@dcloudio/uni-app'; 221 import { onLoad, onReady, onShow } from '@dcloudio/uni-app';
222 import { useUploadImgs } from '@/common/utils/useUploadImgs' 222 import { useUploadImgs } from '@/common/utils/useUploadImgs'
223 import { getYlWorkersPage, universalApproval } from '@/api/work-order-manage/work-order-manage' 223 import { getYlWorkersPage, universalApproval } from '@/api/work-order-manage/work-order-manage'
224 -import { workRecordSubmit } from '@/api/common' 224 +import { workRecordSubmit, getConfiguredWorkTypes } from '@/api/common'
225 import { nextStepMap } from '@/common/utils/common' 225 import { nextStepMap } from '@/common/utils/common'
226 import { useUserStore } from '@/pinia/user'; 226 import { useUserStore } from '@/pinia/user';
227 const userStore = useUserStore(); 227 const userStore = useUserStore();
@@ -243,6 +243,15 @@ const dynamicFieldCount = ref(0) @@ -243,6 +243,15 @@ const dynamicFieldCount = ref(0)
243 // 动态字段提交幂等流水号:同一页面生命周期内保持不变,网络重试只落一条记录 243 // 动态字段提交幂等流水号:同一页面生命周期内保持不变,网络重试只落一条记录
244 let workRecordClientSeq = '' 244 let workRecordClientSeq = ''
245 245
  246 +// 来源列表页标识(work-order/regional/ai),提交后回到用户进入时的列表
  247 +let fromPage = 'work-order'
  248 +// 来源标识 -> 列表页路径
  249 +const BACK_URL_MAP = {
  250 + 'work-order': '/pages-sub/problem/work-order-manage/index',
  251 + 'regional': '/pages-sub/problem/regional-order-manage/index',
  252 + 'ai': '/pages-sub/problem/ai-manage/index'
  253 +}
  254 +
246 // 页面状态 255 // 页面状态
247 const showActionSheet = ref(false) 256 const showActionSheet = ref(false)
248 const currentActionSheetData = reactive({ 257 const currentActionSheetData = reactive({
@@ -372,6 +381,8 @@ onLoad((options) =&gt; { @@ -372,6 +381,8 @@ onLoad((options) =&gt; {
372 } 381 }
373 382
374 const { tempKey } = options; 383 const { tempKey } = options;
  384 + // 来源列表页:养护员实施可能从工单管理、区域工单、AI 工单进入,提交后回原列表
  385 + fromPage = options.from || 'work-order';
375 let orderItem = {}; 386 let orderItem = {};
376 // 2. 读取缓存并校验缓存数据是否有效 387 // 2. 读取缓存并校验缓存数据是否有效
377 orderItem = uni.getStorageSync(tempKey) || {}; 388 orderItem = uni.getStorageSync(tempKey) || {};
@@ -425,6 +436,9 @@ onLoad((options) =&gt; { @@ -425,6 +436,9 @@ onLoad((options) =&gt; {
425 if (orderItem.workTypeId) { 436 if (orderItem.workTypeId) {
426 workOrderForm.workTypeId = orderItem.workTypeId 437 workOrderForm.workTypeId = orderItem.workTypeId
427 workOrderForm.workTypeName = uni.$dict.getDictLabel('maintain_type', orderItem.workTypeId) || '' 438 workOrderForm.workTypeName = uni.$dict.getDictLabel('maintain_type', orderItem.workTypeId) || ''
  439 + } else {
  440 + // 该业务线只配了一个作业类型的字段时自动选中,进页即可看到填报项
  441 + loadDefaultWorkType()
428 } 442 }
429 // 共同处理人(如有数据则回显,转换为数组格式) 443 // 共同处理人(如有数据则回显,转换为数组格式)
430 if (orderItem.coHandlers && orderItem.coHandlersName) { 444 if (orderItem.coHandlers && orderItem.coHandlersName) {
@@ -728,6 +742,34 @@ const onDynamicFieldsLoaded = (count) =&gt; { @@ -728,6 +742,34 @@ const onDynamicFieldsLoaded = (count) =&gt; {
728 dynamicFieldCount.value = count || 0 742 dynamicFieldCount.value = count || 0
729 } 743 }
730 744
  745 +/**
  746 + * 自动带出作业类型:该业务线下只有一个作业类型配置了填报项时直接选中,
  747 + * 动态字段块随之渲染(v-if 绑在 workTypeId 上),用户不用先猜该选哪个作业类型。
  748 + * 配了多个时不自动选,交给用户手选。
  749 + */
  750 +const loadDefaultWorkType = async () => {
  751 + if (!workOrderForm.businessType) {
  752 + return
  753 + }
  754 + try {
  755 + const list = await getConfiguredWorkTypes({
  756 + businessType: workOrderForm.businessType,
  757 + bizType: 1
  758 + })
  759 + if (!Array.isArray(list) || list.length !== 1) {
  760 + return
  761 + }
  762 + const only = list[0]
  763 + workOrderForm.workTypeId = only.workTypeId
  764 + workOrderForm.workTypeName = only.workTypeName
  765 + || uni.$dict.getDictLabel('maintain_type', only.workTypeId)
  766 + || ''
  767 + dynamicFieldCount.value = 0
  768 + } catch (error) {
  769 + console.warn('获取已配置填报项的作业类型失败:', error)
  770 + }
  771 +}
  772 +
731 // 动态字段提交幂等流水号(后端按 userId+clientSeq 去重) 773 // 动态字段提交幂等流水号(后端按 userId+clientSeq 去重)
732 const genClientSeq = () => `${Date.now()}-${Math.random().toString(16).slice(2, 10)}` 774 const genClientSeq = () => `${Date.now()}-${Math.random().toString(16).slice(2, 10)}`
733 775
@@ -916,10 +958,10 @@ const submitWorkOrder = async () =&gt; { @@ -916,10 +958,10 @@ const submitWorkOrder = async () =&gt; {
916 duration: 1000 958 duration: 1000
917 }) 959 })
918 960
919 - // 延迟跳转 961 + // 延迟跳转:来源列表页在 onShow 中不做刷新,用 reLaunch 重建页面保证待办数据最新
920 setTimeout(() => { 962 setTimeout(() => {
921 uni.reLaunch({ 963 uni.reLaunch({
922 - url: '/pages-sub/problem/work-order-manage/index' 964 + url: BACK_URL_MAP[fromPage] || BACK_URL_MAP['work-order']
923 }) 965 })
924 }, 1000) 966 }, 1000)
925 } catch (error) { 967 } catch (error) {
pages-sub/problem/work-order-manage/index.vue
@@ -557,9 +557,9 @@ const handleUnifiedProcess = async (item, action = null) =&gt; { @@ -557,9 +557,9 @@ const handleUnifiedProcess = async (item, action = null) =&gt; {
557 : await queryUnifiedActions(item) 557 : await queryUnifiedActions(item)
558 if (actions) { 558 if (actions) {
559 const target = action || actions[0] 559 const target = action || actions[0]
560 - // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页  
561 - if (target?.code === 'HANDLE') {  
562 - toWorkerImplementPage(item) 560 + // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页;
  561 + // 该业务线未配置工单动态字段时返回 false,继续走统一动作弹窗
  562 + if (target?.code === 'HANDLE' && toWorkerImplementPage(item, 'work-order')) {
563 return 563 return
564 } 564 }
565 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 565 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择
@@ -595,7 +595,7 @@ const handleUnifiedSuccess = () =&gt; { @@ -595,7 +595,7 @@ const handleUnifiedSuccess = () =&gt; {
595 595
596 // 待办-处理工单 596 // 待办-处理工单
597 const handleProcess = async (item) => { 597 const handleProcess = async (item) => {
598 - console.log(nextStepMap[item.taskKey].name) 598 + console.log(nextStepMap[item.taskKey]?.name)
599 try { 599 try {
600 if (nextStepMap[item.taskKey]?.name == '养护组长分配') { 600 if (nextStepMap[item.taskKey]?.name == '养护组长分配') {
601 uni.navigateTo({ 601 uni.navigateTo({
pages-sub/problem/work-order-manage/order-detail.vue
@@ -854,9 +854,9 @@ const handleUnifiedProcess = async (item: any, action: any = null) =&gt; { @@ -854,9 +854,9 @@ const handleUnifiedProcess = async (item: any, action: any = null) =&gt; {
854 : await queryUnifiedActions(item) 854 : await queryUnifiedActions(item)
855 if (actions) { 855 if (actions) {
856 const target = action || actions[0] 856 const target = action || actions[0]
857 - // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页  
858 - if (target?.code === 'HANDLE') {  
859 - toWorkerImplementPage(item) 857 + // 实施动作要选作业类型、填动态字段、传五组照片,统一动作弹窗承载不了,进「作业填报」页;
  858 + // 该业务线未配置工单动态字段时返回 false,继续走统一动作弹窗
  859 + if (target?.code === 'HANDLE' && toWorkerImplementPage(item, 'work-order')) {
860 return 860 return
861 } 861 }
862 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 862 // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择