zjk
2026-04-22 d489de67bd1d939ad1027f10d60210e3c5ed18e9
feat: 统一日期格式并完善多个功能模块

- 为多个视图的日期选择器添加统一的 `format="yyyy/MM/dd"` 格式
- 在车辆管理模块中集成车型的增删改查后端 API
- 在免密支付策略模块中集成后端 API 并调整表单字段
- 为多个下拉选择组件添加空状态图片及错误回退处理
- 更新路由配置中免密支付策略相关页面的标题
- 优化 API 函数参数拼接方式及代码格式
15个文件已修改
875 ■■■■■ 已修改文件
src/router/routes.static.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/transaction.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/vehicleConvoy.ts 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/assetManagement/vehicleModel/components/AddOrEditModal.vue 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/assetManagement/vehicleModel/index.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/businessOperations/geofenceManagement/detail.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/cruiseCheckInDetails/index.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/cruiseCheckInRule/add.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/cruiseCheckInStatistics/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/directServiceManagement/add.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/directServiceManagement/index.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/passwordFreeStrategy/add.vue 399 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/passwordFreeStrategy/index.vue 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/userContent/active/activityManagement/add.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/userContent/whitelistManagement/whitelist/detail.vue 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes.static.ts
@@ -1030,7 +1030,7 @@
  {
    name: 'passwordFreeStrategy',
    path: '/transaction/passwordFreeStrategy',
    title: '免密支付策略配置',
    title: '免密支付策略',
    requiresAuth: true,
    icon: 'icon-park-outline:list-view',
    menuType: 'page',
@@ -1042,7 +1042,7 @@
  {
    name: 'passwordFreeStrategyAdd',
    path: '/transaction/passwordFreeStrategy/add',
    title: '新增免密支付策略',
    title: '新增策略',
    requiresAuth: true,
    icon: 'icon-park-outline:list-view',
    menuType: 'page',
@@ -1057,7 +1057,7 @@
  {
    name: 'passwordFreeStrategyEdit',
    path: '/transaction/passwordFreeStrategy/edit',
    title: '编辑免密支付策略',
    title: '编辑策略',
    requiresAuth: true,
    icon: 'icon-park-outline:list-view',
    menuType: 'page',
@@ -1072,7 +1072,7 @@
  {
    name: 'passwordFreeStrategyDetail',
    path: '/transaction/passwordFreeStrategy/detail',
    title: '免密支付策略详情',
    title: '策略详情',
    requiresAuth: true,
    icon: 'icon-park-outline:list-view',
    menuType: 'page',
src/service/api/transaction.ts
@@ -47,15 +47,7 @@
// 获取可用车辆列表
export function getAvailableVehicleList(params: any) {
  const query = new URLSearchParams({
    orderId: String(params.orderId ?? ''),
    orderType: String(params.orderType ?? ''),
  })
  if (params.plateNumber !== undefined && params.plateNumber !== null)
    query.set('plateNumber', String(params.plateNumber))
  if (params.fleetName !== undefined && params.fleetName !== null)
    query.set('fleetName', String(params.fleetName))
  return request.Get<Service.ResponseResult<any>>(`/vehicleConvoy/api/v1/vehicle/availableList?${query.toString()}`)
  return request.Get<Service.ResponseResult<any>>(`/vehicleConvoy/api/v1/vehicle/availableList?orderId=${params.orderId}&orderType=${params.orderType}&plateNumber=${params.plateNumber}&fleetName=${params.fleetName}`)
}
/** 订单评价 */
@@ -140,3 +132,28 @@
export function setRule(params: any) {
  return request.Post<Service.ResponseResult<any>>('/operation/api/v1/pricing/setRule', params)
}
// 新增免密支付策略
export function addPasswordFreePolicy(params: any) {
  return request.Post<Service.ResponseResult<any>>('/operation/api/v1/passwordFreePolicy/add', params)
}
// 编辑免密支付策略
export function editPasswordFreePolicy(params: any) {
  return request.Post<Service.ResponseResult<any>>('/operation/api/v1/passwordFreePolicy/edit', params)
}
// 删除免密支付策略
export function deletePasswordFreePolicy(id: any) {
  return request.Delete<Service.ResponseResult<any>>(`/operation/api/v1/passwordFreePolicy/deleteById/${id}`)
}
// 获取免密支付策略列表
export function getPasswordFreePolicyList(params: any) {
  return request.Post<Service.ResponseResult<any>>('/operation/api/v1/passwordFreePolicy/pageList', params)
}
// 获取免密支付策略详情
export function getPasswordFreePolicyDetail(id: any) {
  return request.Get<Service.ResponseResult<any>>(`/operation/api/v1/passwordFreePolicy/queryById?id=${id}`)
}
src/service/api/vehicleConvoy.ts
@@ -1,113 +1,108 @@
import { request } from '@/service/http'
// POST
// ​/api​/v1​/vehicle​/batchStock
// 批量在库
export function batchStock(data: any) {
  return request.Post<Service.ResponseResult<any>>('/vehicleConvoy/api/v1/vehicle/batchStock?idStr=' + data.idStr,)
}
// POST
// ​/api​/v1​/vehicle​/operationExportExcel
// 运营车辆管理列表导出
    export function operationExportExcel(data: any) {
 const method= request.Post('/vehicleConvoy/api/v1/vehicle/operationExportExcel', data, { responseType: 'blob' })
 method.meta = { ...method.meta, isBlob: true }
 return method
  return request.Post<Service.ResponseResult<any>>(`/vehicleConvoy/api/v1/vehicle/batchStock?idStr=${data.idStr}`)
}
// POST
// ​/api​/v1​/vehicle​/operationPageList
// 运营车辆管理列表导出
export function operationExportExcel(data: any) {
  const method = request.Post('/vehicleConvoy/api/v1/vehicle/operationExportExcel', data, { responseType: 'blob' })
  method.meta = { ...method.meta, isBlob: true }
  return method
}
// 运营车辆管理分页列表
export function operationPageList(data: any) {
  return request.Post<Service.ResponseResult<any>>('/vehicleConvoy/api/v1/vehicle/operationPageList', data)
}
// POST
// ​/api​/v1​/vehicle​/queryTaskRoutineByVehicleId
// 通过车辆id查询年检分页列表
export function queryTaskRoutineByVehicleId(data: any) {
  return request.Post<Service.ResponseResult<any>>('/vehicleConvoy/api/v1/vehicle/queryTaskRoutineByVehicleId', data)
}
// DELETE
// ​/api​/v1​/chargingRecord​/delete​/{id}
// 删除充电记录
export function deleteChargingRecordById(id: string) {
  return request.Delete<Service.ResponseResult<any>>(`/maintenance/api/v1/chargingRecord/delete/${id}`)
}
// DELETE
// ​/api​/v1​/task​/delete​/{id}
// 删除删除任务/事故
export function deleteTaskById(id: string) {
  return request.Delete<Service.ResponseResult<any>>(`/maintenance/api/v1/task/delete/${id}`)
}
// GET
// ​/api​/v1​/task​/errorTypeTreeList
// 事故类型列表
export function errorTypeTreeList() {
  return request.Get<Service.ResponseResult<any>>('/maintenance/api/v1/task/errorTypeTreeList')
}
// POST
// ​/api​/v1​/vehicle​/queryChargingByVehicleId
// 通过车辆id查询充电分页列表
export function queryChargingByVehicleId(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/vehicle/queryChargingByVehicleId', data)
}
// POST
// ​/api​/v1​/vehicle​/queryDetectionByVehicleId
// 通过车辆id查询检测分页列表
export function queryDetectionByVehicleId(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/vehicle/queryDetectionByVehicleId', data)
}
// POST
// ​/api​/v1​/vehicle​/queryPreparationByVehicleId
// 通过车辆ID查询整备分页列表
export function queryPreparationByVehicleId(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/vehicle/queryPreparationByVehicleId', data)
}
// POST
// /api/v1/vehicleClean/list
// 车辆管理-清洁列表
export function queryCleanByVehicleId(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/vehicleClean/list', data)
}
// DELETE
// /api/v1/vehicleClean/delete
// 车辆管理-删除清洁记录
export function deleteCleanRecordById(id: string | number) {
  return request.Delete<Service.ResponseResult<any>>(`/maintenance/api/v1/vehicleClean/delete?id=${id}`)
}
// POST
// ​/api​/v1​/vehicle​/queryRepairByVehicleId
// 通过车辆id查询维修分页列表
export function queryRepairByVehicleId(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/vehicle/queryRepairByVehicleId', data)
}
// POST
// ​/api​/v1​/vehicle​/queryTaskByVehicleId
// 通过车辆id查询任务事故分页列表
export function queryTaskByVehicleId(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/api/v1/vehicle/queryTaskByVehicleId', data)
}
// GET
// ​/api​/v1​/electronicFence​/list
// 获取不分页的电子围栏列表
export function electronicFenceList() {
  return request.Get<Service.ResponseResult<any>>('/operation/api/v1/electronicFence/list')
}
// GET
// /api/v1/taskManagement/taskDetail
// 任务/事故详情
export function getTaskDetail(id: string) {
  return request.Get<Service.ResponseResult<any>>('/maintenance/api/v1/taskManagement/taskDetail', { params: { id } })
}
// 车辆管理-车型列表
export function queryVehicleModelList(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/logan/inner/xpVehicleModel/pageList', data)
}
// 车辆管理-新增车型
export function addVehicleModel(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/logan/inner/xpVehicleModel/add', data)
}
// 车辆管理-编辑车型
export function editVehicleModel(data: any) {
  return request.Post<Service.ResponseResult<any>>('/maintenance/logan/inner/xpVehicleModel/edit', data)
}
// 车辆管理-删除车型
export function deleteVehicleModelById(id: string | number) {
  return request.Delete<Service.ResponseResult<any>>(`/maintenance/logan/inner/xpVehicleModel/deleteById?id=${id}`)
}
// 车辆管理-车型详情
export function getVehicleModelDetail(id: string) {
  return request.Get<Service.ResponseResult<any>>(`/maintenance/logan/inner/xpVehicleModel/getById?id=${id}`)
}
src/views/assetManagement/vehicleModel/components/AddOrEditModal.vue
@@ -2,6 +2,7 @@
import { ref } from 'vue'
import type { FormInst, FormRules } from 'naive-ui'
import { NButton, NForm, NFormItem, NInput, NInputNumber, NModal, NSpace, useMessage } from 'naive-ui'
import { addVehicleModel, editVehicleModel, getVehicleModelDetail } from '@/service/api/vehicleConvoy'
const emit = defineEmits<{
  refresh: []
@@ -14,20 +15,20 @@
const formRef = ref<FormInst | null>(null)
const defaultModel = {
  id: undefined as string | undefined,
  modelName: '',
  seats: null as number | null,
  id: undefined as string | number | undefined,
  name: '',
  seat: null as number | null,
}
const formModel = ref({ ...defaultModel })
const rules: FormRules = {
  modelName: {
  name: {
    required: true,
    message: '请输入车型名称',
    trigger: ['blur', 'input'],
  },
  seats: {
  seat: {
    required: true,
    type: 'number',
    message: '请输入座位数',
@@ -35,10 +36,28 @@
  },
}
function openModal(row?: any) {
async function openModal(row?: any) {
  isEdit.value = !!row
  if (row) {
    formModel.value = { ...row }
    formModel.value = {
      ...defaultModel,
      ...row,
    }
    if (row.id !== undefined && row.id !== null) {
      try {
        const res = await getVehicleModelDetail(String(row.id))
        if (res.code === 200 && res.data) {
          formModel.value = {
            ...defaultModel,
            ...res.data,
            seat: Number(res.data.seat),
          }
        }
      }
      catch (error) {
        console.error('获取车型详情失败:', error)
      }
    }
  }
  else {
    formModel.value = { ...defaultModel }
@@ -50,19 +69,34 @@
  visible.value = false
}
function handleSubmit() {
  formRef.value?.validate((errors) => {
    if (!errors) {
      loading.value = true
      // 模拟提交
      setTimeout(() => {
        loading.value = false
        message.success(isEdit.value ? '编辑成功' : '新增成功')
        visible.value = false
        emit('refresh')
      }, 500)
async function handleSubmit() {
  if (loading.value)
    return
  try {
    await formRef.value?.validate()
    loading.value = true
    const params = {
      id: formModel.value.id,
      name: formModel.value.name.trim(),
      seat: formModel.value.seat,
    }
  })
    const request = isEdit.value ? editVehicleModel(params) : addVehicleModel(params)
    const res = await request
    if (res.code === 200) {
      message.success(isEdit.value ? '编辑成功' : '新增成功')
      visible.value = false
      emit('refresh')
      return
    }
    message.warning(res.msg || '保存失败')
  }
  catch (error) {
    console.error('保存车型失败:', error)
    message.error('请求失败,请稍后重试')
  }
  finally {
    loading.value = false
  }
}
defineExpose({
@@ -72,13 +106,11 @@
<template>
  <NModal
    v-model:show="visible"
    preset="card"
    :title="isEdit ? '编辑车型' : '新增车型'"
    style="width: 400px; border-radius: 8px;"
    :segmented="{ content: true }"
    content-style="padding: 24px;"
    footer-style="padding: 16px 24px;"
    v-model:show="visible" :mask-closable="false" preset="card" :title="isEdit ? '编辑车型' : '新增车型'" class="w-400px"
    :segmented="{
      content: true,
      action: true,
    }"
  >
    <NForm
      ref="formRef"
@@ -87,16 +119,16 @@
      label-placement="top"
      require-mark-placement="left"
    >
      <NFormItem label="车型名称" path="modelName">
      <NFormItem label="车型名称" path="name">
        <NInput
          v-model:value="formModel.modelName"
          v-model:value="formModel.name"
          placeholder="请输入"
          clearable
        />
      </NFormItem>
      <NFormItem label="座位数" path="seats">
      <NFormItem label="座位数" path="seat">
        <NInputNumber
          v-model:value="formModel.seats"
          v-model:value="formModel.seat"
          placeholder="请输入"
          clearable
          :min="1"
@@ -106,7 +138,7 @@
      </NFormItem>
    </NForm>
    <template #footer>
    <template #action>
      <NSpace justify="end">
        <NButton @click="handleCancel">
          取消
src/views/assetManagement/vehicleModel/index.vue
@@ -5,14 +5,16 @@
import { useBoolean } from '@/hooks'
import SearchPanel from '@/components/custom/SearchPanel.vue'
import Pagination from '@/components/common/Pagination.vue'
import { deleteVehicleModelById, queryVehicleModelList } from '@/service/api/vehicleConvoy'
import AddOrEditModal from './components/AddOrEditModal.vue'
import dayjs from 'dayjs'
const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(false)
const dialog = useDialog()
const addOrEditModalRef = ref()
const initialModel = {
  modelName: '',
  name: '',
}
const model = ref({ ...initialModel })
const pagination = reactive({
@@ -35,8 +37,8 @@
const filterItems = computed(() => [
  {
    label: '车型名称',
    path: 'modelName',
    render: () => <n-input v-model:value={model.value.modelName} placeholder="请输入" clearable />,
    path: 'name',
    render: () => <n-input v-model:value={model.value.name} placeholder="请输入" clearable />,
  },
])
@@ -59,16 +61,19 @@
    key: 'createTime',
    width: 160,
    resizable: true,
    render: (row) => {
      return row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'
    },
  },
  {
    title: '车型名称',
    key: 'modelName',
    key: 'name',
    width: 300,
    resizable: true,
  },
  {
    title: '座位数',
    key: 'seats',
    key: 'seat',
    width: 100,
    resizable: true,
  },
@@ -102,21 +107,33 @@
async function getList() {
  startLoading()
  // Mock data simulation
  setTimeout(() => {
    const mockData = Array.from({ length: pagination.pageSize }).map((_, index) => {
      const idx = (pagination.page - 1) * pagination.pageSize + index + 1
      return {
        id: `mock-id-${idx}`,
        createTime: '2025-05-07 14:53',
        modelName: idx === 1 ? 'Robotaxi R1' : 'Robotaxi X1',
        seats: idx === 1 ? 4 : (idx === 2 ? 6 : 4),
      }
    })
    count.value = 1000
    listData.value = mockData
  try {
    const params = {
      pageNum: pagination.page,
      pageSize: pagination.pageSize,
      name: model.value.name?.trim() || undefined,
    }
    const res = await queryVehicleModelList(params)
    if (res.code === 200) {
      // 兼容分页/非分页两种返回结构
      const records = res.data?.records || res.data?.list || []
      count.value = Number(res.data?.total ?? records.length ?? 0)
      listData.value = Array.isArray(records) ? records : []
      return
    }
    listData.value = []
    count.value = 0
    window.$message?.warning(res.msg || '获取车型列表失败')
  }
  catch (error) {
    console.error('获取车型列表失败:', error)
    listData.value = []
    count.value = 0
    window.$message?.error('请求车型列表失败')
  }
  finally {
    endLoading()
  }, 500)
  }
}
function handleAdd() {
@@ -130,12 +147,18 @@
function handleDelete(row: any) {
  dialog.create({
    title: '是否确认删除',
    content: `确认删除车型 ${row.modelName} 吗?`,
    content: `确认删除该车型?删除后不可恢复。`,
    positiveText: '确定',
    negativeText: '取消',
    onPositiveClick: () => {
      window.$message?.success('删除成功')
      getList()
    onPositiveClick: async () => {
      const res = await deleteVehicleModelById(row.id)
      if (res.code === 200) {
        window.$message?.success('删除成功')
        getList()
      }
      else {
        window.$message?.warning(res.msg || '删除失败')
      }
    },
  })
}
src/views/businessOperations/geofenceManagement/detail.vue
@@ -2298,7 +2298,7 @@
                      fenceDetail.effectType === 1
                        ? "立即生效"
                        : dayjs(fenceDetail.effectTime).format(
                          "YYYY-MM-DD HH:mm:ss",
                          "YYYY/MM/DD HH:mm:ss",
                        ) || "-"
                    }}
                  </div>
@@ -2312,7 +2312,7 @@
                      fenceDetail.failureType === 1
                        ? "永不失效"
                        : dayjs(fenceDetail.failureTime).format(
                          "YYYY-MM-DD HH:mm:ss",
                          "YYYY/MM/DD HH:mm:ss",
                        ) || "-"
                    }}
                  </div>
src/views/operations/cruiseCheckInDetails/index.vue
@@ -225,6 +225,7 @@
        clearable
        actions={[]}
        close-on-select={true}
        format="yyyy/MM/dd"
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        separator="-"
src/views/operations/cruiseCheckInRule/add.vue
@@ -206,6 +206,7 @@
            clearable
            class="flex-1"
            placeholder="请选择起止日期"
            format="yyyy/MM/dd"
            :actions="[]"
            :close-on-select="true"
          />
src/views/operations/cruiseCheckInStatistics/index.vue
@@ -29,6 +29,7 @@
        v-model:value={model.value.dateRange}
        type="daterange"
        clearable
        format="yyyy/MM/dd"
        actions={[]}
        close-on-select={true}
        start-placeholder="开始时间"
@@ -63,7 +64,7 @@
    data: ['2026-03-23', '2026-03-24', '2026-03-25', '2026-03-26', '2026-03-27', '2026-03-28'],
    axisTick: { show: false },
    axisLine: { lineStyle: { color: '#E5E6EB' } },
    axisLabel: { color: '#4E5969' }
    axisLabel: { color: '#4E5969' },
  },
  yAxis: {
    type: 'value',
@@ -71,7 +72,7 @@
    max: 250,
    interval: 50,
    splitLine: { lineStyle: { type: 'solid', color: '#E5E6EB' } },
    axisLabel: { color: '#4E5969' }
    axisLabel: { color: '#4E5969' },
  },
  series: [
    {
@@ -122,7 +123,7 @@
        show: true,
        position: 'inner',
        formatter: '{d}%',
        color: '#fff'
        color: '#fff',
      },
      emphasis: {
        itemStyle: {
@@ -150,7 +151,7 @@
    data: ['2026-03-23', '2026-03-24', '2026-03-25', '2026-03-26', '2026-03-27', '2026-03-28'],
    axisTick: { show: false },
    axisLine: { lineStyle: { color: '#E5E6EB' } },
    axisLabel: { color: '#4E5969' }
    axisLabel: { color: '#4E5969' },
  },
  yAxis: {
    type: 'value',
@@ -158,7 +159,7 @@
    max: 250,
    interval: 50,
    splitLine: { lineStyle: { type: 'solid', color: '#E5E6EB' } },
    axisLabel: { color: '#4E5969' }
    axisLabel: { color: '#4E5969' },
  },
  series: [
    {
@@ -209,7 +210,7 @@
        show: true,
        position: 'inner',
        formatter: '{d}%',
        color: '#fff'
        color: '#fff',
      },
      emphasis: {
        itemStyle: {
@@ -271,4 +272,4 @@
.w-full {
  width: 100%;
}
</style>
</style>
src/views/transaction/directServiceManagement/add.vue
@@ -591,6 +591,15 @@
                      class="arrow-icon" style="width: 16px; height: 16px" alt="arrow"
                    >
                  </template>
                  <template #empty>
                    <div class="flex-center">
                      <img
                        src="/src/assets/element-img/no-data.png"
                        style="width: 123px; height: 125px"
                        @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
                      >
                    </div>
                  </template>
                </NCascader>
              </n-form-item-gi>
@@ -603,12 +612,12 @@
                        formModel.startTime = val
                        startTimePicker?.handlePanelClose()
                      },
                    }" :disabled="formModel.isLongValid === 1" placeholder="请选择开始时间" class="max-w-[200px]"
                    }" :disabled="formModel.isLongValid === 1" format="yyyy/MM/dd HH:mm" placeholder="请选择开始时间" class="max-w-[200px]"
                  />
                  <span class="text-gray-400 shrink-0">至</span>
                  <NDatePicker
                    ref="endTimePicker" v-model:value="formModel.endTime" type="datetime" clearable
                    :actions="null" :disabled="formModel.isLongValid === 1" placeholder="请选择结束时间" class="max-w-[200px]"
                    :actions="null" :disabled="formModel.isLongValid === 1" format="yyyy/MM/dd HH:mm" placeholder="请选择结束时间" class="max-w-[200px]"
                    :time-picker-props="{
                      onConfirm: (val) => {
                        formModel.endTime = val
src/views/transaction/directServiceManagement/index.vue
@@ -90,6 +90,15 @@
              alt="arrow"
            />
          ),
          empty: () => (
            <div class="flex-center">
              <img
                src="/src/assets/element-img/no-data.png"
                style={{ width: '123px', height: '125px' }}
                onError={(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }}
              />
            </div>
          ),
        }}
      </n-cascader>
    ),
@@ -256,7 +265,7 @@
function handleDelete(row: any) {
  dialog.create({
    title: '删除确认',
    content: '确定要删除该定向服务吗?',
    content: '确认删除该定向服务?删除后不可恢复。',
    positiveText: '确定',
    negativeText: '取消',
    onPositiveClick: () => {
src/views/transaction/passwordFreeStrategy/add.vue
@@ -1,7 +1,10 @@
<script setup lang="tsx">
import { computed, onMounted, ref, watch } from 'vue'
import { onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { NButton, NCheckbox, NDatePicker, NForm, NFormItemGi, NGrid, NInputNumber, NRadio, NRadioGroup, NSelect, NSpace, NSwitch, useMessage } from 'naive-ui'
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 { useTabStore } from '@/store'
const tabStore = useTabStore()
@@ -12,67 +15,69 @@
const id = ref<string | null>(null)
const pageType = ref<'add' | 'edit' | 'view'>('add')
const loading = ref(false)
const saving = ref(false)
const isCityOpen = ref(false)
const isOperationAreaOpen = ref(false)
const formModel = ref({
  city: null as string | null,
  operationArea: null as string | null,
  status: 1,
  startTime: null as number | null,
  endTime: null as number | null,
  longTermEffective: false,
  maxRetryCount: null as number | null,
  retryInterval: null as number | null,
  sendNotification: true,
  priceDifferenceThreshold: null as number | null,
  validTimeStart: null as number | null,
  validTimeEnd: null as number | null,
  validTimeLong: false,
  maxRetriesNumber: null as number | null,
  retriesInterval: null as number | null,
  sendNotification: 1 as 0 | 1,
  differenceRatio: null as number | null,
})
const rules = {
  city: { required: true, message: '请选择城市', trigger: ['blur', 'change'] },
  operationArea: { required: true, message: '请选择运营区域', trigger: ['blur', 'change'] },
  status: { required: true, type: 'number', message: '请选择状态', trigger: ['blur', 'change'] },
  status: { required: true, type: 'number', message: '请选择状态', trigger: ['blur', 'change'] } as FormItemRule,
}
watch(() => formModel.value.longTermEffective, (val) => {
watch(() => formModel.value.validTimeLong, (val) => {
  if (val) {
    formModel.value.startTime = null
    formModel.value.endTime = null
    formModel.value.validTimeStart = null
    formModel.value.validTimeEnd = null
  }
})
const formRef = ref<any>(null)
const pageTitle = computed(() => {
  if (pageType.value === 'add')
    return '免密支付策略配置'
  if (pageType.value === 'edit')
    return '编辑免密支付策略'
  return '免密支付策略详情'
})
const validTimeStartPicker = ref<any>(null)
const validTimeEndPicker = ref<any>(null)
async function fetchDetail() {
  if (!id.value)
    return
  loading.value = true
  try {
    // Mock fetching detail
    setTimeout(() => {
    const res = await getPasswordFreePolicyDetail(id.value)
    if (res.code === 200 && res.data) {
      const data = res.data
      formModel.value = {
        city: 'shenzhen',
        operationArea: 'nanshan',
        status: 1,
        startTime: null,
        endTime: null,
        longTermEffective: true,
        maxRetryCount: 3,
        retryInterval: 60,
        sendNotification: true,
        priceDifferenceThreshold: 20,
        city: data.city ?? data.cityId ?? null,
        operationArea: data.operationArea ?? data.operationAreaId ?? null,
        status: Number(data.status ?? 1),
        validTimeStart: data.validTimeStart ? dayjs(data.validTimeStart).valueOf() : null,
        validTimeEnd: data.validTimeEnd ? dayjs(data.validTimeEnd).valueOf() : null,
        validTimeLong: data.validTimeLong === true || data.validTimeLong === 1,
        maxRetriesNumber: data.maxRetriesNumber ?? null,
        retriesInterval: data.retriesInterval ?? null,
        sendNotification: data.sendNotification === 1 || data.sendNotification === true ? 1 : 0,
        differenceRatio: data.differenceRatio ?? null,
      }
      loading.value = false
    }, 500)
      return
    }
    message.warning(res.msg || '获取策略详情失败')
  }
  catch (error) {
    console.error(error)
    console.error('获取策略详情失败:', error)
    message.error('请求策略详情失败')
  }
  finally {
    loading.value = false
  }
}
@@ -82,17 +87,66 @@
  router.back()
}
function handleSave() {
  formRef.value?.validate((errors: any) => {
    if (!errors) {
      // Mock API call
async function handleSave() {
  if (saving.value)
    return
  try {
    await formRef.value?.validate()
    saving.value = true
    const params = {
      id: id.value ? Number(id.value) : undefined,
      city: formModel.value.city,
      cityId: formModel.value.city,
      operationArea: formModel.value.operationArea,
      operationAreaId: formModel.value.operationArea,
      status: Number(formModel.value.status),
      validTimeLong: formModel.value.validTimeLong ? 1 : 0,
      validTimeStart: formModel.value.validTimeLong || !formModel.value.validTimeStart
        ? undefined
        : dayjs(formModel.value.validTimeStart).format('YYYY-MM-DD HH:mm:ss'),
      validTimeEnd: formModel.value.validTimeLong || !formModel.value.validTimeEnd
        ? undefined
        : dayjs(formModel.value.validTimeEnd).format('YYYY-MM-DD HH:mm:ss'),
      maxRetriesNumber: formModel.value.maxRetriesNumber,
      retriesInterval: formModel.value.retriesInterval,
      sendNotification: Number(formModel.value.sendNotification),
      differenceRatio: formModel.value.differenceRatio,
    }
    const request = pageType.value === 'edit' ? editPasswordFreePolicy(params) : addPasswordFreePolicy(params)
    const res = await request
    if (res.code === 200) {
      message.success('保存成功')
      handleCancel()
      return
    }
    message.warning(res.msg || '保存失败')
  }
  catch (error) {
    console.error('保存免密支付策略失败:', error)
    message.error('请求失败,请稍后重试')
  }
  finally {
    saving.value = false
  }
}
const cityList = ref<any[]>([])
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
      })
    }
  })
}
onMounted(() => {
  getCityListData()
  if (route.query.id) {
    id.value = route.query.id as string
    pageType.value = route.query.type === 'view' ? 'view' : 'edit'
@@ -104,12 +158,6 @@
<template>
  <div class="w-full h-full relative content flex flex-col">
    <div class="p-12px main flex flex-col flex-1 overflow-y-auto">
      <div class="box mb-12px shrink-0">
        <div class="text-xl">
          {{ pageTitle }}
        </div>
      </div>
      <NForm
        ref="formRef"
        :model="formModel"
@@ -124,46 +172,115 @@
          <div class="head shrink-0">
            基础信息
          </div>
          <NGrid :cols="24" :x-gap="24" :y-gap="16" class="mt-4">
            <NFormItemGi :span="5" label="城市" path="city">
              <NSelect v-model:value="formModel.city" placeholder="请选择" :options="[]" class="w-240px" />
            </NFormItemGi>
            <NFormItemGi :span="8" label="运营区域" path="operationArea">
              <NSelect v-model:value="formModel.operationArea" placeholder="请选择" :options="[]" class="w-240px" />
            </NFormItemGi>
            <NFormItemGi :span="8" label="状态" path="status">
              <NRadioGroup v-model:value="formModel.status">
                <NSpace>
                  <NRadio :value="1">启用</NRadio>
                  <NRadio :value="0">禁用</NRadio>
                </NSpace>
              </NRadioGroup>
            </NFormItemGi>
            <NFormItemGi :span="24" label="生效时间段" :required="!formModel.longTermEffective">
              <div class="flex items-center gap-2">
          <div class="row-group mb-8px">
            <n-form-item label="城市" path="city" required class="inline-item">
              <NSelect
                v-model:value="formModel.city"
                placeholder="请选择"
                :options="cityList"
                class="w-300px"
                @update:show="(val: boolean) => isCityOpen = val"
              >
                <template #arrow>
                  <img
                    src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
                    class="arrow-icon"
                    :class="{ 'arrow-icon--open': isCityOpen }"
                    alt="arrow"
                  >
                </template>
                l                <template #empty>
                  <div class="flex-center">
                    <img
                      src="/src/assets/element-img/no-data.png"
                      style="width: 50%;"
                      @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
                    >
                  </div>
                </template>
              </NSelect>
            </n-form-item>
            <n-form-item label="运营区域" path="operationArea" required class="inline-item">
              <NSelect
                v-model:value="formModel.operationArea"
                placeholder="请选择"
                :options="[]"
                class="w-300px"
                @update:show="(val: boolean) => isOperationAreaOpen = val"
              >
                <template #arrow>
                  <img
                    src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
                    class="arrow-icon"
                    :class="{ 'arrow-icon--open': isOperationAreaOpen }"
                    alt="arrow"
                  >
                </template>
                <template #empty>
                  <div class="flex-center">
                    <img
                      src="/src/assets/element-img/no-data.png"
                      style="width: 50%;"
                      @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
                    >
                  </div>
                </template>
              </NSelect>
            </n-form-item>
          </div>
          <div class="row-group">
            <n-form-item label="生效时间段" required class="inline-item time-item">
              <div class="inline-line">
                <NDatePicker
                  v-model:value="formModel.startTime"
                  ref="validTimeStartPicker"
                  v-model:value="formModel.validTimeStart"
                  type="datetime"
                  placeholder="请选择"
                  class="w-200px"
                  :disabled="formModel.longTermEffective"
                  class="w-240px"
                  :disabled="formModel.validTimeLong"
                  :actions="null"
                  close-on-select
                  format="yyyy/MM/dd HH:mm"
                  :time-picker-props="{
                    onConfirm: (val) => {
                      formModel.validTimeStart = val
                      validTimeStartPicker?.handlePanelClose()
                    },
                  }"
                />
                <span class="text-gray-600 mx-2">至</span>
                <span class="inline-text">至</span>
                <NDatePicker
                  v-model:value="formModel.endTime"
                  ref="validTimeEndPicker"
                  v-model:value="formModel.validTimeEnd"
                  type="datetime"
                  placeholder="请选择"
                  class="w-200px"
                  :disabled="formModel.longTermEffective"
                  class="w-240px"
                  :disabled="formModel.validTimeLong"
                  format="yyyy/MM/dd HH:mm"
                  :actions="null"
                  close-on-select
                  :time-picker-props="{
                    onConfirm: (val) => {
                      formModel.validTimeEnd = val
                      validTimeEndPicker?.handlePanelClose()
                    },
                  }"
                />
                <NCheckbox v-model:checked="formModel.longTermEffective" class="ml-4">
                <NCheckbox v-model:checked="formModel.validTimeLong" class="ml-4">
                  长期有效
                </NCheckbox>
                <span class="status-label"><i>*</i>状态</span>
                <NSwitch v-model:value="formModel.status" :checked-value="1" :unchecked-value="2">
                  <template #checked>
                    启用
                  </template>
                  <template #unchecked>
                    禁用
                  </template>
                </NSwitch>
              </div>
            </NFormItemGi>
          </NGrid>
            </n-form-item>
          </div>
        </div>
        <!-- 卡片1:免密支付扣款失败重试策略 -->
@@ -171,37 +288,37 @@
          <div class="head shrink-0">
            免密支付扣款失败重试策略
          </div>
          <NGrid :cols="24" :x-gap="24" :y-gap="16" class="mt-4">
            <NFormItemGi :span="24" label="" :show-label="false">
              <div class="flex items-center text-[14px] text-gray-800">
                最大重试次数
          <div class="row-group mb-8px">
            <n-form-item :show-label="false" class="full-row">
              <div class="inline-line">
                <span>最大重试次数</span>
                <NInputNumber
                  v-model:value="formModel.maxRetryCount"
                  min="0"
                  v-model:value="formModel.maxRetriesNumber"
                  :min="0"
                  :show-button="false"
                  placeholder="请输入"
                  class="mx-2 w-120px"
                  class="w-109px"
                />
                次,重试间隔
                <span>次,重试间隔</span>
                <NInputNumber
                  v-model:value="formModel.retryInterval"
                  min="0"
                  v-model:value="formModel.retriesInterval"
                  :min="0"
                  :show-button="false"
                  placeholder="请输入"
                  class="mx-2 w-120px"
                  class="w-109px"
                />
                秒
                <span>秒</span>
              </div>
            </NFormItemGi>
            <NFormItemGi :span="24" label="" :show-label="false">
              <div class="flex items-center text-[14px] text-gray-800">
                <span class="mr-4">重试失败后,是否给乘客发送推送通知</span>
                <NSwitch v-model:value="formModel.sendNotification" />
            </n-form-item>
          </div>
          <div class="row-group">
            <n-form-item :show-label="false" class="full-row">
              <div class="inline-line">
                <span>重试失败后,是否给乘客发送推送通知</span>
                <NSwitch v-model:value="formModel.sendNotification" :unchecked-value="0" :checked-value="1" />
              </div>
            </NFormItemGi>
          </NGrid>
            </n-form-item>
          </div>
        </div>
        <!-- 卡片2:免密支付 -->
@@ -209,22 +326,21 @@
          <div class="head shrink-0">
            免密支付
          </div>
          <NGrid :cols="24" :x-gap="24" :y-gap="16" class="mt-4">
            <NFormItemGi :span="24" label="" :show-label="false">
              <div class="flex items-center text-[14px] text-gray-800">
                当首泡发单预估金额 与 行程结束实际金额差异大于
          <div class="row-group mb-8px">
            <n-form-item :show-label="false" class="full-row">
              <div class="inline-line">
                <span>当首泡发单预估金额与行程结束实际金额差异大于</span>
                <NInputNumber
                  v-model:value="formModel.priceDifferenceThreshold"
                  min="0"
                  v-model:value="formModel.differenceRatio"
                  :min="0"
                  :show-button="false"
                  placeholder="请输入"
                  class="mx-2 w-120px"
                  class="w-109px"
                />
                %时,乘客端触发二次确认弹窗
                <span>%时,乘客端触发二次确认弹窗</span>
              </div>
            </NFormItemGi>
          </NGrid>
            </n-form-item>
          </div>
        </div>
      </NForm>
    </div>
@@ -235,7 +351,7 @@
        <NButton class="w-84px" @click="handleCancel">
          取消
        </NButton>
        <NButton v-if="pageType !== 'view'" type="primary" class="w-84px" @click="handleSave">
        <NButton v-if="pageType !== 'view'" type="primary" class="w-84px" :loading="saving" @click="handleSave">
          保存
        </NButton>
      </NSpace>
@@ -246,6 +362,7 @@
<style scoped lang="scss">
.box {
  padding: 24px;
  padding-bottom: 16px;
  background-color: #fff;
  border-radius: 6px;
  width: 100%;
@@ -261,7 +378,7 @@
  color: #171f26;
  position: relative;
  text-indent: 11px;
  margin-bottom: 8px;
  margin-bottom: 16px;
  &::before {
    content: "";
@@ -277,6 +394,66 @@
  }
}
.row-group {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}
.inline-item {
  margin-bottom: 0;
}
.time-item {
  width: 100%;
}
.full-row {
  width: 100%;
  margin-bottom: 0;
}
.inline-line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  color: #171f26;
  font-size: 14px;
}
.status-label {
  display: inline-flex;
  align-items: center;
  margin-left: 8px;
  color: #171f26;
  font-size: 14px;
}
.status-label i {
  font-style: normal;
  color: #ff3a30;
  margin-right: 2px;
}
.content {
  background: #f5f7fa;
}
.main {
  gap: 12px;
}
.arrow-icon {
  width: 16px;
  height: 16px;
  transition: transform 0.2s ease;
}
.arrow-icon--open {
  transform: rotate(180deg);
}
.footer {
  position: sticky;
  bottom: 0;
@@ -287,4 +464,8 @@
  box-shadow: 0px 0px 5px 0px rgba(23, 31, 38, 0.05);
  padding: 16px 24px;
}
:deep(.n-form-item .n-form-item-label) {
  padding-right: 8px;
}
</style>
src/views/transaction/passwordFreeStrategy/index.vue
@@ -2,7 +2,7 @@
import type { DataTableColumns } from 'naive-ui'
import { computed, onMounted, ref } from 'vue'
import { useBoolean } from '@/hooks'
import { getRegionCascaderNoArea } from '@/service/api/operations'
import { getPasswordFreePolicyList } from '@/service/api/transaction'
import { NButton, NTag, useDialog } from 'naive-ui'
import { useRouter } from 'vue-router'
import SearchPanel from '@/components/custom/SearchPanel.vue'
@@ -36,28 +36,6 @@
const count = ref(0)
const listData = ref<any[]>([])
const pcaOptions = ref<any[]>([])
// 获取城市数据
function formatCascaderData(list: any[]) {
  return list.map((item) => {
    const newItem = { ...item }
    if (newItem.children && newItem.children.length > 0) {
      newItem.children = formatCascaderData(newItem.children)
    }
    else {
      delete newItem.children
    }
    return newItem
  })
}
async function fetchCascaderData() {
  const res = await getRegionCascaderNoArea()
  if (res.code === 200 && res.data) {
    pcaOptions.value = formatCascaderData(res.data)
  }
}
// 搜索项
const filterItems = computed(() => [
@@ -67,10 +45,13 @@
    render: () => (
      <n-date-picker
        v-model:value={model.value.createTimeRange}
        type="datetimerange"
        type="daterange"
        clearable
        format="yyyy/MM/dd"
        placeholder="开始时间 - 结束时间"
        style={{ width: '320px' }}
        actions={null}
        close-on-select={true}
      />
    ),
  },
@@ -84,33 +65,32 @@
// 获取列表数据
async function getList() {
  startLoading()
  // Mock data simulation
  setTimeout(() => {
    const mockData = Array.from({ length: 10 }).map((_, index) => {
      const isPermanent = index === 1
      const isEnabled = index !== 1
      // City generation based on selection or random
      let cityName = '成都市 > 金牛区'
      if (model.value.cityName) {
        cityName = `已选城市(${model.value.cityName})`
      }
      return {
        id: `mock-id-${pageParams.value.page}-${index}`,
        createTime: '2021/07/29 10:59',
        cityName,
        isPermanent,
        startTime: isPermanent ? null : '2026-3-20 19:35:43',
        endTime: isPermanent ? null : '2026-3-20 19:36:01',
        status: isEnabled ? 1 : 0,
      }
    })
    count.value = 1000 // Mock total count
    listData.value = mockData
  try {
    const params = {
      pageNum: pageParams.value.page,
      pageSize: pageParams.value.size,
      cityName: model.value.cityName?.trim() || 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 HH:mm:ss')
      //   : undefined,
    }
    const res = await getPasswordFreePolicyList(params)
    if (res.code === 200) {
      listData.value = res.data?.records || []
      count.value = res.data?.total ?? 0
    }
  }
  catch (error) {
    console.error('获取免密支付策略列表失败:', error)
    listData.value = []
    count.value = 0
  }
  finally {
    endLoading()
  }, 500)
  }
}
// 分页变化
@@ -136,12 +116,14 @@
    key: 'createTime',
    width: 150,
    resizable: true,
    render: row => (row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm') : '-'),
  },
  {
    title: '适用城市',
    key: 'cityName',
    width: 160,
    resizable: true,
  },
  {
    title: '生效时间段',
@@ -149,10 +131,10 @@
    width: 280,
    resizable: true,
    render: (row) => {
      if (row.isPermanent)
      if (row.validTimeLong)
        return '长期有效'
      const start = row.startTime ? dayjs(row.startTime).format('YYYY/MM/DD HH:mm') : ''
      const end = row.endTime ? dayjs(row.endTime).format('YYYY/MM/DD HH:mm') : ''
      const start = row.validTimeStart ? dayjs(row.validTimeStart).format('YYYY/MM/DD HH:mm') : ''
      const end = row.validTimeEnd ? dayjs(row.validTimeEnd).format('YYYY/MM/DD HH:mm') : ''
      if (start && end)
        return `${start} ~ ${end}`
      return '-'
@@ -164,18 +146,11 @@
    width: 100,
    resizable: true,
    render: (row) => {
      const isEnabled = row.status === 1 || row.status === '1' || row.status === true
      const label = isEnabled ? '启用' : '禁用'
      const label = row.status ? '启用' : '禁用'
      return (
        <NTag
          round
          bordered={false}
          style={{
            borderRadius: '4px',
            border: 'none',
            color: isEnabled ? '#0BB52D' : '#666666',
            backgroundColor: isEnabled ? '#DCF5DD' : 'rgba(23, 31, 38, 0.05)',
          }}
          type={row.status ? 'success' : 'default'}
        >
          {label}
        </NTag>
@@ -256,7 +231,6 @@
  })
}
onMounted(() => {
  fetchCascaderData()
  getList()
})
</script>
src/views/userContent/active/activityManagement/add.vue
@@ -336,6 +336,7 @@
            <div class="flex items-center gap-12px">
              <NDatePicker
                v-model:value="formModel.timeRange"
                format="yyyy/MM/dd"
                type="daterange"
                clearable
                start-placeholder="请选择日期"
@@ -487,7 +488,10 @@
                    <NDatePicker
                      v-model:value="strategy.effectDate"
                      type="date"
                      format="yyyy/MM/dd"
                      clearable
                      :actions="null"
                      close-on-select
                      placeholder="请选择日期"
                      style="width: 200px;"
                    />
@@ -521,7 +525,10 @@
                    <NDatePicker
                      v-model:value="strategy.expireDate"
                      type="date"
                      format="yyyy/MM/dd"
                      clearable
                      :actions="null"
                      close-on-select
                      placeholder="请选择日期"
                      style="width: 200px;"
                    />
src/views/userContent/whitelistManagement/whitelist/detail.vue
@@ -147,6 +147,7 @@
        type="daterange"
        clearable
        actions={null}
        format="yyyy/MM/dd"
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        style={{ width: '260px' }}
@@ -280,6 +281,19 @@
const isOrderSourceOpen = ref(false)
const isOrderCityOpen = ref(false)
const isOrderStatusOpen = ref(false)
const noDataFallbackImg = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png'
function renderDropdownEmpty() {
  return (
    <div class="flex-center">
      <img
        src="/src/assets/element-img/no-data.png"
        style={{ width: '50%' }}
        onError={(e: any) => { e.target.src = noDataFallbackImg }}
      />
    </div>
  )
}
const fleetOptions = ref<any[]>([])
const channelOptions = [{ label: '小鹏小程序', value: 1 }]
@@ -330,14 +344,7 @@
              alt="arrow"
            />
          ),
          empty: () => (
            <div class="flex-center">
              <img
                src="/src/assets/element-img/no-data.png"
                style={{ width: '50%' }}
              />
            </div>
          ),
          empty: () => renderDropdownEmpty(),
        }}
      </NSelect>
    ),
@@ -362,14 +369,7 @@
              alt="arrow"
            />
          ),
          empty: () => (
            <div class="flex-center">
              <img
                src="/src/assets/element-img/no-data.png"
                style={{ width: '50%' }}
              />
            </div>
          ),
          empty: () => renderDropdownEmpty(),
        }}
      </NSelect>
    ),
@@ -397,6 +397,7 @@
              alt="arrow"
            />
          ),
          empty: () => renderDropdownEmpty(),
        }}
      </NCascader>
    ),
@@ -421,14 +422,7 @@
              alt="arrow"
            />
          ),
          empty: () => (
            <div class="flex-center">
              <img
                src="/src/assets/element-img/no-data.png"
                style={{ width: '50%' }}
              />
            </div>
          ),
          empty: () => renderDropdownEmpty(),
        }}
      </NSelect>
    ),
@@ -444,7 +438,8 @@
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        style={{ width: '260px' }}
        actions={[]}
        actions={null}
        format="yyyy/MM/dd"
        close-on-select={true}
      >
        {{