gaoluyang
9 小时以前 07f9f8657d057a38792c3822acc9b08d83478967
src/views/productionManagement/productionOrder/index.vue
@@ -3,16 +3,8 @@
    <div class="search_form">
      <el-form :model="searchForm"
               :inline="true">
        <el-form-item label="客户名称:">
          <el-input v-model="searchForm.customerName"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery" />
        </el-form-item>
        <el-form-item label="合同号:">
          <el-input v-model="searchForm.salesContractNo"
        <el-form-item label="生产订单号:">
          <el-input v-model="searchForm.npsNo"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
@@ -20,7 +12,7 @@
                    @change="handleQuery" />
        </el-form-item>
        <el-form-item label="产品名称:">
          <el-input v-model="searchForm.productCategory"
          <el-input v-model="searchForm.productName"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
@@ -28,21 +20,42 @@
                    @change="handleQuery" />
        </el-form-item>
        <el-form-item label="规格:">
          <el-input v-model="searchForm.specificationModel"
          <el-input v-model="searchForm.model"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 160px;"
                    @change="handleQuery" />
        </el-form-item>
        <el-form-item label="状态:">
          <el-select v-model="searchForm.status"
                     placeholder="请选择"
                     style="width: 160px;"
                     @change="handleQuery">
            <el-option label="待开始"
                       value="1" />
            <el-option label="进行中"
                       value="2" />
            <el-option label="已完成"
                       value="3" />
            <el-option label="已取消"
                       value="4" />
            <el-option label="已结束"
                       value="5" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
          <el-button type="info"
                     @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
      <div>
        <el-button type="primary" @click="isShowNewModal = true">新增</el-button>
        <el-button type="danger" @click="handleDelete">删除</el-button>
      <div class="action-buttons">
        <!-- <el-button type="primary"
                   @click="isShowNewModal = true">新增</el-button> -->
        <el-button type="danger"
                   @click="handleDelete">退回</el-button>
        <el-button @click="handleOut">导出</el-button>
      </div>
    </div>
@@ -54,14 +67,33 @@
                :tableLoading="tableLoading"
                :row-class-name="tableRowClassName"
                :isSelection="true"
                :selectable="row => !row.endOrder"
                @selection-change="handleSelectionChange"
                @pagination="pagination">
        <template #completionStatus="{ row }">
          <el-progress
            :percentage="toProgressPercentage(row?.completionStatus)"
            :color="progressColor(toProgressPercentage(row?.completionStatus))"
            :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''"
          />
          <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
                       :color="progressColor(toProgressPercentage(row?.completionStatus))"
                       :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
        </template>
        <template #processRouteStatus="{ row }">
          <div v-if="row.processRouteStatus && row.processRouteStatus.length"
               class="process-progress-container">
            <div v-for="(item, index) in row.processRouteStatus"
                 :key="index"
                 class="process-step">
              <div class="step-content">
                <div class="step-circle"
                     :class="{ 'is-completed': item.percentage >= 100 }">
                  <span class="step-percentage"
                        :style="{ color: item.percentage >= 70 ? item.percentage >= 100 ? '#67c23a' : '#f56c6c' : '#000' }">{{ item.percentage }}%</span>
                </div>
                <div class="step-name">{{ item.name }}</div>
              </div>
              <div v-if="index < row.processRouteStatus.length - 1"
                   class="step-line"></div>
            </div>
          </div>
          <span v-else>-</span>
        </template>
      </PIMTable>
    </div>
@@ -90,15 +122,107 @@
        </span>
      </template>
    </el-dialog>
    <!-- 来源数据弹窗 -->
    <el-dialog v-model="sourceDataDialogVisible"
               title="来源数据"
               width="1200px">
      <div v-if="sourceRowData"
           class="applyno-summary1">
        <div class="summary-item">
          <span class="summary-label">产品名称:</span>
          <span class="summary-value">
            <el-tag type="primary">{{ sourceRowData.productName || '-' }}</el-tag>
          </span>
        </div>
        <div class="summary-item">
          <span class="summary-label">规格:</span>
          <span class="summary-value">{{ sourceRowData.model || '-' }}</span>
        </div>
        <div class="summary-item">
          <span class="summary-label">订单需求数量:</span>
          <span class="summary-value">{{ sourceRowData.quantity || 0 }}</span>
        </div>
      </div>
      <div class="source-table-container">
        <div class="source-data-cards-container">
          <div v-for="(item, index) in sourceTableData"
               :key="index"
               class="source-data-card">
            <div class="card-body">
              <div class="info-grid">
                <div class="info-item">
                  <div class="info-label">计划号</div>
                  <div class="info-value">{{ item.mpsNo || '-' }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">数据来源</div>
                  <div class="info-value">
                    <el-tag :type="item.source === '销售' ? 'primary' : 'warning'">
                      {{ item.source || '未知' }}
                    </el-tag>
                  </div>
                </div>
                <div class="info-item">
                  <div class="info-label">合同号</div>
                  <div class="info-value">{{ item.salesContractNo || '-' }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">客户名称</div>
                  <div class="info-value">{{ item.customerName || '-' }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">项目名称</div>
                  <div class="info-value">{{ item.projectName || '-' }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">计划需求数量</div>
                  <div class="info-value">{{ item.qtyRequired || 0 }} {{ item.unit || '' }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">单位</div>
                  <div class="info-value">{{ item.unit || '-' }}</div>
                </div>
                <div class="info-item">
                  <div class="info-label">需求日期</div>
                  <div class="info-value">{{ item.requiredDate ? dayjs(item.requiredDate).format('YYYY-MM-DD') : '-' }}</div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </el-dialog>
    <MaterialLedgerDialog v-model="materialDialogVisible"
                          :order-row="currentMaterialOrder"
                          @saved="getList" />
    <MaterialDetailDialog v-model="materialDetailDialogVisible"
                          :order-row="currentMaterialDetailOrder"
                          @confirmed="getList" />
    <MaterialSupplementDialog v-model="materialSupplementDialogVisible"
                              :order-row="currentMaterialSupplementOrder"
                              @saved="getList" />
    <new-product-order v-if="isShowNewModal"
                         v-model:visible="isShowNewModal"
                         @completed="handleQuery" />
                       v-model:visible="isShowNewModal"
                       @completed="handleQuery" />
    <!-- 打印领料单组件 -->
    <div class="print-requisition-wrapper">
      <PrintMaterialRequisition ref="printRef"
                                :order-row="printOrderRow"
                                :material-list="printMaterialList" />
    </div>
  </div>
</template>
<script setup>
  import { onMounted, ref } from "vue";
  import {
    computed,
    defineAsyncComponent,
    getCurrentInstance,
    onMounted,
    reactive,
    ref,
    toRefs,
  } from "vue";
  import { ElMessageBox } from "element-plus";
  import dayjs from "dayjs";
  import { useRouter } from "vue-router";
@@ -106,48 +230,95 @@
    productOrderListPage,
    listProcessRoute,
    bindingRoute,
    listProcessBom, delProductOrder,
    listProcessBom,
    delProductOrder,
    getProductOrderSource,
    updateProductOrder,
  } from "@/api/productionManagement/productionOrder.js";
  import { productWorkOrderPage } from "@/api/productionManagement/workOrder.js";
  import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
  import {fileDel} from "@/api/financialManagement/revenueManagement.js";
  import MaterialLedgerDialog from "@/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue";
  import MaterialDetailDialog from "@/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue";
  import MaterialSupplementDialog from "@/views/productionManagement/productionOrder/components/MaterialSupplementDialog.vue";
  import PrintMaterialRequisition from "@/views/productionManagement/productionOrder/components/PrintMaterialRequisition.vue";
  import PIMTable from "@/components/PIMTable/PIMTable.vue";
  const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
  import { listPage } from "@/api/productionManagement/processRoute.js";
  import {
    listMaterialPickingDetail,
    listMaterialPickingBom,
  } from "@/api/productionManagement/productionOrder.js";
  const NewProductOrder = defineAsyncComponent(() =>
    import("@/views/productionManagement/productionOrder/New.vue")
  );
  const { proxy } = getCurrentInstance();
  const router = useRouter();
  const isShowNewModal = ref(false);
  const sourceDataDialogVisible = ref(false);
  const sourceTableData = ref([]);
  const sourceRowData = ref(null);
  const sourcePage = reactive({
    total: 0,
  });
  const tableColumn = ref([
  const processColumnWidth = computed(() => {
    if (!tableData.value || tableData.value.length === 0) return "200px";
    const maxProcesses = Math.max(
      ...tableData.value.map(row => row.processRouteStatus?.length || 0)
    );
    if (maxProcesses === 0) return "100px";
    // 每个工序圆圈 36px + 线条 30px = 66px,额外加 60px 边距和文字空间
    return `${maxProcesses * 66 + 60}px`;
  });
  const tableColumn = computed(() => [
    {
      label: "生产订单号",
      prop: "npsNo",
      width: '120px',
      width: "150px",
    },
    // 1.待开始、2.进行中、3.已完成、4.已取消、5.已结束
    {
      label: "销售合同号",
      prop: "salesContractNo",
      width: '150px',
    },
    {
      label: "客户名称",
      prop: "customerName",
      width: '200px',
      label: "状态",
      prop: "status",
      width: "150px",
      dataType: "tag",
      formatData: val =>
        val === 1
          ? "待开始"
          : val === 2
          ? "进行中"
          : val === 3
          ? "已完成"
          : val === 5
          ? "已结束"
          : "已取消",
      formatType: val =>
        val === 1
          ? "primary"
          : val === 2
          ? "warning"
          : val === 3
          ? "success"
          : val === 5
          ? "danger"
          : "info",
    },
    {
      label: "产品名称",
      prop: "productCategory",
      width: '120px',
      prop: "productName",
      width: "120px",
    },
    {
      label: "规格",
      prop: "specificationModel",
      width: '120px',
      prop: "model",
      width: "120px",
    },
    {
      label: "工艺路线编号",
      prop: "processRouteCode",
      width: '200px',
      width: "200px",
    },
    {
      label: "需求数量",
@@ -156,6 +327,13 @@
    {
      label: "完成数量",
      prop: "completeQuantity",
    },
    {
      label: "工序生产进度",
      prop: "processRouteStatus",
      dataType: "slot",
      slot: "processRouteStatus",
      width: processColumnWidth.value,
    },
    {
      dataType: "slot",
@@ -177,8 +355,8 @@
      width: 120,
    },
    {
      label: "交付日期",
      prop: "deliveryDate",
      label: "计划完成时间",
      prop: "planCompleteTime",
      formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
      width: 120,
    },
@@ -187,11 +365,12 @@
      label: "操作",
      align: "center",
      fixed: "right",
      width: 200,
      width: 280,
      operation: [
        {
          name: "工艺路线",
          type: "text",
          showHide: row => row.processRouteCode,
          clickFun: row => {
            showRouteItemModal(row);
          },
@@ -199,16 +378,83 @@
        {
          name: "绑定工艺路线",
          type: "text",
          showHide: row => !row.processRouteCode,
          showHide: row => !row.processRouteCode && !row.endOrder,
          clickFun: row => {
            openBindRouteDialog(row);
            openBindRouteDialog(row, "add");
          },
        },
        {
          name: "产品结构",
          name: "更换工艺路线",
          type: "text",
          showHide: row => row.processRouteCode && !row.endOrder,
          clickFun: row => {
            openBindRouteDialog(row, "change");
          },
        },
        {
          name: "来源",
          type: "text",
          clickFun: row => {
            showProductStructure(row);
            showSourceData(row);
          },
        },
        {
          name: "领料",
          type: "text",
          color: "#5EC7AB",
          showHide: row => !row.endOrder && !row.returned,
          clickFun: row => {
            openMaterialDialog(row);
          },
        },
        {
          name: "补料",
          type: "text",
          color: "#5EC7AB",
          showHide: row => !row.endOrder && !row.returned,
          clickFun: row => {
            openMaterialSupplementDialog(row);
          },
        },
        {
          name: "领料详情",
          type: "text",
          color: "#5EC7AB",
          clickFun: row => {
            openMaterialDetailDialog(row);
          },
        },
        {
          name: "打印领料单",
          type: "text",
          color: "#5EC7AB",
          showHide: row => !row.endOrder,
          clickFun: row => {
            handlePrint(row);
          },
        },
        {
          name: "生产追溯",
          type: "text",
          color: "#409eff",
          clickFun: row => {
            router.push({
              path: "/productionManagement/productionTraceability",
              query: {
                npsNo: row.npsNo,
                productName: row.productName,
                model: row.model,
              },
            });
          },
        },
        {
          name: "结束订单",
          type: "text",
          color: "red",
          showHide: row => !row.endOrder,
          clickFun: row => {
            handleEndOrder(row);
          },
        },
      ],
@@ -225,11 +471,13 @@
  const data = reactive({
    searchForm: {
      npsNo: "",
      customerName: "",
      salesContractNo: "",
      projectName: "",
      productCategory: "",
      specificationModel: "",
      productName: "",
      model: "",
      status: "",
    },
  });
  const { searchForm } = toRefs(data);
@@ -253,18 +501,18 @@
  // 添加表行类名方法
  const tableRowClassName = ({ row }) => {
    if (!row.deliveryDate) return '';
    if (row.isFh) return '';
    if (!row.planCompleteTime) return "";
    if (row.isFh) return "";
    const diff = row.deliveryDaysDiff;
    if (diff === 15) {
      return 'yellow';
      return "yellow";
    } else if (diff === 10) {
      return 'pink';
      return "pink";
    } else if (diff === 2) {
      return 'purple';
      return "purple";
    } else if (diff < 2) {
      return 'red';
      return "red";
    }
  };
@@ -277,10 +525,52 @@
    orderId: null,
    routeId: null,
  });
  const materialDialogVisible = ref(false);
  const currentMaterialOrder = ref(null);
  const materialDetailDialogVisible = ref(false);
  const currentMaterialDetailOrder = ref(null);
  const materialSupplementDialogVisible = ref(false);
  const currentMaterialSupplementOrder = ref(null);
  const openBindRouteDialog = async row => {
  // 打印相关
  const printOrderRow = ref(null);
  const printMaterialList = ref([]);
  const handlePrint = async row => {
    printOrderRow.value = row;
    proxy.$modal.loading("正在获取领料数据...");
    try {
      printMaterialList.value = [];
      const detailRes = await listMaterialPickingDetail(row.id);
      const detailList = Array.isArray(detailRes?.data)
        ? detailRes.data
        : detailRes?.data?.records || [];
      if (detailList.length > 0) {
        printMaterialList.value = detailList;
      }
      if (printMaterialList.value.length === 0) {
        proxy.$modal.msgWarning("暂无领料数据");
        return;
      }
      // 等待 DOM 更新后执行打印
      proxy.$nextTick(() => {
        setTimeout(() => {
          window.print();
        }, 800);
      });
    } catch (e) {
      console.error("获取领料数据失败:", e);
      proxy.$modal.msgError("获取领料数据失败");
    } finally {
      proxy.$modal.closeLoading();
    }
  };
  const openBindRouteDialog = async (row, type) => {
    bindForm.orderId = row.id;
    bindForm.routeId = null;
    bindForm.routeId = type === "add" ? null : row.processRouteCode;
    bindRouteDialogVisible.value = true;
    routeOptions.value = [];
    if (!row.productModelId) {
@@ -290,8 +580,8 @@
    }
    bindRouteLoading.value = true;
    try {
      const res = await listProcessRoute({ productModelId: row.productModelId });
      routeOptions.value = res.data || [];
      const res = await listPage({ productModelId: row.productModelId });
      routeOptions.value = res.data.records || [];
    } catch (e) {
      console.error("获取工艺路线列表失败:", e);
      proxy.$modal.msgError("获取工艺路线列表失败");
@@ -309,7 +599,7 @@
    try {
      await bindingRoute({
        id: bindForm.orderId,
        routeId: bindForm.routeId,
        technologyRoutingId: bindForm.routeId,
      });
      proxy.$modal.msgSuccess("绑定成功");
      bindRouteDialogVisible.value = false;
@@ -320,6 +610,35 @@
    } finally {
      bindRouteSaving.value = false;
    }
  };
  const openMaterialDialog = row => {
    currentMaterialOrder.value = row;
    materialDialogVisible.value = true;
  };
  const openMaterialDetailDialog = async row => {
    currentMaterialDetailOrder.value = row;
    materialDetailDialogVisible.value = true;
  };
  const openMaterialSupplementDialog = row => {
    currentMaterialSupplementOrder.value = row;
    materialSupplementDialogVisible.value = true;
  };
  const handleReset = () => {
    searchForm.value = {
      ...searchForm.value,
      npsNo: "",
      customerName: "",
      salesContractNo: "",
      projectName: "",
      productName: "",
      model: "",
      status: "",
    };
    handleQuery();
  };
  // 查询列表
@@ -349,10 +668,35 @@
    const params = { ...searchForm.value, ...page };
    params.entryDate = undefined;
    productOrderListPage(params)
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.data.records;
      .then(async res => {
        const records = res.data.records || [];
        // 为每个订单查询对应的工序进度数据
        const processPromises = records.map(async item => {
          if (item.npsNo) {
            try {
              const workOrderRes = await productWorkOrderPage({
                npsNo: item.npsNo,
                size: 100,
              });
              const workOrders = workOrderRes.data.records || [];
              // 按照工序顺序排序(如果有顺序字段,假设为 orderNum 或按返回顺序)
              // 转换为 processRouteStatus 格式
              const processRouteStatus = workOrders.map(wo => ({
                name: wo.operationName || "未知工序",
                percentage: wo.completionStatus > 100 ? 100 : wo.completionStatus,
              }));
              return { ...item, processRouteStatus };
            } catch (error) {
              console.error(`获取工单 ${item.npsNo} 进度失败:`, error);
              return { ...item, processRouteStatus: [] };
            }
          }
          return { ...item, processRouteStatus: [] };
        });
        tableData.value = await Promise.all(processPromises);
        page.total = res.data.total;
        tableLoading.value = false;
      })
      .catch(() => {
        tableLoading.value = false;
@@ -372,13 +716,16 @@
        path: "/productionManagement/processRouteItem",
        query: {
          id: data.id,
          bomId: data.orderBomId,
          processRouteCode: data.processRouteCode || "",
          productName: data.productName || "",
          model: data.model || "",
          bomNo: data.bomNo || "",
          productName: row.productName || "",
          model: row.model || "",
          bomNo: row.bomNo || "",
          description: data.description || "",
          quantity: row.quantity || 0,
          orderId,
          type: "order",
          editable: !row.endOrder,
        },
      });
    } catch (e) {
@@ -393,39 +740,65 @@
      query: {
        id: row.id,
        bomNo: row.bomNo || "",
        productName: row.productCategory || "",
        productModelName: row.specificationModel || "",
        productName: row.productName || "",
        productModelName: row.model || "",
        orderId: row.id,
        type: "order",
      },
    });
  };
  // 查看来源生产计划数据
  const showSourceData = row => {
    // 存储点击来源按钮时传递的row参数
    sourceRowData.value = row;
    // 调用API获取来源数据
    getProductOrderSource(row.id)
      .then(res => {
        if (res.code === 200) {
          // 直接存储返回的扁平化数据
          sourceTableData.value = res.data || [];
          sourcePage.total = sourceTableData.value.length;
          // 打开弹窗
          sourceDataDialogVisible.value = true;
        } else {
          proxy.$modal.msgError(res.msg || "获取来源数据失败");
        }
      })
      .catch(err => {
        proxy.$modal.msgError("获取来源数据失败");
        console.error(err);
      });
  };
  // 表格选择数据
  const handleSelectionChange = (selection) => {
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
  const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
      ids = selectedRows.value.map((item) => item.id);
      ids = selectedRows.value.map(item => item.id);
    } else {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
    ElMessageBox.confirm("是否退回该生产订单?", "退回", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    }).then(() => {
      delProductOrder(ids).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
    })
      .then(() => {
        console.log(ids, "ids");
        delProductOrder(ids).then(res => {
          proxy.$modal.msgSuccess("退回成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
    }).catch(() => {
      proxy.$modal.msg("已取消");
    });
  };
  // 导出
@@ -436,11 +809,35 @@
      type: "warning",
    })
      .then(() => {
        proxy.download("/productOrder/export", {...searchForm.value}, "生产订单.xlsx");
        proxy.download(
          "/productOrder/export",
          { ...searchForm.value },
          "生产订单.xlsx"
        );
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  // 结束订单
  const handleEndOrder = row => {
    ElMessageBox.confirm(`是否确认结束订单:${row.npsNo}?`, "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        const params = {
          id: row.id,
          endOrder: true,
        };
        updateProductOrder(params).then(() => {
          proxy.$modal.msgSuccess("结束订单成功");
          getList();
        });
      })
      .catch(() => {});
  };
  const handleConfirmRoute = () => {};
@@ -451,23 +848,177 @@
</script>
<style scoped lang="scss">
.search_form{
  align-items: start;
}
  .search_form {
    align-items: start;
  }
::v-deep .yellow {
  background-color: #FAF0DE;
}
  .action-buttons {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
  }
::v-deep .pink {
  background-color: #FAE1DE;
}
  :deep(.yellow) {
    background-color: #faf0de;
  }
::v-deep .red {
  background-color: #f80202;
}
  :deep(.pink) {
    background-color: #fae1de;
  }
::v-deep .purple{
  background-color: #F4DEFA;
}
  :deep(.red) {
    background-color: #f80202;
  }
  :deep(.purple) {
    background-color: #f4defa;
  }
  .table_list {
    margin-top: unset;
  }
  .process-progress-container {
    display: inline-flex;
    align-items: center;
    padding: 10px 0;
    white-space: nowrap;
    .process-step {
      display: flex;
      align-items: center;
      position: relative;
      .step-content {
        display: flex;
        flex-direction: column;
        align-items: center;
        z-index: 1;
        .step-circle {
          width: 36px;
          height: 36px;
          border-radius: 50%;
          border: 2px solid #409eff;
          display: flex;
          align-items: center;
          justify-content: center;
          background-color: #fff;
          margin-bottom: 4px;
          .step-percentage {
            font-size: 11px;
            font-weight: bold;
          }
          &.is-completed {
            border-color: #67c23a;
            .step-percentage {
              color: #67c23a;
            }
          }
        }
        .step-name {
          font-size: 12px;
          color: #606266;
          white-space: nowrap;
        }
      }
      .step-line {
        width: 30px;
        height: 1px;
        background-color: #dcdfe6;
        margin: 0 -2px;
        margin-top: -20px; // 向上偏移以对齐圆心
      }
    }
  }
</style>
<style lang="scss">
  .status-cell {
    font-weight: 600;
    color: #409eff;
    font-family: "Courier New", monospace;
    text-shadow: 0 1px 2px rgba(64, 158, 255, 0.2);
  }
  .source-table-container {
    margin-top: 20px;
  }
  .source-data-cards-container {
    display: flex;
    flex-direction: column;
    gap: 16px;
    max-height: 500px;
    overflow-y: auto;
    padding: 10px;
    background-color: #f5f7fa;
    border-radius: 4px;
    padding-bottom: 20px;
    .source-data-card {
      background: #fff;
      border-radius: 8px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      overflow: hidden;
      .card-body {
        padding: 20px;
        .info-grid {
          display: grid;
          grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
          gap: 16px;
          .info-item {
            display: flex;
            flex-direction: column;
            .info-label {
              font-size: 12px;
              color: #909399;
              margin-bottom: 4px;
              font-weight: 500;
            }
            .info-value {
              font-size: 14px;
              color: #303133;
              font-weight: 500;
            }
          }
        }
      }
    }
  }
  .applyno-summary1 {
    padding: 16px 20px;
    background: #f5f7fa;
    border-bottom: 1px solid #e4e7ed;
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    .summary-item {
      display: flex;
      align-items: center;
      margin-right: 20px;
      .summary-label {
        font-size: 13px;
        color: #909399;
        margin-right: 8px;
        font-weight: 500;
      }
      .summary-value {
        font-size: 14px;
        color: #303133;
        font-weight: 500;
      }
    }
  }
</style>