Browse Source

fix: 更新路由配置

xiaweibo 1 month ago
parent
commit
de2377a462

+ 15 - 1
src/router/routers/production-safety-router/risk-identification-and-control.ts

@@ -661,7 +661,7 @@ const riskIdentificationAndControlRoutes: RouteComponent[] = [{
       parentId: 90014,
       name: 'workInjuryApplyManageAdmin',
       path: 'work-injury-apply-manage-admin',
-      component: '/production-safety/risk-identification-and-control/work-injury-apply-manage/listAdmin',
+      component: '/production-safety/risk-identification-and-control/work-injury-apply-manage-admin/listAdmin',
       meta: {
         title: '工伤认定申请(管理员)',
         icon: 'OverviewIcon',
@@ -670,6 +670,20 @@ const riskIdentificationAndControlRoutes: RouteComponent[] = [{
         noCache: false,
       }
     },
+    {
+      id: 93037,
+      parentId: 90014,
+      name: 'workInjuryApplyManageAdminItem',
+      path: 'work-injury-apply-manage-admin-item',
+      component: '/production-safety/risk-identification-and-control/work-injury-apply-manage-admin/Item',
+      meta: {
+        title: '工伤认定申请详情(管理员)',
+        icon: 'OverviewIcon',
+        isRoot: false,
+        hidden: false,
+        noCache: false,
+      }
+    },
     {
       id: 930038,
       parentId: 90014,

+ 46 - 0
src/views/production-safety/risk-identification-and-control/work-injury-apply-manage-admin/Item.vue

@@ -0,0 +1,46 @@
+<template>
+  <div class="safety-platform-container">
+    <header class="safety-platform-container__header">
+      <BreadcrumbBack />
+      <span class="breadcrumb-title">{{ headerTitle }}</span>
+    </header>
+    <Detail />
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { computed } from 'vue';
+  import { useRoute } from 'vue-router';
+  import BreadcrumbBack from '@/components/BreadcrumbBack.vue';
+  import Detail from './components/detail.vue';
+
+  const route = useRoute();
+  const operate = route.query.operate as string;
+
+  const headerTitle = computed(() => {
+    switch (operate) {
+      case 'inventory-create':
+        return '新增工伤认定申请';
+      case 'inventory-edit':
+        return '编辑工伤认定申请';
+      case 'inventory-view':
+        return '查看工伤认定申请';
+      case 'inventory-audit':
+        return '审核工伤认定申请';
+      default:
+        return '工伤认定申请详情';
+    }
+  });
+</script>
+
+<style scoped lang="scss">
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+
+  .safety-platform-container__header {
+    flex-direction: row !important;
+    justify-content: flex-start !important;
+    gap: 8px !important;
+  }
+</style>
+

+ 941 - 0
src/views/production-safety/risk-identification-and-control/work-injury-apply-manage-admin/components/detail.vue

@@ -0,0 +1,941 @@
+<template>
+  <main class="safety-platform-container__main">
+    <el-alert
+      v-if="rejectReason && (Number(approvalStatus) === 3)"
+      type="error"
+      :title="'不通过原因:' + rejectReason"
+      show-icon
+      class="detail-reject-alert"
+    />
+    <div class="detail-reject-alert">
+      <div class="detail-reject-alert-name">
+        填表说明:
+      </div>
+      <div class="detail-reject-alert-content">
+        <div>
+          <div>
+            1.用蓝、黑色钢笔或者签字笔填写,字体工整清楚,可打印。
+          </div>
+          <div>
+            2.单位名称、法定代表人(负责人)栏,应按提供的有效证明复印件上载明事项填写。
+            <span class="more-text-btn" @click="moreText = !moreText" v-if="!moreText">
+              {{ moreText ? '收起' : '展开'}}
+              <el-icon><CaretBottom /></el-icon>
+            </span>
+          </div>
+        </div>
+        <div v-if="moreText">
+          <div>
+            3.受伤害从业人员姓名、身份证号码栏,应按提供的受伤害从业人员身份证明复印件上载明事项填写。
+          </div>
+          <div>
+            4.参加工作时间栏,应填写受伤害从业人员首次参加工作的时间。
+          </div>
+          <div>
+            5.学历栏,按最高学历且只能选择一项填写。
+          </div>
+          <div>
+            6.职业或者工种栏,应按发生事故伤害或者被诊断为职业病时从事的职业或者工种填写。
+          </div>
+          <div>
+            7.受伤部位栏,最多可以选择五项填写,超过五项的填写伤最重的五项。受伤程度栏,根据出院小结和诊断结论填写,可填写如骨折、截肢等程度性表述。
+          </div>
+          <div>
+            8.职业病名称栏,应按职业病诊断书载明的填写。
+          </div>
+          <div>
+            9.事故伤害(患职业病)经过简述栏,发生事故伤害的,应写清事故的地点,当时所从事的工作,受伤原因以及伤害部位和具体程度,还应写明是否有目击证人;患职业病的,应写明接触有毒有害作业的过程。
+          </div>
+          <div>
+            10.申请事项一栏主要记述本次申请的目的。
+          </div>
+          <div>
+            11.申请人为个人的应当在表格下方签名,申请人为单位的应当在表格下方盖单位公章。
+            <span class="more-text-btn" @click="moreText = !moreText" v-if="moreText">
+              {{ moreText ? '收起' : '展开'}}
+              <el-icon><CaretTop /></el-icon>
+            </span>
+          </div>
+        </div>
+        <span class="detail-reject-alert-content-download" @click="downloadFile('./skyeye-file-upload/sfysecurity/TEMPLATE/施工证申请表.doc', '事故报告模板')">
+            事故报告  下载
+        </span>
+        <span class="detail-reject-alert-content-download" @click="downloadFile('./skyeye-file-upload/sfysecurity/TEMPLATE/施工证申请表.doc', '委托书模板')">
+            委托书  下载
+        </span>
+        <span class="detail-reject-alert-content-download" @click="downloadFile('./skyeye-file-upload/sfysecurity/TEMPLATE/施工证申请表.doc', '地址确认书模板')">
+            地址确认书  下载
+        </span>
+        <span class="detail-reject-alert-content-download" @click="downloadFile('./skyeye-file-upload/sfysecurity/TEMPLATE/施工证申请表.doc', '申请表模板')">
+            申请表  下载
+        </span>
+      </div>
+    </div>
+    <BasicForm
+      ref="basicFormRef"
+      :formData="ruleFormData"
+      :formRules="isViewMode ? undefined : formRules"
+      :formConfig="computedFormConfig"
+    >
+      <template #approvalTemplateId>
+        <el-select
+          class="select-box--item__select"
+          v-model="ruleFormData.approvalTemplateId"
+          placeholder="审批流程"
+          filterable
+          :disabled="isViewMode || isAuditMode"
+          popper-class="el-scrollbar--custom"
+        >
+          <el-option v-for="item in approvalList" :key="item.id" :label="item.templateName" :value="item.id" />
+        </el-select>
+      </template>
+      <template #reviewDepartmentId>
+        <el-cascader
+          v-model="ruleFormData.departmentCode"
+          ref="cascaderRef" 
+          :options="firstLevelDepts"
+          :props="cascaderProp"
+          :show-all-levels="false"
+          placeholder="部门名称"
+          filterable
+          :disabled="isViewMode || isAuditMode"
+          @change="handleChangeDept"
+        />
+      </template>
+
+      <template #accidentReport>
+        <UploadFiles
+          v-if="!isViewMode && !isAuditMode"
+          label="上传事故报告"
+          :maxCount="1"
+          :file-list="accidentCertUrl"
+          :disabled="isViewMode || isAuditMode"
+          @uploadSuccess="handleAccidentReportUploadSuccess"
+        />
+        <div class="file-list" v-else>
+          <div v-if="accidentCertUrl && accidentCertUrl.length > 0">
+            <div class="file-item" v-for="file in accidentCertUrl" :key="file.fileId">
+              <span class="file-item--name">{{ file.fileName }}</span>
+              <div class="file-item--footer">
+                <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
+                  >预览</el-button
+                >
+                <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
+                  >下载</el-button
+                >
+              </div>
+            </div>
+          </div>
+          <div v-else class="no-attachment">暂无附件</div>
+        </div>
+      </template>
+
+      <template #powerOfAttorney>
+        <UploadFiles
+          v-if="!isViewMode && !isAuditMode"
+          label="上传委托书"
+          :maxCount="1"
+          :file-list="powerAttorneyUrl"
+          :disabled="isViewMode || isAuditMode"
+          @uploadSuccess="handlePowerOfAttorneyUploadSuccess"
+        />
+        <div class="file-list" v-else>
+          <div v-if="powerAttorneyUrl && powerAttorneyUrl.length > 0">
+            <div class="file-item" v-for="file in powerAttorneyUrl" :key="file.fileId">
+              <span class="file-item--name">{{ file.fileName }}</span>
+              <div class="file-item--footer">
+                <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
+                  >预览</el-button
+                >
+                <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
+                  >下载</el-button
+                >
+              </div>
+            </div>
+          </div>
+          <div v-else class="no-attachment">暂无附件</div>
+        </div>
+      </template>
+      <template #addressConfirmation>
+        <UploadFiles
+          v-if="!isViewMode && !isAuditMode"
+          label="上传地址确认书"
+          :maxCount="1"
+          :file-list="addressConfirmUrl"
+          :disabled="isViewMode || isAuditMode"
+          @uploadSuccess="handleAddressConfirmationUploadSuccess"
+        />
+        <div class="file-list" v-else>
+          <div v-if="addressConfirmUrl && addressConfirmUrl.length > 0">
+            <div class="file-item" v-for="file in addressConfirmUrl" :key="file.fileId">
+              <span class="file-item--name">{{ file.fileName }}</span>
+              <div class="file-item--footer">
+                <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
+                  >预览</el-button
+                >
+                <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
+                  >下载</el-button
+                >
+              </div>
+            </div>
+          </div>
+          <div v-else class="no-attachment">暂无附件</div>
+        </div>
+      </template>
+      <template #applicationForm>
+        <UploadFiles
+          v-if="!isViewMode && !isAuditMode"
+          label="上传申请表"
+          :maxCount="1"
+          :file-list="applicationFormUrl"
+          :disabled="isViewMode || isAuditMode"
+          @uploadSuccess="handleApplicationFormUploadSuccess"
+        />
+        <div class="file-list" v-else>
+          <div v-if="applicationFormUrl && applicationFormUrl.length > 0">
+            <div class="file-item" v-for="file in applicationFormUrl" :key="file.fileId">
+              <span class="file-item--name">{{ file.fileName }}</span>
+              <div class="file-item--footer">
+                <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
+                  >预览</el-button
+                >
+                <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
+                  >下载</el-button
+                >
+              </div>
+            </div>
+          </div>
+          <div v-else class="no-attachment">暂无附件</div>
+        </div>
+      </template>
+      <template #idCard>
+        <UploadFiles
+          v-if="!isViewMode && !isAuditMode"
+          label="上传身份证正反面"
+          :maxCount="1"
+          :file-list="idCardUrl"
+          :disabled="isViewMode || isAuditMode"
+          @uploadSuccess="handleIdCardUploadSuccess"
+        />
+        <div class="file-list" v-else>
+          <div v-if="idCardUrl && idCardUrl.length > 0">
+            <div class="file-item" v-for="file in idCardUrl" :key="file.fileId">
+              <span class="file-item--name">{{ file.fileName }}</span>
+              <div class="file-item--footer">
+                <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
+                  >预览</el-button
+                >
+                <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
+                  >下载</el-button
+                >
+              </div>
+            </div>
+          </div>
+          <div v-else class="no-attachment">暂无附件</div>
+        </div>
+      </template>
+      <template #laborContract>
+        <UploadFiles
+          v-if="!isViewMode && !isAuditMode"
+          label="上传劳动合同"
+          :maxCount="1"
+          :file-list="laborContractUrl"
+          :disabled="isViewMode || isAuditMode"
+          @uploadSuccess="handleLaborContractUploadSuccess"
+        />
+        <div class="file-list" v-else>
+          <div v-if="laborContractUrl && laborContractUrl.length > 0">
+            <div class="file-item" v-for="file in laborContractUrl" :key="file.fileId">
+              <span class="file-item--name">{{ file.fileName }}</span>
+              <div class="file-item--footer">
+                <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
+                  >预览</el-button
+                >
+                <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
+                  >下载</el-button
+                >
+              </div>
+            </div>
+          </div>
+          <div v-else class="no-attachment">暂无附件</div>
+        </div>
+      </template>
+      <template #initialMedicalCertificate>
+        <UploadFiles
+          v-if="!isViewMode && !isAuditMode"
+          label="上传初次医疗证明"
+          :maxCount="1"
+          :file-list="initialMedicalCertUrl"
+          :disabled="isViewMode || isAuditMode"
+          @uploadSuccess="handleInitialMedicalCertificateUploadSuccess"
+        />
+        <div class="file-list" v-else>
+          <div v-if="initialMedicalCertUrl && initialMedicalCertUrl.length > 0">
+            <div class="file-item" v-for="file in initialMedicalCertUrl" :key="file.fileId">
+              <span class="file-item--name">{{ file.fileName }}</span>
+              <div class="file-item--footer">
+                <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
+                  >预览</el-button
+                >
+                <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
+                  >下载</el-button
+                >
+              </div>
+            </div>
+          </div>
+          <div v-else class="no-attachment">暂无附件</div>
+        </div>
+      </template>
+      <template #agentIdCard>
+        <UploadFiles
+          v-if="!isViewMode && !isAuditMode"
+          label="上传被委托人员身份证正反面"
+          :maxCount="1"
+          :file-list="trusteeIdCardUrl"
+          :disabled="isViewMode || isAuditMode"
+          @uploadSuccess="handleAgentIdCardUploadSuccess"
+        />
+        <div class="file-list" v-else>
+          <div v-if="trusteeIdCardUrl && trusteeIdCardUrl.length > 0">
+            <div class="file-item" v-for="file in trusteeIdCardUrl" :key="file.fileId">
+              <span class="file-item--name">{{ file.fileName }}</span>
+              <div class="file-item--footer">
+                <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
+                  >预览</el-button
+                >
+                <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
+                  >下载</el-button
+                >
+              </div>
+            </div>
+          </div>
+          <div v-else class="no-attachment">暂无附件</div>
+        </div>
+      </template>
+      <template #status>
+        <el-radio-group v-model="ruleFormData.status" :disabled="isViewMode">
+          <el-radio label="ENABLE">启用</el-radio>
+          <el-radio label="DISABLE">禁用</el-radio>
+        </el-radio-group>
+      </template>
+    </BasicForm>
+    <PreviewOnline ref="previewOnlineRef" />
+    <BasicDialog ref="basicDialogRef" title="提交审批" @refresh="closeDialog">
+      <template #form>
+        <div class="form">
+          <el-form ref="approvalFormRef" :model="approvalForm">
+            <!-- <el-form-item label="审批描述:" label-position="top">
+              <el-input v-model="approvalForm.description" placeholder="请输入审批描述" type="textarea" />
+            </el-form-item> -->
+            <div class="form-item">
+              <span>审批流程:</span>
+              <template v-for="item in approvalNodeList" :key="item.id">
+                <el-form-item
+                  :label="`第${item.approvalOrder}步:${item.nodeDescription}(${APPROVAL_TYPE_MAP[item.approvalType]})`"
+                  label-position="top"
+                  :prop="item.approverType !== APPROVER_TYPE.FIX ? `approvers.${item.id}` : ''"
+                  :rules="{ required: true, message: '请选择审批人员', trigger: 'change' }"
+                >
+                  <el-input
+                    v-if="item.approverType === APPROVER_TYPE.FIX"
+                    :model-value="item.approverInfoList.map((info) => info.approverName).join(',')"
+                    disabled
+                  ></el-input>
+                  <el-select
+                    v-else
+                    v-model="approvalForm.approvers[item.id]"
+                    placeholder="请选择审批人员"
+                    value-key="id"
+                    filterable
+                    remote
+                    collapse-tags
+                    collapse-tags-tooltip
+                    :max-collapse-tags="2"
+                    :remote-method="remoteMethod"
+                    :loading="loading"
+                    multiple
+                  >
+                    <el-option
+                      v-for="option in userOptions"
+                      :key="option.id"
+                      :label="`${option.realname}(${option.username})${option.deptName}`"
+                      :value="option.id"
+                    />
+                  </el-select>
+                </el-form-item>
+              </template>
+            </div>
+          </el-form>
+        </div>
+      </template>
+      <template #footer>
+        <el-button type="primary" @click="handleSubmitApproval">提交</el-button>
+        <el-button @click="basicDialogRef.closeDialog">取消</el-button>
+      </template>
+    </BasicDialog>
+    <!-- 审核不通过原因 -->
+    <el-dialog
+      v-model="showRejectDialog"
+      title="审核不通过"
+      width="400px"
+      destroy-on-close
+      @close="rejectReason = ''"
+    >
+      <el-radio-group v-model="rejectReason" v-if="auditType">
+        <el-radio value="1">责任事故</el-radio>
+        <el-radio value="2">非责任事故</el-radio>
+        <el-radio value="3">交通事故</el-radio>
+      </el-radio-group>
+      <el-input
+      v-else
+        v-model="rejectReason"
+        type="textarea"
+        :rows="3"
+        placeholder="请输入审核不通过原因"
+      />
+      <template #footer>
+        <el-button @click="showRejectDialog = false">取消</el-button>
+        <el-button type="danger" :loading="auditSubmitting" @click="handleAuditReject">
+          确定
+        </el-button>
+      </template>
+    </el-dialog>
+  </main>
+  <footer class="safety-platform-container__footer">
+    <el-button @click="router.back()">返回</el-button>
+    <template v-if="isCreateMode || isEditMode">
+      <el-button type="primary" :loading="submitting" @click="handleSubmit">
+        {{ isCreateMode ? '提交' : '保存' }}
+      </el-button>
+    </template>
+    <template v-if="isAuditMode">
+      <el-button type="primary" :loading="auditSubmitting" @click="showRejectDialog = true;auditType = true">
+        审核通过
+      </el-button>
+      <el-button type="primary" :loading="auditSubmitting" @click="showRejectDialog = true;auditType = false">
+        审核不通过
+      </el-button>
+    </template>
+  </footer>
+</template>
+
+<script setup lang="ts">
+  import { computed, onMounted, ref , reactive } from 'vue';
+  import { useRoute, useRouter } from 'vue-router';
+  import { ElMessage } from 'element-plus';
+  import { CaretBottom, CaretTop } from '@element-plus/icons-vue';
+  import BasicForm from '@/components/BasicForm.vue';
+  import { useFormConfigHook } from '@/hooks/useFormConfigHook';
+  import { INVENTORY_FORM_CONFIG, INVENTORY_FORM_DATA, INVENTORY_FORM_RULES } from '../configs/form';
+  import { 
+    queryWorkInjuryApplyDetail, 
+    saveBusinessInformation, 
+    updateInventory , 
+    submitApprovalProcess, 
+    auditPurchaseApply,
+    updateWorkInjuryApply,
+   } from '@/api/inventory';
+  import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
+  import type { FileItem } from '@/components/UploadFiles/types';
+  import { formatAttachmentList } from '@/components/UploadFiles/utils';
+  import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import BasicDialog from '@/components/BasicDialog.vue';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import type { ApprovalNodeInstanceType } from '@/views/system/approval/types';
+  import { APPROVAL_TYPE_MAP, APPROVER_TYPE } from '../configs/constant';
+  import { useEmergencySuppliesHook } from '@/views/emergency/emergency-supplies/src/hook';
+  import { useEmergencyHook } from '@/views/emergency/src/hoos';
+  import { getApprovalNodeInstanceList } from '@/api/approval/approval';
+  import { template } from 'lodash-es';
+  import { downloadFile } from '@/views/disaster/utils';
+
+
+  const router = useRouter();
+  const route = useRoute();
+
+  const cascaderProp = {
+    expandTrigger: 'click',
+    checkStrictly: true,
+    // emitPath: false,
+    value: 'id',
+    label: 'deptName',
+  };
+  const { approvalList, getApprovalList } = useEmergencyHook()
+  const moreText = ref(false);
+  const operate = computed(() => (route.query.operate as string) || 'inventory-create');
+  const currentId = computed(() => Number(route.query.id));
+  const newFormId = ref('');
+
+  const firstLevelDepts = ref<any[]>([]);
+
+  const isCreateMode = computed(() => operate.value === 'inventory-create');
+  const isEditMode = computed(() => operate.value === 'inventory-edit');
+  const isViewMode = computed(() => operate.value === 'inventory-view');
+  const isAuditMode = computed(() => operate.value === 'inventory-audit');
+  const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
+  const cascaderRef = ref();
+  const rejectReason = ref<string>(route.query.rejectReason as string || '');
+  const approvalOrder = ref<string>(route.query.approvalOrder as string || '');
+  const approvalTemplateId = ref<string>(route.query.approvalTemplateId as string || '');
+  const approvalStatus = ref<string>(route.query.approvalStatus as string || '');
+  const auditType = ref(true);
+
+  const basicDialogRef = ref();
+  const approvalFormRef = ref();
+  const approvalForm = reactive({
+    description: '',
+    approvers: {} as Record<number, any[]>,
+  });
+  const approvalNodeList = ref<ApprovalNodeInstanceType[]>([]);
+  const { userOptions, loading, remoteMethod } = useEmergencySuppliesHook();
+  const submitting = ref(false);
+  const auditSubmitting = ref(false);
+  const showRejectDialog = ref(false);
+
+  const { ruleFormData, formRules, ruleFormConfig, cloneRuleFormData, beforeRouteLeave } =
+    useFormConfigHook(INVENTORY_FORM_CONFIG, INVENTORY_FORM_DATA, INVENTORY_FORM_RULES);
+
+  // 查看模式下,所有字段设为只读
+  const viewFormConfig = ref(
+    INVENTORY_FORM_CONFIG.map((item) => ({
+      ...item,
+      componentProps: {
+        ...item.componentProps,
+        disabled: true,
+      },
+    })),
+  );
+
+  const computedFormConfig = computed(() => {
+    if (isViewMode.value) {
+      return viewFormConfig.value;
+    }
+    if (isAuditMode.value) {
+      return viewFormConfig.value;
+    }
+    return ruleFormConfig.value;
+  });
+
+  const basicFormRef = ref<InstanceType<typeof BasicForm>>();
+
+  const handleValidate = async () => {
+    if (!basicFormRef.value) return;
+    const res = await basicFormRef.value.validateForm();
+    return res;
+  };
+
+  const getDetail = async () => {
+    if (!currentId.value) return;
+    try {
+      const res = await queryWorkInjuryApplyDetail(currentId.value);
+      if (res) {
+        // 映射接口字段到表单字段
+        ruleFormData.itemName = res.applicantName || ''; // 申请人姓名
+      ruleFormData.employeeId = res.employeeId || ''; // 工号
+      ruleFormData.warehouseDate = res.injuryTime ? res.injuryTime.split('T')[0] : ''; // 受伤时间
+      ruleFormData.status = res.status ? 'ENABLE' : 'DISABLE'; // 状态
+      ruleFormData.remarks = res.injuryReason || ''; // 受伤原因
+      ruleFormData.accidentCertUrl = res.accidentCertUrl || ''; // 事故报告
+      ruleFormData.powerAttorneyUrl = res.powerAttorneyUrl || ''; // 委托书
+      ruleFormData.addressConfirmUrl = res.addressConfirmUrl || ''; // 地址确认书
+      ruleFormData.applicationFormUrl = res.applicationFormUrl || ''; // 申请表
+      ruleFormData.idCardUrl = res.idCardUrl || ''; // 身份证正反面
+      ruleFormData.laborContractUrl = res.laborContractUrl || ''; // 劳动合同
+      ruleFormData.initialMedicalCertUrl = res.initialMedicalCertUrl || ''; // 初次医疗证明
+      ruleFormData.trusteeIdCardUrl = res.trusteeIdCardUrl || ''; // 被委托人员身份证正反面
+      ruleFormData.departmentCode = JSON.parse(res.departmentCode || '[]') || ''; // 部门编码
+      ruleFormData.departmentName = res.departmentName || ''; // 添加这一行,设置部门名称
+      ruleFormData.approvalTemplateId = res.templateId || ''; // 审批模板ID
+      }
+      cloneRuleFormData();
+    } catch (e) {
+      console.error('获取物品库存详情失败:', e);
+      ElMessage.error('获取详情失败');
+    }
+  };
+
+  const handleSubmit = async () => {
+    const res = await handleValidate();
+    if (!res) return;
+    try {
+      const basePayload = {
+        applicantName: ruleFormData.itemName,
+        employeeId: ruleFormData.employeeId,
+        injuryTime: ruleFormData.warehouseDate
+          ? new Date(ruleFormData.warehouseDate).toISOString()
+          : '',
+        status: ruleFormData.status === 'ENABLE',
+        injuryReason: ruleFormData.remarks || '',
+        accidentCertUrl: ruleFormData.accidentCertUrl,
+        powerAttorneyUrl: ruleFormData.powerAttorneyUrl,
+        addressConfirmUrl: ruleFormData.addressConfirmUrl,
+        applicationFormUrl: ruleFormData.applicationFormUrl,
+        idCardUrl: ruleFormData.idCardUrl,
+        laborContractUrl: ruleFormData.laborContractUrl,
+        initialMedicalCertUrl: ruleFormData.initialMedicalCertUrl,
+        trusteeIdCardUrl: ruleFormData.trusteeIdCardUrl,
+        departmentName: ruleFormData.departmentName || '',
+        departmentCode: ruleFormData.departmentCode || '',
+        templateId: Number(ruleFormData.approvalTemplateId),
+      };
+
+      if (isCreateMode.value) {
+        await saveBusinessInformation(basePayload).then((res)=>{
+          newFormId.value = res || '';
+        });
+        ElMessage.success('创建成功');
+        await getApprovalNode(Number(ruleFormData.approvalTemplateId));
+        basicDialogRef.value.openDialog();
+        return;
+      } else if (isEditMode.value && currentId.value) {
+        await updateWorkInjuryApply({
+          id: currentId.value,
+          ...basePayload,
+        });
+        ElMessage.success('保存成功');
+        await getApprovalNode(Number(ruleFormData.approvalTemplateId));
+        basicDialogRef.value.openDialog();
+        return;
+      }
+      cloneRuleFormData();
+      router.back();
+    } catch (e) {
+      console.error('保存物品库存失败:', e);
+      ElMessage.error('保存失败,请重试');
+    }
+  };
+
+  const handlePreview = (url: string) => {
+    if (url) {
+      // 根据文件扩展名判断文件类型
+      const extension = url.split('.').pop()?.toLowerCase() || '';
+      let fileType: 'pdf' | 'word' | 'excel' | 'ppt' = 'pdf';
+      if (extension === 'doc' || extension === 'docx') {
+        fileType = 'word';
+      } else if (extension === 'xls' || extension === 'xlsx') {
+        fileType = 'excel';
+      } else if (extension === 'ppt' || extension === 'pptx') {
+        fileType = 'ppt';
+      }
+      previewOnlineRef.value?.open(url, fileType);
+    }
+  };
+
+   /** 附件 JSON [{file_name, url}] 转 FileItem 列表,供 UploadFiles 使用(新增/编辑/查看/审核统一展示) */
+  function convertAttachmentJsonToFileItems(attachmentStr: string): FileItem[] {
+    if (!attachmentStr || !String(attachmentStr).trim()) return [];
+    try {
+      const arr = JSON.parse(attachmentStr);
+      if (!Array.isArray(arr)) return [];
+      return arr.map((item: any, index: number) => {
+        const fileName = item.file_name || item.fileName || `附件${index + 1}`;
+        const url = item.url || item.fileUrl || '';
+        const ext = (fileName || '').split('.').pop()?.toLowerCase() || '';
+        let fileType = 'pdf';
+        if (['doc', 'docx'].includes(ext)) fileType = 'word';
+        else if (['xls', 'xlsx'].includes(ext)) fileType = 'excel';
+        else if (['ppt', 'pptx'].includes(ext)) fileType = 'ppt';
+        return { fileId: index + 1, fileName, fileType, fileSize: '0', fileUrl: url };
+      });
+    } catch {
+      return [];
+    }
+  }
+
+  const accidentCertUrl = computed(() => convertAttachmentJsonToFileItems(ruleFormData.accidentCertUrl || ''));
+  const powerAttorneyUrl = computed(() => convertAttachmentJsonToFileItems(ruleFormData.powerAttorneyUrl || ''));
+  const addressConfirmUrl = computed(() => convertAttachmentJsonToFileItems(ruleFormData.addressConfirmUrl || ''));
+  const applicationFormUrl = computed(() => convertAttachmentJsonToFileItems(ruleFormData.applicationFormUrl || ''));
+  const idCardUrl = computed(() => convertAttachmentJsonToFileItems(ruleFormData.idCardUrl || ''));
+  const laborContractUrl = computed(() => convertAttachmentJsonToFileItems(ruleFormData.laborContractUrl || ''));
+  const initialMedicalCertUrl = computed(() => convertAttachmentJsonToFileItems(ruleFormData.initialMedicalCertUrl || ''));
+  const trusteeIdCardUrl = computed(() => convertAttachmentJsonToFileItems(ruleFormData.trusteeIdCardUrl || ''));
+
+  async function handleAccidentReportUploadSuccess(files: FileItem[]) {
+    if (!files?.length) {
+      ruleFormData.accidentCertUrl = '';
+      return;
+    }
+    try {
+      const list = await formatAttachmentList(files);
+      const jsonArr = (list || []).map((r) => ({
+        fileName: r.fileName,
+        fileId: r.fileId || '',
+        fileSize: r.fileSize || '',
+        fileType: r.fileType || '',
+        fileUrl: r.fileUrl || '',
+      })).filter((x) => x.fileId);
+      ruleFormData.accidentCertUrl = JSON.stringify(jsonArr);
+    } catch (e) {
+      console.error('事故报告上传失败:', e);
+      ElMessage.error(e?.message || e?.data || '事故报告上传失败,请重试');
+    }
+  }
+
+  async function handlePowerOfAttorneyUploadSuccess(files: FileItem[]) {
+    if (!files?.length) {
+      ruleFormData.powerAttorneyUrl = '';
+      return;
+    }
+    try {
+      const list = await formatAttachmentList(files);
+      const jsonArr = (list || []).map((r) => ({
+        fileName: r.fileName,
+        fileId: r.fileId || '',
+        fileSize: r.fileSize || '',
+        fileType: r.fileType || '',
+        fileUrl: r.fileUrl || '',
+      })).filter((x) => x.fileId);
+      ruleFormData.powerAttorneyUrl = JSON.stringify(jsonArr);
+    } catch (e) {
+      console.error('委托书上传失败:', e);
+      ElMessage.error(e?.message || e?.data || '委托书上传失败,请重试');
+    }
+  }
+
+  async function handleAddressConfirmationUploadSuccess(files: FileItem[]) {
+    if (!files?.length) {
+      ruleFormData.addressConfirmUrl = '';
+      return;
+    }
+    try {
+      const list = await formatAttachmentList(files);
+      const jsonArr = (list || []).map((r) => ({
+        file_name: r.fileName,
+        fileId: r.fileId || '',
+        fileSize: r.fileSize || '',
+        fileType: r.fileType || '',
+        fileUrl: r.fileUrl || '',
+      })).filter((x) => x.fileId);
+      ruleFormData.addressConfirmUrl = JSON.stringify(jsonArr);
+    } catch (e) {
+      console.error('地址确认书上传失败:', e);
+      ElMessage.error(e?.message || e?.data || '地址确认书上传失败,请重试');
+    }
+  }
+
+  async function handleApplicationFormUploadSuccess(files: FileItem[]) {
+    if (!files?.length) {
+      ruleFormData.applicationFormUrl = '';
+      return;
+    }
+    try {
+      const list = await formatAttachmentList(files);
+      const jsonArr = (list || []).map((r) => ({
+        file_name: r.fileName,
+        fileId: r.fileId || '',
+        fileSize: r.fileSize || '',
+        fileType: r.fileType || '',
+        fileUrl: r.fileUrl || '',
+      })).filter((x) => x.fileId);
+      ruleFormData.applicationFormUrl = JSON.stringify(jsonArr);
+    } catch (e) {
+      console.error('申请表上传失败:', e);
+      ElMessage.error(e?.message || e?.data || '申请表上传失败,请重试');
+    }
+  }
+
+  async function handleIdCardUploadSuccess(files: FileItem[]) {
+    if (!files?.length) {
+      ruleFormData.idCardUrl = '';
+      return;
+    }
+    try {
+      const list = await formatAttachmentList(files);
+      const jsonArr = (list || []).map((r) => ({
+        fileName: r.fileName,
+        fileId: r.fileId || '',
+        fileSize: r.fileSize || '',
+        fileType: r.fileType || '',
+        fileUrl: r.fileUrl || '',
+      })).filter((x) => x.fileId);
+      ruleFormData.idCardUrl = JSON.stringify(jsonArr);
+    } catch (e) {
+      console.error('身份证正反面上传失败:', e);
+      ElMessage.error(e?.message || e?.data || '身份证正反面上传失败,请重试');
+    }
+  }
+
+  async function handleLaborContractUploadSuccess(files: FileItem[]) {
+    if (!files?.length) {
+      ruleFormData.laborContractUrl = '';
+      return;
+    }
+    try {
+      const list = await formatAttachmentList(files);
+      const jsonArr = (list || []).map((r) => ({
+        file_name: r.fileName,
+        fileId: r.fileId || '',
+        fileSize: r.fileSize || '',
+        fileType: r.fileType || '',
+        fileUrl: r.fileUrl || '',
+      })).filter((x) => x.fileId);
+      ruleFormData.laborContractUrl = JSON.stringify(jsonArr);
+    } catch (e) {
+      console.error('劳动合同上传失败:', e);
+      ElMessage.error(e?.message || e?.data || '劳动合同上传失败,请重试');
+    }
+  }
+
+  async function handleInitialMedicalCertificateUploadSuccess(files: FileItem[]) {
+    if (!files?.length) {
+      ruleFormData.initialMedicalCertUrl = '';
+      return;
+    }
+    try {
+      const list = await formatAttachmentList(files);
+      const jsonArr = (list || []).map((r) => ({
+        file_name: r.fileName,
+        fileId: r.fileId || '',
+        fileSize: r.fileSize || '',
+        fileType: r.fileType || '',
+        fileUrl: r.fileUrl || '',
+      })).filter((x) => x.fileId);
+      ruleFormData.initialMedicalCertUrl = JSON.stringify(jsonArr);
+    } catch (e) {
+      console.error('初次医疗证明上传失败:', e);
+      ElMessage.error(e?.message || e?.data || '初次医疗证明上传失败,请重试');
+    }
+  }
+
+  async function handleAgentIdCardUploadSuccess(files: FileItem[]) {
+    if (!files?.length) {
+      ruleFormData.trusteeIdCardUrl = '';
+      return;
+    }
+    try {
+      const list = await formatAttachmentList(files);
+      const jsonArr = (list || []).map((r) => ({
+        file_name: r.fileName,
+        fileId: r.fileId || '',
+        fileSize: r.fileSize || '',
+        fileType: r.fileType || '',
+        fileUrl: r.fileUrl || '',
+      })).filter((x) => x.fileId);
+      ruleFormData.trusteeIdCardUrl = JSON.stringify(jsonArr);
+    } catch (e) {
+      console.error('被委托人员身份证正反面上传失败:', e);
+      ElMessage.error(e?.message || e?.data || '被委托人员身份证正反面上传失败,请重试');
+    }
+  }
+
+  const getDeptData = () => {
+    getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+
+  const handleChangeDept = () => {
+    const deptInfo = cascaderRef.value?.getCheckedNodes();
+    if (deptInfo?.[0]) {
+      ruleFormData.departmentName = deptInfo[0].label;
+      ruleFormData.departmentCode = deptInfo[0].pathValues;
+    }
+  };
+
+  const refreshForm = () => {
+    approvalFormRef.value?.resetFields();
+    approvalForm.description = '';
+  };
+
+  const closeDialog = () => {
+    refreshForm();
+    basicDialogRef.value.closeDialog();
+  };
+
+  const handleSubmitApproval = () => {
+    approvalFormRef.value.validate(async (valid: boolean) => {
+      if (valid) {
+        // 构造后端需要的数据格式
+        const approvalData = {
+          id: currentId.value || newFormId.value || '',
+          templateId: ruleFormData.approvalTemplateId,
+          approvalDescription: approvalForm.description,
+          approvalInfoList: approvalNodeList.value.map((node) => {
+            let approverIdList: number[] = [];
+            if (node.approverType === APPROVER_TYPE.FIX) {
+              approverIdList = node.approverInfoList.map((info) => info.approverId);
+            } else if (approvalForm.approvers[node.id]) {
+              approverIdList = approvalForm.approvers[node.id];
+            }
+            return {
+              approvalOrder: node.approvalOrder,
+              approverIdList,
+            };
+          }),
+        };
+        await submitApprovalProcess(approvalData);
+        ElMessage.success('提交成功');
+        basicDialogRef.value.closeDialog();
+        cloneRuleFormData();
+        router.back();
+      }
+    });
+  };
+
+  const getApprovalNode = async (id: number) => {
+    const res = await getApprovalNodeInstanceList(id);
+    approvalNodeList.value = res.approvalNodeInfoList || [];
+  };
+
+  async function handleAuditReject() {
+    if (!rejectReason.value?.trim()) {
+      ElMessage.warning('请选择审核不通过原因');
+      return;
+    }
+    if (!currentId.value) return;
+    auditSubmitting.value = true;
+    try {
+      await auditPurchaseApply({ id: currentId.value, status: auditType.value === true ? 2 : 3, rejectReason: rejectReason.value.trim(), approvalOrder: Number(approvalOrder.value),templateId: approvalTemplateId.value,code: rejectReason.value });
+      ElMessage.success('审核通过');
+      showRejectDialog.value = false;
+      router.back();
+    } catch (e) {
+      console.error('审核失败:', e);
+      ElMessage.error('审核失败,请重试');
+    } finally {
+      auditSubmitting.value = false;
+    }
+  }
+
+  const previewOnline = (url: string | undefined, type) => {
+    if (url) {
+      previewOnlineRef.value?.open(url, type);
+    }
+  };
+
+  onMounted(() => {
+    cloneRuleFormData();
+    beforeRouteLeave();
+    getDeptData();
+    getApprovalList();
+    if (isEditMode.value || isViewMode.value || isAuditMode.value) {
+      getDetail();
+    }
+  });
+</script>
+
+<style scoped lang="scss">
+  @use '@/styles/page-details-layout.scss' as *;
+  .detail-reject-alert{
+    margin-bottom: 20px;
+  }
+  .detail-reject-alert-name{
+    color: #aaa;
+    margin-bottom: 5px;
+  }
+  .detail-reject-alert-content{
+    color: #aaa;
+  }
+  .detail-reject-alert-content-download{
+    color: #409eff;
+    margin-right: 15px;
+    cursor: pointer;
+  }
+  .more-text-btn{
+    cursor: pointer;
+    color: #409eff;
+
+  }
+</style>

+ 85 - 0
src/views/production-safety/risk-identification-and-control/work-injury-apply-manage-admin/configs/constant.ts

@@ -0,0 +1,85 @@
+export enum EMERGENCY_PLAN_STATUS {
+  UNAPPROVED = 0,
+  APPROVAL_IN_PROGRESS,
+  RETURNED,
+  PUBLISHED,
+}
+
+export const EMERGENCY_PLAN_STATUS_MAP = {
+  [EMERGENCY_PLAN_STATUS.UNAPPROVED]: '未审批',
+  [EMERGENCY_PLAN_STATUS.APPROVAL_IN_PROGRESS]: '预案审批中',
+  [EMERGENCY_PLAN_STATUS.RETURNED]: '预案已退回',
+  [EMERGENCY_PLAN_STATUS.PUBLISHED]: '已公示',
+};
+
+export const EMERGENCY_PLAN_STATUS_OPTIONS = [
+  {
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.UNAPPROVED],
+    value: EMERGENCY_PLAN_STATUS.UNAPPROVED,
+  },
+  {
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.APPROVAL_IN_PROGRESS],
+    value: EMERGENCY_PLAN_STATUS.APPROVAL_IN_PROGRESS,
+  },
+  {
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.RETURNED],
+    value: EMERGENCY_PLAN_STATUS.RETURNED,
+  },
+  {
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.PUBLISHED],
+    value: EMERGENCY_PLAN_STATUS.PUBLISHED,
+  },
+];
+
+export enum APPROVAL_TYPE {
+  COUNTER_SIGN = 0,
+  ORDINARY_SIGN,
+}
+
+export const APPROVAL_TYPE_MAP = {
+  [APPROVAL_TYPE.COUNTER_SIGN]: '会签',
+  [APPROVAL_TYPE.ORDINARY_SIGN]: '或签',
+};
+
+export enum APPROVER_TYPE{
+  FIX = 0,
+  CUSTOM,
+}
+
+export const APPROVER_TYPE_MAP = {
+  [APPROVER_TYPE.FIX]: '固定',
+  [APPROVER_TYPE.CUSTOM]: '自选',
+};
+
+export enum APPROVAL_STATUS {
+  PENDING = 1,
+  APPROVED,
+  REJECTED,
+  OHTER,
+}
+
+export const APPROVAL_STATUS_MAP = {
+  [APPROVAL_STATUS.PENDING]: '待审批',
+  [APPROVAL_STATUS.APPROVED]: '已审批',
+  [APPROVAL_STATUS.REJECTED]: '退回',
+  [APPROVAL_STATUS.OHTER]: '他人已审批',
+};
+
+export const APPROVAL_STATUS_OPTIONS = [
+  {
+    label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.PENDING],
+    value: APPROVAL_STATUS.PENDING,
+  },
+  {
+    label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.APPROVED],
+    value: APPROVAL_STATUS.APPROVED,
+  },
+  {
+    label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.REJECTED],
+    value: APPROVAL_STATUS.REJECTED,
+  },
+  {
+    label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.OHTER],
+    value: APPROVAL_STATUS.OHTER,
+  },
+];

+ 131 - 0
src/views/production-safety/risk-identification-and-control/work-injury-apply-manage-admin/configs/form.ts

@@ -0,0 +1,131 @@
+import { FormConfig } from '@/types/basic-form';
+
+export const INVENTORY_FORM_CONFIG: FormConfig[] = [
+  {
+    prop: 'itemName',
+    label: '姓名:',
+    component: 'ElInput',
+    componentProps: {
+      placeholder: '请输入姓名',
+    },
+  },
+   {
+    prop: 'employeeId',
+    label: '工号:',
+    component: 'ElInput',
+    componentProps: {
+      placeholder: '请输入工号',
+    },
+  },
+   {
+    prop: 'departmentName',
+    label: '所属部门:',
+    slot: 'reviewDepartmentId',
+  },
+  {
+    prop: 'warehouseDate',
+    label: '受伤时间:',
+    component: 'ElDatePicker',
+    componentProps: {
+      type: 'date',
+      placeholder: '请选择受伤时间',
+      valueFormat: 'YYYY-MM-DD',
+    },
+  },
+  {
+    label: '受伤原因:',
+    prop: 'remarks',
+    component: 'ElInput',
+    componentProps: {
+      type: 'textarea',
+      rows: 5,
+      placeholder: '请输入受伤原因',
+    },
+  },
+  {
+    prop: 'approvalTemplateId',
+    label: '审批流程:',
+    slot: 'approvalTemplateId',
+  },
+  {
+    prop: 'accidentCertUrl',
+    label: '事故报告:',
+    slot: 'accidentReport',
+  },
+  {
+    prop: 'powerAttorneyUrl',
+    label: '委托书:',
+    slot: 'powerOfAttorney',
+  },
+  {
+    prop: 'addressConfirmUrl',
+    label: '地址确认书:',
+    slot: 'addressConfirmation',
+  },
+  {
+    prop: 'applicationFormUrl',
+    label: '申请表:',
+    slot: 'applicationForm',
+  },
+  {
+    prop: 'idCardUrl',
+    label: '身份证正反面:',
+    slot: 'idCard',
+  },
+  {
+    prop: 'laborContractUrl',
+    label: '劳动合同:',
+    slot: 'laborContract',
+  },
+  {
+    prop: 'initialMedicalCertUrl',
+    label: '初次医疗证明:',
+    slot: 'initialMedicalCertificate',
+  },
+  {
+    prop: 'trusteeIdCardUrl',
+    label: '被委托人员身份证正反面:',
+    slot: 'agentIdCard',
+  },
+];
+
+export const INVENTORY_FORM_DATA = {
+  status: 'ENABLE',
+  itemName: '',
+  warehouseDate: '',
+  remarks: '',
+  accidentCertUrl: '',
+  powerAttorneyUrl: '',
+  addressConfirmUrl: '',
+  applicationFormUrl: '',
+  idCardUrl: '',
+  laborContractUrl: '',
+  initialMedicalCertUrl: '',
+  trusteeIdCardUrl: '',
+  applicantName: '',
+  applicantCode: '',
+  departmentCode: '',
+  departmentName: '',
+  approvalTemplateId: '',
+  approvalOrder: 0,
+  employeeId: '',
+};
+
+export const INVENTORY_FORM_RULES = {
+  status: [{ required: true, message: '请选择状态', trigger: 'change' }],
+  itemName: [{ required: true, message: '请输入物品名称', trigger: 'blur' }],
+  warehouseDate: [{ required: true, message: '请选择入库日期', trigger: 'change' }],
+  employeeId: [{ required: true, message: '请输入工号', trigger: 'blur' }],
+  departmentCode: [{ required: true, message: '请选择所属部门', trigger: 'change' }],
+  remarks: [{ required: true, message: '请输入受伤原因', trigger: 'blur' }],
+  departmentName: [{ required: true, message: '请选择所属部门', trigger: 'change' }],
+  approvalTemplateId: [{ required: true, message: '请选择审批流程', trigger: 'change' }],
+  accidentCertUrl: [{ required: true, message: '请上传事故报告', trigger: 'change' }],
+  powerAttorneyUrl: [{ required: true, message: '请上传委托书', trigger: 'change' }],
+  addressConfirmUrl: [{ required: true, message: '请上传地址确认书', trigger: 'change' }],
+  applicationFormUrl: [{ required: true, message: '请上传申请表', trigger: 'change' }],
+  idCardUrl: [{ required: true, message: '请上传身份证正反面', trigger: 'change' }],
+  laborContractUrl: [{ required: true, message: '请上传劳动合同', trigger: 'change' }],
+  initialMedicalCertUrl: [{ required: true, message: '请上传初次医疗证明', trigger: 'change' }],
+  trusteeIdCardUrl: [{ required: true, message: '请上传被委托人员身份证正反面', trigger: 'change' }],
+};

+ 79 - 0
src/views/production-safety/risk-identification-and-control/work-injury-apply-manage-admin/configs/tables.ts

@@ -0,0 +1,79 @@
+import type { TableColumnProps } from '@/types/basic-table';
+
+// 基础表格样式配置
+export const TABLE_OPTIONS = {
+  emptyText: '暂无数据',
+  loading: true,
+  maxHeight: 'calc(70vh - 150px)',
+};
+
+export const INVENTORY_TABLE_COLUMNS: TableColumnProps[] = [
+  {
+    label: '编号',
+    type: 'index',
+    align: 'center',
+    width: '80px',
+  },
+  {
+    label: '申请单号',
+    prop: 'applyNo',
+    align: 'left',
+    minWidth: '120px',
+  },
+  {
+    label: '工号',
+    prop: 'applicantCode',
+    align: 'left',
+    minWidth: '120px',
+  },
+  {
+    label: '姓名',
+    prop: 'applicantName',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    label: '所属部门',
+    prop: 'departmentName',
+    align: 'left',
+    minWidth: '120px',
+  },
+  {
+    label: '受伤原因',
+    prop: 'injuryReason',
+    align: 'left',
+    minWidth: '150px',
+  },
+  {
+    label: '受伤时间',
+    prop: 'injuryTime',
+    align: 'left',
+    minWidth: '150px',
+  },
+  {
+    label: '工伤类别',
+    prop: 'injuryCategoryName',
+    slot: 'injuryCategoryCode',
+  },
+  // {
+  //   label: '备注',
+  //   prop: 'remark',
+  //   align: 'left',
+  //   minWidth: '150px',
+  // },
+  {
+    label: '状态',
+    prop: 'status',
+    slot: 'status',
+    align: 'center',
+    minWidth: '100px',
+  },
+  {
+    label: '操作',
+    prop: 'action',
+    slot: 'action',
+    fixed: 'right',
+    width: '180px',
+    align: 'left',
+  },
+];

+ 430 - 0
src/views/production-safety/risk-identification-and-control/work-injury-apply-manage-admin/listAdmin.vue

@@ -0,0 +1,430 @@
+<template>
+  <div class="safety-platform-container">
+    <header class="safety-platform-container__header">
+      <div class="breadcrumb-title">工伤认定申请</div>
+    </header>
+    <main class="safety-platform-container__main">
+      <div class="search-table-container">
+        <header>
+          <div style="position: relative">
+            <!-- <el-button type="primary" class="search-table-container--button" @click="handleCreate">
+              添加
+            </el-button> -->
+            <!-- <el-button plain class="search-table-container--button" @click="handleImport">
+              导入
+            </el-button>
+            <el-button plain class="search-table-container--button" @click="handleDownload">
+              导出
+            </el-button> -->
+          </div>
+
+          <div class="act-search">
+            <section class="select-box">
+              <div class="select-box--item">
+                <span>单号:</span>
+                <el-input
+                  v-model="tableQuery.queryParam.queryKey"
+                  placeholder="搜索申请单号/工号/姓名"
+                  class="act-search-input"
+                />
+              </div>
+              <!-- <div class="select-box--item">
+                <span>状态:</span>
+                <el-select
+                  v-model="tableQuery.queryParam.status"
+                  placeholder="请选择状态"
+                  clearable
+                >
+                  <el-option label="待审核" :value="1" />
+                  <el-option label="申请加盖公章及材料申请" :value="2" />
+                  <el-option label="审核不通过" :value="3" />
+                  <el-option label="已完成" :value="4" />
+                </el-select>
+              </div> -->
+              <div class="select-box--item">
+                <span>所属部门:</span>
+                 <el-cascader
+                  v-model="tableQuery.queryParam.deptCode"
+                  style="width: 170px"
+                  ref="cascaderRef"
+                  :options="firstLevelDepts"
+                  :props="cascaderProp"
+                  :show-all-levels="false"
+                  placeholder="部门名称"
+                  filterable
+                  @change="handleChangeDept"
+                />
+              </div>
+            </section>
+            <section class="search-btn">
+              <el-button type="primary" @click="handleSearch">查询</el-button>
+              <el-button @click="handleReset">重置</el-button>
+            </section>
+          </div>
+        </header>
+
+        <div class="batch-table">
+          <BasicTable
+            ref="basicTableRef"
+            :tableData="tableData"
+            :tableConfig="tableConfig"
+            @update:pageSize="handleSizeChange"
+            @update:pageNumber="handleCurrentChange"
+          >
+            <template #status="scope">
+              <span>
+                {{ scope.row.approvalStatus === 1 ? '待审核' : scope.row.approvalStatus === 2 ? '申请加盖公章及材料申请' : scope.row.approvalStatus === 3 ? '审核不通过' : scope.row.approvalStatus === 4 ? '已完成' : '-' }}
+              </span>
+            </template>
+            <template #injuryCategoryCode="scope">
+              <span>
+                {{ scope.row.injuryCategoryCode === '1' ? '责任事故' : scope.row.injuryCategoryCode === '2' ? '非责任事故' :  scope.row.injuryCategoryCode == '3' ? "交通事故" : '-' }}
+              </span>
+            </template>
+            <template #action="scope">
+              <div class="action-container--div" style="justify-content: left">
+                
+                <!-- 待审核:查看、审核 -->
+                <template v-if="scope.row.approvalStatus === 1 || scope.row.approvalStatus === '1'">
+                  <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                  <ActionButton text="审核" @click="handleAudit(scope.row.id,scope.row)" />
+                </template>
+                <!-- 申请加盖公章及材料申请 -->
+                <template v-else-if="scope.row.approvalStatus === 2 || scope.row.approvalStatus === '2'">
+                  <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                  <!-- <ActionButton text="确认" @click="confirmDialog = true;confirmId = scope.row.id;" /> -->
+                </template>
+                <!-- 审核不通过:编辑、删除、查看 -->
+                <template v-else-if="scope.row.approvalStatus === 3 || scope.row.approvalStatus === '3'">
+                  <!-- <ActionButton text="编辑" @click="handleEdit(scope.row.id,scope.row)" />
+                  <ActionButton
+                    text="删除"
+                    :popconfirm="{ title: '确定要删除该申请吗?' }"
+                    @confirm="handleDelete(scope.row.id)"
+                  /> -->
+                  <ActionButton text="查看" @click="handleView(scope.row.id!)" />
+                </template>
+                <!-- 已完成:查看 -->
+                <template v-else-if="scope.row.approvalStatus === 4 || scope.row.approvalStatus === '4'">
+                  <ActionButton text="查看" @click="handleView(scope.row.id!)" />
+                </template>
+              </div>
+            </template>
+          </BasicTable>
+        </div>
+      </div>
+      <!-- 确定弹窗 -->
+      <el-dialog
+        v-model="confirmDialog"
+        title="用户告知内容"
+        width="800px"
+        destroy-on-close
+        @close="confirmValue = '';confirmDialog = false"
+      >
+        <div class="editor-container">
+          <Toolbar 
+            style="border-bottom: 1px solid #dcdfe6" 
+            :editor="editorRef" 
+          />
+          <Editor
+            style="height: 400px; overflow-y: auto"
+            v-model="confirmValue"
+            mode="default"
+            :defaultConfig="editorConfig"
+            @on-created="handleEditorCreated"
+          />
+        </div>
+        <template #footer>
+          <el-button @click="confirmDialog = false">取消</el-button>
+          <el-button type="danger" :loading="auditSubmitting" @click="confirmRequest">
+            确定
+          </el-button>
+        </template>
+      </el-dialog>
+    </main>
+    <BatchImport
+      v-if="batchImportVisible"
+      :visible="batchImportVisible"
+      :import-api-url="importApiUrl"
+      :template-url="templateUrl"
+      template-name="下载模板"
+      :show-template="false"
+      @close="batchImportVisible = false"
+      @update="handleUpdate"
+    />
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { onMounted, reactive, ref ,shallowRef ,computed } from 'vue';
+  import { ElMessage } from 'element-plus';
+  import BasicTable from '@/components/BasicTable.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import ActionButton from '@/components/ActionButton.vue';
+  import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
+  import { useRouter } from 'vue-router';
+  import type { QueryPageRequest } from '@/types/basic-query';
+  import { queryInventoryManage, deleteInventory, exportInventory, auditWorkInjuryConfirm } from '@/api/inventory';
+  import { downloadByData } from '@/utils/file/download';
+  import BatchImport from '@/components/batch-import/BatchImport.vue';
+  import { useGlobSetting } from '@/hooks/setting';
+  import urlJoin from 'url-join';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import {
+    queryWorkInjuryApplyList,
+    queryWorkInjuryApplyListAdmin,
+    type InventoryItem,
+    type InventoryQueryParam,
+  } from '@/api/production-safety/business-registration-application';
+  import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
+  import '@wangeditor/editor/dist/css/style.css';
+
+  const router = useRouter();
+  const auditSubmitting = ref(false);
+  const confirmDialog = ref(false);
+  const confirmValue = ref('');
+  const confirmId = ref('');
+  // 富文本编辑器
+  const editorRef = shallowRef();
+  const editorConfig = computed(() => ({
+    placeholder: '请输入文档内容',
+  }));
+  
+  const firstLevelDepts = ref<any[]>([]);
+  const cascaderProp = {
+    expandTrigger: 'click',
+    checkStrictly: true,
+    // emitPath: false,
+    value: 'id',
+    label: 'deptName',
+  };
+  const cascaderRef = ref();
+
+  // 表格
+  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+
+  const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
+
+  const tableData = ref<any[]>([]);
+
+  const tableQuery = reactive<QueryPageRequest<any>>({
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {
+      queryKey: '', // 物品名称
+      status: '', // 状态,默认启用
+      ids: [], // 选择数据的ID
+      deptCode: '', // 所属部门ID
+    },
+  });
+
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    tableQuery.pageSize = value;
+    getTableData();
+  };
+
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    tableQuery.pageNumber = value;
+    getTableData();
+  };
+
+
+  async function getTableData() {
+    tableConfig.loading = true;
+    try {
+      const res = await queryWorkInjuryApplyListAdmin(tableQuery);
+      if (res) {
+        // 映射返回数据字段到表格字段
+        tableData.value = res.records.map((item) => ({
+          id: item.id,
+          applyNo: item.applyNo, // 申请单号
+          applicantCode: item.applicantCode, // 工号
+          applicantName: item.applicantName, // 姓名
+          departmentName: item.departmentName, // 所属部门
+          injuryReason: item.injuryReason, // 受伤原因
+          injuryTime: item.injuryTime, // 受伤时间
+          injuryCategoryName: item.injuryCategoryName, // 工伤类别
+          remark: item.remark, // 备注
+          approvalStatus: item.approvalStatus, // 状态
+          approvalTemplateId: item.approvalTemplateId, // 审批模板ID
+          approvalOrder: item.approvalOrder, // 审批订单
+          templateId: item.templateId, // 模板ID
+          injuryCategoryCode: item.injuryCategoryCode, // 工伤类别编码
+          rejectReason: item.rejectReason, // 拒绝原因
+        }));
+        pagination.total = res.totalRow;
+      }
+    } catch (e) {
+      console.error('获取物品库存列表失败:', e);
+      tableData.value = [];
+      pagination.total = 0;
+    } finally {
+      tableConfig.loading = false;
+    }
+  }
+
+  const handleSearch = () => {
+    pagination.pageNumber = 1;
+    tableQuery.pageNumber = 1;
+    getTableData();
+  };
+
+  const handleReset = () => {
+    tableQuery.queryParam.queryKey = '';
+    tableQuery.queryParam.status = ''; // 重置为默认启用状态
+    tableQuery.queryParam.ids = [];
+    tableQuery.queryParam.deptCode = ''; // 重置为默认启用状态
+    handleSearch();
+  };
+
+  // 批量导入
+  const batchImportVisible = ref(false);
+  const { urlPrefix } = useGlobSetting();
+  const importApiUrl = ref(urlJoin(urlPrefix, '/inventory/importInventory'));
+  const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-inventory-template.xlsx');
+
+  const handleImport = () => {
+    batchImportVisible.value = true;
+  };
+
+  const handleUpdate = () => {
+    batchImportVisible.value = false;
+    getTableData();
+  };
+
+  const handleDownload = async () => {
+    try {
+      const exportParams = {
+        queryKey: tableQuery.queryParam.queryKey || undefined,
+        status: tableQuery.queryParam.status,
+        ids: tableQuery.queryParam.ids.length > 0 ? tableQuery.queryParam.ids : undefined,
+      };
+      const response = await exportInventory(exportParams);
+      if (response) {
+        const fileName = `物品库存管理_${new Date().toISOString().split('T')[0]}.xlsx`;
+        downloadByData(response, fileName);
+        ElMessage.success('导出成功');
+      }
+    } catch (e) {
+      console.error('导出物品库存失败:', e);
+      ElMessage.error('导出失败,请重试');
+    }
+  };
+
+  const handleCreate = () => {
+    router.push({
+      name: 'workInjuryApplyManageAdminItem',
+      query: {
+        operate: 'inventory-create',
+      },
+    });
+  };
+
+  const handleEdit = (id: number,row: any) => {
+    router.push({
+      name: 'workInjuryApplyManageAdminItem',
+      query: {
+        id,
+        rejectReason:row.rejectReason ?? '',
+        approvalTemplateId:row.templateId ?? '',
+        approvalOrder:row.approvalOrder ?? '',
+        approvalStatus:row.approvalStatus ?? '',
+        injuryCategoryCode:row.injuryCategoryCode ?? '',
+        operate: 'inventory-edit',
+      },
+    });
+  };
+
+  const handleAudit = (id: number,row: any) => {
+    router.push({
+      name: 'workInjuryApplyManageAdminItem',
+      query: {
+        id,
+        approvalTemplateId:row.templateId ?? '',
+        approvalOrder:row.approvalOrder ?? '',
+        operate: 'inventory-audit',
+      },
+    });
+  }
+
+  const handleDelete = async (id: number) => {
+    try {
+      await deleteInventory(id);
+      ElMessage.success('删除成功');
+      getTableData();
+    } catch (e) {
+      console.error('删除物品库存失败:', e);
+      ElMessage.error('删除失败,请重试');
+    }
+  };
+
+  const handleView = (id: number) => {
+    router.push({
+      name: 'workInjuryApplyManageAdminItem',
+      query: {
+        id,
+        operate: 'inventory-view',
+      },
+    });
+  };
+
+  const getDeptData = () => {
+    getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+  
+  const handleChangeDept = () => {
+    // const deptInfo = cascaderRef.value?.getCheckedNodes();
+    // if (deptInfo?.[0]) {
+    //   tableQuery.queryParam.department = deptInfo[0].label;
+    //   tableQuery.queryParam.departmentId = deptInfo[0].pathValues;
+    // }
+  };
+
+  const handleEditorCreated = (editor: any) => {
+    editorRef.value = editor;
+  };
+
+  const confirmRequest = async () => {
+    auditSubmitting.value = true;
+    try {
+      if (!confirmValue.value) {
+        ElMessage.error('请先填写用户告知内容!');
+        return;
+      }
+      await auditWorkInjuryConfirm(Number(confirmId.value), confirmValue.value);
+      ElMessage.success('操作成功');
+      confirmDialog.value = false;
+      confirmValue.value = '';
+      getTableData();
+    } catch (e) {
+      console.error('操作失败:', e);
+      ElMessage.error('操作失败,请重试');
+    } finally {
+      auditSubmitting.value = false;
+    }
+  };
+
+  onMounted(() => {
+    getTableData();
+    getDeptData();
+  });
+</script>
+
+<style scoped lang="scss">
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+  @use '@/views/traffic/violation/style/act-search-table.scss' as *;
+  @use '@/styles/page-details-layout.scss' as *;
+  .editor-container {
+    width: 100%;
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    overflow: hidden;
+  }
+</style>

+ 3 - 3
utils/devProxy/staff/proxy.ts

@@ -3,14 +3,14 @@ import path from 'path';
 
 // staff环境
 const proxyStaff: PROXY_TYPE = {
-  serverHost: 'http://192.168.6.42:8802/',
-//   serverHost: 'http://192.168.22.148:8802/',
+//   serverHost: 'http://192.168.6.42:8802/',
+  serverHost: 'http://14.103.151.10:8005/',
   skyeyeLoginHost: 'http://192.168.6.42:7000/skyeye-login/#/',
   skyeyePlatformHost: 'http://192.168.6.42:7000/skyeye-pc/#/',
   skyeyeAdminHost: 'http://192.168.6.42:7000/skyeye-admin/#/',
   skyeyeH5Host: 'http://192.168.6.42:7000/skyeye-h5/#/',
   tiansuoHost: 'http://192.168.6.33:91/',
-  fileUploadHost: 'http://192.168.13.102:9000/',
+  fileUploadHost: 'http://14.103.151.10:9000/',
   violation_src: 'http://192.168.13.102:62/violation_src',
   push_stream_host: 'http://192.168.6.42:7000/skyeye-admin/push_stream_host/',
 };