Преглед изворни кода

feat(订单): 新增形象店申请审核功能

yz пре 1 недеља
родитељ
комит
932a34d657
3 измењених фајлова са 1131 додато и 0 уклоњено
  1. 171 0
      src/api/order/image-store-apply.js
  2. 22 0
      src/router/views/index.js
  3. 938 0
      src/views/order/image-store-apply/index.vue

+ 171 - 0
src/api/order/image-store-apply.js

@@ -0,0 +1,171 @@
+import request from '@/router/axios';
+
+/**
+ * @typedef {Object} ImageStoreApplyRecord
+ * @property {string} id - 申请ID
+ * @property {string} createUser - 创建用户ID
+ * @property {string} createDept - 创建部门ID
+ * @property {string} createTime - 创建时间
+ * @property {string} updateUser - 更新用户ID
+ * @property {string} updateTime - 更新时间
+ * @property {number} status - 状态
+ * @property {number} isDeleted - 是否删除
+ * @property {string} applyNo - 申请编号
+ * @property {number} applicantType - 申请人类型
+ * @property {number} customerId - 客户ID
+ * @property {string} customerCode - 客户编码
+ * @property {string} customerName - 客户名称
+ * @property {string} contactName - 联系人姓名
+ * @property {string} contactPhone - 联系人电话
+ * @property {number} brandId - 品牌ID
+ * @property {string} brandCode - 品牌编码
+ * @property {string} brandName - 品牌名称
+ * @property {string} qualificationInfo - 资质信息JSON字符串
+ * @property {string} applyAmount - 申请金额
+ * @property {number} needReimburse - 是否需要报销
+ * @property {number} auditStatus - 审核状态 0-未审核 1-审核通过 2-审核不通过
+ * @property {string} auditAmount - 审核金额
+ * @property {string|null} auditRemark - 审核备注
+ * @property {string|null} auditorId - 审核人ID
+ * @property {string|null} auditorName - 审核人姓名
+ * @property {string|null} auditTime - 审核时间
+ * @property {string} submitTime - 提交时间
+ */
+
+/**
+ * @typedef {Object} QualificationItem
+ * @property {string} certNo - 证书编号
+ * @property {string} certName - 证书名称
+ * @property {string} expiryDate - 到期日期
+ */
+
+/**
+ * @typedef {Object} ImageStoreApplyQueryParams
+ * @property {string} [applyNo] - 申请编号
+ * @property {string} [customerCode] - 客户编码
+ * @property {string} [customerName] - 客户名称
+ * @property {string} [brandCode] - 品牌编码
+ * @property {number} [auditStatus] - 审核状态
+ * @property {string} [submitTimeStart] - 提交时间开始
+ * @property {string} [submitTimeEnd] - 提交时间结束
+ */
+
+/**
+ * @typedef {Object} ImageStoreApplyListResponse
+ * @property {number} code - 响应码
+ * @property {boolean} success - 是否成功
+ * @property {Object} data - 响应数据
+ * @property {ImageStoreApplyRecord[]} data.records - 记录列表
+ * @property {number} data.total - 总数
+ * @property {number} data.size - 页大小
+ * @property {number} data.current - 当前页
+ * @property {number} data.pages - 总页数
+ * @property {string} msg - 响应消息
+ */
+
+/**
+ * @typedef {Object} ImageStoreApplyDetailResponse
+ * @property {number} code - 响应码
+ * @property {boolean} success - 是否成功
+ * @property {ImageStoreApplyRecord} data - 申请详情
+ * @property {string} msg - 响应消息
+ */
+
+/**
+ * 获取形象店申请列表
+ * @param {number} current - 当前页码
+ * @param {number} size - 页大小
+ * @param {ImageStoreApplyQueryParams} [params] - 查询参数
+ * @returns {Promise<ImageStoreApplyListResponse>} 申请列表响应
+ */
+export const getList = (current, size, params) => {
+  return request({
+    url: '/api/blade-factory/api/factory/image-store-apply',
+    method: 'get',
+    params: {
+      ...params,
+      current: current,
+      size
+    }
+  })
+}
+
+/**
+ * 获取形象店申请详情
+ * @param {string} id - 申请ID
+ * @returns {Promise<ImageStoreApplyDetailResponse>} 申请详情响应
+ */
+export const getDetail = (id) => {
+  return request({
+    url: `/api/blade-factory/api/factory/image-store-apply/${id}`,
+    method: 'get'
+  })
+}
+
+/**
+ * 更新形象店申请(用于审核操作)
+ * @param {ImageStoreApplyRecord} row - 申请数据
+ * @returns {Promise<Object>} 更新响应
+ */
+export const update = (row) => {
+  return request({
+    url: '/api/blade-factory/api/factory/image-store-apply',
+    method: 'put',
+    data: row
+  })
+}
+
+/**
+ * @typedef {Object} ApplyAttachmentRecord
+ * @property {string} id - 附件ID
+ * @property {string} createUser - 创建用户ID
+ * @property {string} createDept - 创建部门ID
+ * @property {string} createTime - 创建时间
+ * @property {string} updateUser - 更新用户ID
+ * @property {string} updateTime - 更新时间
+ * @property {number} status - 状态
+ * @property {number} isDeleted - 是否删除
+ * @property {number} applyId - 申请ID
+ * @property {string} fileName - 文件名
+ * @property {string} fileUrl - 文件URL
+ * @property {string} fileType - 文件类型
+ * @property {number} fileSize - 文件大小(字节)
+ * @property {string} attachType - 附件类型
+ */
+
+/**
+ * @typedef {Object} ApplyAttachmentQueryParams
+ * @property {number} applyId - 申请ID
+ */
+
+/**
+ * @typedef {Object} ApplyAttachmentListResponse
+ * @property {number} code - 响应码
+ * @property {boolean} success - 是否成功
+ * @property {Object} data - 响应数据
+ * @property {ApplyAttachmentRecord[]} data.records - 附件列表
+ * @property {number} data.total - 总数
+ * @property {number} data.size - 页大小
+ * @property {number} data.current - 当前页
+ * @property {number} data.pages - 总页数
+ * @property {string} msg - 响应消息
+ */
+
+/**
+ * 获取申请附件列表
+ * @param {number} current - 当前页码
+ * @param {number} size - 页大小
+ * @param {ApplyAttachmentQueryParams} params - 查询参数
+ * @returns {Promise<ApplyAttachmentListResponse>} 附件列表响应
+ */
+export const getAttachmentList = (current, size, params) => {
+  return request({
+    url: '/api/blade-factory/api/factory/apply-attachment',
+    method: 'get',
+    params: {
+      ...params,
+      current: current,
+      size
+    }
+  })
+}

+ 22 - 0
src/router/views/index.js

@@ -189,6 +189,28 @@ export default [
         ]
     },
     {
+        path: "/image-store-apply",
+        component: Layout,
+        redirect: "/image-store-apply/index",
+        meta: {
+            title: '形象店申请审核',
+            keepAlive: true,
+            permission: ['image_store_apply']
+        },
+        children: [
+            {
+                path: 'index',
+                name: '形象店申请审核',
+                component: () => import('@/views/order/image-store-apply/index'),
+                meta: {
+                    title: '形象店申请审核',
+                    keepAlive: true,
+                    permission: ['image_store_apply']
+                }
+            }
+        ]
+    },
+    {
         path: "/forecast",
         component: Layout,
         redirect: "/forecast/index",

+ 938 - 0
src/views/order/image-store-apply/index.vue

@@ -0,0 +1,938 @@
+<template>
+  <basic-container>
+    <avue-crud
+      :option="option"
+      :table-loading="loading"
+      :data="data"
+      :page.sync="page"
+      :permission="permissionList"
+      :before-open="beforeOpen"
+      v-model="form"
+      ref="crud"
+      @search-change="searchChange"
+      @search-reset="searchReset"
+      @selection-change="selectionChange"
+      @selection-clear="selectionClear"
+      @current-change="currentChange"
+      @size-change="sizeChange"
+      @refresh-change="refreshChange"
+      @on-load="onLoad"
+    >
+      <template slot="menuLeft">
+        <el-button
+          type="primary"
+          size="small"
+          icon="el-icon-refresh"
+          @click="refreshChange"
+        >
+          刷新
+        </el-button>
+      </template>
+
+      <!-- 审核状态显示 -->
+      <template slot="auditStatus" slot-scope="{row}">
+        <el-tag
+          :type="getAuditStatusType(row.auditStatus)"
+          size="small"
+        >
+          {{ getAuditStatusText(row.auditStatus) }}
+        </el-tag>
+      </template>
+
+      <!-- 申请金额格式化 -->
+      <template slot="applyAmount" slot-scope="{row}">
+        ¥{{ formatAmount(row.applyAmount) }}
+      </template>
+
+      <!-- 审核金额格式化 -->
+      <template slot="auditAmount" slot-scope="{row}">
+        <span v-if="row.auditAmount && parseFloat(row.auditAmount) > 0">
+          ¥{{ formatAmount(row.auditAmount) }}
+        </span>
+        <span v-else>-</span>
+      </template>
+
+      <!-- 操作列 -->
+      <template slot="menu" slot-scope="{row}">
+        <el-button
+          type="text"
+          size="small"
+          @click="handleView(row)"
+        >
+          查看详情
+        </el-button>
+        <el-button
+          v-if="row.auditStatus === 0"
+          type="text"
+          size="small"
+          @click="handleAudit(row, 1)"
+        >
+          审核通过
+        </el-button>
+        <el-button
+          v-if="row.auditStatus === 0"
+          type="text"
+          size="small"
+          @click="handleAudit(row, 2)"
+        >
+          审核不通过
+        </el-button>
+      </template>
+    </avue-crud>
+
+    <!-- 详情对话框 -->
+    <el-dialog
+      title="形象店申请详情"
+      :visible.sync="detailVisible"
+      width="80%"
+      :close-on-click-modal="false"
+    >
+      <div v-if="detailData" class="detail-container">
+        <!-- 基本信息 -->
+        <el-card class="detail-card" shadow="never">
+          <div slot="header" class="card-header">
+            <span>基本信息</span>
+          </div>
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>申请编号:</label>
+                <span>{{ detailData.applyNo }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>客户编码:</label>
+                <span>{{ detailData.customerCode }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>客户名称:</label>
+                <span>{{ detailData.customerName }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>联系人:</label>
+                <span>{{ detailData.contactName }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>联系电话:</label>
+                <span>{{ detailData.contactPhone }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>品牌名称:</label>
+                <span>{{ detailData.brandName }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>申请金额:</label>
+                <span class="amount">¥{{ formatAmount(detailData.applyAmount) }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>提交时间:</label>
+                <span>{{ detailData.submitTime }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>审核状态:</label>
+                <el-tag
+                  :type="getAuditStatusType(detailData.auditStatus)"
+                  size="small"
+                >
+                  {{ getAuditStatusText(detailData.auditStatus) }}
+                </el-tag>
+              </div>
+            </el-col>
+          </el-row>
+        </el-card>
+
+        <!-- 资质信息 -->
+        <el-card class="detail-card" shadow="never">
+          <div slot="header" class="card-header">
+            <span>资质信息</span>
+          </div>
+          <el-table
+            :data="qualificationList"
+            border
+            size="small"
+          >
+            <el-table-column prop="certName" label="证书名称" />
+            <el-table-column prop="certNo" label="证书编号" />
+            <el-table-column prop="expiryDate" label="到期日期" />
+          </el-table>
+        </el-card>
+
+        <!-- 附件信息 -->
+        <el-card class="detail-card" shadow="never">
+          <div slot="header" class="card-header">
+            <span>相关附件</span>
+          </div>
+          <el-table
+            :data="attachmentList"
+            border
+            size="small"
+            v-loading="attachmentLoading"
+          >
+            <el-table-column prop="fileName" label="文件名" />
+            <el-table-column prop="attachType" label="附件类型" />
+            <el-table-column prop="fileType" label="文件类型" />
+            <el-table-column prop="fileSize" label="文件大小">
+              <template slot-scope="{row}">
+                {{ formatFileSize(row.fileSize) }}
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" width="120">
+              <template slot-scope="{row}">
+                <el-button
+                  type="text"
+                  size="small"
+                  @click="handleDownload(row)"
+                >
+                  下载
+                </el-button>
+                <el-button
+                  v-if="isImageFile(row.fileType)"
+                  type="text"
+                  size="small"
+                  @click="handlePreview(row)"
+                >
+                  预览
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-card>
+
+        <!-- 审核信息 -->
+        <el-card
+          v-if="detailData.auditStatus !== 0"
+          class="detail-card"
+          shadow="never"
+        >
+          <div slot="header" class="card-header">
+            <span>审核信息</span>
+          </div>
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>审核人:</label>
+                <span>{{ detailData.auditorName || '-' }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>审核时间:</label>
+                <span>{{ detailData.auditTime || '-' }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>审核金额:</label>
+                <span class="amount">
+                  {{ detailData.auditAmount && parseFloat(detailData.auditAmount) > 0
+                     ? '¥' + formatAmount(detailData.auditAmount) : '-' }}
+                </span>
+              </div>
+            </el-col>
+            <el-col :span="24">
+              <div class="detail-item">
+                <label>审核备注:</label>
+                <span>{{ detailData.auditRemark || '-' }}</span>
+              </div>
+            </el-col>
+          </el-row>
+        </el-card>
+      </div>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="detailVisible = false">关闭</el-button>
+        <el-button
+          v-if="detailData && detailData.auditStatus === 0"
+          type="success"
+          @click="handleAudit(detailData, 1)"
+        >
+          审核通过
+        </el-button>
+        <el-button
+          v-if="detailData && detailData.auditStatus === 0"
+          type="danger"
+          @click="handleAudit(detailData, 2)"
+        >
+          审核不通过
+        </el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 审核对话框 -->
+    <el-dialog
+      :title="auditForm.auditStatus === 1 ? '审核通过' : '审核不通过'"
+      :visible.sync="auditVisible"
+      width="500px"
+      :close-on-click-modal="false"
+    >
+      <el-form
+        :model="auditForm"
+        :rules="auditRules"
+        ref="auditFormRef"
+        label-width="100px"
+      >
+        <el-form-item label="申请编号">
+          <span>{{ auditForm.applyNo }}</span>
+        </el-form-item>
+        <el-form-item label="客户名称">
+          <span>{{ auditForm.customerName }}</span>
+        </el-form-item>
+        <el-form-item label="申请金额">
+          <span class="amount">¥{{ formatAmount(auditForm.applyAmount) }}</span>
+        </el-form-item>
+        <el-form-item
+          v-if="auditForm.auditStatus === 1"
+          label="审核金额"
+          prop="auditAmount"
+        >
+          <el-input-number
+            v-model="auditForm.auditAmount"
+            :precision="2"
+            :min="0"
+            :max="parseFloat(auditForm.applyAmount)"
+            placeholder="请输入审核金额"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="审核备注" prop="auditRemark">
+          <el-input
+            v-model="auditForm.auditRemark"
+            type="textarea"
+            :rows="4"
+            placeholder="请输入审核备注"
+          />
+        </el-form-item>
+      </el-form>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="auditVisible = false">取消</el-button>
+        <el-button
+          type="primary"
+          :loading="auditLoading"
+          @click="submitAudit"
+        >
+          确定
+        </el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 图片预览对话框 -->
+    <el-dialog
+      title="图片预览"
+      :visible.sync="previewVisible"
+      width="60%"
+      :close-on-click-modal="false"
+    >
+      <div class="preview-container">
+        <img
+          v-if="previewUrl"
+          :src="previewUrl"
+          alt="预览图片"
+          class="preview-image"
+        />
+      </div>
+    </el-dialog>
+  </basic-container>
+</template>
+
+<script>
+import { getList, getDetail, update, getAttachmentList } from '@/api/order/image-store-apply'
+import { mapGetters } from 'vuex'
+
+/**
+ * @typedef {import('@/api/order/image-store-apply').ImageStoreApplyRecord} ImageStoreApplyRecord
+ * @typedef {import('@/api/order/image-store-apply').QualificationItem} QualificationItem
+ * @typedef {import('@/api/order/image-store-apply').ApplyAttachmentRecord} ApplyAttachmentRecord
+ * @typedef {import('@/api/order/image-store-apply').ImageStoreApplyQueryParams} ImageStoreApplyQueryParams
+ */
+
+export default {
+  name: 'ImageStoreApply',
+  data() {
+    return {
+      /** @type {ImageStoreApplyRecord[]} */
+      data: [],
+      /** @type {ImageStoreApplyRecord} */
+      form: {},
+      /** @type {ImageStoreApplyQueryParams} */
+      query: {},
+      loading: true,
+
+      // 分页信息
+      page: {
+        pageSize: 10,
+        currentPage: 1,
+        total: 0
+      },
+
+      // 详情对话框
+      detailVisible: false,
+      /** @type {ImageStoreApplyRecord|null} */
+      detailData: null,
+      /** @type {QualificationItem[]} */
+      qualificationList: [],
+      /** @type {ApplyAttachmentRecord[]} */
+      attachmentList: [],
+      attachmentLoading: false,
+
+      // 审核对话框
+      auditVisible: false,
+      auditLoading: false,
+      /** @type {Object} */
+      auditForm: {
+        id: '',
+        applyNo: '',
+        customerName: '',
+        applyAmount: '',
+        auditStatus: 0,
+        auditAmount: 0,
+        auditRemark: ''
+      },
+      /** @type {Object} */
+      auditRules: {
+        auditAmount: [
+          { required: true, message: '请输入审核金额', trigger: 'blur' },
+          { type: 'number', min: 0, message: '审核金额不能小于0', trigger: 'blur' }
+        ],
+        auditRemark: [
+          { required: true, message: '请输入审核备注', trigger: 'blur' },
+          { min: 5, max: 500, message: '审核备注长度在5到500个字符', trigger: 'blur' }
+        ]
+      },
+
+      // 图片预览
+      previewVisible: false,
+      previewUrl: '',
+
+      // 表格配置
+      option: {
+        height: 'auto',
+        calcHeight: 30,
+        tip: false,
+        searchShow: true,
+        searchMenuSpan: 6,
+        border: true,
+        index: true,
+        viewBtn: false,
+        editBtn: false,
+        delBtn: false,
+        addBtn: false,
+        column: [
+          {
+            label: '申请编号',
+            prop: 'applyNo',
+            minWidth: 140,
+            search: true,
+            searchPlaceholder: '请输入申请编号'
+          },
+          {
+            label: '客户编码',
+            prop: 'customerCode',
+            minWidth: 120,
+            search: true,
+            searchPlaceholder: '请输入客户编码'
+          },
+          {
+            label: '客户名称',
+            prop: 'customerName',
+            minWidth: 180,
+            search: true,
+            searchPlaceholder: '请输入客户名称'
+          },
+          {
+            label: '联系人',
+            prop: 'contactName',
+            minWidth: 100
+          },
+          {
+            label: '联系电话',
+            prop: 'contactPhone',
+            minWidth: 120
+          },
+          {
+            label: '品牌名称',
+            prop: 'brandName',
+            minWidth: 120,
+            search: true,
+            searchPlaceholder: '请输入品牌名称'
+          },
+          {
+            label: '申请金额',
+            prop: 'applyAmount',
+            minWidth: 120,
+            slot: true
+          },
+          {
+            label: '审核状态',
+            prop: 'auditStatus',
+            minWidth: 100,
+            slot: true,
+            search: true,
+            type: 'select',
+            dicData: [
+              { label: '未审核', value: 0 },
+              { label: '审核通过', value: 1 },
+              { label: '审核不通过', value: 2 }
+            ]
+          },
+          {
+            label: '审核金额',
+            prop: 'auditAmount',
+            minWidth: 120,
+            slot: true
+          },
+          {
+            label: '审核人',
+            prop: 'auditorName',
+            minWidth: 100
+          },
+          {
+            label: '审核时间',
+            prop: 'auditTime',
+            minWidth: 150
+          },
+          {
+            label: '提交时间',
+            prop: 'submitTime',
+            minWidth: 150,
+            search: true,
+            type: 'daterange',
+            searchPlaceholder: '请选择提交时间范围',
+            formatter: (row, column, cellValue) => {
+              if (!cellValue) return '-'
+              // 如果是数组格式,取第一个元素
+              if (Array.isArray(cellValue)) {
+                return cellValue[0] || '-'
+              }
+              return cellValue
+            }
+          }
+        ]
+      }
+    }
+  },
+
+  computed: {
+    ...mapGetters(['permission']),
+
+    /** @returns {string[]} */
+    permissionList() {
+      return {
+        // viewBtn: this.vaildData(this.permission.image_store_apply_view, false),
+        // editBtn: this.vaildData(this.permission.image_store_apply_edit, false),
+        // delBtn: this.vaildData(this.permission.image_store_apply_delete, false),
+        // addBtn: this.vaildData(this.permission.image_store_apply_add, false)
+        viewBtn: false,
+        editBtn: false,
+        delBtn: false,
+        addBtn: false,
+      }
+    },
+
+    /** @returns {string[]} */
+    ids() {
+      const ids = []
+      this.selectionList.forEach(ele => {
+        ids.push(ele.id)
+      })
+      return ids
+    }
+  },
+
+  methods: {
+    /**
+     * 获取审核状态文本
+     * @param {number} status - 审核状态
+     * @returns {string} 状态文本
+     */
+    getAuditStatusText(status) {
+      const statusMap = {
+        0: '未审核',
+        1: '审核通过',
+        2: '审核不通过'
+      }
+      return statusMap[status] || '未知状态'
+    },
+
+    /**
+     * 获取审核状态标签类型
+     * @param {number} status - 审核状态
+     * @returns {string} 标签类型
+     */
+    getAuditStatusType(status) {
+      const typeMap = {
+        0: 'warning',
+        1: 'success',
+        2: 'danger'
+      }
+      return typeMap[status] || 'info'
+    },
+
+    /**
+     * 格式化金额显示
+     * @param {string|number} amount - 金额
+     * @returns {string} 格式化后的金额
+     */
+    formatAmount(amount) {
+      if (!amount) return '0.00'
+      const num = parseFloat(amount)
+      return num.toLocaleString('zh-CN', {
+        minimumFractionDigits: 2,
+        maximumFractionDigits: 2
+      })
+    },
+
+    /**
+     * 格式化文件大小
+     * @param {number} size - 文件大小(字节)
+     * @returns {string} 格式化后的文件大小
+     */
+    formatFileSize(size) {
+      if (!size) return '0 B'
+      const units = ['B', 'KB', 'MB', 'GB']
+      let index = 0
+      let fileSize = size
+
+      while (fileSize >= 1024 && index < units.length - 1) {
+        fileSize /= 1024
+        index++
+      }
+
+      return `${fileSize.toFixed(2)} ${units[index]}`
+    },
+
+    /**
+     * 判断是否为图片文件
+     * @param {string} fileType - 文件类型
+     * @returns {boolean} 是否为图片
+     */
+    isImageFile(fileType) {
+      const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
+      return imageTypes.includes(fileType.toLowerCase())
+    },
+
+    /**
+     * 查看详情
+     * @param {ImageStoreApplyRecord} row - 行数据
+     * @returns {Promise<void>}
+     */
+    async handleView(row) {
+      try {
+        this.detailVisible = true
+        this.detailData = null
+        this.qualificationList = []
+        this.attachmentList = []
+
+        // 获取详情数据
+        const res = await getDetail(row.id)
+        this.detailData = res.data.data
+
+        // 解析资质信息
+        if (this.detailData.qualificationInfo) {
+          try {
+            this.qualificationList = JSON.parse(this.detailData.qualificationInfo)
+          } catch (error) {
+            console.warn('解析资质信息失败:', error)
+            this.qualificationList = []
+          }
+        }
+
+        // 加载附件列表
+        await this.loadAttachments(row.id)
+      } catch (error) {
+        console.error('获取详情失败:', error)
+        this.$message.error('获取详情失败')
+      }
+    },
+
+    /**
+     * 加载附件列表
+     * @param {string} applyId - 申请ID
+     * @returns {Promise<void>}
+     */
+    async loadAttachments(applyId) {
+      try {
+        this.attachmentLoading = true
+        const res = await getAttachmentList(1, 100, { applyId: parseInt(applyId) })
+        this.attachmentList = res.data.data.records || []
+      } catch (error) {
+        console.error('获取附件列表失败:', error)
+        this.$message.error('获取附件列表失败')
+      } finally {
+        this.attachmentLoading = false
+      }
+    },
+
+    /**
+     * 处理审核操作
+     * @param {ImageStoreApplyRecord} row - 行数据
+     * @param {number} auditStatus - 审核状态 1-通过 2-不通过
+     */
+    handleAudit(row, auditStatus) {
+      this.auditForm = {
+        id: row.id,
+        applyNo: row.applyNo,
+        customerName: row.customerName,
+        applyAmount: row.applyAmount,
+        auditStatus: auditStatus,
+        auditAmount: auditStatus === 1 ? parseFloat(row.applyAmount) : 0,
+        auditRemark: ''
+      }
+
+      // 重置表单验证
+      this.$nextTick(() => {
+        if (this.$refs.auditFormRef) {
+          this.$refs.auditFormRef.clearValidate()
+        }
+      })
+
+      this.auditVisible = true
+    },
+
+    /**
+     * 提交审核
+     * @returns {Promise<void>}
+     */
+    async submitAudit() {
+      try {
+        // 表单验证
+        await this.$refs.auditFormRef.validate()
+
+        this.auditLoading = true
+
+        // 构建更新数据
+        const updateData = {
+          ...this.detailData,
+          auditStatus: this.auditForm.auditStatus,
+          auditAmount: this.auditForm.auditAmount,
+          auditRemark: this.auditForm.auditRemark,
+          auditorId: this.$store.getters.userInfo.user_id,
+          auditorName: this.$store.getters.userInfo.real_name,
+          auditTime: new Date().toISOString().slice(0, 19).replace('T', ' ')
+        }
+
+        await update(updateData)
+
+        this.$message.success('审核操作成功')
+        this.auditVisible = false
+        this.detailVisible = false
+
+        // 刷新列表
+        await this.onLoad(this.page)
+      } catch (error) {
+        if (error.message) {
+          // 表单验证错误
+          return
+        }
+        console.error('审核操作失败:', error)
+        this.$message.error('审核操作失败')
+      } finally {
+        this.auditLoading = false
+      }
+    },
+
+    /**
+     * 下载附件
+     * @param {ApplyAttachmentRecord} row - 附件数据
+     */
+    handleDownload(row) {
+      if (!row.fileUrl) {
+        this.$message.warning('文件链接不存在')
+        return
+      }
+
+      // 创建下载链接
+      const link = document.createElement('a')
+      link.href = row.fileUrl
+      link.download = row.fileName
+      link.target = '_blank'
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+    },
+
+    /**
+     * 预览图片
+     * @param {ApplyAttachmentRecord} row - 附件数据
+     */
+    handlePreview(row) {
+      if (!row.fileUrl) {
+        this.$message.warning('文件链接不存在')
+        return
+      }
+
+      this.previewUrl = row.fileUrl
+      this.previewVisible = true
+    },
+
+    /**
+     * 新增前的回调
+     * @param {Function} done - 完成回调
+     * @param {string} type - 操作类型
+     */
+    beforeOpen(done, type) {
+      // 此页面不支持新增和编辑
+      done()
+    },
+
+    /**
+     * 获取数据
+     * @param {Object} page - 分页信息
+     * @param {ImageStoreApplyQueryParams} [params] - 查询参数
+     * @returns {Promise<void>}
+     */
+    async onLoad(page, params = {}) {
+      this.loading = true
+
+      try {
+        // 处理时间范围查询
+        const queryParams = { ...params }
+        if (queryParams.submitTime && Array.isArray(queryParams.submitTime)) {
+          queryParams.submitTimeStart = queryParams.submitTime[0]
+          queryParams.submitTimeEnd = queryParams.submitTime[1]
+          delete queryParams.submitTime
+        }
+
+        const res = await getList(page.currentPage, page.pageSize, queryParams)
+        const data = res.data.data
+
+        this.data = data.records || []
+        this.page.total = data.total || 0
+      } catch (error) {
+        console.error('获取数据失败:', error)
+        this.$message.error('获取数据失败')
+      } finally {
+        this.loading = false
+      }
+    },
+
+    /**
+     * 搜索变更
+     * @param {ImageStoreApplyQueryParams} params - 查询参数
+     * @param {Function} done - 完成回调
+     */
+    searchChange(params, done) {
+      this.query = params
+      this.onLoad(this.page, params)
+      done()
+    },
+
+    /**
+     * 搜索重置
+     * @param {Function} done - 完成回调
+     */
+    searchReset(done) {
+      this.query = {}
+      this.onLoad(this.page)
+      done()
+    },
+
+    /**
+     * 选择变更
+     * @param {ImageStoreApplyRecord[]} list - 选中的数据
+     */
+    selectionChange(list) {
+      this.selectionList = list
+    },
+
+    /**
+     * 清空选择
+     */
+    selectionClear() {
+      this.selectionList = []
+    },
+
+    /**
+     * 当前页变更
+     * @param {number} currentPage - 当前页
+     */
+    currentChange(currentPage) {
+      this.page.currentPage = currentPage
+    },
+
+    /**
+     * 页大小变更
+     * @param {number} pageSize - 页大小
+     */
+    sizeChange(pageSize) {
+      this.page.pageSize = pageSize
+    },
+
+    /**
+     * 刷新变更
+     */
+    refreshChange() {
+      this.onLoad(this.page, this.query)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.detail-container {
+  .detail-card {
+    margin-bottom: 20px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .card-header {
+      font-weight: bold;
+      color: #303133;
+    }
+  }
+
+  .detail-item {
+    margin-bottom: 15px;
+
+    label {
+      font-weight: bold;
+      color: #606266;
+      margin-right: 8px;
+    }
+
+    .amount {
+      color: #E6A23C;
+      font-weight: bold;
+    }
+  }
+}
+
+.preview-container {
+  text-align: center;
+
+  .preview-image {
+    max-width: 100%;
+    max-height: 500px;
+    object-fit: contain;
+  }
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+// 表格中的金额样式
+::v-deep .el-table {
+  .amount {
+    color: #E6A23C;
+    font-weight: bold;
+  }
+}
+</style>