gongchunyi
2026-06-02 cd756c237631bc6a1324029818d85a94f725853d
Merge branch 'dev_NEW_pro' into dev_pro_山西_晋和园

# Conflicts:
# multiple/config.json
已添加5个文件
已修改8个文件
332 ■■■■■ 文件已修改
multiple/assets/favicon/RFSYLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/favicon/RFSYfavicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/favicon/XHKSfavicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/logo/RFSYLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/logo/XHKSLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/sealManagement/index.vue 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-list/approveListConstants.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionPlan/productionPlan/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/favicon/RFSYLogo.png
multiple/assets/favicon/RFSYfavicon.ico
multiple/assets/favicon/XHKSfavicon.ico
multiple/assets/logo/RFSYLogo.png
multiple/assets/logo/XHKSLogo.png
src/views/collaborativeApproval/sealManagement/index.vue
@@ -7,7 +7,6 @@
        </div>
      </template>
   <!-- 用印申请管理 -->
        <div class="tab-content">
            <el-row :gutter="20" class="mb-20 ">
@@ -177,6 +176,7 @@
const sealFormRef = ref()
const userList = ref([])
const sealForm = reactive({
  id: null,
  applicationNum: '',
  title: '',
  sealType: '',
@@ -241,9 +241,9 @@
// 用印申请表格列配置(需在 getStatusText/getSealTypeText 等之后定义)
const sealTableColumn = ref([
  { label: '申请编号', prop: 'applicationNum',},
  { label: '申请编号', prop: 'applicationNum' },
  { label: '申请标题', prop: 'title', showOverflowTooltip: true },
  { label: '申请人', prop: 'createUserName', },
  { label: '申请人', prop: 'createUserName' },
  { label: '所属部门', prop: 'department', width: 150 },
  {
    label: '用印类型',
@@ -261,22 +261,28 @@
    formatData: (v) => getStatusText(v),
    formatType: (v) => getStatusType(v)
  },
  { label: '审批人', prop: 'approveUserName', width: 100 },
  {
    dataType: 'action',
    label: '操作',
    width: 200,
    width: 250,
    fixed: 'right',
    align: 'center',
    operation: [
      {
        name: '审批',
        clickFun: (row) => approveSeal(row),
        showHide: (row) => row.status === 'pending'
        showHide: (row) => row.status === 'pending' && Number(userStore.id) === row.approveUserId
      },
      {
        name: '拒绝',
        clickFun: (row) => rejectSeal(row),
        showHide: (row) => row.status === 'pending'
        showHide: (row) => row.status === 'pending' && Number(userStore.id) === row.approveUserId
      },
      {
        name: '重新申请',
        clickFun: (row) => reapplySeal(row),
        showHide: (row) => row.status === 'rejected' && Number(userStore.id) === row.createUser
      },
            { name: '详情', clickFun: (row) => viewSealDetail(row) }
    ]
@@ -287,8 +293,6 @@
const searchSealApplications = () => {
  page.current=1
  getSealApplicationList()
  // ElMessage.success('搜索完成')
}
// 重置印章申请搜索
const resetSealSearch = () => {
@@ -297,16 +301,36 @@
  sealSearchForm.applicationNum = ''
  searchSealApplications()
}
// 重新申请用印
const reapplySeal = (row) => {
  // 预填表单数据
  Object.assign(sealForm, {
    id: row.id,
    applicationNum: row.applicationNum,
    title: row.title,
    sealType: row.sealType,
    reason: row.reason,
    approveUserId: row.approveUserId,
    urgency: row.urgency || 'normal',
    status: 'pending',
    storageBlobDTOs: row.storageBlobVOList || []
  })
  showSealApplyDialog.value = true
}
// 提交用印申请
const submitSealApplication = async () => {
  try {
    await sealFormRef.value.validate()
    addSealApplication(sealForm).then(res => {
    const request = sealForm.id ? updateSealApplication : addSealApplication
    request(sealForm).then(res => {
      if(res.code == 200){
        ElMessage.success('申请提交成功')
        ElMessage.success(sealForm.id ? '重新申请成功' : '申请提交成功')
        closeSealApplyDialog()
        getSealApplicationList()
        Object.assign(sealForm, {
          id: null,
        applicationNum: '',
        title: '',
        sealType: '',
@@ -320,14 +344,15 @@
    }).catch(err => {
      console.log(err.msg)
    })
  } catch (error) {
  }
}
// 关闭用印申请对话框
const closeSealApplyDialog = () => {
  // 清空表单数据
  Object.assign(sealForm, {
    id: null,
    applicationNum: '',
    title: '',
    sealType: '',
@@ -399,6 +424,7 @@
    inputErrorMessage: '拒绝原因不能为空'
  }).then(({ value }) => {
    row.status = 'rejected'
    row.reason = value
    updateSealApplication(row).then(res => {
      if(res.code == 200){
        ElMessage.success('已拒绝申请')
src/views/officeProcessAutomation/ApproveManage/approve-list/approveListConstants.js
@@ -457,6 +457,9 @@
    currentNodeIndex: 0,
    approvalRecords,
    rejectReason: approvalRecords.find(r => r.result === "rejected")?.opinion || "",
    purchaseContractNumber: row.purchaseContractNumber || "",
    quotationNo: row.quotationNo || "",
    shippingNo: row.shippingNo || "",
  };
}
src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
@@ -35,9 +35,116 @@
    </div>
    <div class="detail-block">
      <div class="detail-block-title">填报内容</div>
      <FormPayloadFields :fields="formResolved.fields"
      <!-- 默认表单展示 -->
      <FormPayloadFields v-if="!isSpecialApprovalType"
                         :fields="formResolved.fields"
                         :form-payload="formResolved.formPayload"
                         readonly />
      <!-- 发货审批详情 -->
      <template v-else-if="row.businessType === 7">
        <div v-if="detailData.shippingInfo" class="shipment-detail">
          <el-divider content-position="left">发货详情</el-divider>
          <el-descriptions :column="2" border>
            <el-descriptions-item label="销售订单">{{ detailData.shippingInfo.salesContractNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货订单号">{{ detailData.shippingInfo.shippingNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="客户名称">{{ detailData.shippingInfo.customerName || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货类型">{{ detailData.shippingInfo.type || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货日期">{{ detailData.shippingInfo.shippingDateDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="审核状态">{{ detailData.shippingInfo.status || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货车牌号">{{ detailData.shippingInfo.shippingCarNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="快递公司">{{ detailData.shippingInfo.expressCompany || "--" }}</el-descriptions-item>
            <el-descriptions-item label="快递单号" :span="2">{{ detailData.shippingInfo.expressNumber || "--" }}</el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.shippingProductDetailDtoList.length" style="margin-top: 20px;">
            <h4>产品明细</h4>
            <el-table :data="detailData.shippingProductDetailDtoList"
                      border
                      size="small"
                      style="width: 100%">
              <el-table-column label="批号" prop="batchNo" min-width="160" show-overflow-tooltip />
              <el-table-column label="产品名称" prop="productName" min-width="160" show-overflow-tooltip />
              <el-table-column label="规格型号" prop="specificationModel" min-width="160" show-overflow-tooltip />
              <el-table-column label="发货数量" prop="deliveryQuantity" min-width="120" align="center" />
            </el-table>
          </div>
        </div>
      </template>
      <!-- 采购审批详情 -->
      <template v-else-if="row.businessType === 5">
        <div v-if="detailData" class="procurement-detail">
          <el-divider content-position="left">采购详情</el-divider>
          <el-descriptions :column="2" border>
            <el-descriptions-item label="采购合同号">{{ detailData.purchaseContractNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="供应商名称">{{ detailData.supplierName || "--" }}</el-descriptions-item>
            <el-descriptions-item label="项目名称">{{ detailData.projectName || "--" }}</el-descriptions-item>
            <el-descriptions-item label="销售合同号">{{ detailData.salesContractNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="签订日期">{{ detailData.executionDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="录入日期">{{ detailData.entryDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="付款方式">{{ detailData.paymentMethod || "--" }}</el-descriptions-item>
            <el-descriptions-item label="合同金额" :span="2">
              <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
                ¥{{ Number(detailData.contractAmount ?? 0).toFixed(2) }}
              </span>
            </el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.productData.length" style="margin-top: 20px;">
            <h4>产品明细</h4>
            <el-table :data="detailData.productData"
                      border
                      style="width: 100%">
              <el-table-column prop="productCategory" label="产品名称" />
              <el-table-column prop="specificationModel" label="规格型号" />
              <el-table-column prop="unit" label="单位" />
              <el-table-column prop="quantity" label="数量" />
              <el-table-column prop="taxInclusiveUnitPrice" label="含税单价">
                <template #default="scope">¥{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template>
              </el-table-column>
              <el-table-column prop="taxInclusiveTotalPrice" label="含税总价">
                <template #default="scope">¥{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
              </el-table-column>
            </el-table>
          </div>
        </div>
      </template>
      <!-- 报价审批详情 -->
      <template v-else-if="row.businessType === 6">
        <div v-if="detailData" class="quotation-detail">
          <el-divider content-position="left">报价详情</el-divider>
          <el-descriptions :column="2" border>
            <el-descriptions-item label="报价单号">{{ detailData.quotationNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="客户名称">{{ detailData.customer || "--" }}</el-descriptions-item>
            <el-descriptions-item label="业务员">{{ detailData.salesperson || "--" }}</el-descriptions-item>
            <el-descriptions-item label="报价日期">{{ detailData.quotationDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="有效期至">{{ detailData.validDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="付款方式">{{ detailData.paymentMethod || "--" }}</el-descriptions-item>
            <el-descriptions-item label="报价总额" :span="2">
              <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
                ¥{{ Number(detailData.totalAmount ?? 0).toFixed(2) }}
              </span>
            </el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.products.length" style="margin-top: 20px;">
            <h4>产品明细</h4>
            <el-table :data="detailData.products"
                      border
                      style="width: 100%">
              <el-table-column prop="product" label="产品名称" />
              <el-table-column prop="specification" label="规格型号" />
              <el-table-column prop="unit" label="单位" />
              <el-table-column prop="unitPrice" label="单价">
                <template #default="scope">¥{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template>
              </el-table-column>
            </el-table>
          </div>
          <div v-if="detailData.remark" style="margin-top: 20px;">
            <h4>备注</h4>
            <p>{{ detailData.remark }}</p>
          </div>
        </div>
      </template>
    </div>
    <div v-if="attachmentList.length"
         class="detail-block">
@@ -86,10 +193,22 @@
  const props = defineProps({
    row: { type: Object, default: () => ({}) },
    detailData: { type: Object, default: () => ({}) },
  });
  const formResolved = computed(() => resolveInstanceFormFields(props.row));
  // 是否为特殊审批类型(采购、发货、报价)
  const isSpecialApprovalType = computed(() => {
    return [5, 7, 6].includes(props.row.businessType);
  });
  // 详情数据(直接使用传入的 detail-data 参数)
  const detailData = computed(() => {
    return props.detailData || {};
  });
  const attachmentList = computed(() => {
    const list = props.row.storageBlobVOList || props.row.storageBlobDTOs || [];
    return Array.isArray(list) ? list : [];
src/views/officeProcessAutomation/ApproveManage/approve-list/index.vue
@@ -172,7 +172,7 @@
      class="approve-detail-dialog"
    >
      <div class="approve-detail-body">
        <ApproveDetailPanel :row="detailRow" />
        <ApproveDetailPanel :row="detailRow" :detail-data="detailData" />
        <div class="detail-block">
          <div class="detail-block-title">
            审批流程({{ detailRow.tasks?.length || detailRow.flowNodes?.length || 0 }} 项)
@@ -290,7 +290,7 @@
      destroy-on-close
      @closed="approveOpinion = ''"
    >
      <ApproveDetailPanel :row="approveDialog.row" />
      <ApproveDetailPanel :row="approveDialog.row" :detail-data="detailData" />
      <div class="detail-block mt16">
        <div class="detail-block-title">
          审批流程({{ approveDialog.row?.tasks?.length || approveDialog.row?.flowNodes?.length || 0 }} 项)
@@ -369,6 +369,7 @@
  tableColumn,
  detailDialog,
  detailRow,
  detailData,
  reimburseDialog,
  approveDialog,
  approveOpinion,
src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js
@@ -10,6 +10,9 @@
  saveApprovalInstance,
  updateApprovalInstance,
} from "@/api/officeProcessAutomation/approvalInstance.js";
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
import { getDeliveryDetailByShippingNo } from "@/api/salesManagement/deliveryLedger.js";
import useUserStore from "@/store/modules/user";
import { Search } from "@element-plus/icons-vue";
import { ElMessage, ElMessageBox } from "element-plus";
@@ -77,6 +80,7 @@
  const detailDialog = reactive({ visible: false });
  const detailRow = ref({});
  const detailData = ref({});
  const approveDialog = reactive({ visible: false, row: null });
  const approveOpinion = ref("");
@@ -220,7 +224,7 @@
        fetchBusinessTypeOptions(),
        listApprovalTemplate(TEMPLATE_TYPE_CUSTOM),
      ]);
      submitBusinessTypeOptions.value = typeOptions;
      submitBusinessTypeOptions.value = typeOptions.filter((x) => ![5, 6, 7].includes(x.value));
      allSubmitTemplates.value = unwrapTemplateList(customRes)
        .filter((row) => mapEnabledFromApi(row.enabled))
        .map(mapSubmitTemplateCard);
@@ -288,11 +292,46 @@
      await openReimburseDetail(row, "detail");
      return;
    }
    detailRow.value = { ...row };
    // 报价审批:用审批事由字段承载的"报价单号"去查报价列表
    if (row.businessType === 6) {
      const quotationNo = row?.quotationNo;
      if (quotationNo) {
        const res = await getQuotationList({ quotationNo });
        const records = res?.data?.records || [];
        detailData.value = records[0] || {};
      }
    }
    // 采购审批:用审批事由字段承载的"采购合同号"去查采购详情
    else if (row.businessType === 5) {
      const purchaseContractNumber = row?.purchaseContractNumber;
      if (purchaseContractNumber) {
        const res = await getPurchaseByCode({ purchaseContractNumber });
        detailData.value = res || {};
      }
    }
    // 发货审批:用审批事由字段承载的"发货单号"去查发货详情
    else if (row.businessType === 7) {
      const shippingNo = row?.shippingNo;
      if (shippingNo) {
        const res = await getDeliveryDetailByShippingNo({ shippingNo });
        detailData.value = res?.data || res || {};
      }
    }
    // 其他审批类型
    else {
      detailData.value = {};
    }
    detailDialog.visible = true;
  }
  async function openApprove(row) {
    if (inferReimburseModuleKeyFromInstance(row)) {
      approveOpinion.value = "";
      await openReimburseDetail(row, "approve");
@@ -300,6 +339,38 @@
    }
    approveDialog.row = { ...row };
    approveOpinion.value = "";
    // 报价审批:用审批事由字段承载的"报价单号"去查报价列表
    if (row.businessType === 6) {
      const quotationNo = row?.quotationNo;
      if (quotationNo) {
        const res = await getQuotationList({ quotationNo });
        const records = res?.data?.records || [];
        detailData.value = records[0] || {};
      }
    }
    // 采购审批:用审批事由字段承载的"采购合同号"去查采购详情
    else if (row.businessType === 5) {
      const purchaseContractNumber = row?.purchaseContractNumber;
      if (purchaseContractNumber) {
        const res = await getPurchaseByCode({ purchaseContractNumber });
        detailData.value = res || {};
      }
    }
    // 发货审批:用审批事由字段承载的"发货单号"去查发货详情
    else if (row.businessType === 7) {
      const shippingNo = row?.shippingNo;
      if (shippingNo) {
        const res = await getDeliveryDetailByShippingNo({ shippingNo });
        detailData.value = res?.data || res || {};
      }
    }
    // 其他审批类型
    else {
      detailData.value = {};
    }
    approveDialog.visible = true;
  }
@@ -586,6 +657,7 @@
    tableColumn,
    detailDialog,
    detailRow,
    detailData,
    reimburseDialog,
    approveDialog,
    approveOpinion,
src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue
@@ -380,23 +380,18 @@
      <template v-if="detailAttachments.length">
        <el-tag
        <div class="detail-attachment-list">
          <div
          v-for="(f, i) in detailAttachments"
          :key="i"
          class="detail-attachment-tag"
          type="info"
          effect="plain"
            class="detail-attachment-item"
            @click="openAttachmentFile(f)"
        >
          {{ attachmentDisplayName(f) }}
        </el-tag>
            <el-icon class="attachment-icon"><Document /></el-icon>
            <span class="attachment-name">{{ attachmentDisplayName(f) }}</span>
            <el-icon class="attachment-download"><Download /></el-icon>
          </div>
        </div>
      </template>
@@ -422,7 +417,7 @@
<script setup>
import { ArrowRight, Plus, RefreshRight } from "@element-plus/icons-vue";
import { ArrowRight, Document, Download, Plus, RefreshRight } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
@@ -525,6 +520,14 @@
}
function openAttachmentFile(file) {
  const url = file?.url || file?.previewURL || file?.downloadURL || file?.previewUrl || "";
  if (url) {
    window.open(url, "_blank");
  } else {
    ElMessage.warning("无法打开该附件");
  }
}
function unwrapArray(payload) {
@@ -795,10 +798,40 @@
}
.detail-attachment-tag {
.detail-attachment-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
  margin: 0 8px 8px 0;
.detail-attachment-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  background: var(--el-fill-color-light);
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.2s;
}
.detail-attachment-item:hover {
  background: var(--el-fill-color);
}
.attachment-icon {
  font-size: 16px;
  color: var(--el-text-color-regular);
}
.attachment-name {
  font-size: 14px;
  color: var(--el-text-color-primary);
}
.attachment-download {
  font-size: 14px;
  color: var(--el-text-color-secondary);
}
.text-muted {
src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js
@@ -214,10 +214,21 @@
    });
  }
  function openFormDialog(mode, row) {
  async function openFormDialog(mode, row) {
    formDialog.mode = mode;
    formDialog.title = mode === "add" ? "新建审批模板" : "编辑审批模板";
    if (mode === "edit" && row?.id) {
      // 编辑时先查询详情获取完整数据(包含附件)
      try {
        const res = await getApprovalTemplateDetail(row.id);
        const detailData = mapTemplateFromApi(unwrapTemplateDetail(res));
        resetForm(detailData);
      } catch {
        resetForm(row);
      }
    } else {
    resetForm(mode === "edit" ? row : null);
    }
    formDialog.visible = true;
  }
src/views/productionPlan/productionPlan/index.vue
@@ -775,6 +775,7 @@
    mergeForm.totalAssignedQuantity = totalAssignedQuantity;
    mergeForm.planCompleteTime = firstRow.requiredDate || "";
    mergeForm.productId = firstRow.productId || "";
    mergeForm.createTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
    mergeForm.ids = selectedRows.value.map(row => row.id);
    // 打开弹窗