Просмотр исходного кода

Merge remote-tracking branch 'origin/master' into master

肖路 6 дней назад
Родитель
Сommit
5c32fafa70

+ 2 - 0
src/api/order/orderDeliver/types.ts

@@ -82,6 +82,8 @@ export interface OrderDeliverVO {
   remark: string;
 
   deliverProductList: any[];
+
+  deliverCode?: string;
 }
 
 export interface OrderDeliverForm extends BaseEntity {

+ 63 - 0
src/api/supplier/erpSupplierInfo/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ErpSupplierInfoVO, ErpSupplierInfoForm, ErpSupplierInfoQuery } from '@/api/supplier/erpSupplierInfo/types';
+
+/**
+ * 查询erp供应商信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listErpSupplierInfo = (query?: ErpSupplierInfoQuery): AxiosPromise<ErpSupplierInfoVO[]> => {
+  return request({
+    url: '/customer/erpSupplierInfo/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询erp供应商信息详细
+ * @param id
+ */
+export const getErpSupplierInfo = (id: string | number): AxiosPromise<ErpSupplierInfoVO> => {
+  return request({
+    url: '/customer/erpSupplierInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增erp供应商信息
+ * @param data
+ */
+export const addErpSupplierInfo = (data: ErpSupplierInfoForm) => {
+  return request({
+    url: '/customer/erpSupplierInfo',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改erp供应商信息
+ * @param data
+ */
+export const updateErpSupplierInfo = (data: ErpSupplierInfoForm) => {
+  return request({
+    url: '/customer/erpSupplierInfo',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除erp供应商信息
+ * @param id
+ */
+export const delErpSupplierInfo = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/erpSupplierInfo/' + id,
+    method: 'delete'
+  });
+};

+ 204 - 0
src/api/supplier/erpSupplierInfo/types.ts

@@ -0,0 +1,204 @@
+export interface ErpSupplierInfoVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 关联供应商ID
+   */
+  supplierId: string | number;
+
+  /**
+   * 采购人员id
+   */
+  purchaseId: string | number;
+
+  /**
+   * 所属部门
+   */
+  belongingDepartmentId: string | number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+   * 单价含税
+   */
+  unitPrice: string;
+
+  /**
+   * 交易币别
+   */
+  dealCurrencyId: string | number;
+
+  /**
+   * 账款归属
+   */
+  accountBelong: string;
+
+  /**
+   * 税码id
+   */
+  rateId: string | number;
+
+  /**
+   * 采购开票类型id
+   */
+  purchaseInvoiceId: string | number;
+
+  /**
+   * 采购开票类型编号
+   */
+  purchaseInvoiceNo: string;
+
+  /**
+   * 采购开票类型
+   */
+  purchaseInvoice: string;
+
+  settlementMethod: string;
+}
+
+export interface ErpSupplierInfoForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 关联供应商ID
+   */
+  supplierId?: string | number;
+
+  /**
+   * 采购人员id
+   */
+  purchaseId?: string | number;
+
+  /**
+   * 所属部门
+   */
+  belongingDepartmentId?: string | number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+  /**
+   * 单价含税
+   */
+  unitPrice?: string;
+
+  /**
+   * 交易币别
+   */
+  dealCurrencyId?: string | number;
+
+  /**
+   * 账款归属
+   */
+  accountBelong?: string;
+
+  /**
+   * 税码id
+   */
+  rateId?: string | number;
+
+  /**
+   * 采购开票类型id
+   */
+  purchaseInvoiceId?: string | number;
+
+  /**
+   * 采购开票类型编号
+   */
+  purchaseInvoiceNo?: string;
+
+  /**
+   * 采购开票类型
+   */
+  purchaseInvoice?: string;
+
+  settlementMethod?: string;
+}
+
+export interface ErpSupplierInfoQuery extends PageQuery {
+  /**
+   * 关联供应商ID
+   */
+  supplierId?: string | number;
+
+  /**
+   * 采购人员id
+   */
+  purchaseId?: string | number;
+
+  /**
+   * 所属部门
+   */
+  belongingDepartmentId?: string | number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 单价含税
+   */
+  unitPrice?: string;
+
+  /**
+   * 交易币别
+   */
+  dealCurrencyId?: string | number;
+
+  /**
+   * 账款归属
+   */
+  accountBelong?: string;
+
+  /**
+   * 税码id
+   */
+  rateId?: string | number;
+
+  /**
+   * 采购开票类型id
+   */
+  purchaseInvoiceId?: string | number;
+
+  /**
+   * 采购开票类型编号
+   */
+  purchaseInvoiceNo?: string;
+
+  /**
+   * 采购开票类型
+   */
+  purchaseInvoice?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 12 - 11
src/views/bill/statementInvoice/addInvoiceDialog.vue

@@ -173,20 +173,21 @@ const beforeUpload = (file: any) => {
 };
 
 /** 上传成功回调 */
-const handleUploadSuccess = (response: any, uploadFile: any) => {
+function handleUploadSuccess(response: any, file: any, fileListParam: any[]) {
   if (response.code === 200) {
-    uploadFile.url = response.data.url;
-    nextTick(() => {
-      form.value.invoiceAnnex = fileList.value
-        .map((f) => f.url)
-        .filter(Boolean)
-        .join(',');
-    });
-    proxy?.$modal.msgSuccess('上传成功');
+    // 更新 fileList
+    fileList.value = fileListParam;
+    // 收集所有已上传成功的文件URL
+    const urls = fileListParam
+      .filter((f: any) => f.response?.code === 200 || f.url)
+      .map((f: any) => f.response?.data?.url || f.url)
+      .filter(Boolean);
+    form.value.invoiceAnnex = urls.join(',');
+    proxy?.$modal.msgSuccess('文件上传成功');
   } else {
-    proxy?.$modal.msgError(response.msg || '上传失败');
+    proxy?.$modal.msgError(response.msg || '文件上传失败');
   }
-};
+}
 
 /** 删除文件 */
 const handleRemoveUploadFile = (uploadFile: any) => {

+ 314 - 0
src/views/order/checkOrder/addOrderStatusLogDrawer.vue

@@ -0,0 +1,314 @@
+<template>
+  <!-- 订单状态日志抽屉 -->
+  <el-drawer v-model="drawerVisible" title="变更物流状态" size="38%" :destroy-on-close="true" :close-on-click-modal="true">
+    <div class="status-log-container">
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="物流单号" prop="logisticNos">
+          <el-input v-model="form.logisticNos" disabled />
+        </el-form-item>
+
+        <el-form-item label="包裹单号" prop="packageNo">
+          <el-input v-model="form.packageNo" disabled />
+        </el-form-item>
+
+        <el-form-item label="所在状态" prop="statusName">
+          <el-select v-model="form.statusName" placeholder="请选择状态" style="width: 100%" @change="handleStatusChange">
+            <el-option
+              v-for="item in statusOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+              :disabled="isStatusDisabled(item.value)"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="发货人" prop="shipper">
+          <el-input v-model="form.shipper" disabled />
+        </el-form-item>
+
+        <el-form-item label="操作时间" prop="operateTime">
+          <el-date-picker v-model="form.operateTime" type="date" placeholder="请选择操作时间" style="width: 100%" />
+        </el-form-item>
+
+        <el-form-item label="快递员手机号" prop="courierPhone">
+          <el-input v-model="form.courierPhone" disabled />
+        </el-form-item>
+
+        <el-form-item label="上传图片" prop="images" v-if="form.statusName === '已签收'">
+          <div class="image-selector-wrapper">
+            <!-- 修改点 1: 使用 !selectedImages.length 替代 length === 0,并确保样式一致 -->
+            <div
+              v-if="!selectedImages || selectedImages.length === 0"
+              class="upload-box"
+              @click="showFileSelector = true"
+              style="
+                width: 150px;
+                height: 150px;
+                border: 2px dashed #d9d9d9;
+                border-radius: 4px;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                cursor: pointer;
+                transition: all 0.3s;
+              "
+            >
+              <div style="text-align: center; color: #8c939d">
+                <el-icon :size="40" style="margin-bottom: 8px">
+                  <Plus />
+                </el-icon>
+                <div style="font-size: 14px">点击上传</div>
+              </div>
+            </div>
+
+            <!-- 修改点 2: 列表渲染区域 -->
+            <div v-else class="selected-images-list">
+              <div
+                v-for="(img, index) in selectedImages"
+                :key="img.url || index"
+                style="position: relative; display: inline-block; margin: 0 8px 8px 0"
+              >
+                <!-- 确保 img.url 存在才渲染,防止报错 -->
+                <el-image
+                  v-if="img.url"
+                  :src="img.url"
+                  style="width: 150px; height: 150px"
+                  fit="cover"
+                  :preview-src-list="selectedImages.filter((i) => i.url).map((i) => i.url)"
+                />
+                <el-button
+                  type="danger"
+                  :icon="Delete"
+                  circle
+                  size="small"
+                  style="position: absolute; top: 5px; right: 5px; z-index: 10"
+                  @click="removeImage(index)"
+                />
+              </div>
+
+              <!-- 修改点 3: 如果未满 3 张,显示“继续添加”按钮 -->
+              <div
+                v-if="selectedImages.length < 3"
+                class="upload-box-more"
+                @click="showFileSelector = true"
+                style="
+                  width: 150px;
+                  height: 150px;
+                  border: 2px dashed #d9d9d9;
+                  border-radius: 4px;
+                  display: inline-flex;
+                  align-items: center;
+                  justify-content: center;
+                  cursor: pointer;
+                  transition: all 0.3s;
+                  vertical-align: top;
+                  background-color: #f5f7fa; /* 加个背景色区分 */
+                "
+              >
+                <el-icon :size="30" color="#8c939d">
+                  <Plus />
+                </el-icon>
+              </div>
+            </div>
+          </div>
+        </el-form-item>
+
+        <!-- 文件选择器 -->
+        <FileSelector v-model="showFileSelector" :multiple="true" :allowed-types="[1]" title="选择图片" @confirm="handleImagesSelected" />
+      </el-form>
+    </div>
+
+    <template #footer>
+      <div class="drawer-footer">
+        <el-button @click="closeDrawer">取消</el-button>
+        <el-button type="primary" @click="handleSubmit" :loading="submitLoading">保存</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup name="AddOrderStatusLogDrawer" lang="ts">
+import { ref, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+import { Plus, Delete } from '@element-plus/icons-vue';
+import { addOrderStatusLog } from '@/api/order/orderStatusLog';
+import FileSelector from '@/components/FileSelector/index.vue';
+
+const drawerVisible = ref(false);
+const submitLoading = ref(false);
+const formRef = ref<any>(null);
+const showFileSelector = ref(false);
+const selectedImages = ref<any[]>([]);
+
+// 表单数据
+const form = reactive({
+  orderNo: '',
+  orderId: undefined as string | number | undefined,
+  customerNo: '',
+  customerId: undefined as string | number | undefined,
+  deliverMethod: '0',
+  statusName: '',
+  logisticNos: '',
+  packageNo: '',
+  shipper: '',
+  operateTime: '',
+  courierPhone: '',
+  images: '',
+  status: '0'
+});
+
+// 状态顺序定义
+const statusOrder = ['已下单', '已揽件', '运输中', '派件中', '已签收'];
+
+// 当前订单状态
+const currentStatus = ref('');
+
+// 状态选项
+const statusOptions = [
+  { label: '已下单', value: '已下单' },
+  { label: '已揽件', value: '已揽件' },
+  { label: '运输中', value: '运输中' },
+  { label: '派件中', value: '派件中' },
+  { label: '已签收', value: '已签收' }
+];
+const rules = {
+  statusName: [{ required: true, message: '请选择状态名称', trigger: 'change' }]
+};
+
+// 打开抽屉
+const openDrawer = (orderData?: any, currentOrderStatus?: string) => {
+  if (orderData) {
+    form.orderNo = orderData.orderNo || '';
+    form.orderId = orderData.orderId || '';
+    form.shipper = orderData.deliverMan || '';
+    form.courierPhone = orderData.phone || '';
+    form.packageNo = orderData.deliverCode || '';
+    form.logisticNos = orderData.deliverCode || '';
+    form.customerNo = orderData.customerNo || '';
+    form.customerId = orderData.customerId;
+    form.operateTime = orderData.createTime || '';
+    form.deliverMethod = orderData.deliverMethod || '0';
+    form.statusName = currentOrderStatus || '';
+    form.images = orderData.images || '';
+
+    selectedImages.value = [];
+    if (form.images) {
+      const urls = form.images.split(',');
+      selectedImages.value = urls.filter((u) => u && u.trim()).map((u) => ({ url: u.trim(), name: 'Image' }));
+    }
+
+    currentStatus.value = currentOrderStatus || '';
+  }
+  drawerVisible.value = true;
+};
+
+// 关闭抽屉
+const closeDrawer = () => {
+  drawerVisible.value = false;
+  resetForm();
+};
+
+// 判断是否禁用某个状态选项
+const isStatusDisabled = (statusValue: string) => {
+  if (!currentStatus.value) return false;
+  const currentIndex = statusOrder.indexOf(currentStatus.value);
+  const targetIndex = statusOrder.indexOf(statusValue);
+  // 如果目标状态在当前状态之前(索引更小),则禁用
+  return targetIndex < currentIndex;
+};
+
+// 重置表单
+const resetForm = () => {
+  form.statusName = '';
+  form.logisticNos = '';
+  form.packageNo = '';
+  form.orderId = undefined;
+  form.shipper = '';
+  form.operateTime = '';
+  form.courierPhone = '';
+  form.images = '';
+  selectedImages.value = [];
+  showFileSelector.value = false;
+  currentStatus.value = '';
+};
+
+// 处理选择的图片 (优化健壮性)
+const handleImagesSelected = (files: any[]) => {
+  if (!files || files.length === 0) {
+    showFileSelector.value = false;
+    return;
+  }
+
+  const remainingSlots = 3 - selectedImages.value.length;
+  if (remainingSlots <= 0) {
+    ElMessage.warning('最多上传 3 张图片');
+    showFileSelector.value = false;
+    return;
+  }
+
+  const filesToAdd = files.slice(0, remainingSlots);
+
+  // 映射为标准格式 { url, name }
+  const newItems = filesToAdd
+    .map((f) => ({
+      url: f.fileUrl || f.url || f.path, // 兼容多种返回字段
+      name: f.fileName || 'Image'
+    }))
+    .filter((item) => item.url); // 过滤掉没有 url 的无效项
+
+  if (newItems.length > 0) {
+    // 重新赋值数组以触发视图更新
+    selectedImages.value = [...selectedImages.value, ...newItems];
+    form.images = selectedImages.value.map((img) => img.url).join(',');
+  }
+
+  showFileSelector.value = false;
+};
+
+// 移除已选择的图片
+const removeImage = (index: number) => {
+  selectedImages.value.splice(index, 1);
+  form.images = selectedImages.value.map((img) => img.url).join(',');
+};
+
+// 状态变化处理
+const handleStatusChange = () => {
+  // 当状态变化时,如果不是已签收,清空图片
+  if (form.statusName !== '已签收') {
+    form.images = '';
+    selectedImages.value = [];
+  }
+};
+const handleSubmit = async () => {
+  await formRef.value?.validate();
+  submitLoading.value = true;
+  try {
+    await addOrderStatusLog(form);
+    ElMessage.success('保存成功');
+    closeDrawer();
+  } catch (error) {
+    console.error('保存失败:', error);
+    ElMessage.error('保存失败');
+  } finally {
+    submitLoading.value = false;
+  }
+};
+
+// 暴露方法给父组件
+defineExpose({
+  openDrawer
+});
+</script>
+
+<style scoped>
+.status-log-container {
+  padding: 20px;
+}
+
+.drawer-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 12px;
+}
+</style>

+ 3 - 5
src/views/order/checkOrder/deliverDialog.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog :model-value="modelValue" title="发货" width="1200px" @update:model-value="handleDialogChange" @open="handleOpen" @close="handleClose">
+  <el-dialog :model-value="modelValue" title="发货" width="50%" @update:model-value="handleDialogChange" @open="handleOpen" @close="handleClose">
     <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
       <el-row :gutter="20">
         <el-col :span="12">
@@ -255,10 +255,8 @@ const handleLogisticsCompanyChange = (val: any) => {
 const loadProductList = async () => {
   try {
     const res = await getOrderMain(props.orderId);
-    console.log(res.data.orderProductList);
-
     // 为每个商品添加发货数量字段,默认为未发货数量
-    productList.value = (res.data.orderProductList || []).map((item: OrderProductVO) => ({
+    productList.value = (res.data.orderProductList.filter((item) => item.unsentQuantity != 0) || []).map((item: OrderProductVO) => ({
       ...item,
       deliverNum: 0,
       productNo: item.productNo,
@@ -267,7 +265,7 @@ const loadProductList = async () => {
       productUnit: item.productUnit,
       productUnitId: item.productUnitId
     }));
-    total.value = res.data.orderProductList.length || 0;
+    total.value = res.data.orderProductList.filter((item) => item.unsentQuantity != 0).length || 0;
   } catch (error) {
     console.error('加载商品列表失败:', error);
     ElMessage.error('加载商品列表失败');

+ 436 - 0
src/views/order/checkOrder/editDeliverDialog.vue

@@ -0,0 +1,436 @@
+<template>
+  <el-dialog
+    :model-value="modelValue"
+    title="编辑发货信息"
+    width="50%"
+    @update:model-value="handleDialogChange"
+    @open="handleOpen"
+    @close="handleClose"
+  >
+    <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="订单编号" prop="orderCode">
+            <el-input v-model="form.orderCode" disabled />
+          </el-form-item>
+        </el-col>
+
+        <el-col :span="12" v-if="form.deliverMethod === '0'">
+          <el-form-item label="送货人" prop="deliverMan">
+            <el-input v-model="form.deliverMan" placeholder="请输入送货人姓名" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12" v-if="form.deliverMethod === '1'">
+          <el-form-item label="物流公司名称" prop="logisticsCompanyId">
+            <el-select
+              v-model="form.logisticsCompanyId"
+              placeholder="请选择"
+              style="width: 100%"
+              filterable
+              @change="handleLogisticsCompanyChange"
+              disabled
+            >
+              <el-option v-for="company in logisticsCompanyList" :key="company.id" :label="company.logisticsName" :value="company.id" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item v-if="form.deliverMethod === '1'" label="物流单号" prop="logisticNo">
+            <el-input v-model="form.logisticNo" placeholder="请输入物流单号" disabled />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="发货方式" prop="deliverMethod">
+            <el-radio-group v-model="form.deliverMethod">
+              <el-radio v-for="dict in deliver_method" :key="dict.value" :value="dict.value" disabled>{{ dict.label }}</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="12" v-if="form.deliverMethod === '1'">
+          <el-form-item label="收货人手机" prop="consigneePhone">
+            <el-input v-model="form.consigneePhone" placeholder="请输入收货人手机" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12" v-if="form.deliverMethod === '0'">
+          <el-form-item label="手机号码" prop="phone">
+            <el-input v-model="form.phone" placeholder="请输入手机号码" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="发货备注" prop="deliverRemark">
+            <el-input v-model="form.deliverRemark" type="textarea" :rows="3" placeholder="请输入内容" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <!-- 商品列表 -->
+    <el-table :data="productList" border style="width: 100%" max-height="600px">
+      <el-table-column prop="productNo" label="产品编号" width="100" />
+      <el-table-column label="产品图片" width="100">
+        <template #default="scope">
+          <el-image v-if="scope.row.productImage" :src="scope.row.productImage" style="width: 60px; height: 60px" fit="cover" />
+          <span v-else>暂无图片</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="productName" label="产品名称" min-width="200" show-overflow-tooltip />
+      <el-table-column prop="productUnit" label="单位" width="120" />
+      <el-table-column prop="orderPrice" label="商品单价" width="160" />
+      <el-table-column label="发货数量">
+        <template #default="scope">
+          <el-input-number
+            v-model="scope.row.deliverNum"
+            :min="0"
+            :max="scope.row.unsentQuantity"
+            :precision="0"
+            size="small"
+            disabled
+            :controls="false"
+            style="width: 100%"
+            @change="handleDeliveryQuantityChange(scope.$index)"
+          />
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" :loading="submitLoading" @click="handleSubmit">确认</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, computed, onMounted } from 'vue';
+import { getOrderMain } from '@/api/order/orderMain';
+import { OrderMainVO } from '@/api/order/orderMain/types';
+import { listOrderProduct } from '@/api/order/orderProduct';
+import { OrderProductVO } from '@/api/order/orderProduct/types';
+import { listLogisticsCompany } from '@/api/company/logisticsCompany';
+import { LogisticsCompanyVO } from '@/api/company/logisticsCompany/types';
+import { getOrderDeliver, addOrderDeliver, updateOrderDeliver } from '@/api/order/orderDeliver';
+import { OrderDeliverVO, OrderDeliverForm } from '@/api/order/orderDeliver/types';
+import { ElMessage } from 'element-plus';
+import { de } from 'element-plus/es/locale/index.mjs';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { deliver_method } = toRefs<any>(proxy?.useDict('deliver_method'));
+
+interface Props {
+  modelValue: boolean;
+  orderId?: string | number;
+  orderNo?: string;
+  operateType?: string;
+  deliverId?: string | number;
+}
+
+interface Emits {
+  (e: 'update:modelValue', value: boolean): void;
+  (e: 'success'): void;
+}
+
+const props = defineProps<Props>();
+const emit = defineEmits<Emits>();
+
+const formRef = ref();
+const submitLoading = ref(false);
+const productList = ref<any[]>([]);
+const total = ref(0);
+
+// 物流公司列表
+const logisticsCompanyList = ref<LogisticsCompanyVO[]>([]);
+
+// 查询参数
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 20,
+  orderId: undefined as string | number | undefined
+});
+
+// 表单数据
+const form = reactive<OrderDeliverForm>({
+  orderId: undefined,
+  orderCode: '',
+  logisticPackNo: '',
+  deliverMethod: '1',
+  deliverMan: '',
+  phone: '',
+  logisticsStatus: '',
+  deliverRemark: '',
+  checklistRemark: '',
+  logisticsCompanyId: undefined,
+  logisticsCompanyCode: '',
+  logisticNo: '',
+  logisticPackStatus: '',
+  consigneePhone: '',
+  remark: '',
+  orderDeliverProducts: []
+});
+
+// 动态校验规则
+// 动态校验规则
+const rules = computed(() => {
+  const baseRules: any = {
+    deliverMethod: [{ required: true, message: '请选择发货方式', trigger: 'change' }]
+  };
+
+  // 第三方物流(deliverMethod === '1')
+  if (form.deliverMethod === '1') {
+    baseRules.logisticsCompanyId = [{ required: true, message: '请选择物流公司', trigger: 'change' }];
+    baseRules.logisticNo = [{ required: true, message: '请输入物流单号', trigger: 'blur' }];
+    baseRules.consigneePhone = [
+      { required: true, message: '请输入收货人手机号码', trigger: 'blur' },
+      { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+    ];
+  }
+
+  // 自有物流(deliverMethod === '0')
+  if (form.deliverMethod === '0') {
+    baseRules.deliverMan = [{ required: true, message: '请输入送货人姓名', trigger: 'blur' }];
+    baseRules.phone = [
+      { required: true, message: '请输入手机号码', trigger: 'blur' },
+      { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+    ];
+  }
+
+  return baseRules;
+});
+
+// 对话框状态变化
+const handleDialogChange = (val: boolean) => {
+  emit('update:modelValue', val);
+};
+
+// 对话框打开时触发
+const handleOpen = async () => {
+  resetForm();
+
+  // 如果传入deliverId,直接根据deliverId查询回显
+  if (props.deliverId) {
+    await loadDeliverInfoById(props.deliverId);
+  } else if (props.orderId) {
+    form.orderId = props.orderId;
+    form.orderCode = props.orderNo || '';
+    queryParams.value.orderId = props.orderId;
+    await loadProductList();
+  }
+};
+
+// 对话框关闭时触发
+const handleClose = () => {
+  resetForm();
+};
+
+// 重置表单
+const resetForm = () => {
+  form.orderId = undefined;
+  form.orderCode = '';
+  form.logisticsCompanyId = undefined;
+  form.logisticsCompanyCode = '';
+  form.logisticNo = '';
+  form.deliverMethod = '1';
+  form.deliverMan = '';
+  form.phone = '';
+  form.consigneePhone = '';
+  form.deliverRemark = '';
+  productList.value = [];
+  queryParams.value.pageNum = 1;
+  formRef.value?.clearValidate();
+};
+
+const handleLogisticsCompanyChange = (val: any) => {
+  const selectedCompany = logisticsCompanyList.value.find((item) => item.id === val);
+  if (selectedCompany) {
+    form.logisticsCompanyCode = selectedCompany.logisticsCode;
+  }
+};
+
+// 加载商品列表
+const loadProductList = async () => {
+  try {
+    const res = await getOrderMain(props.orderId);
+    // 为每个商品添加发货数量字段,默认为未发货数量
+    productList.value = (res.data.orderProductList || []).map((item: OrderProductVO) => ({
+      ...item,
+      deliverNum: 0,
+      productNo: item.productNo,
+      productId: item.productId,
+      orderPrice: item.orderPrice,
+      productUnit: item.productUnit,
+      productUnitId: item.productUnitId
+    }));
+    total.value = res.data.orderProductList.length || 0;
+  } catch (error) {
+    console.error('加载商品列表失败:', error);
+    ElMessage.error('加载商品列表失败');
+    productList.value = [];
+    total.value = 0;
+  }
+};
+
+// 加载物流公司列表
+const loadLogisticsCompanyList = async () => {
+  try {
+    const res = await listLogisticsCompany({
+      isShow: '0',
+      pageNum: 1,
+      pageSize: 1000
+    });
+    logisticsCompanyList.value = res.rows || [];
+  } catch (error) {
+    console.error('加载物流公司列表失败:', error);
+    logisticsCompanyList.value = [];
+  }
+};
+
+// 加载发货信息
+const loadDeliverInfo = async () => {
+  try {
+    const res = await getOrderDeliver(props.orderId);
+    if (res.code === 200 && res.data) {
+      const deliverData = res.data;
+      form.logisticsCompanyId = deliverData.logisticsCompanyId;
+      form.logisticsCompanyCode = deliverData.logisticsCompanyCode;
+      form.logisticNo = deliverData.logisticNo;
+      form.deliverMethod = deliverData.deliverMethod || '1';
+      form.consigneePhone = deliverData.consigneePhone;
+      form.deliverRemark = deliverData.deliverRemark;
+    }
+  } catch (error) {
+    console.error('加载发货信息失败:', error);
+  }
+};
+
+// 根据deliverId加载发货信息
+const loadDeliverInfoById = async (deliverId: string | number) => {
+  try {
+    const res = await getOrderDeliver(deliverId);
+    if (res.code === 200 && res.data) {
+      const deliverData = res.data;
+      form.orderId = deliverData.orderId;
+      form.orderCode = deliverData.orderCode;
+      form.logisticsCompanyId = deliverData.logisticsCompanyId;
+      form.logisticsCompanyCode = deliverData.logisticsCompanyCode;
+      form.logisticNo = deliverData.logisticNo;
+      form.deliverMan = deliverData.deliverMan;
+      form.phone = deliverData.phone;
+      form.deliverMethod = deliverData.deliverMethod || '1';
+      form.consigneePhone = deliverData.consigneePhone;
+      form.deliverRemark = deliverData.deliverRemark;
+      productList.value = deliverData.deliverProductList;
+    }
+  } catch (error) {
+    console.error('加载发货信息失败:', error);
+    ElMessage.error('加载发货信息失败');
+  }
+};
+
+// 发货数量变化
+const handleDeliveryQuantityChange = (index: number) => {
+  const product = productList.value[index];
+  if (product) {
+    // 确保发货数量不超过未发货数量
+    if (product.deliverNum > product.unsentQuantity) {
+      product.deliverNum = product.unsentQuantity;
+      ElMessage.warning('发货数量不能大于未发货数量');
+    }
+    // 确保发货数量不小于0
+    if (product.deliverNum < 0) {
+      product.deliverNum = 0;
+    }
+  }
+};
+
+// 删除商品
+const handleDeleteProduct = (index: number) => {
+  productList.value.splice(index, 1);
+};
+
+// 分页大小变化
+const handleSizeChange = () => {
+  queryParams.value.pageNum = 1;
+  loadProductList();
+};
+
+// 页码变化
+const handleCurrentChange = () => {
+  loadProductList();
+};
+
+// 取消
+const handleCancel = () => {
+  emit('update:modelValue', false);
+};
+
+// 提交
+const handleSubmit = async () => {
+  try {
+    // 验证表单
+    await formRef.value?.validate();
+
+    // 验证是否有发货商品
+    const deliveryProducts = productList.value.filter((item) => item.deliverNum > 0);
+    if (deliveryProducts.length === 0) {
+      ElMessage.warning('请至少选择一个商品进行发货');
+      return;
+    }
+
+    submitLoading.value = true;
+
+    // 组装发货数据
+    const deliveryData: OrderDeliverForm = {
+      id: props.deliverId,
+      orderId: form.orderId,
+      orderCode: form.orderCode,
+      logisticsCompanyId: form.logisticsCompanyId,
+      logisticsCompanyCode: form.logisticsCompanyCode,
+      logisticNo: form.logisticNo,
+      deliverMethod: form.deliverMethod,
+      deliverMan: form.deliverMan,
+      phone: form.phone,
+      consigneePhone: form.consigneePhone,
+      deliverRemark: form.deliverRemark
+    };
+
+    // 调用发货API
+    await updateOrderDeliver(deliveryData);
+
+    ElMessage.success('编辑成功');
+    emit('success');
+    emit('update:modelValue', false);
+  } catch (error) {
+    console.error('发货失败:', error);
+    if (error !== false) {
+      // 不是表单验证失败
+      ElMessage.error('发货失败,请重试');
+    }
+  } finally {
+    submitLoading.value = false;
+  }
+};
+
+// 组件挂载时加载物流公司列表
+onMounted(() => {
+  loadLogisticsCompanyList();
+});
+</script>
+
+<style scoped lang="scss">
+.mt-4 {
+  margin-top: 16px;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>

+ 53 - 28
src/views/order/checkOrder/logisticsDetail.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog v-model="visible" title="物流信息" width="700px" :before-close="handleClose">
+  <el-drawer v-model="visible" title="物流信息" size="38%" direction="rtl" :before-close="handleClose" :close-on-click-modal="true">
     <div class="logistics-detail">
       <div class="section-title">单号查询</div>
 
@@ -9,8 +9,8 @@
             <el-option
               v-for="item in logisticsList"
               :key="item.id"
-              :label="`${item.logisticNo},${getDictLabel(deliver_method, item.deliverMethod)}`"
-              :value="item.logisticNo"
+              :label="`${item.logisticNo || item.deliverCode},${getDictLabel(deliver_method, item.deliverMethod)}`"
+              :value="item.logisticNo || item.deliverCode"
             />
           </el-select>
         </el-form-item>
@@ -21,7 +21,7 @@
       <el-timeline v-if="logisticsInfo.length > 0">
         <el-timeline-item v-for="(item, index) in logisticsInfo" :key="index" :timestamp="item.time" placement="top">
           <div class="timeline-content">
-            <div class="timeline-status">{{ index }}</div>
+            <div class="timeline-status">{{ index + 1 }}</div>
             <div class="timeline-detail">
               <div>{{ item.time }}</div>
               <div>{{ item.location }}</div>
@@ -33,13 +33,13 @@
 
       <el-empty v-else description="暂无物流信息" />
     </div>
-  </el-dialog>
+  </el-drawer>
 </template>
 
 <script setup lang="ts">
 import { listOrderDeliver, queryTrack } from '@/api/order/orderDeliver';
 import { OrderDeliverVO } from '@/api/order/orderDeliver/types';
-
+import { listOrderStatusLog } from '@/api/order/orderStatusLog';
 interface Props {
   modelValue: boolean;
   orderId?: string | number;
@@ -88,7 +88,7 @@ const loadLogisticsList = async () => {
     logisticsList.value = res.rows || [];
 
     if (logisticsList.value.length > 0) {
-      form.value.selectedLogisticNo = logisticsList.value[0].logisticNo;
+      form.value.selectedLogisticNo = logisticsList.value[0].logisticNo || logisticsList.value[0].deliverCode;
       handleLogisticNoChange(form.value.selectedLogisticNo);
     }
   } catch (error) {
@@ -98,29 +98,54 @@ const loadLogisticsList = async () => {
 
 const handleLogisticNoChange = async (logisticNo: string) => {
   const selected = logisticsList.value.find((item) => item.logisticNo === logisticNo);
-  if (!selected) return;
-
   try {
-    const res = await queryTrack({
-      logisticNo: logisticNo,
-      pageNum: 1,
-      pageSize: 100
-    });
-
-    if (res.data && Array.isArray(res.data) && res.data.length > 0) {
-      logisticsInfo.value = res.data.map((item: any) => ({
-        time: item.acceptTime || item.time || '',
-        location: selected.orderCode ? `${selected.orderCode}` : '',
-        status: item.context || ''
-      }));
+    if (selected) {
+      const res = await queryTrack({
+        logisticNo: logisticNo,
+        pageNum: 1,
+        pageSize: 100
+      });
+      // 1. 兼容处理:有些接口返回在 res.data,有些可能直接是 res
+      const dataList = res.data || [];
+      if (Array.isArray(dataList) && dataList.length > 0) {
+        logisticsInfo.value = dataList.map((item: any) => {
+          // 2. 核心修复:精准匹配时间字段
+          // 顺丰用 'time',韵达用 'ftime'。
+          // 优先取 ftime (韵达标准),如果没有则取 time (顺丰标准)
+          const displayTime = item.ftime || item.time || item.acceptTime || '';
+
+          return {
+            time: displayTime,
+            // 3. 建议:保留原始状态字段,方便后续筛选(如“已签收”)
+            status: item.context || item.content || '',
+            // 4. 建议:如果有地址字段,也可以映射进来,没有则保持订单号
+            location: item.location || (selected.orderCode ? `${selected.orderCode}` : '')
+          };
+        });
+      }
     } else {
-      logisticsInfo.value = [
-        {
-          time: (selected as any).createTime || '',
-          location: selected.orderCode ? `${selected.orderCode}` : '',
-          status: '已下单'
-        }
-      ];
+      await listOrderStatusLog({
+        orderId: props.orderId,
+        logisticNos: form.value.selectedLogisticNo,
+        pageNum: 1,
+        pageSize: 100
+      }).then((res) => {
+        logisticsInfo.value = res.rows.map((item: any) => {
+          return {
+            time: item.createTime,
+            location: item.orderCode ? `${item.orderCode}` : '',
+            status: item.statusName
+          };
+        });
+      });
+
+      // logisticsInfo.value = [
+      //   {
+      //     time: (selected as any).createTime || '',
+      //     location: selected.orderCode ? `${selected.orderCode}` : '',
+      //     status: '已下单'
+      //   }
+      // ];
     }
   } catch (error) {
     console.error('Failed to query track:', error);

+ 162 - 21
src/views/order/checkOrder/sendDetail.vue

@@ -36,7 +36,7 @@
           </div>
           <div class="detail-item">
             <span class="label">发票类型:</span>
-            <span>{{ invoiceTypeInfo.invoiceTypeNo || '--' }},{{ invoiceTypeInfo.invoiceTypeName || '--' }}</span>
+            <span>{{ orderDetail.invoiceType }}</span>
           </div>
           <div class="detail-item">
             <span class="label">发货仓库:</span>
@@ -154,32 +154,56 @@
       </el-table>
     </el-card>
     <!-- 发货对话框 -->
-    <DeliverDialog v-model="showDeliverDialog" :order-id="currentOrderId" :order-no="currentOrderNo" @success="handleDeliverSuccess" />
+    <DeliverDialog
+      v-model="showDeliverDialog"
+      :order-id="currentOrderId"
+      :order-no="currentOrderNo"
+      :operate-type="operateType"
+      @success="handleDeliverSuccess"
+    />
+
+    <!-- 编辑发货信息对话框 -->
+    <EditDeliverDialog v-model="showEditDeliverDialog" :deliver-id="editDeliverId" @success="handleDeliverSuccess" />
     <!-- 发货信息 -->
     <el-card shadow="never" class="mb-2" v-show="orderDetail.orderStatus != '0'">
       <template #header>
         <div class="card-header">
-          <span>发货信息:共{{ 0 }}个包裹</span>
-          <el-button type="primary" style="float: right" @click="handleAddDeliver(orderDetail)">添加发货信息</el-button>
+          <span>发货信息:共{{ orderDeliverList.length }}个包裹</span>
+          <el-button type="primary" v-if="orderDetail.orderStatus == '2' || orderDetail.orderStatus == '3'" @click="handleAddDeliver(orderDetail)"
+            >添加发货信息</el-button
+          >
         </div>
       </template>
-      <div v-show="totalQuantitySent > 0">
-        <div style="white-space: nowrap" class="mb-2">
-          <span style="margin-right: 16px">发货单号:--</span>
-          <span style="margin-right: 16px">发货时间:--</span>
-          <span style="margin-right: 16px">发货方式:--</span>
-          <span style="margin-right: 16px">送货人:--</span>
-          <span style="margin-right: 16px">手机:--</span>
-          <span style="margin-right: 16px">物流状态:--</span>
-          <span>发货备注:--</span>
+      <el-card v-for="deliver in orderDeliverList" :key="deliver.id">
+        <div class="mb-2" style="background: #f3f3f3; padding: 10px">
+          <el-row :gutter="20" justify="space-between" align="middle">
+            <el-col :span="18">
+              <div style="display: flex; flex-wrap: wrap; gap: 16px">
+                <span>发货单号:{{ (deliver as any).deliverCode || '--' }}</span>
+                <span>发货时间:{{ (deliver as any).createTime || '--' }}</span>
+                <span>发货方式:{{ getDictLabel(deliver_method, deliver.deliverMethod || '--') }}</span>
+                <span>送货人:{{ deliver.deliverMan || '--' }}</span>
+                <span>手机:{{ deliver.phone || '--' }}</span>
+                <span style="margin-left: 30px">物流状态:{{ deliver.logisticsStatus || '--' }}</span>
+                <span style="margin-left: 20px">发货备注:{{ deliver.deliverRemark || '--' }}</span>
+              </div>
+            </el-col>
+            <el-col :span="6">
+              <div style="text-align: right">
+                <el-button type="primary" @click="handleEditDeliver(deliver)">编辑发货信息</el-button>
+                <el-button type="primary" v-if="deliver.deliverMethod == '0'" @click="handleEditLogistics(deliver)">变更物流状态</el-button>
+                <el-button type="primary" @click="handleViewLogistics(orderDetail)">查看物流</el-button>
+              </div>
+            </el-col>
+          </el-row>
         </div>
-        <el-table :data="deliverProductList" border style="width: 100%">
+        <el-table :data="deliver.deliverProductList" border style="width: 100%">
           <el-table-column label="产品编号" prop="productNo" align="center" />
           <el-table-column label="商品名称" prop="productName" align="center" />
           <el-table-column label="单位" prop="productUnit" align="center" />
           <el-table-column label="发货数量" prop="deliverNum" align="center" />
         </el-table>
-      </div>
+      </el-card>
     </el-card>
 
     <!-- A10备货信息 -->
@@ -207,18 +231,27 @@
     <div class="text-center mt-4">
       <el-button @click="goBack">返回</el-button>
     </div>
+    <!-- 物流详情对话框 -->
+    <LogisticsDetail v-model="showLogisticsDialog" :order-id="logisticsOrderId" />
+    <!-- 订单状态日志抽屉 -->
+    <AddOrderStatusLogDrawer ref="statusLogDrawerRef" />
   </div>
 </template>
 
 <script setup name="SendDetail" lang="ts">
 import { ref, computed, onMounted } from 'vue';
 import DeliverDialog from './deliverDialog.vue';
+import EditDeliverDialog from './editDeliverDialog.vue';
+import AddOrderStatusLogDrawer from './addOrderStatusLogDrawer.vue';
 import { useRoute, useRouter } from 'vue-router';
 import { getOrderMain } from '@/api/order/orderMain';
 import { OrderMainVO } from '@/api/order/orderMain/types';
 import { listOrderProduct } from '@/api/order/orderProduct';
 import { OrderProductVO } from '@/api/order/orderProduct/types';
 import { DeliverProductVO } from '@/api/order/deliverProduct/types';
+import { listOrderDeliver } from '@/api/order/orderDeliver';
+import { OrderDeliverVO } from '@/api/order/orderDeliver/types';
+import { listDeliverProduct } from '@/api/order/deliverProduct';
 import { getShippingAddress } from '@/api/customer/customerFile/shippingAddress';
 import { ShippingAddressVO } from '@/api/customer/customerFile/shippingAddress/types';
 import { getWarehouse } from '@/api/company/warehouse';
@@ -229,10 +262,12 @@ import { getCustomerInfo } from '@/api/customer/customerFile/customerInfo';
 import { CustomerInfoVO } from '@/api/customer/customerFile/customerInfo/types';
 import { getInvoiceType } from '@/api/customer/invoiceType';
 import { InvoiceTypeVO } from '@/api/customer/invoiceType/types';
+import { selectNewOneLog } from '@/api/order/orderStatusLog';
 
+import LogisticsDetail from './logisticsDetail.vue';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { order_status, payment_status, fee_type, pay_method } = toRefs<any>(
-  proxy?.useDict('order_status', 'payment_status', 'fee_type', 'pay_method')
+const { order_status, payment_status, fee_type, pay_method, deliver_method } = toRefs<any>(
+  proxy?.useDict('order_status', 'payment_status', 'fee_type', 'pay_method', 'deliver_method')
 );
 const route = useRoute();
 const router = useRouter();
@@ -255,18 +290,34 @@ const invoiceTypeInfo = ref<InvoiceTypeVO>({} as InvoiceTypeVO);
 // 商品明细列表
 const productList = ref<OrderProductVO[]>([]);
 
+// 发货包裹列表
+const orderDeliverList = ref<OrderDeliverVO[]>([]);
 const deliverProductList = ref<DeliverProductVO[]>([]);
 
 // 收货地址信息
 const shippingAddress = ref<ShippingAddressVO>({} as ShippingAddressVO);
 
+const operateType = ref('add');
+
 // 发货对话框
 const showDeliverDialog = ref(false);
 const currentOrderId = ref<string | number>();
 const currentOrderNo = ref<string>();
 
+// 编辑发货对话框
+const showEditDeliverDialog = ref(false);
+const editDeliverId = ref<string | number>();
+
+const showLogisticsDialog = ref(false);
+const logisticsOrderId = ref<string | number>();
+
+// 订单状态日志抽屉
+const statusLogDrawerRef = ref<any>(null);
+
 /** 发货成功回调 */
-const handleDeliverSuccess = () => {};
+const handleDeliverSuccess = () => {
+  getOrderDetail();
+};
 
 // 计算商品总数(所有商品的采购数量之和)
 const totalQuantity = computed(() => {
@@ -308,6 +359,11 @@ const getOrderDetail = async () => {
       await getDeliverProductList(orderDetail.value);
     }
 
+    // 获取发货单及关联的物流商品信息
+    if (orderDetail.value.id) {
+      await getOrderDeliverListData(orderDetail.value.id);
+    }
+
     // 获取收货地址
     if (orderDetail.value.shippingAddressId) {
       await getShippingAddressDetail(orderDetail.value.shippingAddressId);
@@ -329,9 +385,9 @@ const getOrderDetail = async () => {
     }
 
     // 获取发票类型信息
-    if (orderDetail.value.invoiceType) {
-      await getInvoiceTypeDetail(orderDetail.value.invoiceType);
-    }
+    // if (orderDetail.value.invoiceType) {
+    //   await getInvoiceTypeDetail(orderDetail.value.invoiceType);
+    // }
   } catch (error) {
     console.error('获取订单详情失败:', error);
     proxy?.$modal.msgError('获取订单详情失败');
@@ -344,11 +400,64 @@ const handleAddDeliver = (row?: OrderMainVO) => {
     proxy?.$modal.msgWarning('订单ID不能为空');
     return;
   }
+  operateType.value = 'add';
   currentOrderId.value = row.id;
   currentOrderNo.value = row.orderNo;
   showDeliverDialog.value = true;
 };
 
+/** 编辑发货信息操作 */
+const handleEditDeliver = (deliver: any) => {
+  if (!deliver?.id) {
+    proxy?.$modal.msgWarning('发货信息ID不能为空');
+    return;
+  }
+  editDeliverId.value = deliver.id;
+  showEditDeliverDialog.value = true;
+};
+
+const handleViewLogistics = (row?: OrderMainVO) => {
+  if (!row?.id) {
+    proxy?.$modal.msgWarning('订单ID不能为空');
+    return;
+  }
+  logisticsOrderId.value = row.id;
+
+  showLogisticsDialog.value = true;
+};
+
+/** 变更物流状态 */
+const handleEditLogistics = async (row?: any) => {
+  if (!row?.orderId) {
+    proxy?.$modal.msgWarning('订单ID不能为空');
+    return;
+  }
+
+  // 补充客户信息
+  row.customerId = orderDetail.value.customerId;
+  row.customerNo = orderDetail.value.customerCode;
+
+  let currentOrderStatus = '';
+
+  try {
+    const res = await selectNewOneLog({
+      orderId: row.orderId,
+      customerId: row.customerId,
+      logisticNos: row.deliverCode
+    });
+
+    if (res.code == 200 && res.data) {
+      row.images = res.data.images;
+      currentOrderStatus = res.data.statusName || '';
+    }
+  } catch (error) {
+    console.error('查询物流失败:', error);
+  }
+
+  // 4. 使用获取到的状态打开弹窗
+  statusLogDrawerRef.value?.openDrawer(row, currentOrderStatus);
+};
+
 // 获取商品明细列表
 const getProductList = async (orderDetail: OrderMainVO) => {
   try {
@@ -367,6 +476,31 @@ const getDeliverProductList = async (orderDetail: OrderMainVO) => {
   }
 };
 
+// 获取发货单列表
+const getOrderDeliverListData = async (orderId: string | number) => {
+  try {
+    const res = await listOrderDeliver({ orderId, pageNum: 1, pageSize: 100 });
+    const deliverList = (res as any).rows || res.data || [];
+
+    // 为每条发货记录获取商品明细
+    for (const deliver of deliverList) {
+      if (deliver.id) {
+        try {
+          const productRes = await listDeliverProduct({ deliverId: deliver.id, pageNum: 1, pageSize: 100 });
+          deliver.deliverProductList = (productRes as any).rows || productRes.data || [];
+        } catch (error) {
+          console.error(`获取发货单${deliver.id}的商品明细失败:`, error);
+          deliver.deliverProductList = [];
+        }
+      }
+    }
+
+    orderDeliverList.value = deliverList;
+  } catch (error) {
+    console.error('获取发货单列表失败:', error);
+  }
+};
+
 // 获取收货地址详情
 const getShippingAddressDetail = async (addressId: string | number) => {
   try {
@@ -496,6 +630,13 @@ onMounted(() => {
   flex: 1;
 }
 
+.card-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  min-height: 40px;
+}
+
 @media print {
   .el-button {
     display: none;

+ 2 - 2
src/views/order/saleOrder/deliverDialog.vue

@@ -256,7 +256,7 @@ const loadProductList = async () => {
   try {
     const res = await getOrderMain(props.orderId);
     // 为每个商品添加发货数量字段,默认为未发货数量
-    productList.value = (res.data.orderProductList || []).map((item: OrderProductVO) => ({
+    productList.value = (res.data.orderProductList.filter((item) => item.unsentQuantity != 0) || []).map((item: OrderProductVO) => ({
       ...item,
       deliverNum: 0,
       productNo: item.productNo,
@@ -265,7 +265,7 @@ const loadProductList = async () => {
       productUnit: item.productUnit,
       productUnitId: item.productUnitId
     }));
-    total.value = res.data.orderProductList.length || 0;
+    total.value = res.data.orderProductList.filter((item) => item.unsentQuantity != 0).length || 0;
   } catch (error) {
     console.error('加载商品列表失败:', error);
     ElMessage.error('加载商品列表失败');

+ 50 - 25
src/views/order/saleOrder/logisticsDetail.vue

@@ -9,8 +9,8 @@
             <el-option
               v-for="item in logisticsList"
               :key="item.id"
-              :label="`${item.logisticNo},${getDictLabel(deliver_method, item.deliverMethod)}`"
-              :value="item.logisticNo"
+              :label="`${item.logisticNo || item.deliverCode},${getDictLabel(deliver_method, item.deliverMethod)}`"
+              :value="item.logisticNo || item.deliverCode"
             />
           </el-select>
         </el-form-item>
@@ -39,7 +39,7 @@
 <script setup lang="ts">
 import { listOrderDeliver, queryTrack } from '@/api/order/orderDeliver';
 import { OrderDeliverVO } from '@/api/order/orderDeliver/types';
-
+import { listOrderStatusLog } from '@/api/order/orderStatusLog';
 interface Props {
   modelValue: boolean;
   orderId?: string | number;
@@ -88,7 +88,7 @@ const loadLogisticsList = async () => {
     logisticsList.value = res.rows || [];
 
     if (logisticsList.value.length > 0) {
-      form.value.selectedLogisticNo = logisticsList.value[0].logisticNo;
+      form.value.selectedLogisticNo = logisticsList.value[0].logisticNo || logisticsList.value[0].deliverCode;
       handleLogisticNoChange(form.value.selectedLogisticNo);
     }
   } catch (error) {
@@ -98,29 +98,54 @@ const loadLogisticsList = async () => {
 
 const handleLogisticNoChange = async (logisticNo: string) => {
   const selected = logisticsList.value.find((item) => item.logisticNo === logisticNo);
-  if (!selected) return;
-
   try {
-    const res = await queryTrack({
-      logisticNo: logisticNo,
-      pageNum: 1,
-      pageSize: 100
-    });
-
-    if (res.data && Array.isArray(res.data) && res.data.length > 0) {
-      logisticsInfo.value = res.data.map((item: any) => ({
-        time: item.acceptTime || item.time || '',
-        location: selected.orderCode ? `${selected.orderCode}` : '',
-        status: item.context || ''
-      }));
+    if (selected) {
+      const res = await queryTrack({
+        logisticNo: logisticNo,
+        pageNum: 1,
+        pageSize: 100
+      });
+      // 1. 兼容处理:有些接口返回在 res.data,有些可能直接是 res
+      const dataList = res.data || [];
+      if (Array.isArray(dataList) && dataList.length > 0) {
+        logisticsInfo.value = dataList.map((item: any) => {
+          // 2. 核心修复:精准匹配时间字段
+          // 顺丰用 'time',韵达用 'ftime'。
+          // 优先取 ftime (韵达标准),如果没有则取 time (顺丰标准)
+          const displayTime = item.ftime || item.time || item.acceptTime || '';
+
+          return {
+            time: displayTime,
+            // 3. 建议:保留原始状态字段,方便后续筛选(如“已签收”)
+            status: item.context || item.content || '',
+            // 4. 建议:如果有地址字段,也可以映射进来,没有则保持订单号
+            location: item.location || (selected.orderCode ? `${selected.orderCode}` : '')
+          };
+        });
+      }
     } else {
-      logisticsInfo.value = [
-        {
-          time: (selected as any).createTime || '',
-          location: selected.orderCode ? `${selected.orderCode}` : '',
-          status: '已下单'
-        }
-      ];
+      await listOrderStatusLog({
+        orderId: props.orderId,
+        logisticNos: form.value.selectedLogisticNo,
+        pageNum: 1,
+        pageSize: 100
+      }).then((res) => {
+        logisticsInfo.value = res.rows.map((item: any) => {
+          return {
+            time: item.createTime,
+            location: item.orderCode ? `${item.orderCode}` : '',
+            status: item.statusName
+          };
+        });
+      });
+
+      // logisticsInfo.value = [
+      //   {
+      //     time: (selected as any).createTime || '',
+      //     location: selected.orderCode ? `${selected.orderCode}` : '',
+      //     status: '已下单'
+      //   }
+      // ];
     }
   } catch (error) {
     console.error('Failed to query track:', error);

+ 3 - 1
src/views/order/saleOrder/sendDetail.vue

@@ -315,7 +315,9 @@ const logisticsOrderId = ref<string | number>();
 const statusLogDrawerRef = ref<any>(null);
 
 /** 发货成功回调 */
-const handleDeliverSuccess = () => {};
+const handleDeliverSuccess = () => {
+  getOrderDetail();
+};
 
 // 计算商品总数(所有商品的采购数量之和)
 const totalQuantity = computed(() => {

+ 43 - 0
src/views/supplier/info/components/AccountTab.vue

@@ -0,0 +1,43 @@
+<template>
+  <div class="tab-content">
+    <div class="info-section">
+      <div class="section-title-row">
+        <div class="section-title-left">
+          <span class="section-title-text">付款信息</span>
+        </div>
+        <el-button v-if="!isViewMode" type="primary" icon="Plus" @click="emit('addPayment')">新增付款信息</el-button>
+      </div>
+      <el-table :data="paymentInfoList" border style="width: 100%">
+        <el-table-column prop="isture" label="是否主账号" align="center">
+          <template #default="scope">
+            <span>{{ Number(scope.row.isture) === 1 ? '是' : '否' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="bankName" label="开户银行" align="center" />
+        <el-table-column prop="bankNo" label="银行账户" align="center" />
+
+        <el-table-column label="操作" align="center" width="120">
+          <template #default="scope">
+            <el-button link type="primary" @click="emit('viewPayment', scope.row)">查看</el-button>
+            <el-button v-if="!isViewMode" link type="primary" @click="emit('editPayment', scope.row)">编辑</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+defineProps<{
+  paymentInfoList: any[];
+  isViewMode: boolean;
+}>();
+
+const emit = defineEmits<{
+  (e: 'addPayment'): void;
+  (e: 'viewPayment', row: any): void;
+  (e: 'editPayment', row: any): void;
+  (e: 'delete', row: any): void;
+  (e: 'change-deafult', row: any): void;
+}>();
+</script>

+ 75 - 34
src/views/supplier/info/components/BasicInfoTab.vue

@@ -6,11 +6,11 @@
           <span class="section-title-text">企业基本信息</span>
           <span class="section-title-divider">/</span>
           <span class="supplier-no">供应商编码:{{ detailData.supplierNo }}</span>
-          <el-tag 
-            v-if="detailData?.supplyStatus !== undefined && detailData?.supplyStatus !== null" 
-            :type="getStatusConfig(detailData.supplyStatus).type" 
-            effect="light" 
-            style="margin-left: 8px;"
+          <el-tag
+            v-if="detailData?.supplyStatus !== undefined && detailData?.supplyStatus !== null"
+            :type="getStatusConfig(detailData.supplyStatus).type"
+            effect="light"
+            style="margin-left: 8px"
           >
             {{ getStatusConfig(detailData.supplyStatus).text }}
           </el-tag>
@@ -27,7 +27,14 @@
         <el-row :gutter="12" class="form-row">
           <el-col :span="8">
             <el-form-item label="所属公司:" required>
-              <el-select v-model="detailData.ownedCompany" placeholder="请选择" clearable filterable style="width: 100%;" :disabled="!isAddMode || !isEditing">
+              <el-select
+                v-model="detailData.ownedCompany"
+                placeholder="请选择"
+                clearable
+                filterable
+                style="width: 100%"
+                :disabled="!isAddMode || !isEditing"
+              >
                 <el-option v-for="company in companyOptions" :key="company.id" :label="company.companyName" :value="company.id" />
               </el-select>
             </el-form-item>
@@ -39,11 +46,7 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="工商名称:" required>
-              <el-input
-                v-model="detailData.businessName"
-                placeholder="请输入工商名称"
-                :disabled="!isEditing"
-              />
+              <el-input v-model="detailData.businessName" placeholder="请输入工商名称" :disabled="!isEditing" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -56,14 +59,21 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="供应商等级:" required>
-              <el-select v-model="detailData.cooperateLevel" placeholder="请选择" clearable filterable style="width: 100%;" :disabled="!isAddMode || !isEditing">
+              <el-select
+                v-model="detailData.cooperateLevel"
+                placeholder="请选择"
+                clearable
+                filterable
+                style="width: 100%"
+                :disabled="!isAddMode || !isEditing"
+              >
                 <el-option v-for="level in supplierLevelOptions" :key="level.id" :label="level.supplierLevelName" :value="String(level.id)" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item label="企业规模:" required>
-              <el-select v-model="detailData.membershipSize" placeholder="请选择" clearable filterable style="width: 100%;" :disabled="!isEditing">
+              <el-select v-model="detailData.membershipSize" placeholder="请选择" clearable filterable style="width: 100%" :disabled="!isEditing">
                 <el-option v-for="scale in enterpriseScaleOptions" :key="scale.id" :label="scale.enterpriseScaleName" :value="scale.id" />
               </el-select>
             </el-form-item>
@@ -73,27 +83,40 @@
         <el-row :gutter="12" class="form-row">
           <el-col :span="8">
             <el-form-item label="行业类别:" required>
-              <el-select v-model="detailData.industrCategory" placeholder="请选择" clearable filterable style="width: 100%;" :disabled="!isAddMode || !isEditing">
-                <el-option v-for="industry in industryCategoryOptions" :key="industry.id" :label="industry.industryCategoryName" :value="industry.id" />
+              <el-select
+                v-model="detailData.industrCategory"
+                placeholder="请选择"
+                clearable
+                filterable
+                style="width: 100%"
+                :disabled="!isAddMode || !isEditing"
+              >
+                <el-option
+                  v-for="industry in industryCategoryOptions"
+                  :key="industry.id"
+                  :label="industry.industryCategoryName"
+                  :value="industry.id"
+                />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item label="供应商类型:" required>
-              <el-select v-model="detailData.supplierType" placeholder="请选择" clearable filterable style="width: 100%;" :disabled="!isAddMode || !isEditing">
+              <el-select
+                v-model="detailData.supplierType"
+                placeholder="请选择"
+                clearable
+                filterable
+                style="width: 100%"
+                :disabled="!isAddMode || !isEditing"
+              >
                 <el-option v-for="type in supplierTypeOptions" :key="type.id" :label="type.supplierTypeName" :value="type.id" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item label="固定电话:">
-              <el-input
-                v-model="detailData.fixedPhone"
-                placeholder="请输入固定电话"
-                type="tel"
-                @input="onFixedPhoneInput"
-                :disabled="!isEditing"
-              />
+              <el-input v-model="detailData.fixedPhone" placeholder="请输入固定电话" type="tel" @input="onFixedPhoneInput" :disabled="!isEditing" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -111,7 +134,13 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="开始时间:">
-              <el-date-picker v-model="detailData.validityFromDate" type="date" placeholder="请选择" style="width: 100%;" :disabled="!isAddMode || !isEditing" />
+              <el-date-picker
+                v-model="detailData.validityFromDate"
+                type="date"
+                placeholder="请选择"
+                style="width: 100%"
+                :disabled="!isAddMode || !isEditing"
+              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -119,7 +148,13 @@
         <el-row :gutter="12" class="form-row">
           <el-col :span="8">
             <el-form-item label="结束时间:">
-              <el-date-picker v-model="detailData.validityToDate" type="date" placeholder="请选择" style="width: 100%;" :disabled="!isAddMode || !isEditing" />
+              <el-date-picker
+                v-model="detailData.validityToDate"
+                type="date"
+                placeholder="请选择"
+                style="width: 100%"
+                :disabled="!isAddMode || !isEditing"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="8">
@@ -137,7 +172,16 @@
         <el-row :gutter="12" class="form-row">
           <el-col :span="8">
             <el-form-item label="详细地址:" required>
-              <el-cascader v-model="selectedOfficeRegionProxy" :options="regionOptions" placeholder="请选择省市区" clearable filterable style="width: 100%;" @change="onOfficeRegionChange" :disabled="!isEditing" />
+              <el-cascader
+                v-model="selectedOfficeRegionProxy"
+                :options="regionOptions"
+                placeholder="请选择省市区"
+                clearable
+                filterable
+                style="width: 100%"
+                @change="onOfficeRegionChange"
+                :disabled="!isEditing"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="8">
@@ -147,7 +191,7 @@
           </el-col>
         </el-row>
 
-        <el-row :gutter="12" class="form-row">
+        <!-- <el-row :gutter="12" class="form-row">
           <el-col :span="8">
             <el-form-item label="营业执照:">
               <ImageUpload
@@ -172,7 +216,7 @@
               />
             </el-form-item>
           </el-col>
-        </el-row>
+        </el-row> -->
       </el-form>
     </div>
 
@@ -240,14 +284,13 @@
         <el-col :span="24">
           <div class="form-item">
             <span class="label">工商地址:</span>
-            <el-input v-model="businessInfo.businessAddress" placeholder="工商地址" style="width: 70%;" :disabled="!isEditing" />
+            <el-input v-model="businessInfo.businessAddress" placeholder="工商地址" style="width: 70%" :disabled="!isEditing" />
           </div>
         </el-col>
       </el-row>
-
     </div>
 
-    <div class="info-section">
+    <!-- <div class="info-section">
       <div class="section-title-row">
         <div class="section-title-left">
           <span class="section-title-text">付款信息</span>
@@ -262,9 +305,7 @@
         <el-table-column prop="bankName" label="开户银行" align="center" />
         <el-table-column prop="bankNo" label="银行账户" align="center" />
       </el-table>
-
-
-    </div>
+    </div> -->
   </div>
 </template>
 

+ 74 - 0
src/views/supplier/info/components/QualificationTab.vue

@@ -0,0 +1,74 @@
+<template>
+  <div class="tab-content">
+    <div class="info-section">
+      <div class="section-title-row">
+        <div class="section-title-left">
+          <span class="section-title-text">基本资质</span>
+        </div>
+      </div>
+
+      <!-- 资质信息列表 -->
+
+      <el-table :data="qualificationList" border style="width: 100%">
+        <el-table-column prop="qualificationName" label="资质名称" align="center" />
+
+        <el-table-column prop="qualificationLevel" label="资质级别" align="center" />
+
+        <el-table-column prop="certificateNo" label="证件编号" align="center" />
+
+        <el-table-column prop="issuingAuthority" label="发证机构" align="center" />
+
+        <el-table-column label="资质到期日" align="center">
+          <template #default="scope">
+            <span v-if="scope.row.isLongValid == 1"> {{ formatDate(scope.row.endDate) }} 长期有效 </span>
+
+            <span v-else>{{ formatDate(scope.row.endDate) }}</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="资质文件" align="center" min-width="300">
+          <template #default="scope">
+            <el-button v-if="scope.row.attachmentUrl" link type="primary" @click="emit('downloadQualification', scope.row)">
+              {{ scope.row.attachmentName || '下载文件' }}
+            </el-button>
+
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <!-- <el-table-column label="操作" align="center" width="200" fixed="right">
+          <template #default="scope">
+            <el-button link type="primary" @click="emit('viewQualification', scope.row)">查看</el-button>
+          </template>
+        </el-table-column> -->
+      </el-table>
+
+      <!-- 空状态 -->
+
+      <!-- <div v-if="qualificationList.length === 0" class="empty-state">暂无资质信息</div> -->
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+defineProps<{
+  qualificationList: any[];
+  isViewMode: boolean;
+}>();
+
+/** 格式化日期 */
+
+const formatDate = (dateStr: string) => {
+  if (!dateStr) return '';
+
+  // 去掉时分秒,只保留日期部分
+
+  return dateStr.split(' ')[0];
+};
+
+const emit = defineEmits<{
+  (e: 'downloadQualification', row: any): void;
+  // (e: 'viewQualification', row: any): void;
+  (e: 'delete', row: any): void;
+}>();
+</script>

+ 10 - 5
src/views/supplier/info/components/SupplyInfoTab.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="tab-content">
-    <div class="info-section">
+    <!-- <div class="info-section">
       <div class="section-title-row">
         <div class="section-title-left">
           <span class="section-title-text">供货类目</span>
@@ -30,7 +30,7 @@
         </el-tag>
         <span v-if="selectedBrands.length === 0" style="color: #999;">暂无品牌信息</span>
       </div>
-    </div>
+    </div> 
 
     <div class="info-section">
       <div class="section-title-row">
@@ -52,7 +52,7 @@
           </template>
         </el-table-column>
       </el-table>
-    </div>
+    </div>-->
 
     <div class="info-section">
       <div class="section-title">授权详情信息列表</div>
@@ -94,8 +94,13 @@
         </el-table-column>
       </el-table>
 
-      <div style="margin-top: 20px; display: flex; justify-content: flex-end;">
-        <Pagination v-model:page="authorizationPagination.pageNum" v-model:limit="authorizationPagination.pageSize" :total="authorizationPagination.total" @pagination="emit('authorizationPagination')" />
+      <div style="margin-top: 20px; display: flex; justify-content: flex-end">
+        <Pagination
+          v-model:page="authorizationPagination.pageNum"
+          v-model:limit="authorizationPagination.pageSize"
+          :total="authorizationPagination.total"
+          @pagination="emit('authorizationPagination')"
+        />
       </div>
     </div>
   </div>

+ 197 - 219
src/views/supplier/info/index.vue

@@ -34,6 +34,29 @@
         />
       </el-tab-pane>
 
+      <el-tab-pane label="基本资质" name="qualification">
+        <QualificationTab :qualificationList="qualificationList" :isViewMode="false" @downloadQualification="handleDownload" />
+      </el-tab-pane>
+
+      <!-- 产品线及资质 -->
+      <el-tab-pane label="产品线及资质" name="supply">
+        <SupplyInfoTab
+          v-model:selectedCategories="selectedCategories"
+          :isViewMode="false"
+          :productCategoryList="productCategoryList"
+          :selectedBrands="selectedBrands"
+          :supplyAreaList="supplyAreaList"
+          :authorizationList="authorizationList"
+          :authorizationPagination="authorizationPagination"
+          :formatDate="formatDate"
+          :getAuthorizedStatusText="getAuthorizedStatusText"
+          @saveCategories="handleSaveCategories"
+          @addBrand="handleAddBrand"
+          @removeBrand="handleRemoveBrand"
+          @editSupplyArea="handleEditSupplyArea"
+          @authorizationPagination="getAuthorizationList"
+        />
+      </el-tab-pane>
       <!-- 采购信息 -->
       <el-tab-pane label="采销信息" name="purchase">
         <PurchaseInfoTab
@@ -60,7 +83,7 @@
       </el-tab-pane>
 
       <!-- 供应信息 -->
-      <el-tab-pane label="供应信息" name="supply">
+      <!-- <el-tab-pane label="供应信息" name="supply">
         <SupplyInfoTab
           v-model:selectedCategories="selectedCategories"
           :isViewMode="false"
@@ -78,16 +101,21 @@
           @editSupplyArea="handleEditSupplyArea"
           @authorizationPagination="getAuthorizationList"
         />
-      </el-tab-pane>
+      </el-tab-pane> -->
 
       <!-- 地址管理 -->
       <el-tab-pane label="地址管理" name="address">
-        <AddressTab
-          :addressList="addressList"
+        <AddressTab :addressList="addressList" :isViewMode="false" @add="handleAddAddress" @edit="handleEditAddress" @delete="handleDeleteAddress" />
+      </el-tab-pane>
+
+      <!-- 财务信息 -->
+      <el-tab-pane label="财务信息" name="account">
+        <AccountTab
+          :paymentInfoList="paymentInfoList"
           :isViewMode="false"
-          @add="handleAddAddress"
-          @edit="handleEditAddress"
-          @delete="handleDeleteAddress"
+          @addPayment="handleAddPayment"
+          @editPayment="handleEditPayment"
+          @viewPayment="handleViewPayment"
         />
       </el-tab-pane>
 
@@ -116,41 +144,20 @@
     </el-tabs>
 
     <!-- 付款信息对话框 -->
-    <el-dialog
-      v-model="paymentDialogVisible"
-      :title="paymentDialogTitle"
-      width="1000px"
-      :close-on-click-modal="false"
-    >
-      <el-form
-        ref="paymentFormRef"
-        :model="paymentForm"
-        :rules="paymentFormRules"
-        label-width="140px"
-        :disabled="paymentDialogReadonly"
-      >
+    <el-dialog v-model="paymentDialogVisible" :title="paymentDialogTitle" width="1000px" :close-on-click-modal="false">
+      <el-form ref="paymentFormRef" :model="paymentForm" :rules="paymentFormRules" label-width="140px" :disabled="paymentDialogReadonly">
         <el-form-item label="开票类型:" prop="invoiceTypeNo">
-          <el-select
-            v-model="paymentForm.invoiceTypeNo"
-            placeholder="请选择"
-            style="width: 100%;"
-            @change="handleInvoiceTypeChange"
-          >
-            <el-option
-              v-for="item in invoiceTypeList"
-              :key="item.id"
-              :label="item.invoiceTypeName"
-              :value="item.id"
-            />
+          <el-select v-model="paymentForm.invoiceTypeNo" placeholder="请选择" style="width: 100%" @change="handleInvoiceTypeChange">
+            <el-option v-for="item in invoiceTypeList" :key="item.id" :label="item.invoiceTypeName" :value="item.id" />
           </el-select>
         </el-form-item>
 
         <el-form-item label="发票抬头:" prop="businessName">
-          <el-input v-model="paymentForm.businessName" placeholder="企业工商名称" disabled/>
+          <el-input v-model="paymentForm.businessName" placeholder="企业工商名称" disabled />
         </el-form-item>
 
         <el-form-item label="纳税人识别号:" prop="circlesName">
-          <el-input v-model="paymentForm.circlesName" placeholder="请输入纳税人识别号" disabled/>
+          <el-input v-model="paymentForm.circlesName" placeholder="请输入纳税人识别号" disabled />
         </el-form-item>
 
         <el-form-item label="开户行行号:" prop="bankNum">
@@ -158,18 +165,8 @@
         </el-form-item>
 
         <el-form-item label="开户行名称:" prop="bankInfoNo">
-          <el-select
-            v-model="paymentForm.bankInfoNo"
-            placeholder="请选择"
-            style="width: 100%;"
-            @change="handleBankChange"
-          >
-            <el-option
-              v-for="item in systemBankList"
-              :key="item.id"
-              :label="item.bnName"
-              :value="item.id"
-            />
+          <el-select v-model="paymentForm.bankInfoNo" placeholder="请选择" style="width: 100%" @change="handleBankChange">
+            <el-option v-for="item in systemBankList" :key="item.id" :label="item.bnName" :value="item.id" />
           </el-select>
         </el-form-item>
 
@@ -202,19 +199,8 @@
     </el-dialog>
 
     <!-- 联系人对话框 -->
-    <el-dialog
-      v-model="contactDialogVisible"
-      :title="contactDialogTitle"
-      width="900px"
-      :close-on-click-modal="false"
-    >
-      <el-form
-        ref="contactFormRef"
-        :model="contactForm"
-        :rules="contactFormRules"
-        label-width="140px"
-        :disabled="contactDialogReadonly"
-      >
+    <el-dialog v-model="contactDialogVisible" :title="contactDialogTitle" width="900px" :close-on-click-modal="false">
+      <el-form ref="contactFormRef" :model="contactForm" :rules="contactFormRules" label-width="140px" :disabled="contactDialogReadonly">
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="员工姓名:" prop="userName">
@@ -223,12 +209,7 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="手机号:" prop="phone">
-              <el-input
-                v-model="contactForm.phone"
-                placeholder="请输入手机号"
-                maxlength="11"
-                @input="onContactPhoneInput"
-              />
+              <el-input v-model="contactForm.phone" placeholder="请输入手机号" maxlength="11" @input="onContactPhoneInput" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -262,7 +243,7 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="主要联系人:" prop="isPrimaryContact">
-              <el-select v-model="contactForm.isPrimaryContact" placeholder="请选择" style="width: 100%;">
+              <el-select v-model="contactForm.isPrimaryContact" placeholder="请选择" style="width: 100%">
                 <el-option label="是" value="1" />
                 <el-option label="否" value="0" />
               </el-select>
@@ -270,7 +251,7 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="允许登录供应商端:" prop="isRegister">
-              <el-select v-model="contactForm.isRegister" placeholder="请选择" style="width: 100%;">
+              <el-select v-model="contactForm.isRegister" placeholder="请选择" style="width: 100%">
                 <el-option label="是" value="1" />
                 <el-option label="否" value="0" />
               </el-select>
@@ -289,12 +270,7 @@
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="备注:" prop="remark">
-              <el-input
-                v-model="contactForm.remark"
-                type="textarea"
-                :rows="3"
-                placeholder="请输入备注"
-              />
+              <el-input v-model="contactForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -309,12 +285,7 @@
     </el-dialog>
 
     <!-- 重置联系人密码对话框 -->
-    <el-dialog
-      v-model="resetPwdDialogVisible"
-      title="重置密码"
-      width="520px"
-      :close-on-click-modal="false"
-    >
+    <el-dialog v-model="resetPwdDialogVisible" title="重置密码" width="520px" :close-on-click-modal="false">
       <el-form ref="resetPwdFormRef" :model="resetPwdForm" :rules="resetPwdRules" label-width="120px">
         <el-form-item label="新密码:" prop="password">
           <el-input v-model="resetPwdForm.password" type="password" show-password placeholder="请输入新密码" />
@@ -333,12 +304,7 @@
     </el-dialog>
 
     <!-- 供货区域编辑对话框 -->
-    <el-dialog
-      v-model="supplyAreaDialogVisible"
-      title="编辑供货区域"
-      width="700px"
-      :close-on-click-modal="false"
-    >
+    <el-dialog v-model="supplyAreaDialogVisible" title="编辑供货区域" width="700px" :close-on-click-modal="false">
       <RegionCascader v-model="selectedSupplyAreaCodes" :multiple="true" :options="supplyAreaOptions" :show-district="false" />
 
       <template #footer>
@@ -350,19 +316,8 @@
     </el-dialog>
 
     <!-- 地址管理对话框 -->
-    <el-dialog
-      v-model="addressDialogVisible"
-      :title="addressDialogTitle"
-      width="650px"
-      :close-on-click-modal="false"
-    >
-      <el-form
-        ref="addressFormRef"
-        :model="addressForm"
-        :rules="addressFormRules"
-        label-width="120px"
-        :disabled="addressDialogReadonly"
-      >
+    <el-dialog v-model="addressDialogVisible" :title="addressDialogTitle" width="650px" :close-on-click-modal="false">
+      <el-form ref="addressFormRef" :model="addressForm" :rules="addressFormRules" label-width="120px" :disabled="addressDialogReadonly">
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="供应商编号:">
@@ -398,7 +353,7 @@
                 placeholder="请选择"
                 clearable
                 filterable
-                style="width: 100%;"
+                style="width: 100%"
                 @change="handleAddressRegionChange"
               />
             </el-form-item>
@@ -408,12 +363,7 @@
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="详细地址:" prop="shippingAddress" required>
-              <el-input
-                v-model="addressForm.shippingAddress"
-                type="textarea"
-                :rows="3"
-                placeholder="请输入详细地址"
-              />
+              <el-input v-model="addressForm.shippingAddress" type="textarea" :rows="3" placeholder="请输入详细地址" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -436,19 +386,8 @@
     </el-dialog>
 
     <!-- 合同管理对话框 -->
-    <el-dialog
-      v-model="contractDialogVisible"
-      :title="contractDialogTitle"
-      width="900px"
-      :close-on-click-modal="false"
-    >
-      <el-form
-        ref="contractFormRef"
-        :model="contractForm"
-        :rules="contractFormRules"
-        label-width="140px"
-        :disabled="contractDialogReadonly"
-      >
+    <el-dialog v-model="contractDialogVisible" :title="contractDialogTitle" width="900px" :close-on-click-modal="false">
+      <el-form ref="contractFormRef" :model="contractForm" :rules="contractFormRules" label-width="140px" :disabled="contractDialogReadonly">
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="合同名称:" prop="contractName">
@@ -460,25 +399,15 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="合同类型:" prop="contractType">
-              <el-select v-model="contractForm.contractType" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in contractTypeDict"
-                  :key="item.dictValue"
-                  :label="item.dictLabel"
-                  :value="item.dictValue"
-                />
+              <el-select v-model="contractForm.contractType" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in contractTypeDict" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="提醒时间:" prop="demandReminderTime">
-              <el-input-number
-                v-model="contractForm.demandReminderTime"
-                :min="1"
-                :max="365"
-                style="width: 150px;"
-              />
-              <span style="margin-left: 10px;">天</span>
+              <el-input-number v-model="contractForm.demandReminderTime" :min="1" :max="365" style="width: 150px" />
+              <span style="margin-left: 10px">天</span>
             </el-form-item>
           </el-col>
         </el-row>
@@ -486,22 +415,12 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="开始时间:" prop="contractStartTime">
-              <el-date-picker
-                v-model="contractForm.contractStartTime"
-                type="date"
-                placeholder="请选择"
-                style="width: 100%;"
-              />
+              <el-date-picker v-model="contractForm.contractStartTime" type="date" placeholder="请选择" style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="截止时间:" prop="contractEndTime">
-              <el-date-picker
-                v-model="contractForm.contractEndTime"
-                type="date"
-                placeholder="请选择"
-                style="width: 100%;"
-              />
+              <el-date-picker v-model="contractForm.contractEndTime" type="date" placeholder="请选择" style="width: 100%" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -509,13 +428,8 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="开票类型:" prop="invoiceType">
-              <el-select v-model="contractForm.invoiceType" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in invoiceTypeList"
-                  :key="item.id"
-                  :label="item.invoiceTypeName"
-                  :value="item.id"
-                />
+              <el-select v-model="contractForm.invoiceType" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in invoiceTypeList" :key="item.id" :label="item.invoiceTypeName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -531,25 +445,15 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="税率:" prop="taxRate">
-              <el-select v-model="contractForm.taxRate" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in taxRateList"
-                  :key="item.id"
-                  :label="item.taxrateName"
-                  :value="item.id"
-                />
+              <el-select v-model="contractForm.taxRate" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in taxRateList" :key="item.id" :label="item.taxrateName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="结算方式:" prop="settlementMethod">
-              <el-select v-model="contractForm.settlementMethod" placeholder="请选择" style="width: 100%;">
-                <el-option
-                  v-for="item in settlementMethodList"
-                  :key="item.id"
-                  :label="item.settlementName"
-                  :value="item.id"
-                />
+              <el-select v-model="contractForm.settlementMethod" placeholder="请选择" style="width: 100%">
+                <el-option v-for="item in settlementMethodList" :key="item.id" :label="item.settlementName" :value="item.id" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -572,12 +476,7 @@
         <el-row :gutter="20">
           <el-col :span="24">
             <el-form-item label="合同说明:" prop="contractDescription">
-              <el-input
-                v-model="contractForm.contractDescription"
-                type="textarea"
-                :rows="4"
-                placeholder="请输入合同说明"
-              />
+              <el-input v-model="contractForm.contractDescription" type="textarea" :rows="4" placeholder="请输入合同说明" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -592,27 +491,17 @@
     </el-dialog>
 
     <!-- 品牌新增对话框 -->
-    <el-dialog
-      v-model="brandDialogVisible"
-      title="添加品牌"
-      width="600px"
-      :close-on-click-modal="false"
-      class="brand-dialog"
-    >
+    <el-dialog v-model="brandDialogVisible" title="添加品牌" width="600px" :close-on-click-modal="false" class="brand-dialog">
       <div class="brand-dialog__search">
         <el-form @submit.prevent>
           <el-row :gutter="12" align="middle">
             <el-col :span="14">
-              <el-form-item label="品牌名称:" style="margin-bottom: 0;">
-                <el-input
-                  v-model="brandSearchKeyword"
-                  placeholder="请输入品牌名称"
-                  @keyup.enter="handleSearchBrand"
-                />
+              <el-form-item label="品牌名称:" style="margin-bottom: 0">
+                <el-input v-model="brandSearchKeyword" placeholder="请输入品牌名称" @keyup.enter="handleSearchBrand" />
               </el-form-item>
             </el-col>
-            <el-col :span="10" style="display: flex; justify-content: flex-end;">
-              <el-form-item label-width="0" style="margin-bottom: 0;">
+            <el-col :span="10" style="display: flex; justify-content: flex-end">
+              <el-form-item label-width="0" style="margin-bottom: 0">
                 <el-button type="primary" @click="handleSearchBrand" :loading="brandSearchLoading">搜索</el-button>
                 <el-button type="primary" @click="handleAddBrandToList()">添加</el-button>
               </el-form-item>
@@ -624,11 +513,12 @@
       <!-- 搜索结果列表 -->
       <div v-if="brandSearchResults.length > 0" class="brand-search-results">
         <div class="search-results-title">搜索结果(点击添加):</div>
-        <div class="brand-result-item"
+        <div
+          class="brand-result-item"
           v-for="brand in brandSearchResults"
           :key="brand.id"
           @click="handleAddBrandToList(brand)"
-          style="cursor: pointer;"
+          style="cursor: pointer"
         >
           <span class="brand-result-name">{{ brand.brandName }}</span>
           <span class="brand-result-no">编号: {{ brand.brandNo }}</span>
@@ -644,11 +534,11 @@
             closable
             @close="handleRemoveTempBrand(brand)"
             type="info"
-            style="margin-right: 10px; margin-bottom: 10px;"
+            style="margin-right: 10px; margin-bottom: 10px"
           >
             {{ brand.brandName }}
           </el-tag>
-          <span v-if="tempSelectedBrands.length === 0" style="color: #999; font-size: 14px;">暂无已选择品牌</span>
+          <span v-if="tempSelectedBrands.length === 0" style="color: #999; font-size: 14px">暂无已选择品牌</span>
         </div>
       </div>
 
@@ -671,7 +561,21 @@ import { useUserStore } from '@/store/modules/user';
 import RegionCascader from '@/components/RegionCascader/index.vue';
 import FileUpload from '@/components/FileUpload/index.vue';
 import Pagination from '@/components/Pagination/index.vue';
-import { getInfo, getStaffListSplice, getSupplierStaffIds, getContactListById, getSupplierCategories, getSupplierContractsById, getBankBySupplierId, getAuthorizeDetailList, getDictData, getTaxRateList, getSettlementMethodList, getInvoiceTypeList } from '@/api/customer/info/index';
+
+import {
+  getInfo,
+  getStaffListSplice,
+  getSupplierStaffIds,
+  getContactListById,
+  getSupplierCategories,
+  getSupplierContractsById,
+  getBankBySupplierId,
+  getAuthorizeDetailList,
+  getDictData,
+  getTaxRateList,
+  getSettlementMethodList,
+  getInvoiceTypeList
+} from '@/api/customer/info/index';
 import { updateInfo as updateSupplierInfo } from '@/api/supplier/info';
 import { getBank, updateBank, addBank } from '@/api/customer/bank/index';
 import { BankForm } from '@/api/customer/bank/types';
@@ -712,6 +616,11 @@ import SupplyInfoTab from './components/SupplyInfoTab.vue';
 import AddressTab from './components/AddressTab.vue';
 import ContractTab from './components/ContractTab.vue';
 
+import { listQualification } from '@/api/supplier/qualification';
+import type { QualificationVO } from '@/api/supplier/qualification/types';
+import AccountTab from './components/AccountTab.vue';
+import QualificationTab from './components/QualificationTab.vue';
+
 const scmEditInfo = (data: any) => updateSupplierInfo(data);
 
 const route = useRoute();
@@ -741,6 +650,9 @@ const contactSearchParams = ref({
   userName: ''
 });
 
+// 供应商资质相关数据
+const qualificationList = ref<QualificationVO[]>([]);
+
 // 联系人对话框相关
 const contactDialogVisible = ref(false);
 const contactDialogTitle = ref('');
@@ -790,7 +702,14 @@ const contactFormRules = {
 const resetPwdDialogVisible = ref(false);
 const resetPwdFormRef = ref<ElFormInstance>();
 const resetPwdSubmitLoading = ref(false);
-const resetPwdForm = ref<{ id: string | number | null; userId: string | number | null; userName: string; phone: string; password: string; confirmPassword: string }>({
+const resetPwdForm = ref<{
+  id: string | number | null;
+  userId: string | number | null;
+  userName: string;
+  phone: string;
+  password: string;
+  confirmPassword: string;
+}>({
   id: null,
   userId: null,
   userName: '',
@@ -967,6 +886,23 @@ const getSystemBankData = async () => {
   }
 };
 
+/** 获取资质列表 */
+const getQualificationList = async () => {
+  try {
+    const res = await listQualification({
+      supplierId: route.query.id as any,
+      pageNum: 1,
+      pageSize: 99
+    });
+    qualificationList.value = res.rows || [];
+  } catch (e) {
+    console.error('获取资质列表失败:', e);
+
+    ElMessage.error('获取资质列表失败');
+  } finally {
+  }
+};
+
 /** 获取付款信息 */
 const getPaymentInfo = async () => {
   const id = route.query.id as string;
@@ -1213,10 +1149,10 @@ const getDetail = async () => {
           // 使用临时表数据覆盖主表数据
           const tempData: any = tempRes.data;
           detailData.value = {
-            ...detailData.value,  // 保留主表的一些基础字段
-            ...tempData,          // 使用临时表的修改数据
-            id: detailData.value.id,  // 确保ID是主表的ID
-            supplierNo: detailData.value.supplierNo  // 确保supplierNo是主表的
+            ...detailData.value, // 保留主表的一些基础字段
+            ...tempData, // 使用临时表的修改数据
+            id: detailData.value.id, // 确保ID是主表的ID
+            supplierNo: detailData.value.supplierNo // 确保supplierNo是主表的
           } as any;
           console.log('已加载临时表数据:', tempData);
         }
@@ -1690,7 +1626,7 @@ const handleAddBrandToList = (brand?: BrandVO) => {
   }
 
   // 检查品牌是否已存在
-  const exists = tempSelectedBrands.value.some(b => b.id === brand!.id);
+  const exists = tempSelectedBrands.value.some((b) => b.id === brand!.id);
 
   if (exists) {
     ElMessage.warning('该品牌已添加');
@@ -1707,7 +1643,7 @@ const handleAddBrandToList = (brand?: BrandVO) => {
 
 /** 删除临时品牌 */
 const handleRemoveTempBrand = (brand: BrandVO) => {
-  const index = tempSelectedBrands.value.findIndex(b => b.id === brand.id);
+  const index = tempSelectedBrands.value.findIndex((b) => b.id === brand.id);
   if (index > -1) {
     tempSelectedBrands.value.splice(index, 1);
   }
@@ -1715,7 +1651,7 @@ const handleRemoveTempBrand = (brand: BrandVO) => {
 
 /** 删除已选择的品牌 */
 const handleRemoveBrand = async (brand: BrandVO) => {
-  const index = selectedBrands.value.findIndex(b => b.id === brand.id);
+  const index = selectedBrands.value.findIndex((b) => b.id === brand.id);
   if (index > -1) {
     selectedBrands.value.splice(index, 1);
     // 立即保存到后端
@@ -1759,7 +1695,7 @@ const saveBrandsToServer = async () => {
   }
 
   // 将品牌ID用逗号分隔保存
-  const brandIds = selectedBrands.value.map(brand => brand.id).join(',');
+  const brandIds = selectedBrands.value.map((brand) => brand.id).join(',');
 
   // 方案B:只提交必要字段,避免EditGroup校验因缺字段失败
   await scmEditInfo({
@@ -1772,25 +1708,28 @@ const saveBrandsToServer = async () => {
 const initBrandList = async () => {
   if (detailData.value.operatingBrand) {
     // 后端返回的是用逗号分隔的品牌ID
-    const brandIds = detailData.value.operatingBrand.split(',').filter(id => id.trim());
+    const brandIds = detailData.value.operatingBrand.split(',').filter((id) => id.trim());
 
     if (brandIds.length > 0) {
       try {
         // 根据品牌ID获取品牌详细信息
-        const brandPromises = brandIds.map(id => getBrand(id.trim()));
+        const brandPromises = brandIds.map((id) => getBrand(id.trim()));
         const brandResults = await Promise.allSettled(brandPromises);
 
         selectedBrands.value = brandResults
-          .filter(result => result.status === 'fulfilled')
-          .map(result => (result as PromiseFulfilledResult<any>).value.data)
-          .filter(brand => brand); // 过滤掉空值
+          .filter((result) => result.status === 'fulfilled')
+          .map((result) => (result as PromiseFulfilledResult<any>).value.data)
+          .filter((brand) => brand); // 过滤掉空值
       } catch (e) {
         console.error('获取品牌详情失败:', e);
         // 降级处理:如果获取品牌详情失败,使用ID作为显示名称
-        selectedBrands.value = brandIds.map(id => ({
-          id: id.trim(),
-          brandName: id.trim()
-        } as BrandVO));
+        selectedBrands.value = brandIds.map(
+          (id) =>
+            ({
+              id: id.trim(),
+              brandName: id.trim()
+            }) as BrandVO
+        );
       }
     }
   }
@@ -1844,9 +1783,7 @@ const getSupplyAreaList = async () => {
     });
 
     // 转换为数组
-    supplyAreaList.value = Object.values(provinceMap).filter((item: any) =>
-      item.province || item.city
-    );
+    supplyAreaList.value = Object.values(provinceMap).filter((item: any) => item.province || item.city);
 
     console.log('供货区域列表:', supplyAreaList.value);
     console.log('保存的原始数据:', savedAreaData.value);
@@ -2056,11 +1993,11 @@ const formatDate = (date: string | Date) => {
 /** 获取合同状态类型 */
 const getContractStatusType = (status: number) => {
   const statusMap = {
-    0: 'info',    // 草稿
+    0: 'info', // 草稿
     1: 'success', // 已生效
     2: 'warning', // 已到期
-    3: 'danger',  // 已终止
-    4: 'danger'   // 已作废
+    3: 'danger', // 已终止
+    4: 'danger' // 已作废
   };
   return statusMap[status] || 'info';
 };
@@ -2071,7 +2008,6 @@ const getContractStatusText = (status: number) => {
     0: '待审核',
     1: '生效',
     2: '失效'
-
   };
   return statusMap[status] || '未知';
 };
@@ -2081,7 +2017,7 @@ const getContractTypeText = (type: string | number) => {
   const typeMap = {
     '0': '年度合作',
     '1': '项目采购',
-    '2': '其他合作',
+    '2': '其他合作'
   };
   return typeMap[type] || '未知';
 };
@@ -2424,7 +2360,7 @@ const handleAddPayment = () => {
 
 /** 发票类型选择改变 */
 const handleInvoiceTypeChange = (value: string | number) => {
-  const selectedInvoice = invoiceTypeList.value.find(item => item.id === value);
+  const selectedInvoice = invoiceTypeList.value.find((item) => item.id === value);
   if (selectedInvoice) {
     paymentForm.value.invoiceTypeNo = selectedInvoice.id;
     paymentForm.value.invoiceTypeName = selectedInvoice.invoiceTypeName;
@@ -2433,7 +2369,7 @@ const handleInvoiceTypeChange = (value: string | number) => {
 
 /** 银行选择改变 */
 const handleBankChange = (value: string | number) => {
-  const selectedBank = systemBankList.value.find(item => item.id === value);
+  const selectedBank = systemBankList.value.find((item) => item.id === value);
   if (selectedBank) {
     paymentForm.value.bankInfoNo = selectedBank.id;
     paymentForm.value.bankName = selectedBank.bnName;
@@ -2480,6 +2416,47 @@ const handlePaymentSubmit = async () => {
   });
 };
 
+/** 下载附件 */
+const handleDownload = async (row: QualificationVO) => {
+  if (!row.attachmentUrl) {
+    ElMessage.warning('暂无附件可下载');
+
+    return;
+  }
+
+  try {
+    // 使用 fetch 获取文件并强制下载
+
+    const response = await fetch(row.attachmentUrl);
+
+    if (!response.ok) throw new Error('下载失败');
+
+    const blob = await response.blob();
+
+    const url = window.URL.createObjectURL(blob);
+
+    const link = document.createElement('a');
+
+    link.href = url;
+
+    link.download = row.attachmentName || '附件';
+
+    document.body.appendChild(link);
+
+    link.click();
+
+    document.body.removeChild(link);
+
+    window.URL.revokeObjectURL(url);
+
+    ElMessage.success('开始下载');
+  } catch (e) {
+    console.error('下载附件失败:', e);
+
+    ElMessage.error('下载失败');
+  }
+};
+
 /** 获取地址列表 */
 const getAddressList = async () => {
   const id = route.query.id as string;
@@ -2745,6 +2722,7 @@ onMounted(async () => {
     getAuthorizationList(); // 获取授权详情列表
     getAddressList(); // 获取地址列表
     getSupplyAreaList(); // 获取供货区域列表
+    getQualificationList();
   }
 });
 </script>