feat(transaction/attendance): 实现待改派工单列表与免密策略运营区域联动

- 待改派工单页面替换 mock 数据为真实接口,增加状态筛选和日期格式化
- 免密策略新增页面添加根据城市获取电子围栏列表功能,实现运营区域动态加载
- 统一 API 请求参数格式,修复接口路径和参数拼接方式
4个文件已修改
186 ■■■■■ 已修改文件
src/service/api/attendance.ts 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/transaction.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/taskOrder/pendingReassignment/index.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/passwordFreeStrategy/add.vue 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/attendance.ts
@@ -2,7 +2,6 @@
/** 打卡地址管理 */
// 获取打卡地址列表
export function getCheckLocationList(params: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/check-location/pageList', params)
@@ -20,14 +19,13 @@
// 删除打卡地址
export function deleteCheckLocation(id: any) {
  return request.Delete<Service.ResponseResult<any>>('/maintenance/api/v1/check-location/deleteById?id=' + id)
  return request.Delete<Service.ResponseResult<any>>(`/maintenance/api/v1/check-location/deleteById?id=${id}`)
}
// 启用禁用打卡地址
export function updateCheckLocationStatus(params: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/check-location/updateStatus', params)
}
/** 班次管理 */
@@ -48,12 +46,10 @@
// 删除班次
export function deleteShift(id: any) {
  return request.Delete<Service.ResponseResult<any>>('/maintenance/xp-shift/api/v1/shift/deleteById?id=' + id)
  return request.Delete<Service.ResponseResult<any>>(`/maintenance/xp-shift/api/v1/shift/deleteById?id=${id}`)
}
/** 消息通知管理 */
// 获取消息通知列表
export function getNoticeList() {
@@ -65,9 +61,7 @@
  return request.Post<Service.ResponseResult<any>>('/operation/api/v1/notification/update', params)
}
/** 打卡统计 */
// 获取打卡统计列表
export function getClockInStatisticsList(params: any) {
@@ -104,7 +98,7 @@
// 导出排班
export function exportScheduling(params: any) {
  const method = request.Get<Service.ResponseResult<any>>('/maintenance/api/v1/scheduling/exportExcel?month=' + params.month, {}, { responseType: 'blob' })
  const method = request.Get<Service.ResponseResult<any>>(`/maintenance/api/v1/scheduling/exportExcel?month=${params.month}`, {}, { responseType: 'blob' })
  method.meta = { ...method.meta, isBlob: true }
  return method
}
@@ -113,7 +107,6 @@
export function saveScheduling(params: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/scheduling/saveSchedulingDetail', params)
}
// 获取班次不分页列表
export function getShiftListNoPage() {
@@ -134,7 +127,7 @@
// 获取运维人员详情
export function getOperationsUserDetail(id: any) {
  return request.Get<Service.ResponseResult<any>>('/account/api/v1/operationsUser/detailById?id=' + id)
  return request.Get<Service.ResponseResult<any>>(`/account/api/v1/operationsUser/detailById?id=${id}`)
}
// 新增运维人员
@@ -149,7 +142,7 @@
// 删除运维人员
export function deleteOperationsUser(id: any) {
  return request.Delete<Service.ResponseResult<any>>('/account/api/v1/operationsUser/deleteById?id=' + id)
  return request.Delete<Service.ResponseResult<any>>(`/account/api/v1/operationsUser/deleteById?id=${id}`)
}
// 启用禁用运维人员
@@ -183,7 +176,6 @@
  return request.Post<Service.ResponseResult<any>>('/account/api/v1/operationsUser/importOperationsUser', formData)
}
/** 任务工单 */
// 任务中心列表
@@ -205,17 +197,17 @@
// 获取任务详情
export function getTaskOrderDetail(id: any) {
  return request.Get<Service.ResponseResult<any>>('/maintenance/api/v1/taskManagement/taskDetail?id=' + id)
  return request.Get<Service.ResponseResult<any>>(`/maintenance/api/v1/taskManagement/taskDetail?id=${id}`)
}
// 任务分配
export function assignTaskOrder(params: any) {
  return request.Get<Service.ResponseResult<any>>('/maintenance/api/v1/taskManagement/assigneeTask?id=' + params.id + '&handlerUserId=' + params.handlerUserId)
  return request.Get<Service.ResponseResult<any>>(`/maintenance/api/v1/taskManagement/assigneeTask?id=${params.id}&handlerUserId=${params.handlerUserId}`)
}
// 删除任务
export function deleteTaskOrder(id: any) {
  return request.Delete<Service.ResponseResult<any>>('/maintenance/api/v1/taskManagement/deleteTaskById?id=' + id)
  return request.Delete<Service.ResponseResult<any>>(`/maintenance/api/v1/taskManagement/deleteTaskById?id=${id}`)
}
// 事故类型列表
@@ -227,3 +219,18 @@
export function getVehicleListNoPage() {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/taskManagement/listVehicle')
}
// 待改派工单列表
export function getTaskOrderReassignList(params: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/task/reassign/pageList', params)
}
// 待改派工单详情
export function getTaskOrderReassignDetail(id: any) {
  return request.Get<Service.ResponseResult<any>>(`/maintenance/api/v1/task/reassign/detail?taskId =${id}`)
}
// 可改派的运维人员列表
export function getTaskOrderReassignOperationsUserList(params: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/task/reassign/availableUsers', params)
}
src/service/api/transaction.ts
@@ -155,5 +155,10 @@
// 获取免密支付策略详情
export function getPasswordFreePolicyDetail(id: any) {
  return request.Get<Service.ResponseResult<any>>(`/operation/api/v1/passwordFreePolicy/queryById?id=${id}`)
  return request.Get<Service.ResponseResult<any>>(`/operation/api/v1/passwordFreePolicy/getById/${id}`)
}
// 通过城市获取围栏列表
export function getFenceListByCityId(params: any) {
  return request.Post<Service.ResponseResult<any>>(`/map/api/v1/electronicFence/list`, params)
}
src/views/operations/taskOrder/pendingReassignment/index.vue
@@ -3,11 +3,12 @@
import { computed, onMounted, ref } from 'vue'
import { useBoolean } from '@/hooks'
import { NButton, NTag, useMessage } from 'naive-ui'
import { getTaskAccidentTypeList } from '@/service/api/attendance'
import { getTaskAccidentTypeList, getTaskOrderReassignList } from '@/service/api/attendance'
import SearchPanel from '@/components/custom/SearchPanel.vue'
import Pagination from '@/components/common/Pagination.vue'
import ReassignModal from './components/ReassignModal.vue'
import ReassignDetailModal from './components/ReassignDetailModal.vue'
import dayjs from 'dayjs'
const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(false)
const message = useMessage()
@@ -248,54 +249,35 @@
// 获取列表数据
async function getList() {
  startLoading()
  // Mock data simulation
  setTimeout(() => {
    const mockData = Array.from({ length: 10 }).map((_, index) => {
      const isPending = index < 5 // 前5条待处理,后5条已处理
      const levels = [
        0, // 1
        0, // 2
        2, // 3
        1, // 4
        2, // 5
        3, // 6
        1, // 7
        2, // 8
        1, // 9
        3, // 10
      ]
      const types = [
        '车辆整备',
        '车辆技术故障>关键传感器故障',
        '车辆整备',
        '车辆整备',
        '车辆整备',
        '车辆整备',
        '车辆整备',
        '车辆技术故障>关键传感器故障',
        '车辆技术故障>关键传感器故障',
        '车辆技术故障>关键传感器故障',
      ]
      return {
        id: `mock-id-${pageParams.value.page}-${index}`,
        vehicle: '皖PXV7029',
        taskCategory: '事故',
        type: types[index],
        level: levels[index],
        description: '任务描述内容任务描述内容',
        applyTime: '2025-05-07 14:53',
        reason: '任务分派冲突',
        status: isPending ? 'pending' : 'processed',
      }
    })
    count.value = 1000 // Mock total count
    listData.value = mockData
  try {
    const params = {
      pageNum: pageParams.value.page,
      pageSize: pageParams.value.size,
      plateNumber: model.value.plateNumber || undefined,
      taskCategory: model.value.taskCategory ?? undefined,
      taskGeneralId: model.value.taskGeneralId ?? undefined,
      taskErrorId: model.value.taskErrorId ?? undefined,
      taskUrgencyLevel: model.value.taskUrgencyLevel ?? undefined,
      status: model.value.status ?? undefined,
    }
    const res = await getTaskOrderReassignList(params)
    if (res.code === 200) {
      const records = res.data?.records || []
      listData.value = records
      count.value = res.data?.total || records.length || 0
      return
    }
    listData.value = []
    count.value = 0
  }
  catch (error) {
    console.error('获取待改派工单列表失败:', error)
    listData.value = []
    count.value = 0
  }
  finally {
    endLoading()
  }, 500)
  }
}
// 分页变化
@@ -326,6 +308,7 @@
    key: 'taskCategory',
    width: 100,
    resizable: true,
    render: row => options.find(item => item.value === row.taskCategory)?.label || row.taskCategory || '-',
  },
  {
    title: '类型',
@@ -361,6 +344,7 @@
    key: 'applyTime',
    width: 160,
    resizable: true,
    render: row => row.applyTime ? dayjs(row.applyTime).format('YYYY/MM/DD HH:mm') : '-',
  },
  {
    title: '改派原因',
@@ -374,7 +358,7 @@
    width: 100,
    resizable: true,
    render: (row) => {
      const isPending = row.status === 'pending'
      const isPending = !!row._pending
      return (
        <NTag
          bordered={false}
@@ -391,7 +375,7 @@
    width: 90,
    fixed: 'right',
    render: (row) => {
      const isPending = row.status === 'pending'
      const isPending = !!row._pending
      if (isPending) {
        return (
          <div class="flex items-center justify-start gap-2">
src/views/transaction/passwordFreeStrategy/add.vue
@@ -4,7 +4,7 @@
import { NButton, NCheckbox, NDatePicker, NForm, NInputNumber, NSelect, NSpace, NSwitch, useMessage } from 'naive-ui'
import type { FormItemRule } from 'naive-ui'
import dayjs from 'dayjs'
import { addPasswordFreePolicy, editPasswordFreePolicy, getCityList, getPasswordFreePolicyDetail } from '@/service/api/transaction'
import { addPasswordFreePolicy, editPasswordFreePolicy, getCityList, getFenceListByCityId, getPasswordFreePolicyDetail } from '@/service/api/transaction'
import { useTabStore } from '@/store'
const tabStore = useTabStore()
@@ -20,8 +20,8 @@
const isOperationAreaOpen = ref(false)
const formModel = ref({
  city: null as string | null,
  operationArea: null as string | null,
  city: null as string | number | null,
  operationArea: null as string | number | null,
  status: 1,
  validTimeStart: null as number | null,
  validTimeEnd: null as number | null,
@@ -48,6 +48,29 @@
const formRef = ref<any>(null)
const validTimeStartPicker = ref<any>(null)
const validTimeEndPicker = ref<any>(null)
const operationAreaOptions = ref<any[]>([])
async function getOperationAreaOptions(cityCode: string | number) {
  try {
    const res = await getFenceListByCityId({ cityCode })
    if (res.code === 200) {
      const rawList = res.data?.records || res.data?.list || res.data || []
      const list = Array.isArray(rawList) ? rawList : []
      operationAreaOptions.value = list.map((item: any) => ({
        label: item.electronicName || item.fenceName || item.name || '-',
        value: item.id ?? item.electronicId ?? item.code,
      }))
      return
    }
    operationAreaOptions.value = []
    message.warning(res.msg || '获取运营区域失败')
  }
  catch (error) {
    console.error('获取运营区域失败:', error)
    operationAreaOptions.value = []
    message.error('请求运营区域失败')
  }
}
async function fetchDetail() {
  if (!id.value)
@@ -58,7 +81,7 @@
    if (res.code === 200 && res.data) {
      const data = res.data
      formModel.value = {
        city: data.city ?? data.cityId ?? null,
        city: data.cityCode ?? data.city ?? data.cityId ?? null,
        operationArea: data.operationArea ?? data.operationAreaId ?? null,
        status: Number(data.status ?? 1),
        validTimeStart: data.validTimeStart ? dayjs(data.validTimeStart).valueOf() : null,
@@ -69,6 +92,8 @@
        sendNotification: data.sendNotification === 1 || data.sendNotification === true ? 1 : 0,
        differenceRatio: data.differenceRatio ?? null,
      }
      if (formModel.value.city !== null && formModel.value.city !== undefined)
        await getOperationAreaOptions(formModel.value.city)
      return
    }
    message.warning(res.msg || '获取策略详情失败')
@@ -136,14 +161,23 @@
function getCityListData() {
  getCityList({ type: 0 }).then((res) => {
    if (res.code === 200) {
      cityList.value = res.data || []
      cityList.value.forEach((item) => {
        item.label = item.name
        item.value = item.id
      })
      const list = Array.isArray(res.data) ? res.data : []
      cityList.value = list.map((item: any) => ({
        ...item,
        label: item.name,
        value: item.cityCode ?? item.code ?? item.id,
      }))
    }
  })
}
watch(() => formModel.value.city, async (cityCode) => {
  formModel.value.operationArea = null
  operationAreaOptions.value = []
  if (cityCode === null || cityCode === undefined || cityCode === '')
    return
  await getOperationAreaOptions(cityCode)
})
onMounted(() => {
  getCityListData()
@@ -189,7 +223,7 @@
                    alt="arrow"
                  >
                </template>
                l                <template #empty>
                <template #empty>
                  <div class="flex-center">
                    <img
                      src="/src/assets/element-img/no-data.png"
@@ -204,7 +238,7 @@
              <NSelect
                v-model:value="formModel.operationArea"
                placeholder="请选择"
                :options="[]"
                :options="operationAreaOptions"
                class="w-300px"
                @update:show="(val: boolean) => isOperationAreaOpen = val"
              >