zjk
2026-06-10 f2c860647559c6b75d23c816e35b7603d8f78196
feat: 新增多业务页面搜索筛选条件、路由配置并完善接口逻辑

新增资产管理人员车辆素材管理的页面路由,为评价记录、巡航打卡详情、路线规划、车队规则、待改派任务、订单中心、车型管理、考勤地址、订单管理、定价管理、免密策略、人员审核、运营人员管理、车队管理、专属服务管理、安全员信息、工单中心、政策审核、反馈管理等十余项业务页面新增各类搜索筛选字段。统一优化各页面的搜索参数处理逻辑,添加字符串trim过滤与空值兼容处理,更新服务中心相关API的参数定义以适配新增的搜索字段,补全部分页面表格布局的样式类名。
23个文件已修改
1053 ■■■■■ 已修改文件
src/router/routes.static.ts 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/serviceCenter.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/assetManagement/fleetManagement/index.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/assetManagement/vehicleModel/index.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/attendance/address/index.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/attendance/statistics/index.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/cruiseCheckIn/index.vue 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/cruiseCheckInDetails/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/cruiseCheckInRule/index.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/personnel/personnelManagement/index.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/personnel/safetyOfficerInfo/index.vue 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/taskOrder/pendingReassignment/index.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/taskOrder/taskOrderCenter/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/service/review/personnel/index.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/service/review/policyApplication/index.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/service/ticket/feedback/index.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/service/ticket/workOrder/index.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/directServiceManagement/index.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/navigationAndRoutePlanning/index.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/order/evaluationRecord/index.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/order/orderManagement/index.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/passwordFreeStrategy/index.vue 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/pricingManagement/index.vue 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes.static.ts
@@ -1052,6 +1052,18 @@
    activeMenu: '/assetManagement/vehicleManagement/operatingVehicle',
  },
  {
    name: 'vehicleMaterial',
    path: '/assetManagement/vehicleManagement/vehicleMaterial',
    title: '车辆素材管理',
    requiresAuth: true,
    icon: 'icon-park-outline:pic',
    menuType: 'page',
    componentPath: '/assetManagement/vehicleManagement/vehicleMaterial/index.vue',
    id: 5014,
    keepAlive: false,
    pid: 501,
  },
  {
    name: 'fleetManagement',
    path: '/assetManagement/fleetManagement',
    title: '车队管理',
src/service/api/serviceCenter.ts
@@ -2,16 +2,19 @@
export function fetchQualificationAuditPageList(data: {
  auditStatus?: number
  endTime?: string
  nickName?: string
  operationsUserId?: number | string
  pageNum: number
  pageSize: number
  phoneNumber?: string
  roleId?: number
  startTime?: string
}) {
  return request.Post<Service.ResponseResult<any>>('/account/api/v1/qualificationAudit/pageList', data)
}
export function auditQualification(data: { auditStatus: number; ids: number[]; auditRemarks?: string }) {
export function auditQualification(data: { auditStatus: number, ids: number[], auditRemarks?: string }) {
  return request.Post<Service.ResponseResult<any>>('/account/api/v1/qualificationAudit/audit', data)
}
@@ -20,17 +23,23 @@
}
export function deleteQualificationAuditById(id: number | string) {
  return request.Delete<Service.ResponseResult<any>>('/account/api/v1/qualificationAudit/deleteById?id=' + id)
  return request.Delete<Service.ResponseResult<any>>(`/account/api/v1/qualificationAudit/deleteById?id=${id}`)
}
export function fetchPolicyApplicationPageList(data: {
  auditEndTime?: string
  auditRemarks?: string
  auditStatus?: number
  auditStartTime?: string
  auditUserName?: string
  endTime?: string
  nickName?: string
  pageNum: number
  pageSize: number
  plateNumber?: string
  phoneNumber?: string
  startTime?: string
  vehicleCode?: string
}) {
  return request.Post<Service.ResponseResult<any>>('/vehicleConvoy/api/v1/policyApplication/pageList', data)
}
@@ -49,8 +58,13 @@
export function fetchFeedbackPageList(data: {
  content?: string
  endTime?: string
  feedbackTypeId?: number | string
  nickName?: string
  pageNum: number
  pageSize: number
  phone?: string
  startTime?: string
}) {
  return request.Post<Service.ResponseResult<any>>('/operation/api/v1/userFeedBack/pageList', data)
}
@@ -66,7 +80,7 @@
  return request.Post<Service.ResponseResult<any>>('/operation/api/v1/feedbackType/saveFeedbackType', data)
}
export function updateFeedbackType(data: { id: number | string; feedbackType: string }) {
export function updateFeedbackType(data: { id: number | string, feedbackType: string }) {
  return request.Post<Service.ResponseResult<any>>('/operation/api/v1/feedbackType/updateFeedbackType', data)
}
@@ -75,12 +89,16 @@
}
export function fetchWorkOrderPageList(data: {
  createTimeEnd?: string
  createTimeStart?: string
  feedbackTypeId?: number | string
  feedbackUserPhone?: string
  handleStatus?: number | null
  handleUserName?: string
  pageNum: number
  pageSize: number
  priority?: number | null
  problem?: string
  problemSource?: number | null
}) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/workOrder/pageList', data)
src/views/assetManagement/fleetManagement/index.vue
@@ -17,7 +17,12 @@
const initialModel = {
  fleetName: '', // 车队名称
  operationsUserName: '', // 负责人
  phoneNumber: '', // 负责人电话
  locationName: '', // 关联运营区域
  vehicleCount: '', // 绑定车辆数
  userCount: '', // 绑定人员数
  createTime: null as [number, number] | null, // 创建时间
}
const model = ref({ ...initialModel })
@@ -54,9 +59,34 @@
    render: () => <n-input v-model:value={model.value.fleetName} placeholder="请输入车队名称" />,
  },
  {
    label: '负责人电话',
    label: '负责人',
    path: 'operationsUserName',
    render: () => <n-input v-model:value={model.value.operationsUserName} placeholder="请输入负责人" />,
  },
  {
    label: '联系电话',
    path: 'phoneNumber',
    render: () => <n-input v-model:value={model.value.phoneNumber} placeholder="请输入负责人电话" />,
  },
  {
    label: '关联运营区域',
    path: 'locationName',
    render: () => <n-input v-model:value={model.value.locationName} placeholder="请输入关联运营区域" />,
  },
  {
    label: '绑定车辆数',
    path: 'vehicleCount',
    render: () => <n-input v-model:value={model.value.vehicleCount} placeholder="请输入绑定车辆数" />,
  },
  {
    label: '绑定人员数',
    path: 'userCount',
    render: () => <n-input v-model:value={model.value.userCount} placeholder="请输入绑定人员数" />,
  },
  {
    label: '创建时间',
    path: 'createTime',
    render: () => <n-date-picker v-model:value={model.value.createTime} type="daterange" format="yyyy/MM/dd" clearable actions={[]} close-on-select={true} start-placeholder="开始时间" end-placeholder="结束时间" separator="-" />,
  },
])
@@ -172,8 +202,14 @@
  startLoading()
  try {
    const res = await fetchFleetPageList({
      fleetName: model.value.fleetName,
      phoneNumber: model.value.phoneNumber,
      fleetName: model.value.fleetName?.trim() || undefined,
      operationsUserName: model.value.operationsUserName?.trim() || undefined,
      phoneNumber: model.value.phoneNumber?.trim() || undefined,
      locationName: model.value.locationName?.trim() || undefined,
      vehicleCount: model.value.vehicleCount?.trim() || undefined,
      userCount: model.value.userCount?.trim() || undefined,
      createStartTime: model.value.createTime?.[0] ? dayjs(model.value.createTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
      createEndTime: model.value.createTime?.[1] ? dayjs(model.value.createTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
      pageNum: pageNum.value,
      pageSize: pageSize.value,
    })
@@ -329,6 +365,7 @@
      </template>
      <div class="flex-1 flex flex-col h-full">
        <n-data-table
          v-model:checked-row-keys="selectedRowKeys"
          class="flex-1"
          :columns="columns"
          :data="listData"
@@ -336,7 +373,6 @@
          :scroll-x="1300"
          :bordered="false"
          :row-key="(row: any) => row.id"
          v-model:checked-row-keys="selectedRowKeys"
          flex-height
        >
          <template #empty>
src/views/assetManagement/vehicleModel/index.vue
@@ -17,6 +17,11 @@
const initialModel = {
  name: '',
  seat: '',
  vehicleLength: '',
  vehicleWidth: '',
  vehicleHeight: '',
  createTime: null as [number, number] | null,
}
const model = ref({ ...initialModel })
const pagination = reactive({
@@ -45,6 +50,31 @@
    label: '车型名称',
    path: 'name',
    render: () => <n-input v-model:value={model.value.name} placeholder="请输入" clearable />,
  },
  {
    label: '座位数',
    path: 'seat',
    render: () => <n-input v-model:value={model.value.seat} placeholder="请输入" clearable />,
  },
  {
    label: '车长',
    path: 'vehicleLength',
    render: () => <n-input v-model:value={model.value.vehicleLength} placeholder="请输入" clearable />,
  },
  {
    label: '车宽',
    path: 'vehicleWidth',
    render: () => <n-input v-model:value={model.value.vehicleWidth} placeholder="请输入" clearable />,
  },
  {
    label: '车高',
    path: 'vehicleHeight',
    render: () => <n-input v-model:value={model.value.vehicleHeight} placeholder="请输入" clearable />,
  },
  {
    label: '创建时间',
    path: 'createTime',
    render: () => <n-date-picker v-model:value={model.value.createTime} type="daterange" format="yyyy/MM/dd" clearable actions={[]} close-on-select={true} start-placeholder="开始时间" end-placeholder="结束时间" separator="-" />,
  },
])
@@ -141,6 +171,12 @@
      pageNum: pagination.page,
      pageSize: pagination.pageSize,
      name: model.value.name?.trim() || undefined,
      seat: model.value.seat?.trim() || undefined,
      vehicleLength: model.value.vehicleLength?.trim() || undefined,
      vehicleWidth: model.value.vehicleWidth?.trim() || undefined,
      vehicleHeight: model.value.vehicleHeight?.trim() || undefined,
      createStartTime: model.value.createTime?.[0] ? dayjs(model.value.createTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
      createEndTime: model.value.createTime?.[1] ? dayjs(model.value.createTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    }
    const res = await queryVehicleModelList(params)
    if (res.code === 200) {
src/views/operations/attendance/address/index.vue
@@ -18,8 +18,17 @@
const initialModel = {
  locationAddress: '',
  status: null as number | null,
  createTimeRange: null as [number, number] | null,
}
const model = ref({ ...initialModel })
const isStatusSelectOpen = ref(false)
const statusOptions = [
  { label: '启用中', value: 1 },
  { label: '禁用中', value: 0 },
]
function handleResetSearch() {
  model.value = { ...initialModel }
@@ -202,6 +211,35 @@
    path: 'locationAddress',
    render: () => <n-input v-model:value={model.value.locationAddress} clearable />,
  },
  {
    label: '状态',
    path: 'status',
    render: () => (
      <n-select
        v-model:value={model.value.status}
        options={statusOptions}
        clearable
        placeholder="请选择"
        onUpdate:show={(val: boolean) => isStatusSelectOpen.value = val}
      >
        {{
          arrow: () => (
            <img
              src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
              class={`arrow-icon ${isStatusSelectOpen.value ? 'arrow-icon--open' : ''}`}
              style={{ width: '16px', height: '16px' }}
              alt="arrow"
            />
          ),
        }}
      </n-select>
    ),
  },
  {
    label: '创建时间',
    path: 'createTimeRange',
    render: () => <n-date-picker v-model:value={model.value.createTimeRange} type="daterange" format="yyyy/MM/dd" clearable actions={[]} close-on-select={true} />,
  },
])
const count = ref(0)
@@ -247,7 +285,10 @@
  startLoading()
  const params = {
    ...pageParams.value,
    locationAddress: model.value.locationAddress,
    locationAddress: model.value.locationAddress?.trim() || undefined,
    status: model.value.status ?? undefined,
    createTimeStart: model.value.createTimeRange?.[0] ? dayjs(model.value.createTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    createTimeEnd: model.value.createTimeRange?.[1] ? dayjs(model.value.createTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
  }
  getCheckLocationList(params).then((res) => {
    listData.value = res.data.records || []
src/views/operations/attendance/statistics/index.vue
@@ -5,7 +5,7 @@
import type { DataTableColumns } from 'naive-ui'
import { exportClockInStatistics, getClockInStatisticsList } from '@/service/api/attendance'
import { fetchRoleList } from '@/service/api/fleet'
import { NButton ,NTag} from 'naive-ui'
import { NButton, NTag } from 'naive-ui'
import { downloadFile } from '@/utils'
import SearchPanel from '@/components/custom/SearchPanel.vue'
import dayjs from 'dayjs'
@@ -18,6 +18,11 @@
  name: null as string | null,
  roleId: null as string | null,
  statisticDate: null as [number, number] | null,
  teamName: null as string | null,
  shouldClockInDays: null as string | null,
  clockInDays: null as string | null,
  notClockInDays: null as string | null,
  lateEarly: null as string | null,
})
const roleOptions = ref<any[]>([])
@@ -36,8 +41,27 @@
    name: null,
    roleId: null,
    statisticDate: null,
    teamName: null,
    shouldClockInDays: null,
    clockInDays: null,
    notClockInDays: null,
    lateEarly: null,
  }
  handleSearch()
}
function buildQueryParams() {
  return {
    ...pageParams.value,
    name: searchModel.value.name?.trim() || undefined,
    roleId: searchModel.value.roleId,
    statisticDate: searchModel.value.statisticDate?.map((item: number) => dayjs(item).format('YYYY-MM-DD HH:mm:ss')).join(' - '),
    teamName: searchModel.value.teamName?.trim() || undefined,
    shouldClockInDays: searchModel.value.shouldClockInDays?.trim() || undefined,
    clockInDays: searchModel.value.clockInDays?.trim() || undefined,
    notClockInDays: searchModel.value.notClockInDays?.trim() || undefined,
    lateEarly: searchModel.value.lateEarly?.trim() || undefined,
  }
}
function handleSearch() {
  pageParams.value.pageNum = 1
@@ -45,13 +69,7 @@
}
async function handleExport() {
  const params = {
    ...pageParams.value,
    name: searchModel.value.name,
    roleId: searchModel.value.roleId,
    statisticDate: searchModel.value.statisticDate?.map((item: number) => dayjs(item).format('YYYY-MM-DD HH:mm:ss')).join(' - '),
  }
  const response = await exportClockInStatistics(params)
  const response = await exportClockInStatistics(buildQueryParams())
  if (response instanceof Blob) {
    downloadFile(response, `打卡统计列表_${new Date().getTime()}.xlsx`)
    window.$message.success('导出成功')
@@ -117,15 +135,40 @@
      />
    ),
  },
  {
    label: '所属队伍',
    path: 'teamName',
    render: () => <n-input v-model:value={searchModel.value.teamName} placeholder="请输入" clearable />,
  },
  {
    label: '应打卡天数',
    path: 'shouldClockInDays',
    render: () => <n-input v-model:value={searchModel.value.shouldClockInDays} placeholder="请输入" clearable />,
  },
  {
    label: '正常',
    path: 'clockInDays',
    render: () => <n-input v-model:value={searchModel.value.clockInDays} placeholder="请输入" clearable />,
  },
  {
    label: '缺卡',
    path: 'notClockInDays',
    render: () => <n-input v-model:value={searchModel.value.notClockInDays} placeholder="请输入" clearable />,
  },
  {
    label: '迟到',
    path: 'lateEarly',
    render: () => <n-input v-model:value={searchModel.value.lateEarly} placeholder="请输入" clearable />,
  },
])
const columns = computed<DataTableColumns<any>>(() => [
  { title: '序号', key: 'serialNumber', width: 80, align: 'left', resizable: true, fixed: 'left' },
  { title: '人员', key: 'name', width: 140, align: 'left', resizable: true, fixed: 'left' },
  { title: '角色', key: 'roleName', width: 140, align: 'left', resizable: true,render: row => (
            row.roleName&&<NTag type="primary" bordered={false} size="small" style={{ borderRadius: '4px' }}>{row.roleName}</NTag>
    ), },
  { title: '角色', key: 'roleName', width: 140, align: 'left', resizable: true, render: row => (
    row.roleName && <NTag type="primary" bordered={false} size="small" style={{ borderRadius: '4px' }}>{row.roleName}</NTag>
  ) },
  { title: '所属队伍', key: 'teamName', width: 160, align: 'left', resizable: true },
  { title: '应打卡天数', key: 'shouldClockInDays', width: 120, align: 'left', resizable: true },
  { title: '正常', key: 'clockInDays', width: 120, align: 'left', resizable: true },
@@ -165,13 +208,7 @@
async function getList() {
  startLoading()
  const params = {
    ...pageParams.value,
    name: searchModel.value.name,
    roleId: searchModel.value.roleId,
    statisticDate: searchModel.value.statisticDate?.map((item: number) => dayjs(item).format('YYYY-MM-DD HH:mm:ss')).join(' - '),
  }
  getClockInStatisticsList(params).then((res) => {
  getClockInStatisticsList(buildQueryParams()).then((res) => {
    statisticsList.value = res.data.records || []
    statisticsList.value.forEach((item: any, index: number) => {
      item.serialNumber = (pageParams.value.pageNum - 1) * pageParams.value.pageSize + index + 1
@@ -199,7 +236,7 @@
    <div class="roboTaxi-form-card mb-12px">
      <n-form :model="searchModel" label-placement="left" inline :show-feedback="false">
        <SearchPanel>
          <n-gi v-for="item in filterItems" :key="item.path">
          <n-gi v-for="item in filterItems" :key="item.path" class="n-grid-item">
            <n-form-item :label="item.label" :path="item.path">
              <component :is="item.render" />
            </n-form-item>
src/views/operations/cruiseCheckIn/index.vue
@@ -23,8 +23,17 @@
const initialModel = {
  locationAddress: '',
  status: null as number | null,
  createTimeRange: null as [number, number] | null,
}
const model = ref({ ...initialModel })
const isStatusSelectOpen = ref(false)
const statusOptions = [
  { label: '启用中', value: 1 },
  { label: '禁用中', value: 0 },
]
function handleResetSearch() {
  model.value = { ...initialModel }
@@ -162,6 +171,35 @@
    path: 'locationAddress',
    render: () => <n-input v-model:value={model.value.locationAddress} placeholder="请输入" clearable />,
  },
  {
    label: '状态',
    path: 'status',
    render: () => (
      <n-select
        v-model:value={model.value.status}
        options={statusOptions}
        clearable
        placeholder="请选择"
        onUpdate:show={(val: boolean) => isStatusSelectOpen.value = val}
      >
        {{
          arrow: () => (
            <img
              src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
              class={`arrow-icon ${isStatusSelectOpen.value ? 'arrow-icon--open' : ''}`}
              style={{ width: '16px', height: '16px' }}
              alt="arrow"
            />
          ),
        }}
      </n-select>
    ),
  },
  {
    label: '创建时间',
    path: 'createTimeRange',
    render: () => <n-date-picker v-model:value={model.value.createTimeRange} type="daterange" format="yyyy/MM/dd" clearable actions={[]} close-on-select={true} />,
  },
])
const count = ref(0)
@@ -223,7 +261,10 @@
  startLoading()
  const params = {
    ...pageParams.value,
    locationAddress: model.value.locationAddress,
    locationAddress: model.value.locationAddress?.trim() || undefined,
    status: model.value.status ?? undefined,
    createTimeStart: model.value.createTimeRange?.[0] ? dayjs(model.value.createTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    createTimeEnd: model.value.createTimeRange?.[1] ? dayjs(model.value.createTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    type: 2,
  }
  getCheckLocationList(params).then((res) => {
@@ -253,7 +294,7 @@
    <div class="roboTaxi-form-card mb-12px">
      <n-form ref="formRef" :model="model" label-placement="left" inline :show-feedback="false">
        <SearchPanel>
          <n-gi v-for="item in filterItems" :key="item.path">
          <n-gi v-for="item in filterItems" :key="item.path" class="n-grid-item">
            <n-form-item :label="item.label" :path="item.path">
              <component :is="item.render" />
            </n-form-item>
src/views/operations/cruiseCheckInDetails/index.vue
@@ -26,6 +26,7 @@
  locationAddress: null as string | null,
  phoneNumber: null as string | null,
  clockInDate: null as [number, number] | null,
  checkInTimeRange: null as [number, number] | null,
}
const model = ref({ ...initialModel })
@@ -252,6 +253,23 @@
      />
    ),
  },
  {
    label: '打卡时间',
    path: 'checkInTimeRange',
    render: () => (
      <n-date-picker
        v-model:value={model.value.checkInTimeRange}
        type="daterange"
        clearable
        actions={[]}
        close-on-select={true}
        format="yyyy/MM/dd"
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        separator="-"
      />
    ),
  },
])
const count = ref(0)
@@ -267,6 +285,8 @@
    phoneNumber: model.value.phoneNumber?.trim() || undefined,
    startDate: model.value.clockInDate?.[0] ? dayjs(model.value.clockInDate[0]).format('YYYY-MM-DD') : undefined,
    endDate: model.value.clockInDate?.[1] ? dayjs(model.value.clockInDate[1]).format('YYYY-MM-DD') : undefined,
    checkInTimeStart: model.value.checkInTimeRange?.[0] ? dayjs(model.value.checkInTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    checkInTimeEnd: model.value.checkInTimeRange?.[1] ? dayjs(model.value.checkInTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    pageNum: pageParams.value.pageNum,
    pageSize: pageParams.value.pageSize,
  }
src/views/operations/cruiseCheckInRule/index.vue
@@ -27,6 +27,8 @@
  name: '',
  userName: '',
  phoneNumber: '',
  pointNum: '',
  userNumber: '',
}
const model = ref({ ...initialModel })
@@ -136,6 +138,16 @@
    path: 'phoneNumber',
    render: () => <n-input v-model:value={model.value.phoneNumber} placeholder="请输入" clearable />,
  },
  {
    label: '关联点位',
    path: 'pointNum',
    render: () => <n-input v-model:value={model.value.pointNum} placeholder="请输入" clearable />,
  },
  {
    label: '执行人数',
    path: 'userNumber',
    render: () => <n-input v-model:value={model.value.userNumber} placeholder="请输入" clearable />,
  },
])
const count = ref(0)
@@ -188,6 +200,8 @@
      name: model.value.name?.trim() || undefined,
      userName: model.value.userName?.trim() || undefined,
      phoneNumber: model.value.phoneNumber?.trim() || undefined,
      pointNum: model.value.pointNum?.trim() || undefined,
      userNumber: model.value.userNumber?.trim() || undefined,
    }
    const res = await fetchCruiseCheckInRuleList(params)
    if (res.code === 200) {
@@ -227,7 +241,7 @@
    <div class="roboTaxi-form-card mb-12px">
      <n-form ref="formRef" :model="model" label-placement="left" inline :show-feedback="false">
        <SearchPanel>
          <n-gi v-for="item in filterItems" :key="item.path">
          <n-gi v-for="item in filterItems" :key="item.path" class="n-grid-item">
            <n-form-item :label="item.label" :path="item.path">
              <component :is="item.render" />
            </n-form-item>
src/views/operations/personnel/personnelManagement/index.vue
@@ -1,6 +1,5 @@
<script setup lang="tsx">
import { computed, h, ref } from 'vue'
import { onActivated } from 'vue'
import { computed, h, onActivated, ref } from 'vue'
import { useBoolean, usePermission } from '@/hooks'
import { useRouter } from 'vue-router'
import type { DataTableColumns } from 'naive-ui'
@@ -24,6 +23,9 @@
  phoneNumber: '',
  roleId: null as string | null,
  status: null as string | null,
  uniqueNumber: '',
  createTimeRange: null as [number, number] | null,
  remarks: '',
})
const showFormModal = ref(false)
@@ -59,6 +61,9 @@
    phoneNumber: '',
    roleId: null,
    status: null,
    uniqueNumber: '',
    createTimeRange: null,
    remarks: '',
  }
  handleSearch()
}
@@ -70,6 +75,14 @@
    phoneNumber: searchModel.value.phoneNumber,
    roleId: searchModel.value.roleId,
    status: searchModel.value.status,
    uniqueNumber: searchModel.value.uniqueNumber?.trim() || undefined,
    createTimeStart: searchModel.value.createTimeRange?.[0]
      ? dayjs(searchModel.value.createTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    createTimeEnd: searchModel.value.createTimeRange?.[1]
      ? dayjs(searchModel.value.createTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    remarks: searchModel.value.remarks?.trim() || undefined,
  }
  exportOperationsUser(params).then((res) => {
    if (res instanceof Blob) {
@@ -275,6 +288,21 @@
      </n-select>
    ),
  },
  {
    label: '编号',
    path: 'uniqueNumber',
    render: () => <n-input v-model:value={searchModel.value.uniqueNumber} placeholder="请输入" clearable />,
  },
  {
    label: '创建时间',
    path: 'createTimeRange',
    render: () => <n-date-picker v-model:value={searchModel.value.createTimeRange} type="daterange" format="yyyy/MM/dd" clearable actions={[]} close-on-select={true} />,
  },
  {
    label: '备注',
    path: 'remarks',
    render: () => <n-input v-model:value={searchModel.value.remarks} placeholder="请输入" clearable />,
  },
])
const columns = computed<DataTableColumns<any>>(() => [
@@ -403,6 +431,14 @@
    phoneNumber: searchModel.value.phoneNumber,
    roleId: searchModel.value.roleId,
    status: searchModel.value.status,
    uniqueNumber: searchModel.value.uniqueNumber?.trim() || undefined,
    createTimeStart: searchModel.value.createTimeRange?.[0]
      ? dayjs(searchModel.value.createTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    createTimeEnd: searchModel.value.createTimeRange?.[1]
      ? dayjs(searchModel.value.createTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    remarks: searchModel.value.remarks?.trim() || undefined,
  }
  getOperationsUserList(params).then((res) => {
    personnelList.value = res.data.records || []
src/views/operations/personnel/safetyOfficerInfo/index.vue
@@ -44,6 +44,9 @@
  drivingLicenseNo: '',
  createTimeRange: null as [number, number] | null,
  status: null as number | null,
  gender: null as number | null,
  birthDateRange: null as [number, number] | null,
  createBy: '',
})
const pageParams = ref({
@@ -52,6 +55,7 @@
})
const isStatusSelectOpen = ref(false)
const isGenderSelectOpen = ref(false)
const showOperationLogModal = ref(false)
const checkedRowKeys = ref<Array<string | number>>([])
const listData = ref<SafetyOfficerItem[]>([])
@@ -63,6 +67,11 @@
  { label: '停用', value: 2 },
]
const genderOptions = [
  { label: '男', value: 1 },
  { label: '女', value: 2 },
]
function buildQueryParams() {
  return {
    id: searchModel.value.id ?? undefined,
@@ -70,6 +79,21 @@
    idCardNo: searchModel.value.idCardNo?.trim() || undefined,
    phoneNumber: searchModel.value.phoneNumber?.trim() || undefined,
    drivingLicenseNo: searchModel.value.drivingLicenseNo?.trim() || undefined,
    gender: searchModel.value.gender ?? undefined,
    birthDateStart: searchModel.value.birthDateRange?.[0]
      ? dayjs(searchModel.value.birthDateRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    birthDateEnd: searchModel.value.birthDateRange?.[1]
      ? dayjs(searchModel.value.birthDateRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    createBy: searchModel.value.createBy?.trim() || undefined,
    createTimeStart: searchModel.value.createTimeRange?.[0]
      ? dayjs(searchModel.value.createTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    createTimeEnd: searchModel.value.createTimeRange?.[1]
      ? dayjs(searchModel.value.createTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    status: searchModel.value.status ?? undefined,
    pageNum: pageParams.value.pageNum,
    pageSize: pageParams.value.pageSize,
  }
@@ -111,6 +135,9 @@
    drivingLicenseNo: '',
    createTimeRange: null,
    status: null,
    gender: null,
    birthDateRange: null,
    createBy: '',
  }
  pageParams.value.pageNum = 1
  getList()
@@ -304,6 +331,54 @@
      </n-select>
    ),
  },
  {
    label: '性别',
    path: 'gender',
    render: () => (
      <n-select
        v-model:value={searchModel.value.gender}
        options={genderOptions}
        placeholder="请选择"
        clearable
        onUpdate:show={(val: boolean) => isGenderSelectOpen.value = val}
      >
        {{
          arrow: () => (
            <img
              src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
              class={`arrow-icon ${isGenderSelectOpen.value ? 'arrow-icon--open' : ''}`}
              style={{ width: '16px', height: '16px' }}
              alt="arrow"
            />
          ),
          empty: () => (
            <div class="flex-center">
              <img src="/src/assets/element-img/no-data.png" style={{ width: '50%' }} alt="no-data" />
            </div>
          ),
        }}
      </n-select>
    ),
  },
  {
    label: '出生日期',
    path: 'birthDateRange',
    render: () => (
      <n-date-picker
        v-model:value={searchModel.value.birthDateRange}
        type="daterange"
        clearable
        format="yyyy/MM/dd"
        actions={null}
        close-on-select={true}
      />
    ),
  },
  {
    label: '创建人',
    path: 'createBy',
    render: () => <n-input v-model:value={searchModel.value.createBy} placeholder="请输入" clearable />,
  },
])
const columns = computed<DataTableColumns<SafetyOfficerItem>>(() => [
src/views/operations/taskOrder/pendingReassignment/index.vue
@@ -33,6 +33,9 @@
  errorTypeId: null as number | null,
  taskUrgencyLevel: null as number | null,
  reassignmentStatus: null as number | null,
  taskDescription: '',
  applyTime: null as [number, number] | null,
  reason: '',
}
const model = ref({ ...initialModel })
@@ -84,12 +87,20 @@
function buildQueryParams() {
  return {
    plateNumber: model.value.plateNumber || undefined,
    plateNumber: model.value.plateNumber?.trim() || undefined,
    taskCategory: model.value.taskCategory ?? undefined,
    taskTypeId: model.value.taskTypeId ?? undefined,
    errorTypeId: model.value.errorTypeId ?? undefined,
    taskUrgencyLevel: model.value.taskUrgencyLevel ?? undefined,
    reassignmentStatus: model.value.reassignmentStatus ?? undefined,
    taskDescription: model.value.taskDescription?.trim() || undefined,
    applyStartTime: model.value.applyTime?.[0]
      ? dayjs(model.value.applyTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    applyEndTime: model.value.applyTime?.[1]
      ? dayjs(model.value.applyTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    reason: model.value.reason?.trim() || undefined,
  }
}
@@ -255,6 +266,33 @@
      </n-select>
    ),
  },
  {
    label: '任务描述',
    path: 'taskDescription',
    render: () => <n-input v-model:value={model.value.taskDescription} clearable placeholder="请输入" />,
  },
  {
    label: '申请改派时间',
    path: 'applyTime',
    render: () => (
      <n-date-picker
        format="yyyy/MM/dd"
        v-model:value={model.value.applyTime}
        type="daterange"
        clearable
        actions={[]}
        close-on-select={true}
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        separator="-"
      />
    ),
  },
  {
    label: '改派原因',
    path: 'reason',
    render: () => <n-input v-model:value={model.value.reason} clearable placeholder="请输入" />,
  },
])
// 获取列表数据
src/views/operations/taskOrder/taskOrderCenter/index.vue
@@ -30,6 +30,8 @@
  taskUrgencyLevel: null,
  time: null,
  status: null,
  taskDescription: '',
  handleUserName: '',
}
const model = ref({ ...initialModel })
@@ -263,6 +265,16 @@
      />
    ),
  },
  {
    label: '任务描述',
    path: 'taskDescription',
    render: () => <n-input v-model:value={model.value.taskDescription} clearable />,
  },
  {
    label: '处理人',
    path: 'handleUserName',
    render: () => <n-input v-model:value={model.value.handleUserName} clearable />,
  },
])
const total = ref(0)
@@ -274,11 +286,13 @@
  const params = {
    ...pageParams.value,
    status: model.value.status,
    plateNumber: model.value.plateNumber,
    plateNumber: model.value.plateNumber?.trim() || undefined,
    taskCategory: model.value.taskCategory,
    taskGeneralId: model.value.taskGeneralId,
    taskErrorId: model.value.taskErrorId,
    taskUrgencyLevel: model.value.taskUrgencyLevel,
    taskDescription: model.value.taskDescription?.trim() || undefined,
    handleUserName: model.value.handleUserName?.trim() || undefined,
    startTime: model.value.time ? dayjs(model.value.time?.[0]).format('YYYY-MM-DD HH:mm:ss') : null,
    endTime: model.value.time ? dayjs(model.value.time?.[1]).format('YYYY-MM-DD HH:mm:ss') : null,
  }
@@ -316,11 +330,13 @@
  const params = {
    ...pageParams.value,
    status: model.value.status,
    plateNumber: model.value.plateNumber,
    plateNumber: model.value.plateNumber?.trim() || undefined,
    taskCategory: model.value.taskCategory,
    taskGeneralId: model.value.taskGeneralId,
    taskErrorId: model.value.taskErrorId,
    taskUrgencyLevel: model.value.taskUrgencyLevel,
    taskDescription: model.value.taskDescription?.trim() || undefined,
    handleUserName: model.value.handleUserName?.trim() || undefined,
    startTime: model.value.time ? dayjs(model.value.time?.[0]).format('YYYY-MM-DD HH:mm:ss') : null,
    endTime: model.value.time ? dayjs(model.value.time?.[1]).format('YYYY-MM-DD HH:mm:ss') : null,
  }
src/views/service/review/personnel/index.vue
@@ -25,6 +25,8 @@
  phoneNumber: '',
  roleId: null as number | null,
  auditStatus: null as number | null,
  operationsUserId: '',
  createTimeRange: null as [number, number] | null,
}
const searchForm = ref({ ...initialSearchForm })
@@ -272,17 +274,28 @@
  }
})
function buildQueryParams() {
  return {
    auditStatus: searchForm.value.auditStatus ?? undefined,
    nickName: searchForm.value.nickName.trim() || undefined,
    phoneNumber: searchForm.value.phoneNumber.trim() || undefined,
    roleId: searchForm.value.roleId ?? undefined,
    operationsUserId: searchForm.value.operationsUserId.trim() || undefined,
    startTime: searchForm.value.createTimeRange?.[0]
      ? dayjs(searchForm.value.createTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    endTime: searchForm.value.createTimeRange?.[1]
      ? dayjs(searchForm.value.createTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    pageNum: pagination.value.page,
    pageSize: pagination.value.pageSize,
  }
}
async function getPersonnelList() {
  startLoading()
  try {
    const res = await fetchQualificationAuditPageList({
      auditStatus: searchForm.value.auditStatus ?? undefined,
      nickName: searchForm.value.nickName || undefined,
      phoneNumber: searchForm.value.phoneNumber || undefined,
      roleId: searchForm.value.roleId ?? undefined,
      pageNum: pagination.value.page,
      pageSize: pagination.value.pageSize,
    })
    const res = await fetchQualificationAuditPageList(buildQueryParams())
    if (res.code === 200 && res.data) {
      tableData.value = res.data.records || []
      tableData.value.forEach((item: any, index: number) => {
@@ -394,6 +407,34 @@
      </n-select>
    ),
  },
  {
    label: t('serviceReview.personnel.id'),
    path: 'operationsUserId',
    render: () => (
      <n-input
        v-model:value={searchForm.value.operationsUserId}
        placeholder={t('common.inputPlaceholder')}
        clearable
      />
    ),
  },
  {
    label: t('serviceReview.personnel.uploadTime'),
    path: 'createTimeRange',
    render: () => (
      <n-date-picker
        v-model:value={searchForm.value.createTimeRange}
        type="daterange"
        clearable
        actions={[]}
        close-on-select={true}
        format="yyyy/MM/dd"
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        separator="-"
      />
    ),
  },
])
</script>
@@ -407,7 +448,7 @@
        :show-feedback="false"
      >
        <SearchPanel>
          <n-gi v-for="item in filterItems" :key="item.path">
          <n-gi v-for="item in filterItems" :key="item.path" class="n-grid-item">
            <n-form-item :label="item.label" :path="item.path">
              <component :is="item.render" />
            </n-form-item>
src/views/service/review/policyApplication/index.vue
@@ -1,5 +1,5 @@
<script setup lang="tsx">
import { h, onMounted, ref } from 'vue'
import { computed, h, onMounted, ref } from 'vue'
import type { DataTableColumns } from 'naive-ui'
import { NButton, NTag, NTooltip } from 'naive-ui'
import { useBoolean } from '@/hooks'
@@ -23,7 +23,12 @@
  plateNumber: '',
  nickName: '',
  auditStatus: null as number | null,
  dateRange: null as [string, string] | null,
  dateRange: null as [number, number] | null,
  vehicleCode: '',
  phoneNumber: '',
  auditUserName: '',
  auditTimeRange: null as [number, number] | null,
  auditRemarks: '',
}
const searchForm = ref({ ...initialSearchForm })
@@ -288,23 +293,36 @@
  getPolicyApplicationList()
}
function buildQueryParams() {
  return {
    auditStatus: searchForm.value.auditStatus ?? undefined,
    nickName: searchForm.value.nickName.trim() || undefined,
    plateNumber: searchForm.value.plateNumber.trim() || undefined,
    vehicleCode: searchForm.value.vehicleCode.trim() || undefined,
    phoneNumber: searchForm.value.phoneNumber.trim() || undefined,
    auditUserName: searchForm.value.auditUserName.trim() || undefined,
    auditRemarks: searchForm.value.auditRemarks.trim() || undefined,
    startTime: searchForm.value.dateRange?.[0]
      ? dayjs(searchForm.value.dateRange[0]).format('YYYY-MM-DD')
      : undefined,
    endTime: searchForm.value.dateRange?.[1]
      ? dayjs(searchForm.value.dateRange[1]).format('YYYY-MM-DD')
      : undefined,
    auditStartTime: searchForm.value.auditTimeRange?.[0]
      ? dayjs(searchForm.value.auditTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    auditEndTime: searchForm.value.auditTimeRange?.[1]
      ? dayjs(searchForm.value.auditTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    pageNum: pagination.value.page,
    pageSize: pagination.value.pageSize,
  }
}
async function getPolicyApplicationList() {
  startLoading()
  try {
    const dateRange = searchForm.value.dateRange || []
    const res = await fetchPolicyApplicationPageList({
      auditStatus: searchForm.value.auditStatus ?? undefined,
      nickName: searchForm.value.nickName || undefined,
      plateNumber: searchForm.value.plateNumber || undefined,
      startTime: dateRange[0]
        ? dayjs(dateRange[0]).format('YYYY-MM-DD')
        : undefined,
      endTime: dateRange[1]
        ? dayjs(dateRange[1]).format('YYYY-MM-DD')
        : undefined,
      pageNum: pagination.value.page,
      pageSize: pagination.value.pageSize,
    })
    const res = await fetchPolicyApplicationPageList(buildQueryParams())
    if (res.code === 200 && res.data) {
      tableData.value = res.data.records || []
      count.value = res.data.total || 0
@@ -373,6 +391,31 @@
    path: 'dateRange',
    render: () => <n-date-picker format="yyyy/MM/dd" v-model:value={searchForm.value.dateRange} type="daterange" clearable actions={[]} close-on-select={true} start-placeholder="开始时间" end-placeholder="结束时间" separator="-" />,
  },
  {
    label: t('serviceReview.policyApplication.vehicleCode'),
    path: 'vehicleCode',
    render: () => <n-input v-model:value={searchForm.value.vehicleCode} placeholder={t('common.inputPlaceholder')} clearable />,
  },
  {
    label: t('serviceReview.policyApplication.phoneNumber'),
    path: 'phoneNumber',
    render: () => <n-input v-model:value={searchForm.value.phoneNumber} placeholder={t('common.inputPlaceholder')} clearable />,
  },
  {
    label: t('serviceReview.policyApplication.auditUserName'),
    path: 'auditUserName',
    render: () => <n-input v-model:value={searchForm.value.auditUserName} placeholder={t('common.inputPlaceholder')} clearable />,
  },
  {
    label: t('serviceReview.policyApplication.auditTime'),
    path: 'auditTimeRange',
    render: () => <n-date-picker format="yyyy/MM/dd" v-model:value={searchForm.value.auditTimeRange} type="daterange" clearable actions={[]} close-on-select={true} start-placeholder="开始时间" end-placeholder="结束时间" separator="-" />,
  },
  {
    label: t('serviceReview.policyApplication.auditRemarks'),
    path: 'auditRemarks',
    render: () => <n-input v-model:value={searchForm.value.auditRemarks} placeholder={t('common.inputPlaceholder')} clearable />,
  },
])
</script>
@@ -386,7 +429,7 @@
        :show-feedback="false"
      >
        <SearchPanel>
          <n-gi v-for="item in filterItems" :key="item.path">
          <n-gi v-for="item in filterItems" :key="item.path" class="n-grid-item">
            <n-form-item :label="item.label" :path="item.path">
              <component :is="item.render" />
            </n-form-item>
src/views/service/ticket/feedback/index.vue
@@ -11,7 +11,7 @@
import { useBoolean } from '@/hooks'
import dayjs from 'dayjs'
import { fetchFeedbackPageList } from '@/service/api/serviceCenter'
import { fetchFeedbackPageList, fetchFeedbackTypeList } from '@/service/api/serviceCenter'
const { t } = useI18n()
@@ -25,10 +25,15 @@
const initialSearchForm = {
  feedbackContent: '',
  nickName: '',
  feedbackTypeId: null as number | null,
  phone: '',
  createTimeRange: null as [number, number] | null,
}
const searchForm = ref({ ...initialSearchForm })
const tableData = ref<any[]>([])
const feedbackTypeOptions = ref<any[]>([])
const pagination = ref({
  page: 1,
@@ -160,14 +165,27 @@
  getFeedbackList()
}
function buildQueryParams() {
  return {
    content: searchForm.value.feedbackContent.trim() || undefined,
    nickName: searchForm.value.nickName.trim() || undefined,
    feedbackTypeId: searchForm.value.feedbackTypeId ?? undefined,
    phone: searchForm.value.phone.trim() || undefined,
    startTime: searchForm.value.createTimeRange?.[0]
      ? dayjs(searchForm.value.createTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    endTime: searchForm.value.createTimeRange?.[1]
      ? dayjs(searchForm.value.createTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    pageNum: pagination.value.page,
    pageSize: pagination.value.pageSize,
  }
}
async function getFeedbackList() {
  startLoading()
  try {
    const res = await fetchFeedbackPageList({
      content: searchForm.value.feedbackContent || undefined,
      pageNum: pagination.value.page,
      pageSize: pagination.value.pageSize,
    })
    const res = await fetchFeedbackPageList(buildQueryParams())
    if (res.code === 200 && res.data) {
      tableData.value = res.data.records || []
      count.value = res.data.total || 0
@@ -182,15 +200,91 @@
  }
}
async function getFeedbackTypeOptions() {
  const res = await fetchFeedbackTypeList({ pageNum: 1, pageSize: 9999 })
  if (res.code === 200 && res.data) {
    const list = Array.isArray(res.data) ? res.data : res.data.records || []
    feedbackTypeOptions.value = list.map((item: any) => ({
      label: item.feedbackType,
      value: item.id,
    }))
  }
  else {
    feedbackTypeOptions.value = []
  }
}
onMounted(() => {
  getFeedbackTypeOptions()
  getFeedbackList()
})
const isFeedbackTypeSelectOpen = ref(false)
const filterItems = computed(() => [
  {
    label: t('ticket.feedback.feedbackContent'),
    path: 'feedbackContent',
    render: () => <n-input v-model:value={searchForm.value.feedbackContent} placeholder={t('common.inputPlaceholder')} />,
    render: () => <n-input v-model:value={searchForm.value.feedbackContent} placeholder={t('common.inputPlaceholder')} clearable />,
  },
  {
    label: t('ticket.feedback.feedbackPerson'),
    path: 'nickName',
    render: () => <n-input v-model:value={searchForm.value.nickName} placeholder={t('common.inputPlaceholder')} clearable />,
  },
  {
    label: t('ticket.feedback.feedbackType'),
    path: 'feedbackTypeId',
    render: () => (
      <n-select
        v-model:value={searchForm.value.feedbackTypeId}
        options={feedbackTypeOptions.value}
        placeholder={t('common.selectPlaceholder')}
        clearable
        onUpdate:show={val => isFeedbackTypeSelectOpen.value = val}
      >
        {{
          arrow: () => (
            <img
              src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
              class={`arrow-icon ${isFeedbackTypeSelectOpen.value ? 'arrow-icon--open' : ''}`}
              style={{ width: '16px', height: '16px' }}
              alt="arrow"
            />
          ),
          empty: () => (
            <div class="flex-center">
              <img
                src="/src/assets/element-img/no-data.png"
                style={{ width: '50%' }}
              />
            </div>
          ),
        }}
      </n-select>
    ),
  },
  {
    label: t('ticket.feedback.contact'),
    path: 'phone',
    render: () => <n-input v-model:value={searchForm.value.phone} placeholder={t('common.inputPlaceholder')} clearable />,
  },
  {
    label: t('ticket.feedback.feedbackTime'),
    path: 'createTimeRange',
    render: () => (
      <n-date-picker
        v-model:value={searchForm.value.createTimeRange}
        type="daterange"
        format="yyyy/MM/dd"
        clearable
        actions={[]}
        close-on-select={true}
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        separator="-"
      />
    ),
  },
])
</script>
@@ -205,7 +299,7 @@
        :show-feedback="false"
      >
        <SearchPanel>
          <n-gi v-for="item in filterItems" :key="item.path">
          <n-gi v-for="item in filterItems" :key="item.path" class="n-grid-item">
            <n-form-item :label="item.label" :path="item.path">
              <component :is="item.render" />
            </n-form-item>
src/views/service/ticket/workOrder/index.vue
@@ -1,6 +1,5 @@
<script setup lang="tsx">
import { computed, h, onMounted, ref } from 'vue'
import { onActivated } from 'vue'
import { computed, h, onActivated, onMounted, ref } from 'vue'
import type { DataTableColumns } from 'naive-ui'
import { NButton, NTag } from 'naive-ui'
import { useRouter } from 'vue-router'
@@ -50,6 +49,9 @@
  feedbackTypeId: null as number | null,
  priority: null as number | null,
  handleStatus: null as number | null,
  problem: '',
  handleUserName: '',
  createTimeRange: null as [number, number] | null,
}
const searchForm = ref({ ...initialSearchForm })
@@ -248,6 +250,26 @@
  getWorkOrderList()
}
function buildQueryParams() {
  return {
    feedbackTypeId: searchForm.value.feedbackTypeId || undefined,
    feedbackUserPhone: searchForm.value.feedbackUserPhone.trim() || undefined,
    handleStatus: searchForm.value.handleStatus ?? undefined,
    pageNum: pagination.value.page,
    pageSize: pagination.value.pageSize,
    priority: searchForm.value.priority ?? undefined,
    problemSource: searchForm.value.problemSource ?? undefined,
    problem: searchForm.value.problem.trim() || undefined,
    handleUserName: searchForm.value.handleUserName.trim() || undefined,
    createTimeStart: searchForm.value.createTimeRange?.[0]
      ? dayjs(searchForm.value.createTimeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
    createTimeEnd: searchForm.value.createTimeRange?.[1]
      ? dayjs(searchForm.value.createTimeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
      : undefined,
  }
}
function handleCreate() {
  modalMode.value = 'add'
  currentRow.value = null
@@ -411,15 +433,7 @@
async function getWorkOrderList() {
  startLoading()
  try {
    const res = await fetchWorkOrderPageList({
      feedbackTypeId: searchForm.value.feedbackTypeId || undefined,
      feedbackUserPhone: searchForm.value.feedbackUserPhone || undefined,
      handleStatus: searchForm.value.handleStatus ?? undefined,
      pageNum: pagination.value.page,
      pageSize: pagination.value.pageSize,
      priority: searchForm.value.priority ?? undefined,
      problemSource: searchForm.value.problemSource ?? undefined,
    })
    const res = await fetchWorkOrderPageList(buildQueryParams())
    if (res.code === 200 && res.data) {
      tableData.value = res.data.records || []
      count.value = res.data.total || res.data.records?.length || 0
@@ -586,6 +600,33 @@
      </n-select>
    ),
  },
  {
    label: t('workOrder.problem'),
    path: 'problem',
    render: () => <n-input v-model:value={searchForm.value.problem} placeholder={t('workOrder.search.placeholder')} clearable />,
  },
  {
    label: t('workOrder.handler'),
    path: 'handleUserName',
    render: () => <n-input v-model:value={searchForm.value.handleUserName} placeholder={t('workOrder.search.placeholder')} clearable />,
  },
  {
    label: t('workOrder.addTime'),
    path: 'createTimeRange',
    render: () => (
      <n-date-picker
        v-model:value={searchForm.value.createTimeRange}
        type="daterange"
        format="yyyy/MM/dd"
        clearable
        actions={[]}
        close-on-select={true}
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        separator="-"
      />
    ),
  },
])
</script>
@@ -599,7 +640,7 @@
        :show-feedback="false"
      >
        <SearchPanel>
          <n-gi v-for="item in filterItems" :key="item.path">
          <n-gi v-for="item in filterItems" :key="item.path" class="n-grid-item">
            <n-form-item :label="item.label" :path="item.path">
              <component :is="item.render" />
            </n-form-item>
src/views/transaction/directServiceManagement/index.vue
@@ -19,6 +19,12 @@
const initialModel = {
  cityCode: null,
  effectiveTime: null as [number, number] | null,
  vehicleCount: '',
  whitelistCount: '',
  status: null as number | null,
  remarks: '',
  createTime: null as [number, number] | null,
}
const model = ref({ ...initialModel })
@@ -45,7 +51,13 @@
const listData = ref<any[]>([])
const isCityCodeIdOpen = ref(false)
const isStatusOpen = ref(false)
const pcaOptions = ref<any[]>([])
const statusOptions = [
  { label: '启用', value: 1 },
  { label: '禁用', value: 2 },
]
// 获取城市数据
let parentIdCounter = 0
@@ -109,6 +121,55 @@
      </n-cascader>
    ),
  },
  {
    label: '生效时间段',
    path: 'effectiveTime',
    render: () => <n-date-picker v-model:value={model.value.effectiveTime} type="daterange" format="yyyy/MM/dd" clearable actions={[]} close-on-select={true} />,
  },
  {
    label: '绑定车辆数',
    path: 'vehicleCount',
    render: () => <n-input v-model:value={model.value.vehicleCount} placeholder="请输入" clearable />,
  },
  {
    label: '绑定用户数',
    path: 'whitelistCount',
    render: () => <n-input v-model:value={model.value.whitelistCount} placeholder="请输入" clearable />,
  },
  {
    label: '状态',
    path: 'status',
    render: () => (
      <n-select
        v-model:value={model.value.status}
        options={statusOptions}
        clearable
        placeholder="请选择"
        onUpdate:show={(val: any) => (isStatusOpen.value = val)}
      >
        {{
          arrow: () => (
            <img
              src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
              class={`arrow-icon ${isStatusOpen.value ? 'arrow-icon--open' : ''}`}
              style={{ width: '16px', height: '16px' }}
              alt="arrow"
            />
          ),
        }}
      </n-select>
    ),
  },
  {
    label: '备注',
    path: 'remarks',
    render: () => <n-input v-model:value={model.value.remarks} placeholder="请输入" clearable />,
  },
  {
    label: '添加时间',
    path: 'createTime',
    render: () => <n-date-picker v-model:value={model.value.createTime} type="daterange" format="yyyy/MM/dd" clearable actions={[]} close-on-select={true} />,
  },
])
// 获取列表数据
@@ -117,6 +178,14 @@
  const params = {
    ...pageParams.value,
    cityCode: model.value.cityCode,
    effectiveStartTime: model.value.effectiveTime?.[0] ? dayjs(model.value.effectiveTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    effectiveEndTime: model.value.effectiveTime?.[1] ? dayjs(model.value.effectiveTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    vehicleCount: model.value.vehicleCount?.trim() || undefined,
    whitelistCount: model.value.whitelistCount?.trim() || undefined,
    status: model.value.status ?? undefined,
    remarks: model.value.remarks?.trim() || undefined,
    createStartTime: model.value.createTime?.[0] ? dayjs(model.value.createTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    createEndTime: model.value.createTime?.[1] ? dayjs(model.value.createTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
  }
  getDirectServiceList(params).then((res) => {
    listData.value = res.data.records || []
src/views/transaction/navigationAndRoutePlanning/index.vue
@@ -16,6 +16,9 @@
const initialModel = {
  cityName: '',
  routePlanRule: null,
  planName: '',
  remarks: '',
  createTime: null as [number, number] | null,
}
const model = ref({ ...initialModel })
const pageParams = ref({
@@ -251,6 +254,21 @@
      </n-select>
    ),
  },
  {
    label: '名称',
    path: 'planName',
    render: () => <n-input v-model:value={model.value.planName} clearable />,
  },
  {
    label: '备注',
    path: 'remarks',
    render: () => <n-input v-model:value={model.value.remarks} clearable />,
  },
  {
    label: '添加时间',
    path: 'createTime',
    render: () => <n-date-picker format="yyyy/MM/dd" v-model:value={model.value.createTime} type="daterange" clearable actions={[]} close-on-select={true} />,
  },
])
const count = ref(0)
@@ -270,8 +288,12 @@
  startLoading()
  const params = {
    ...pageParams.value,
    cityName: model.value.cityName,
    cityName: model.value.cityName?.trim() || undefined,
    routePlanRule: model.value.routePlanRule,
    planName: model.value.planName?.trim() || undefined,
    remarks: model.value.remarks?.trim() || undefined,
    createStartTime: model.value.createTime?.[0] ? dayjs(model.value.createTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    createEndTime: model.value.createTime?.[1] ? dayjs(model.value.createTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
  }
  getRoutePlanList(params).then((res) => {
    listData.value = res.data.records || []
src/views/transaction/order/evaluationRecord/index.vue
@@ -15,6 +15,8 @@
  phoneNumber: '',
  plateNumber: '',
  time: null,
  nickName: '',
  orderNumber: '',
}
const model = ref({ ...initialModel })
const pageParams = ref({
@@ -166,6 +168,16 @@
    path: 'time',
    render: () => <n-date-picker format="yyyy/MM/dd" v-model:value={model.value.time} type="daterange" clearable actions={[]} close-on-select={true} />,
  },
  {
    label: '评价用户昵称',
    path: 'nickName',
    render: () => <n-input v-model:value={model.value.nickName} />,
  },
  {
    label: '关联订单号',
    path: 'orderNumber',
    render: () => <n-input v-model:value={model.value.orderNumber} />,
  },
])
const count = ref(0)
@@ -178,6 +190,8 @@
    orderRating: model.value.orderRating,
    phoneNumber: model.value.phoneNumber,
    plateNumber: model.value.plateNumber,
    nickName: model.value.nickName,
    orderNumber: model.value.orderNumber,
    startTime: model.value.time ? dayjs(model.value.time[0]).format('YYYY-MM-DD') : null,
    endTime: model.value.time ? dayjs(model.value.time[1]).format('YYYY-MM-DD') : null,
  }
src/views/transaction/order/orderManagement/index.vue
@@ -24,6 +24,11 @@
const initialModel = {
  orderNumber: '',
  nickName: '',
  phoneNumber: '',
  startPointName: '',
  endPointName: '',
  vehicleModel: '',
  orderMoney: '',
  plateNumber: null,
  fleetId: null,
  orderSource: null,
@@ -598,6 +603,31 @@
    path: 'orderTime',
    render: () => <n-date-picker format="yyyy/MM/dd" v-model:value={model.value.orderTime} type="daterange" clearable actions={[]} close-on-select={true} />,
  },
  {
    label: t('transaction.userPhone'),
    path: 'phoneNumber',
    render: () => <n-input v-model:value={model.value.phoneNumber} />,
  },
  {
    label: t('transaction.pickupLocation'),
    path: 'startPointName',
    render: () => <n-input v-model:value={model.value.startPointName} />,
  },
  {
    label: t('transaction.dropoffLocation'),
    path: 'endPointName',
    render: () => <n-input v-model:value={model.value.endPointName} />,
  },
  {
    label: t('transaction.selectedVehicleType'),
    path: 'vehicleModel',
    render: () => <n-input v-model:value={model.value.vehicleModel} />,
  },
  {
    label: t('transaction.orderAmount'),
    path: 'orderMoney',
    render: () => <n-input v-model:value={model.value.orderMoney} />,
  },
])
const count = ref(0)
@@ -609,6 +639,11 @@
    status: model.value.status,
    orderNumber: model.value.orderNumber,
    nickName: model.value.nickName,
    phoneNumber: model.value.phoneNumber,
    startPointName: model.value.startPointName,
    endPointName: model.value.endPointName,
    vehicleModel: model.value.vehicleModel,
    orderMoney: model.value.orderMoney,
    plateNumber: model.value.plateNumber,
    fleetId: model.value.fleetId,
    orderSource: model.value.orderSource,
@@ -637,6 +672,11 @@
      status: model.value.status,
      orderNumber: model.value.orderNumber,
      nickName: model.value.nickName,
      phoneNumber: model.value.phoneNumber,
      startPointName: model.value.startPointName,
      endPointName: model.value.endPointName,
      vehicleModel: model.value.vehicleModel,
      orderMoney: model.value.orderMoney,
      plateNumber: model.value.plateNumber,
      fleetId: model.value.fleetId,
      orderSource: model.value.orderSource,
src/views/transaction/passwordFreeStrategy/index.vue
@@ -14,10 +14,18 @@
const router = useRouter()
const dialog = useDialog()
const showOperationLogModal = ref(false)
const isStatusOpen = ref(false)
const statusOptions = [
  { label: '启用', value: 1 },
  { label: '禁用', value: 2 },
]
const initialModel = {
  createTimeRange: null as [number, number] | null,
  cityName: null as string | null,
  effectiveTimeRange: null as [number, number] | null,
  status: null as number | null,
}
const model = ref({ ...initialModel })
@@ -66,6 +74,44 @@
    path: 'cityName',
    render: () => <n-input v-model:value={model.value.cityName} />,
  },
  {
    label: '生效时间段',
    path: 'effectiveTimeRange',
    render: () => (
      <n-date-picker
        v-model:value={model.value.effectiveTimeRange}
        type="daterange"
        clearable
        format="yyyy/MM/dd"
        actions={null}
        close-on-select={true}
      />
    ),
  },
  {
    label: '规则状态',
    path: 'status',
    render: () => (
      <n-select
        v-model:value={model.value.status}
        options={statusOptions}
        clearable
        placeholder="请选择"
        onUpdate:show={(value: boolean) => isStatusOpen.value = value}
      >
        {{
          arrow: () => (
            <img
              src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
              class={`arrow-icon ${isStatusOpen.value ? 'arrow-icon--open' : ''}`}
              style={{ width: '16px', height: '16px' }}
              alt="arrow"
            />
          ),
        }}
      </n-select>
    ),
  },
])
// 获取列表数据
@@ -76,12 +122,19 @@
      pageNum: pageParams.value.page,
      pageSize: pageParams.value.size,
      cityName: model.value.cityName?.trim() || undefined,
      status: model.value.status ?? undefined,
      createTimeStart: model.value.createTimeRange?.[0]
        ? dayjs(model.value.createTimeRange[0]).format('YYYY-MM-DD HH:mm:ss')
        : undefined,
      createTimeEnd: model.value.createTimeRange?.[1]
        ? `${dayjs(model.value.createTimeRange[1]).format('YYYY-MM-DD')} 23:59:59`
        : undefined,
      effectiveTimeStart: model.value.effectiveTimeRange?.[0]
        ? dayjs(model.value.effectiveTimeRange[0]).format('YYYY-MM-DD HH:mm:ss')
        : undefined,
      effectiveTimeEnd: model.value.effectiveTimeRange?.[1]
        ? `${dayjs(model.value.effectiveTimeRange[1]).format('YYYY-MM-DD')} 23:59:59`
        : undefined,
    }
    const res = await getPasswordFreePolicyList(params)
    if (res.code === 200) {
src/views/transaction/pricingManagement/index.vue
@@ -19,6 +19,9 @@
const initialModel = {
  vehicleModel: '',
  cityName: '',
  channel: '',
  pricingType: null as number | null,
  createTime: null as [number, number] | null,
}
const model = ref({ ...initialModel })
const pageParams = ref({
@@ -36,6 +39,12 @@
const modalRef = ref()
const showOperationLogModal = ref(false)
const isPricingTypeOpen = ref(false)
const pricingTypeOptions = [
  { label: '动态计费', value: 1 },
  { label: '一口价', value: 2 },
]
function handleOpenOperationLog() {
  showOperationLogModal.value = true
@@ -169,6 +178,39 @@
    path: 'cityName',
    render: () => <n-input v-model:value={model.value.cityName} />,
  },
  {
    label: '渠道',
    path: 'channel',
    render: () => <n-input v-model:value={model.value.channel} />,
  },
  {
    label: '计费规则',
    path: 'pricingType',
    render: () => (
      <n-select
        v-model:value={model.value.pricingType}
        options={pricingTypeOptions}
        clearable
        onUpdate:show={(val: any) => isPricingTypeOpen.value = val}
      >
        {{
          arrow: () => (
            <img
              src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
              class={`arrow-icon ${isPricingTypeOpen.value ? 'arrow-icon--open' : ''}`}
              style={{ width: '16px', height: '16px' }}
              alt="arrow"
            />
          ),
        }}
      </n-select>
    ),
  },
  {
    label: '创建时间',
    path: 'createTime',
    render: () => <n-date-picker format="yyyy/MM/dd" v-model:value={model.value.createTime} type="daterange" clearable actions={[]} close-on-select={true} />,
  },
])
const count = ref(0)
@@ -178,8 +220,12 @@
  startLoading()
  const params = {
    ...pageParams.value,
    cityName: model.value.cityName,
    vehicleModel: model.value.vehicleModel,
    cityName: model.value.cityName?.trim() || undefined,
    vehicleModel: model.value.vehicleModel?.trim() || undefined,
    channel: model.value.channel?.trim() || undefined,
    pricingType: model.value.pricingType ?? undefined,
    createStartTime: model.value.createTime?.[0] ? dayjs(model.value.createTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
    createEndTime: model.value.createTime?.[1] ? dayjs(model.value.createTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') : undefined,
  }
  getPricingList(params).then((res) => {
    listData.value = res.data.records || []