董国庆
2026-06-16 be55ad62d2bf7a3d5da4298737012747f103a66c
Merge branch 'feat/deploy-1.0' into deploy-2.0
3个文件已添加
21个文件已修改
1415 ■■■■■ 已修改文件
.env 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
index.html 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
locales/en_US.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
locales/zh_CN.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
public/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/AppMain.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/common/CopyrightFooter.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/components/common/Logo.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/components/header/UserCenter.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/point.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/assetManagement/ruleConfig/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/assetManagement/vehicleManagement/inventoryVehicle/add.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/build-in/public-access/index.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/taskOrder/taskOrderCenter/components/RegularDetailModal.vue 370 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/taskOrder/taskOrderCenter/components/detailModal.vue 492 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/taskOrder/taskOrderCenter/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/service/review/personnel/components/ReviewModal.vue 310 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/service/review/personnel/index.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/config/index.vue 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/order/evaluationRecord/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/order/orderManagement/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/userContent/banner/index.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env
@@ -2,7 +2,7 @@
VITE_BASE_URL = /
# 项目名称
VITE_APP_NAME = RT后台
VITE_APP_NAME = Robotaxi运营管理系统
# 路由模式 web | hash
VITE_ROUTE_MODE = web
index.html
@@ -3,9 +3,9 @@
<head>
  <meta charset="UTF-8" />
  <link rel="icon" href="/favicon.svg" />
  <link rel="icon" href="/favicon.ico" type="image/x-icon" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>RT后台</title>
  <title>Robotaxi运营管理系统</title>
</head>
<body>
locales/en_US.json
@@ -237,7 +237,7 @@
      "applyTime": "Apply time",
      "vehicleCode": "Vehicle code",
      "phoneNumber": "Phone number",
      "auditStatus": "Review status",
      "auditStatus": "Status",
      "auditUserName": "Reviewer",
      "auditTime": "Review time",
      "auditRemarks": "Review remarks",
locales/zh_CN.json
@@ -403,7 +403,7 @@
      "applyTime": "申请时间",
      "vehicleCode": "车辆编码",
      "phoneNumber": "联系电话",
      "auditStatus": "运营状态",
      "auditStatus": "状态",
      "auditUserName": "审核人",
      "auditTime": "审核时间",
      "auditRemarks": "审核备注",
public/favicon.ico
public/logo.png
src/AppMain.vue
@@ -52,6 +52,7 @@
    <naive-provider>
      <router-view />
      <Watermark :show-watermark="appStore.showWatermark" />
      <CopyrightFooter />
    </naive-provider>
  </n-config-provider>
</template>
src/components/common/CopyrightFooter.vue
New file
@@ -0,0 +1,29 @@
<script setup lang="ts">
// 全局版权信息底部条:固定在窗口底部
const COPYRIGHT_TEXT = '© 2015-2026 广州小鹏汽车科技有限公司 粤ICP备15067788号'
</script>
<template>
  <div class="copyright-footer">
    {{ COPYRIGHT_TEXT }}
  </div>
</template>
<style scoped>
.copyright-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9;
  height: 28px;
  line-height: 28px;
  text-align: center;
  font-size: 12px;
  color: rgba(0, 0, 0, 0.45);
  background-color: var(--card-color, #fff);
  border-top: 1px solid rgba(0, 0, 0, 0.06);
  pointer-events: none;
  user-select: none;
}
</style>
src/layouts/components/common/Logo.vue
@@ -19,7 +19,7 @@
<template>
  <div class="h-68px flex-center cursor-pointer gap-2 p-x-2" @click="router.push('/')">
    <img src="/favicon.svg" alt="logo" class="w-24px h-24px" />
    <img src="/logo.png" alt="logo" class="h-18px w-auto" />
    <span v-show="!hidenLogoText" class="text-ellipsis overflow-hidden whitespace-nowrap title">{{ name }}</span>
  </div>
</template>
src/layouts/components/header/UserCenter.vue
@@ -46,6 +46,11 @@
      class="cursor-pointer w-[24px] h-[24px]"
      :src="userInfo?.avatar"
    >
      <!-- 无 avatar 时:走默认插槽 -->
      <div class="wh-full flex-center">
        <icon-park-outline-user />
      </div>
      <!-- avatar 加载失败时:走 fallback 插槽 -->
      <template #fallback>
        <div class="wh-full flex-center">
          <icon-park-outline-user />
src/layouts/index.vue
@@ -41,7 +41,7 @@
// 移动端抽屉控制
const showMobileDrawer = ref(false)
const sidebarWidth = ref(196)
const sidebarWidth = ref(220)
const sidebarCollapsedWidth = ref(64)
const hasHorizontalMenu = computed(() => ['horizontal', 'mixed-two-column', 'mixed-sidebar'].includes(layoutMode.value))
@@ -67,6 +67,7 @@
    :sidebar-width="sidebarWidth"
    :sidebar-collapsed-width="sidebarCollapsedWidth"
    class="robotaxi-content"
    style="padding-bottom: 28px;"
  >
    <template #logo>
      <Logo />
src/service/api/point.ts
@@ -33,7 +33,7 @@
  return request.Get<Service.ResponseResult<any>>(`/map/api/v1/point/deletePoint?ids=${id}`)
}
export function fetchElectronicFenceAreaList(params: { cityCode?: string } = {}) {
export function fetchElectronicFenceAreaList(params: { cityCode?: string, status?: number } = {}) {
  return request.Post<Service.ResponseResult<Entity.ElectronicFenceArea[]>>('/map/api/v1/point/listElectronicFenceArea', params)
}
src/views/assetManagement/ruleConfig/index.vue
@@ -539,7 +539,7 @@
    <div class="pb-[12px] flex-shrink-0 z-10 bg-[#f5f7fa]">
      <div class="bg-white rounded-sm py-[12px] px-[24px] shadow-sm">
        <div class="text-lg font-bold mb-[12px] text-gray-800">
          任务模板管理
          运维规则配置
        </div>
        <n-radio-group v-model:value="activeTab">
src/views/assetManagement/vehicleManagement/inventoryVehicle/add.vue
@@ -48,7 +48,7 @@
    vehiclePictureId: null as string | number | null, // 车辆图片ID
    purchaseSource: '', // 采购来源
    remark: '', // 备注
    operationArea: null as string | null, // 运营区域
    operationArea: null as number | null, // 运营区域
    vehicleAttribute: null as number | null, // 车辆属性
    vehicleModelType: null as number | null, // 车辆类型
    ownerType: '1', // 所有人类型 1企业 2个人
@@ -83,8 +83,9 @@
const formModel = ref(createInitialFormModel())
// 运营区域选项
const operationAreaOptions = ref<{ label: string, value: string | number }[]>([])
const operationAreaOptions = ref<{ label: string, value: number, electronicId?: string | number | null }[]>([])
const isOperationAreaSelectOpen = ref(false)
const currentOperationElectronicId = ref<string | number | null>(null)
// 车辆型号选项
const modelOptions = ref<{ label: string, value: string | number }[]>([])
@@ -159,6 +160,22 @@
  return Number.isNaN(timestamp) ? null : timestamp
}
function syncOperationAreaValue() {
  if (
    currentOperationElectronicId.value === null
    || currentOperationElectronicId.value === undefined
    || currentOperationElectronicId.value === ''
  ) {
    return
  }
  const matchedOption = operationAreaOptions.value.find(
    item => String(item.electronicId) === String(currentOperationElectronicId.value),
  )
  if (matchedOption) {
    formModel.value.operationArea = Number(matchedOption.value)
  }
}
function toUploadFileList(value: unknown): UploadFileInfo[] {
  return parseFileJson(value).map((item: any, index: number) => ({
    id: item?.id || `${index}`,
@@ -198,7 +215,7 @@
      vehiclePictureId: getVehiclePictureId(data.vehiclePictures),
      purchaseSource: data.procurementSource || '',
      remark: data.remarks || data.remark || '',
      operationArea: data.electronicId === null || data.electronicId === undefined || data.electronicId === '' ? null : String(data.electronicId),
      operationArea: null,
      vehicleAttribute: toNumberOrNull(data.vehicleAttribute),
      vehicleModelType: toNumberOrNull(data.vehicleModelType),
      ownerType: String(data.ownerType ?? '1'),
@@ -225,6 +242,11 @@
      insuranceFiles: toUploadFileList(data.policyInformation),
      onlineCarLicenseFiles: toUploadFileList(data.operationQualification),
    }
    currentOperationElectronicId.value
      = data.electronicId === null || data.electronicId === undefined || data.electronicId === ''
        ? null
        : String(data.electronicId)
    syncOperationAreaValue()
  }
  catch (error) {
    console.error('获取车辆详情失败:', error)
@@ -249,15 +271,17 @@
// 获取运营区域列表
async function getOperationAreaList() {
  try {
    const { data } = await fetchElectronicFenceAreaList()
    const { data } = await fetchElectronicFenceAreaList({ status: 2 })
    if (data) {
      // 过滤出 areaType 为 1 的运营区域
      // 下拉选项使用区域明细 id,提交时也传该 id 给服务端
      operationAreaOptions.value = data
        .filter((item: any) => item.areaType === 1)
        .map((item: any) => ({
          label: item.areaName,
          value: item.electronicId,
          value: item.id,
          electronicId: item.electronicId,
        }))
      syncOperationAreaValue()
    }
  }
  catch (error) {
src/views/build-in/public-access/index.vue
@@ -85,8 +85,8 @@
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="flex justify-between items-center py-4">
          <div class="flex items-center space-x-4">
            <div class="w-10 h-10 flex items-center justify-center">
              <img src="/favicon.svg" alt="Nova Admin Logo" class="w-10 h-10">
            <div class="h-10 flex items-center justify-center">
              <img src="/logo.png" alt="Nova Admin Logo" class="h-10 w-auto">
            </div>
            <span class="text-2xl font-bold text-gray-900">Nova Admin</span>
          </div>
@@ -447,8 +447,8 @@
        <div class="grid md:grid-cols-4 gap-8">
          <div>
            <div class="flex items-center space-x-2 mb-4">
              <div class="w-10 h-10 flex items-center justify-center">
                <img src="/favicon.svg" alt="Nova Admin Logo" class="w-8 h-8">
              <div class="h-8 flex items-center justify-center">
                <img src="/logo.png" alt="Nova Admin Logo" class="h-8 w-auto">
              </div>
              <span class="text-xl font-bold text-white">Nova Admin</span>
            </div>
src/views/operations/taskOrder/taskOrderCenter/components/RegularDetailModal.vue
@@ -97,6 +97,9 @@
  return d.format("YYYY/MM/DD HH:mm");
}
const fallbackImage =
  "https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png";
const currentType = computed(() => {
  if (formModel.value.detectionDetailVO?.id) return "detection";
  if (formModel.value.chargingDetailVO?.id) return "charging";
@@ -155,10 +158,13 @@
  >
    <div v-if="currentDetail" class="regular-detail">
      <div class="vehicle-header">
        <img
          :src="vehicleImage"
        <n-image
          :src="vehicleImage || defaultCarImage"
          :fallback-src="defaultCarImage"
          :width="112"
          :height="64"
          class="vehicle-image"
          @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
          object-fit="contain"
        />
        <div class="vehicle-text">
          <div class="plate-number">
@@ -252,61 +258,81 @@
        <div class="grid-gap-3">
          <div class="block">
            <div class="block-label">传感器清洁:</div>
            <div class="thumb-list">
              <img
                v-for="(item, idx) in getValidImageList(
                  currentDetail.sensorCleaningPicture
                )"
                :key="idx"
                :src="item.url"
                class="thumb"
                @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              />
            </div>
            <n-image-group>
              <div class="thumb-list">
                <n-image
                  v-for="(item, idx) in getValidImageList(
                    currentDetail.sensorCleaningPicture
                  )"
                  :key="idx"
                  :src="item.url"
                  :width="56"
                  :height="56"
                  class="thumb"
                  object-fit="contain"
                  :fallback-src="fallbackImage"
                />
              </div>
            </n-image-group>
          </div>
          <div class="block">
            <div class="block-label">紧急求组按钮/应答机:</div>
            <div class="thumb-list">
              <img
                v-for="(item, idx) in getValidImageList(
                  currentDetail.helpButtonPicture
                )"
                :key="idx"
                :src="item.url"
                class="thumb"
                @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              />
            </div>
            <n-image-group>
              <div class="thumb-list">
                <n-image
                  v-for="(item, idx) in getValidImageList(
                    currentDetail.helpButtonPicture
                  )"
                  :key="idx"
                  :src="item.url"
                  :width="56"
                  :height="56"
                  class="thumb"
                  object-fit="contain"
                  :fallback-src="fallbackImage"
                />
              </div>
            </n-image-group>
          </div>
          <div class="block">
            <div class="block-label">订单系统检查:</div>
            <div class="thumb-list">
              <img
                v-for="(item, idx) in getValidImageList(
                  currentDetail.systemCheckPicture
                )"
                :key="idx"
                :src="item.url"
                class="thumb"
                @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              />
            </div>
            <n-image-group>
              <div class="thumb-list">
                <n-image
                  v-for="(item, idx) in getValidImageList(
                    currentDetail.systemCheckPicture
                  )"
                  :key="idx"
                  :src="item.url"
                  :width="56"
                  :height="56"
                  class="thumb"
                  object-fit="contain"
                  :fallback-src="fallbackImage"
                />
              </div>
            </n-image-group>
          </div>
        </div>
        <div class="grid-gap-3">
          <div class="block">
            <div class="block-label">车内交互屏检查:</div>
            <div class="thumb-list">
              <img
                v-for="(item, idx) in getValidImageList(
                  currentDetail.interactiveScreenPicture
                )"
                :key="idx"
                :src="item.url"
                class="thumb"
                @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              />
            </div>
            <n-image-group>
              <div class="thumb-list">
                <n-image
                  v-for="(item, idx) in getValidImageList(
                    currentDetail.interactiveScreenPicture
                  )"
                  :key="idx"
                  :src="item.url"
                  :width="56"
                  :height="56"
                  class="thumb"
                  object-fit="contain"
                  :fallback-src="fallbackImage"
                />
              </div>
            </n-image-group>
          </div>
          <!-- <div class="block">
@@ -352,6 +378,7 @@
              <n-image
                :src="powerIcon"
                style="width: 25px; height: 12px"
                preview-disabled
              />
              <span style="color: #e85050; font-size: 11px"
                >{{ currentDetail.startRemainingBattery ?? "-" }} km</span
@@ -375,6 +402,7 @@
              <n-image
                :src="poweredIcon"
                style="width: 25px; height: 12px"
                preview-disabled
              />
              <span style="color: #06b752; font-size: 11px"
                >{{ currentDetail.endRemainingBattery ?? "-" }} km</span
@@ -390,28 +418,38 @@
        </div>
        <div class="mt-16px">
          <div class="kv-label mt-4px">充电图片</div>
          <div class="thumb-list">
            <img
              v-for="(item, idx) in getValidImageList(
                currentDetail.startChargingPicture
              )"
              :key="idx"
              :src="item.url"
              class="thumb"
              @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            />
            <template v-if="getValidImageList(currentDetail.endChargingPicture).length">
              <img
              v-for="(item, idx) in getValidImageList(
                currentDetail.endChargingPicture
              )"
              :key="idx"
              :src="item.url"
              class="thumb"
              @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            />
            </template>
          </div>
          <n-image-group>
            <div class="thumb-list">
              <n-image
                v-for="(item, idx) in getValidImageList(
                  currentDetail.startChargingPicture
                )"
                :key="`start-${idx}`"
                :src="item.url"
                :width="56"
                :height="56"
                class="thumb"
                object-fit="contain"
                :fallback-src="fallbackImage"
              />
              <template
                v-if="getValidImageList(currentDetail.endChargingPicture).length"
              >
                <n-image
                  v-for="(item, idx) in getValidImageList(
                    currentDetail.endChargingPicture
                  )"
                  :key="`end-${idx}`"
                  :src="item.url"
                  :width="56"
                  :height="56"
                  class="thumb"
                  object-fit="contain"
                  :fallback-src="fallbackImage"
                />
              </template>
            </div>
          </n-image-group>
        </div>
        <div class="flex mt-16px">
          <div class="flex-1">
@@ -489,45 +527,56 @@
        <div class="grid-gap-3">
          <div class="block">
            <div class="block-label color-06">大灯情况:</div>
            <div class="thumb-list">
              <img
                v-for="(item, idx) in getValidImageList(
                  currentDetail.headLight
                )"
                :key="idx"
                :src="item.url"
                class="thumb"
                @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              />
            </div>
            <n-image-group>
              <div class="thumb-list">
                <n-image
                  v-for="(item, idx) in getValidImageList(currentDetail.headLight)"
                  :key="idx"
                  :src="item.url"
                  :width="56"
                  :height="56"
                  class="thumb"
                  object-fit="contain"
                  :fallback-src="fallbackImage"
                />
              </div>
            </n-image-group>
          </div>
          <div class="block">
            <div class="block-label color-06">转向灯情况:</div>
            <div class="thumb-list">
              <img
                v-for="(item, idx) in getValidImageList(
                  currentDetail.turnSignal
                )"
                :key="idx"
                :src="item.url"
                class="thumb"
                @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              />
            </div>
            <n-image-group>
              <div class="thumb-list">
                <n-image
                  v-for="(item, idx) in getValidImageList(currentDetail.turnSignal)"
                  :key="idx"
                  :src="item.url"
                  :width="56"
                  :height="56"
                  class="thumb"
                  object-fit="contain"
                  :fallback-src="fallbackImage"
                />
              </div>
            </n-image-group>
          </div>
          <div class="block">
            <div class="block-label">舱内清洁及消毒</div>
            <div class="thumb-list">
              <img
                v-for="(item, idx) in getValidImageList(
                  currentDetail.cabinCleaning
                )"
                :key="idx"
                :src="item.url"
                class="thumb"
                @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              />
            </div>
            <div class="block-label color-06">舱内清洁及消毒</div>
            <n-image-group>
              <div class="thumb-list">
                <n-image
                  v-for="(item, idx) in getValidImageList(
                    currentDetail.cabinCleaning
                  )"
                  :key="idx"
                  :src="item.url"
                  :width="56"
                  :height="56"
                  class="thumb"
                  object-fit="contain"
                  :fallback-src="fallbackImage"
                />
              </div>
            </n-image-group>
          </div>
          <!-- <div class="block">
            <div class="block-label color-06">刹车灯情况:</div>
@@ -676,15 +725,20 @@
      <div v-else-if="currentType === 'clean'">
        <div class="block mt-16px">
          <div class="block-label color-06">图片</div>
          <div class="thumb-list">
            <img
              v-for="(item, idx) in getValidImageList(currentDetail.taskImage)"
              :key="idx"
              :src="item.url"
              class="thumb"
              @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            />
          </div>
          <n-image-group>
            <div class="thumb-list">
              <n-image
                v-for="(item, idx) in getValidImageList(currentDetail.taskImage)"
                :key="idx"
                :src="item.url"
                :width="56"
                :height="56"
                class="thumb"
                object-fit="contain"
                :fallback-src="fallbackImage"
              />
            </div>
          </n-image-group>
        </div>
        <div style="display: grid; grid-template-columns: 1fr 1fr">
          <div>
@@ -729,17 +783,22 @@
        </div>
        <div class="block mt-16px">
          <div class="kv-label mb-4px">维修前图片</div>
          <div class="thumb-list">
            <img
              v-for="(item, idx) in getValidImageList(
                currentDetail.startRepairPicture
              )"
              :key="idx"
              :src="item.url"
              class="thumb"
              @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            />
          </div>
          <n-image-group>
            <div class="thumb-list">
              <n-image
                v-for="(item, idx) in getValidImageList(
                  currentDetail.startRepairPicture
                )"
                :key="idx"
                :src="item.url"
                :width="56"
                :height="56"
                class="thumb"
                object-fit="contain"
                :fallback-src="fallbackImage"
              />
            </div>
          </n-image-group>
        </div>
        <div class="flex mt-16px">
          <div class="flex-1">
@@ -765,17 +824,22 @@
        </div>
        <div class="block mt-16px">
          <div class="kv-label mb-4px">维修费用明细单</div>
          <div class="thumb-list">
            <img
              v-for="(item, idx) in getValidImageList(
                currentDetail.repairMoneyDetail
              )"
              :key="idx"
              :src="item.url"
              class="thumb"
              @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            />
          </div>
          <n-image-group>
            <div class="thumb-list">
              <n-image
                v-for="(item, idx) in getValidImageList(
                  currentDetail.repairMoneyDetail
                )"
                :key="idx"
                :src="item.url"
                :width="56"
                :height="56"
                class="thumb"
                object-fit="contain"
                :fallback-src="fallbackImage"
              />
            </div>
          </n-image-group>
        </div>
        <div class="flex mt-16px">
          <div class="flex-1">
@@ -802,15 +866,20 @@
        </div>
        <div class="block">
          <div class="block-label color-06">图片</div>
          <div class="thumb-list">
            <img
              v-for="(item, idx) in getValidImageList(currentDetail.taskImage)"
              :key="idx"
              :src="item.url"
              class="thumb"
              @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            />
          </div>
          <n-image-group>
            <div class="thumb-list">
              <n-image
                v-for="(item, idx) in getValidImageList(currentDetail.taskImage)"
                :key="idx"
                :src="item.url"
                :width="56"
                :height="56"
                class="thumb"
                object-fit="contain"
                :fallback-src="fallbackImage"
              />
            </div>
          </n-image-group>
        </div>
        <div style="display: grid; grid-template-columns: 1fr 1fr">
          <div>
@@ -845,11 +914,11 @@
}
.vehicle-image {
  width: 112px;
  height: 64px;
  border-radius: 4px;
  object-fit: contain;
  flex: none;
}
:deep(.vehicle-image img) {
  border-radius: 4px;
}
.vehicle-text {
@@ -977,10 +1046,11 @@
}
.thumb {
  width: 56px;
  height: 56px;
  overflow: hidden;
}
:deep(.thumb img) {
  border-radius: 4px;
  object-fit: contain;
}
.grid-gap-3 {
  display: grid;
src/views/operations/taskOrder/taskOrderCenter/components/detailModal.vue
@@ -137,6 +137,8 @@
  return d.format('YYYY/MM/DD HH:mm')
}
const fallbackImage = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png'
function getUrgencyLabel(level: number) {
  return taskUrgencyLevelOptions.find(it => it.value === level)?.label || '-'
}
@@ -225,10 +227,14 @@
            </div>
          </div>
          <div class="mb-16px flex items-center">
            <img
            <n-image
              :src="getVehicleImage(formModel.accidentDetailVO.vehiclePictures)"
              class="w-112px h-64px mr-16px accident-vehicle-image" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
              :fallback-src="fallbackImage"
              :width="112"
              :height="64"
              class="mr-16px accident-vehicle-image"
              object-fit="contain"
            />
            <div>
              <div class="plateNumber mb-8px">
                {{ formModel.accidentDetailVO.plateNumber }}
@@ -255,22 +261,32 @@
            <div class="value mb-8px">
              {{ formModel.accidentDetailVO.taskDescription }}
            </div>
            <div v-if="getValidImageList(formModel.accidentDetailVO.taskImage).length" class="imgs">
              <img
                v-for="(item, idx) in getValidImageList(formModel.accidentDetailVO.taskImage)"
                :key="idx"
                :src="item.url"
                class="w-56px h-56px accident-thumb" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              >
            </div>
            <n-image-group v-if="getValidImageList(formModel.accidentDetailVO.taskImage).length">
              <div class="imgs">
                <n-image
                  v-for="(item, idx) in getValidImageList(formModel.accidentDetailVO.taskImage)"
                  :key="idx"
                  :src="item.url"
                  :fallback-src="fallbackImage"
                  :width="56"
                  :height="56"
                  class="accident-thumb"
                  object-fit="contain"
                />
              </div>
            </n-image-group>
          </div>
          <div class="mb-16px flex gap-24px">
            <div class="flex items-center flex-1 gap-8px">
              <img
              <n-image
                v-if="parseAvatarUrl(formModel.accidentDetailVO.reportUserAvatar)"
                :src="parseAvatarUrl(formModel.accidentDetailVO.reportUserAvatar)"
                class="w-40px h-40px accident-avatar" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              >
                :fallback-src="fallbackImage"
                :width="40"
                :height="40"
                class="accident-avatar"
                object-fit="cover"
              />
              <div class="flex-1 min-w-0">
                <div class="label mb-4px">
                  上报人
@@ -331,14 +347,20 @@
            <!-- <div class="value mb-8px">
              {{ formModel.accidentDetailVO.situationDescription }}
            </div> -->
            <div v-if="getValidImageList(formModel.accidentDetailVO.responsibleImage).length" class="imgs">
              <img
                v-for="(item, idx) in getValidImageList(formModel.accidentDetailVO.responsibleImage)"
                :key="idx"
                :src="item.url"
                class="w-56px h-56px accident-thumb" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              >
            </div>
            <n-image-group v-if="getValidImageList(formModel.accidentDetailVO.responsibleImage).length">
              <div class="imgs">
                <n-image
                  v-for="(item, idx) in getValidImageList(formModel.accidentDetailVO.responsibleImage)"
                  :key="idx"
                  :src="item.url"
                  :fallback-src="fallbackImage"
                  :width="56"
                  :height="56"
                  class="accident-thumb"
                  object-fit="contain"
                />
              </div>
            </n-image-group>
          </div>
          <div class="mb-16px">
            <div class="label mb-4px">
@@ -347,14 +369,20 @@
            <div class="value mb-8px">
              {{ formModel.accidentDetailVO.situationDescription }}
            </div>
            <div v-if="getValidImageList(formModel.accidentDetailVO.situationImage).length" class="imgs">
              <img
                v-for="(item, idx) in getValidImageList(formModel.accidentDetailVO.situationImage)"
                :key="idx"
                :src="item.url"
                class="w-56px h-56px accident-thumb" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              >
            </div>
            <n-image-group v-if="getValidImageList(formModel.accidentDetailVO.situationImage).length">
              <div class="imgs">
                <n-image
                  v-for="(item, idx) in getValidImageList(formModel.accidentDetailVO.situationImage)"
                  :key="idx"
                  :src="item.url"
                  :fallback-src="fallbackImage"
                  :width="56"
                  :height="56"
                  class="accident-thumb"
                  object-fit="contain"
                />
              </div>
            </n-image-group>
          </div>
          <div class="mb-16px">
            <div class="label mb-4px">
@@ -363,22 +391,32 @@
            <div class="value mb-8px">
              {{ formModel.accidentDetailVO.disposalDescription }}
            </div>
            <div v-if="getValidImageList(formModel.accidentDetailVO.disposalImage).length" class="imgs">
              <img
                v-for="(item, idx) in getValidImageList(formModel.accidentDetailVO.disposalImage)"
                :key="idx"
                :src="item.url"
                class="w-56px h-56px accident-thumb" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              >
            </div>
            <n-image-group v-if="getValidImageList(formModel.accidentDetailVO.disposalImage).length">
              <div class="imgs">
                <n-image
                  v-for="(item, idx) in getValidImageList(formModel.accidentDetailVO.disposalImage)"
                  :key="idx"
                  :src="item.url"
                  :fallback-src="fallbackImage"
                  :width="56"
                  :height="56"
                  class="accident-thumb"
                  object-fit="contain"
                />
              </div>
            </n-image-group>
          </div>
          <div class="mb-16px flex gap-24px">
            <div class="flex items-center flex-1 gap-8px">
              <img
              <n-image
                v-if="parseAvatarUrl(formModel.accidentDetailVO.handleUserAvatar)"
                :src="parseAvatarUrl(formModel.accidentDetailVO.handleUserAvatar)"
                class="w-40px h-40px accident-avatar" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
              >
                :fallback-src="fallbackImage"
                :width="40"
                :height="40"
                class="accident-avatar"
                object-fit="cover"
              />
              <div class="flex-1 min-w-0">
                <div class="label mb-4px">
                  处理人
@@ -405,10 +443,15 @@
    <div v-if="formModel.detectionDetailVO?.id">
      <div class="content">
        <div class="mb-16px flex items-center">
          <img
            v-if="formModel.detectionDetailVO?.vehiclePictures" :src="formModel.detectionDetailVO.vehiclePictures"
            class="w-112px h-64px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
          >
          <n-image
            v-if="getVehicleImage(formModel.detectionDetailVO?.vehiclePictures)"
            :src="getVehicleImage(formModel.detectionDetailVO?.vehiclePictures)"
            :fallback-src="fallbackImage"
            :width="112"
            :height="64"
            class="mr-16px"
            object-fit="contain"
          />
          <div>
            <div class="plateNumber mb-8px">
              {{ formModel.detectionDetailVO.plateNumber }}
@@ -482,45 +525,77 @@
          <div class="mb-8px">
            车内交互屏检查:
          </div>
          <div class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.detectionDetailVO.interactiveScreenPicture)" :key="idx"
              :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.detectionDetailVO.interactiveScreenPicture)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          <div class="mb-8px">
            紧急求助按钮/应答机:
          </div>
          <div class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.detectionDetailVO.helpButtonPicture)" :key="idx"
              :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.detectionDetailVO.helpButtonPicture)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          <div class="mb-8px">
            交付功能:
          </div>
          <div class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.detectionDetailVO.paymentFunctionPicture)" :key="idx"
              :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.detectionDetailVO.paymentFunctionPicture)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          <div class="mb-8px">
            订单系统检查:
          </div>
          <div class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.detectionDetailVO.systemCheckPicture)" :key="idx"
              :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.detectionDetailVO.systemCheckPicture)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          任务单号:{{ formModel.detectionDetailVO.id }}
@@ -538,10 +613,15 @@
    <div v-if="formModel.chargingDetailVO?.id">
      <div class="content">
        <div class="mb-16px flex items-center">
          <img
            v-if="formModel.chargingDetailVO?.vehiclePictures.url" :src="formModel.chargingDetailVO.vehiclePictures.url"
            class="w-112px h-64px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
          >
          <n-image
            v-if="getVehicleImage(formModel.chargingDetailVO?.vehiclePictures)"
            :src="getVehicleImage(formModel.chargingDetailVO?.vehiclePictures)"
            :fallback-src="fallbackImage"
            :width="112"
            :height="64"
            class="mr-16px"
            object-fit="contain"
          />
          <div>
            <div class="plateNumber mb-8px">
              {{ formModel.chargingDetailVO.plateNumber }}
@@ -572,11 +652,20 @@
          <div class="mb-8px">
            开始充电图片:
          </div>
          <div class="imgs">
            <div v-for="(item, idx) in JSON.parse(formModel.chargingDetailVO.startChargingPicture)" :key="idx">
              <img v-if="item?.url" :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }">
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.chargingDetailVO.startChargingPicture)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          充电后电量:{{ formModel.chargingDetailVO.endRemainingBattery }}%
@@ -592,11 +681,20 @@
          <div class="mb-8px">
            结束充电图片:
          </div>
          <div class="imgs">
            <div v-for="(item, idx) in JSON.parse(formModel.chargingDetailVO.endChargingPicture)" :key="idx">
              <img v-if="item?.url" :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }">
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.chargingDetailVO.endChargingPicture)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </div>
          </n-image-group>
        </div>
      </div>
    </div>
@@ -604,10 +702,15 @@
    <div v-if="formModel.preparationDetailVO?.id">
      <div class="content">
        <div class="mb-16px flex items-center">
          <img
            v-if="formModel.preparationDetailVO?.vehiclePictures" :src="formModel.preparationDetailVO.vehiclePictures"
            class="w-112px h-64px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
          >
          <n-image
            v-if="getVehicleImage(formModel.preparationDetailVO?.vehiclePictures)"
            :src="getVehicleImage(formModel.preparationDetailVO?.vehiclePictures)"
            :fallback-src="fallbackImage"
            :width="112"
            :height="64"
            class="mr-16px"
            object-fit="contain"
          />
          <div>
            <div class="plateNumber mb-8px">
              {{ formModel.preparationDetailVO.plateNumber }}
@@ -635,23 +738,39 @@
          <div class="label mb-8px">
            大灯情况:
          </div>
          <div v-if="formModel.preparationDetailVO.headLight" class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.preparationDetailVO.headLight)" :key="idx" :src="item.url"
              class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group v-if="getValidImageList(formModel.preparationDetailVO.headLight).length">
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.preparationDetailVO.headLight)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          <div class="label mb-8px">
            转向灯情况:
          </div>
          <div v-if="formModel.preparationDetailVO.turnSignal" class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.preparationDetailVO.turnSignal)" :key="idx" :src="item.url"
              class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group v-if="getValidImageList(formModel.preparationDetailVO.turnSignal).length">
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.preparationDetailVO.turnSignal)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <!-- <div class="mb-16px">
          <div class="label mb-8px">
@@ -679,34 +798,58 @@
          <div class="label mb-8px">
            车身标识及清洁:
          </div>
          <div v-if="formModel.preparationDetailVO.bodyEmblem" class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.preparationDetailVO.bodyEmblem)" :key="idx" :src="item.url"
              class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group v-if="getValidImageList(formModel.preparationDetailVO.bodyEmblem).length">
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.preparationDetailVO.bodyEmblem)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          <div class="label mb-8px">
            舱内清洁及消毒:
          </div>
          <div v-if="formModel.preparationDetailVO.cabinCleaning" class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.preparationDetailVO.cabinCleaning)" :key="idx"
              :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group v-if="getValidImageList(formModel.preparationDetailVO.cabinCleaning).length">
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.preparationDetailVO.cabinCleaning)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          <div class="label mb-8px">
            遗失物品上报:
          </div>
          <div v-if="formModel.preparationDetailVO.lostItems" class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.preparationDetailVO.lostItems)" :key="idx" :src="item.url"
              class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group v-if="getValidImageList(formModel.preparationDetailVO.lostItems).length">
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.preparationDetailVO.lostItems)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
          <div class="label mt-8px">
            遗失说明:<div v-html="formModel.preparationDetailVO.lostItemsDetail" />
          </div>
@@ -727,10 +870,15 @@
    <div v-if="formModel.cleanDetailVO?.id">
      <div class="content">
        <div class="mb-16px flex items-center">
          <img
            v-if="formModel.cleanDetailVO?.vehiclePictures" :src="formModel.cleanDetailVO.vehiclePictures"
            class="w-112px h-64px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
          >
          <n-image
            v-if="getVehicleImage(formModel.cleanDetailVO?.vehiclePictures)"
            :src="getVehicleImage(formModel.cleanDetailVO?.vehiclePictures)"
            :fallback-src="fallbackImage"
            :width="112"
            :height="64"
            class="mr-16px"
            object-fit="contain"
          />
          <div>
            <div class="plateNumber mb-8px">
              {{ formModel.cleanDetailVO.plateNumber }}
@@ -748,12 +896,20 @@
          <div class="label mb-8px">
            图片:
          </div>
          <div class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.cleanDetailVO.taskImage)" :key="idx" :src="item.url"
              class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.cleanDetailVO.taskImage)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          任务单号:{{ formModel.cleanDetailVO.id }}
@@ -771,10 +927,15 @@
    <div v-if="formModel.repairDetailVO?.id">
      <div class="content">
        <div class="mb-16px flex items-center">
          <img
            v-if="formModel.repairDetailVO?.vehiclePictures" :src="formModel.repairDetailVO.vehiclePictures"
            class="w-112px h-64px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
          >
          <n-image
            v-if="getVehicleImage(formModel.repairDetailVO?.vehiclePictures)"
            :src="getVehicleImage(formModel.repairDetailVO?.vehiclePictures)"
            :fallback-src="fallbackImage"
            :width="112"
            :height="64"
            class="mr-16px"
            object-fit="contain"
          />
          <div>
            <div class="plateNumber mb-8px">
              {{ formModel.repairDetailVO.plateNumber }}
@@ -799,12 +960,20 @@
          <div class="label mb-8px">
            维修前图片:
          </div>
          <div class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.repairDetailVO.startRepairPicture)" :key="idx"
              :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.repairDetailVO.startRepairPicture)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          送修时间:{{ formModel.repairDetailVO.sendTime
@@ -820,12 +989,20 @@
          <div class="label mb-8px">
            维修费用明细单:
          </div>
          <div class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.repairDetailVO.repairMoneyDetail)" :key="idx"
              :src="item.url" class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.repairDetailVO.repairMoneyDetail)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          取回时间:{{ formModel.repairDetailVO.returnTime
@@ -843,10 +1020,15 @@
    <div v-if="formModel.routineDetailVO?.id">
      <div class="content">
        <div class="mb-16px flex items-center">
          <img
            v-if="formModel.routineDetailVO?.vehiclePictures" :src="formModel.routineDetailVO.vehiclePictures"
            class="w-112px h-64px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
          >
          <n-image
            v-if="getVehicleImage(formModel.routineDetailVO?.vehiclePictures)"
            :src="getVehicleImage(formModel.routineDetailVO?.vehiclePictures)"
            :fallback-src="fallbackImage"
            :width="112"
            :height="64"
            class="mr-16px"
            object-fit="contain"
          />
          <div>
            <div class="plateNumber mb-8px">
              {{ formModel.routineDetailVO.plateNumber }}
@@ -867,12 +1049,20 @@
          <div class="label mb-8px">
            图片:
          </div>
          <div class="imgs">
            <img
              v-for="(item, idx) in JSON.parse(formModel.routineDetailVO.taskImage)" :key="idx" :src="item.url"
              class="w-56px h-56px mr-16px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }"
            >
          </div>
          <n-image-group>
            <div class="imgs">
              <n-image
                v-for="(item, idx) in getValidImageList(formModel.routineDetailVO.taskImage)"
                :key="idx"
                :src="item.url"
                :fallback-src="fallbackImage"
                :width="56"
                :height="56"
                class="mr-16px"
                object-fit="contain"
              />
            </div>
          </n-image-group>
        </div>
        <div class="mb-16px">
          任务单号:{{ formModel.routineDetailVO.id }}
src/views/operations/taskOrder/taskOrderCenter/index.vue
@@ -463,7 +463,7 @@
    align: 'left',
    resizable: true,
    render(row) {
      const option = taskUrgencyLevelOptions.find(item => item.value === row.taskUrgencyLevel)
      const option = taskUrgencyLevelOptions.find(item => item.value == row.taskUrgencyLevel)
      return (
        <n-tag type={option?.type || 'default'} bordered={false}>
          {option?.label || ''}
src/views/service/review/personnel/components/ReviewModal.vue
@@ -1,220 +1,241 @@
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import type { FormInst, FormRules } from "naive-ui";
import { fetchQualificationAuditInfo } from "@/service/api/serviceCenter";
import { computed, ref, watch } from 'vue'
import type { FormInst, FormRules } from 'naive-ui'
import { fetchQualificationAuditInfo } from '@/service/api/serviceCenter'
interface FormModel {
  result: "pass" | "reject";
  auditRemarks: string;
  result: 'pass' | 'reject'
  auditRemarks: string
}
interface QualificationDetail {
  avatar?: string;
  certificateOfNoCriminalRecord?: string;
  driverLicense?: string;
  id?: number | string;
  idCardBack?: string;
  idCardFront?: string;
  nickName?: string;
  operationsUserId?: number | string;
  phoneNumber?: string;
  roleNames?: string[] | string;
  trainingGraduationCertificate?: string;
  avatar?: string
  auditRemarks?: string
  auditStatus?: number
  certificateOfNoCriminalRecord?: string
  driverLicense?: string
  id?: number | string
  idCardBack?: string
  idCardFront?: string
  nickName?: string
  operationsUserId?: number | string
  phoneNumber?: string
  roleNames?: string[] | string
  trainingGraduationCertificate?: string
}
const { t } = useI18n();
const props = withDefaults(
  defineProps<{
    reviewId?: number | null;
    selectedCount?: number;
    show: boolean;
    reviewId?: number | null
    selectedCount?: number
    show: boolean
    mode?: 'review' | 'detail'
  }>(),
  {
    reviewId: null,
    selectedCount: 0,
  }
);
    mode: 'review',
  },
)
const emit = defineEmits<{
  "update:show": [value: boolean];
  confirm: [data: FormModel];
}>();
  'update:show': [value: boolean]
  'confirm': [data: FormModel]
}>()
const { t } = useI18n()
const show = computed({
  get: () => props.show,
  set: (value) => emit("update:show", value),
});
  set: value => emit('update:show', value),
})
const isDetailMode = computed(() => props.mode === 'detail')
const formRef = ref<FormInst | null>(null);
const formRef = ref<FormInst | null>(null)
const formModel = ref<FormModel>({
  result: "pass",
  auditRemarks: "",
});
const detailLoading = ref(false);
const reviewDetail = ref<QualificationDetail | null>(null);
  result: 'pass',
  auditRemarks: '',
})
const detailLoading = ref(false)
const reviewDetail = ref<QualificationDetail | null>(null)
let currentRequestId = 0;
let currentRequestId = 0
const rules: FormRules = {
  result: [
    {
      required: true,
      message: t("serviceReview.common.chooseResult"),
      trigger: "change",
      message: t('serviceReview.common.chooseResult'),
      trigger: 'change',
    },
  ],
  auditRemarks: [
    {
      validator: (_rule, value) => {
        if (
          formModel.value.result === "reject" &&
          (!value || !String(value).trim())
          formModel.value.result === 'reject'
          && (!value || !String(value).trim())
        ) {
          return new Error(t("serviceReview.common.remarkRequired"));
          return new Error(t('serviceReview.common.remarkRequired'))
        }
        return true;
        return true
      },
      trigger: ["input", "blur"],
      trigger: ['input', 'blur'],
    },
  ],
};
}
function resetForm() {
  formModel.value = {
    result: "pass",
    auditRemarks: "",
  };
  formRef.value?.restoreValidation();
    result: 'pass',
    auditRemarks: '',
  }
  formRef.value?.restoreValidation()
}
function resetDetail() {
  currentRequestId += 1;
  detailLoading.value = false;
  reviewDetail.value = null;
  currentRequestId += 1
  detailLoading.value = false
  reviewDetail.value = null
}
function getRoleNames(value: QualificationDetail["roleNames"]) {
function getRoleNames(value: QualificationDetail['roleNames']) {
  if (Array.isArray(value)) {
    return value;
    return value
  }
  if (typeof value === "string" && value.trim()) {
    return value.split(",").map(item => item.trim()).filter(Boolean);
  if (typeof value === 'string' && value.trim()) {
    return value.split(',').map(item => item.trim()).filter(Boolean)
  }
  return [];
  return []
}
function parseImageList(value: unknown) {
  if (!value) {
    return [] as string[];
    return [] as string[]
  }
  if (Array.isArray(value)) {
    return value
      .map(item => {
        if (typeof item === "string") return item;
        return item?.url || "";
      .map((item) => {
        if (typeof item === 'string')
          return item
        return item?.url || ''
      })
      .filter(Boolean);
      .filter(Boolean)
  }
  if (typeof value === "object") {
    return [(value as { url?: string }).url || ""].filter(Boolean);
  if (typeof value === 'object') {
    return [(value as { url?: string }).url || ''].filter(Boolean)
  }
  try {
    const parsed = JSON.parse(String(value));
    const parsed = JSON.parse(String(value))
    if (Array.isArray(parsed)) {
      return parsed
        .map(item => {
          if (typeof item === "string") return item;
          return item?.url || "";
        .map((item) => {
          if (typeof item === 'string')
            return item
          return item?.url || ''
        })
        .filter(Boolean);
        .filter(Boolean)
    }
    if (parsed?.url) {
      return [parsed.url];
      return [parsed.url]
    }
  } catch {
    return [];
  }
  catch {
    return []
  }
  return [];
  return []
}
function getIdCardImages(detail: QualificationDetail | null) {
  if (!detail) {
    return [];
    return []
  }
  return [
    ...parseImageList(detail.idCardFront),
    ...parseImageList(detail.idCardBack),
  ];
  ]
}
function getAuditStatusText(status?: number) {
  if (status === 2) {
    return '通过'
  }
  if (status === 3) {
    return '不通过'
  }
  return '-'
}
async function loadDetail(id: number | string) {
  const requestId = ++currentRequestId;
  detailLoading.value = true;
  const requestId = ++currentRequestId
  detailLoading.value = true
  try {
    const res = await fetchQualificationAuditInfo(id);
    const res = await fetchQualificationAuditInfo(id)
    if (requestId !== currentRequestId) {
      return;
      return
    }
    if (res.code === 200 && res.data) {
      reviewDetail.value = res.data;
      return;
      reviewDetail.value = res.data
      return
    }
    reviewDetail.value = null;
    window.$message?.error(res.msg || "获取审核详情失败");
  } catch (error) {
    reviewDetail.value = null
    window.$message?.error(res.msg || '获取审核详情失败')
  }
  catch (error) {
    if (requestId !== currentRequestId) {
      return;
      return
    }
    reviewDetail.value = null;
    console.error("获取审核详情失败", error);
    window.$message?.error("获取审核详情失败");
  } finally {
    reviewDetail.value = null
    console.error('获取审核详情失败', error)
    window.$message?.error('获取审核详情失败')
  }
  finally {
    if (requestId === currentRequestId) {
      detailLoading.value = false;
      detailLoading.value = false
    }
  }
}
const handleCancel = () => {
  show.value = false;
};
function handleCancel() {
  show.value = false
}
const handleConfirm = async () => {
async function handleConfirm() {
  try {
    await formRef.value?.validate();
    emit("confirm", { ...formModel.value });
    show.value = false;
  } catch (error) {
    console.log(t("serviceReview.common.validateFail"), error);
    await formRef.value?.validate()
    emit('confirm', { ...formModel.value })
    show.value = false
  }
};
  catch (error) {
    console.log(t('serviceReview.common.validateFail'), error)
  }
}
watch(
  () => [props.show, props.reviewId] as const,
  ([visible, reviewId]) => {
    if (!visible) {
      resetForm();
      resetDetail();
      return;
      resetForm()
      resetDetail()
      return
    }
    if (reviewId) {
      loadDetail(reviewId);
      return;
      loadDetail(reviewId)
      return
    }
    resetDetail();
    resetDetail()
  },
  { immediate: true }
);
  { immediate: true },
)
</script>
<template>
@@ -222,7 +243,7 @@
    v-model:show="show"
    :mask-closable="false"
    preset="card"
    title="人员资质审核"
    :title="isDetailMode ? '人员资质详情' : '人员资质审核'"
    :style="{ width: '600px' }"
    :auto-focus="false"
    :segmented="{
@@ -234,11 +255,15 @@
    <n-spin :show="detailLoading">
      <div class="review-modal-content">
        <div v-if="reviewDetail" class="section-container">
          <div class="section-title">人员信息</div>
          <div class="section-title">
            人员信息
          </div>
          <div class="info-grid">
            <div class="info-item">
              <div class="info-label">姓名</div>
              <div class="info-label">
                姓名
              </div>
              <div class="info-value name-value">
                <!-- <img
                  v-if="parseImageList(reviewDetail.avatar)[0]"
@@ -251,21 +276,27 @@
            </div>
            <div class="info-item">
              <div class="info-label">编号</div>
              <div class="info-label">
                编号
              </div>
              <div class="info-value">
                {{ reviewDetail.operationsUserId || "-" }}
              </div>
            </div>
            <div class="info-item">
              <div class="info-label">手机</div>
              <div class="info-label">
                手机
              </div>
              <div class="info-value">
                {{ reviewDetail.phoneNumber || "-" }}
              </div>
            </div>
            <div class="info-item">
              <div class="info-label">角色</div>
              <div class="info-label">
                角色
              </div>
              <div class="info-value role-list">
                <n-tag
                  v-for="role in getRoleNames(reviewDetail.roleNames)"
@@ -281,7 +312,9 @@
            </div>
            <div class="info-item">
              <div class="info-label">身份证</div>
              <div class="info-label">
                身份证
              </div>
              <div class="info-value">
                <div v-if="getIdCardImages(reviewDetail).length" class="image-list">
                  <n-image
@@ -299,7 +332,9 @@
            </div>
            <div class="info-item">
              <div class="info-label">驾驶证</div>
              <div class="info-label">
                驾驶证
              </div>
              <div class="info-value">
                <div
                  v-if="parseImageList(reviewDetail.driverLicense).length"
@@ -320,7 +355,9 @@
            </div>
            <div class="info-item">
              <div class="info-label">无犯罪记录证明</div>
              <div class="info-label">
                无犯罪记录证明
              </div>
              <div class="info-value">
                <div
                  v-if="parseImageList(reviewDetail.certificateOfNoCriminalRecord).length"
@@ -341,7 +378,9 @@
            </div>
            <div class="info-item">
              <div class="info-label">培训结业证</div>
              <div class="info-label">
                培训结业证
              </div>
              <div class="info-value">
                <div
                  v-if="parseImageList(reviewDetail.trainingGraduationCertificate).length"
@@ -368,9 +407,12 @@
        </div>
        <div class="section-container">
          <div class="section-title">资质审核</div>
          <div class="section-title">
            资质审核
          </div>
          <n-form
            v-if="!isDetailMode"
            ref="formRef"
            :model="formModel"
            :rules="rules"
@@ -384,8 +426,12 @@
            >
              <n-radio-group v-model:value="formModel.result">
                <n-space>
                  <n-radio value="pass">通过</n-radio>
                  <n-radio value="reject">不通过</n-radio>
                  <n-radio value="pass">
                    通过
                  </n-radio>
                  <n-radio value="reject">
                    不通过
                  </n-radio>
                </n-space>
              </n-radio-group>
            </n-form-item>
@@ -406,14 +452,36 @@
              />
            </n-form-item>
          </n-form>
          <div v-else class="info-grid">
            <div class="info-item">
              <div class="info-label">
                审核
              </div>
              <div class="info-value">
                {{ getAuditStatusText(reviewDetail?.auditStatus) }}
              </div>
            </div>
            <div class="info-item">
              <div class="info-label">
                备注
              </div>
              <div class="info-value">
                {{ reviewDetail?.auditRemarks?.trim() || '-' }}
              </div>
            </div>
          </div>
        </div>
      </div>
    </n-spin>
    <template #action>
      <n-space justify="end">
        <n-button @click="handleCancel">{{ t("common.cancel") }}</n-button>
        <n-button type="primary" @click="handleConfirm">
        <n-button @click="handleCancel">
          {{ isDetailMode ? t("common.close") : t("common.cancel") }}
        </n-button>
        <n-button v-if="!isDetailMode" type="primary" @click="handleConfirm">
          {{ t("common.confirm") }}
        </n-button>
      </n-space>
src/views/service/review/personnel/index.vue
@@ -146,7 +146,7 @@
  {
    title: t('serviceReview.personnel.actions'),
    key: 'actions',
    width: 100,
    width: 140,
    fixed: 'right',
    render: (row) => {
      return (
@@ -160,6 +160,18 @@
                  onClick={() => handleApprove(row.id)}
                >
                  {t('serviceReview.personnel.audit')}
                </NButton>
              )
            : null}
          {row.auditStatus !== 1
            ? (
                <NButton
                  text
                  v-permission="80112"
                  type="primary"
                  onClick={() => handleViewDetail(row.id)}
                >
                  详情
                </NButton>
              )
            : null}
@@ -188,6 +200,7 @@
const reviewIds = ref<number[]>([])
const selectedIds = ref<number[]>([])
const showOperationLogModal = ref(false)
const reviewModalMode = ref<'review' | 'detail'>('review')
function handleSearch() {
  pagination.value.page = 1
@@ -205,6 +218,7 @@
    window.$message?.warning(t('serviceReview.common.selectPersonnelToReview'))
    return
  }
  reviewModalMode.value = 'review'
  currentReviewId.value = null
  reviewIds.value = [...selectedIds.value]
  showReviewModal.value = true
@@ -215,8 +229,16 @@
}
function handleApprove(id: number) {
  reviewModalMode.value = 'review'
  currentReviewId.value = id
  reviewIds.value = [id]
  showReviewModal.value = true
}
function handleViewDetail(id: number) {
  reviewModalMode.value = 'detail'
  currentReviewId.value = id
  reviewIds.value = []
  showReviewModal.value = true
}
@@ -273,6 +295,7 @@
  if (!visible) {
    currentReviewId.value = null
    reviewIds.value = []
    reviewModalMode.value = 'review'
  }
})
@@ -531,6 +554,7 @@
    <ReviewModal
      v-model:show="showReviewModal"
      :review-id="currentReviewId"
      :mode="reviewModalMode"
      :selected-count="reviewIds.length"
      @confirm="handleConfirmReview"
    />
src/views/system/config/index.vue
@@ -214,26 +214,27 @@
                :allow-input="onlyAllowNumberAndDash"
              />
            </n-form-item>
            <n-form-item label="小程序附近热门站点推荐距离" path="nearPointDistance" required class="row-item">
              <div class="inline-input w-full">
                <n-input-group style="width: 100%;">
                  <n-input
                    :value="formModel.nearPointDistance" placeholder="请输入"
                    :allow-input="onlyAllowNumberAndDash"
                    style="width: 100%;"
                    @update:value="handleNearPointDistanceChange"
                  />
                  <n-input-group-label>m</n-input-group-label>
                </n-input-group>
                <span class="inline-note">内</span>
              </div>
            <n-form-item label="常见问题首页展示数" path="headShowCount" required class="row-item">
              <n-input
                :value="formModel.headShowCount" placeholder="请输入"
                :allow-input="onlyAllowNumberAndDash" style="width: 339px;"
                @update:value="handleHeadShowCountChange"
              />
            </n-form-item>
            <n-form-item label="小程序首页地图推荐距离" path="nearPointDistanceSearch" required class="row-item">
            <n-form-item label="是否开启运营期免收费" path="operateFree" required class="row-item">
              <n-switch v-model:value="formModel.operateFree" :unchecked-value="0" :checked-value="1" />
            </n-form-item>
          </div>
          <div class="form-row gap-x-20px!">
            <n-form-item label="首页附近站点推荐距离" path="nearPointDistance" required class="row-item">
              <div class="inline-input">
                <n-input-group style="width: 222px;">
                  <n-input
                    :value="formModel.nearPointDistanceSearch" placeholder="请输入"
                    :allow-input="onlyAllowNumberAndDash"
                    style="width: 100%;"
                    @update:value="handleNearPointDistanceChange"
                    @update:value="handleNearPointDistanceSearchChange"
                  />
                  <n-input-group-label>m</n-input-group-label>
@@ -241,16 +242,20 @@
                <span class="inline-note">内</span>
              </div>
            </n-form-item>
          </div>
          <div class="form-row gap-x-40px!">
            <n-form-item label="常见问题首页展示数" path="headShowCount" required class="row-item">
              <n-input
                :value="formModel.headShowCount" placeholder="请输入"
                :allow-input="onlyAllowNumberAndDash" style="width: 100%;"
                @update:value="handleHeadShowCountChange"
              />
            <n-form-item label="列表页附近热门站点推荐距离" path="nearPointDistanceSearch" required class="row-item">
              <div class="inline-input">
                <n-input-group style="width: 222px;">
                  <n-input
                    :value="formModel.nearPointDistance" placeholder="请输入"
                    :allow-input="onlyAllowNumberAndDash"
                    @update:value="handleNearPointDistanceChange"
                  />
                  <n-input-group-label>m</n-input-group-label>
                </n-input-group>
                <span class="inline-note">内</span>
              </div>
            </n-form-item>
            <n-form-item label="小程序天气单位" path="temperatureUnit" required class="row-item">
              <n-select
                v-model:value="formModel.temperatureUnit"
src/views/transaction/order/evaluationRecord/index.vue
@@ -67,7 +67,7 @@
    width: 140,
  },
  {
    title: '评价分数',
    title: '评价等级',
    key: 'orderRating',
    resizable: true,
    width: 120,
@@ -128,7 +128,7 @@
    render: () => <n-input v-model:value={model.value.phoneNumber} />,
  },
  {
    label: '评价分数',
    label: '评价等级',
    path: 'orderRating',
    render: () => (
      <n-select
src/views/transaction/order/orderManagement/index.vue
@@ -286,11 +286,11 @@
  },
  {
    title: t('transaction.orderAmount'),
    key: 'orderMoney',
    key: 'payAmount',
    width: 120,
    resizable: true,
    render(row) {
      return row.orderMoney ? `¥${row.orderMoney.toFixed(2)}` : '-'
      return row.payAmount ? `¥${row.payAmount.toFixed(2)}` : '-'
    },
  },
  {
src/views/userContent/banner/index.vue
@@ -234,36 +234,6 @@
      )
    },
  },
  {
    title: '上架状态',
    key: 'bannerStatus',
    width: 100,
    resizable: true,
    render: (row) => {
      return (
        <n-switch
          value={row.bannerStatus === 1}
          onUpdate:value={async (value: boolean) => {
            try {
              const { error, code } = await updateBanner({
                id: row.id,
                bannerStatus: value ? 1 : 2,
              }) as any
              if (!error && code === 200) {
                message.success('状态更新成功')
                fetchData()
              }
            }
            catch (e) {
              console.error('更新状态失败', e)
              // 恢复原状态
              fetchData()
            }
          }}
        />
      )
    },
  },
  // {
  //   title: '跳转类型',
  //   key: 'jumpType',
@@ -306,7 +276,7 @@
    title: '操作',
    key: 'actions',
    align: 'left',
    width: 80,
    width: 180,
    fixed: 'right',
    render: row => (
      <div class="flex justify-start gap-3">
@@ -331,6 +301,15 @@
        >
          删除
        </span>
        <n-switch
          value={row.bannerStatus === 1}
          onUpdate:value={(value: boolean) => handleToggleBannerStatus(row, value)}
        >
          {{
            checked: () => '上架',
            unchecked: () => '下架',
          }}
        </n-switch>
      </div>
    ),
  },
@@ -340,6 +319,23 @@
  showOperationLogModal.value = true
}
async function handleToggleBannerStatus(row: Banner, value: boolean) {
  try {
    const { error, code } = await updateBanner({
      id: row.id,
      bannerStatus: value ? 1 : 2,
    }) as any
    if (!error && code === 200) {
      message.success('状态更新成功')
      fetchData()
    }
  }
  catch (e) {
    console.error('更新状态失败', e)
    fetchData()
  }
}
async function fetchData() {
  startLoading()
  try {