|
|
@@ -1,421 +1,176 @@
|
|
|
<template>
|
|
|
- <div class="app-container">
|
|
|
- <ContentWrap style="border: 0">
|
|
|
- <el-form
|
|
|
- class="-mb-15px"
|
|
|
- :model="queryParams"
|
|
|
- ref="queryForm"
|
|
|
- :inline="true"
|
|
|
- label-width="100px"
|
|
|
- >
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24" :xs="24" :sm="12" :md="6">
|
|
|
- <el-form-item label="事件级别" prop="accidentGrade">
|
|
|
- <el-input
|
|
|
- v-model="queryParams.accidentGrade"
|
|
|
- placeholder="请输入事件级别"
|
|
|
- clearable
|
|
|
- @keyup.enter="handleQuery"
|
|
|
- style="width: 200px"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="24" :xs="24" :sm="12" :md="6">
|
|
|
- <el-form-item label="事件类型" prop="accidentType">
|
|
|
- <el-input
|
|
|
- v-model="queryParams.accidentType"
|
|
|
- placeholder="请选择事件类型"
|
|
|
- clearable
|
|
|
- style="width: 200px"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
- <el-form-item style="display: block">
|
|
|
- <el-button type="primary" @click="handleQuery" :icon="Search">搜索</el-button>
|
|
|
- <el-button @click="resetQuery" :icon="Refresh">重置</el-button>
|
|
|
- <el-button
|
|
|
- type="primary"
|
|
|
- @click="openForm('create')"
|
|
|
- color="#626aef"
|
|
|
- v-hasPermi="['rq:iot-accident-report:create']"
|
|
|
- >
|
|
|
- <Icon icon="ep:plus" class="mr-5px" /> 新增
|
|
|
- </el-button>
|
|
|
- <!-- <el-button type="success" plain @click="handleExport" :loading="exportLoading">
|
|
|
- <Icon icon="ep:download" class="mr-5px" /> 导出
|
|
|
- </el-button> -->
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-form>
|
|
|
- </ContentWrap>
|
|
|
-
|
|
|
- <ContentWrap style="border: 0">
|
|
|
- <el-table
|
|
|
- v-loading="loading"
|
|
|
- :data="list"
|
|
|
- row-key="id"
|
|
|
- border
|
|
|
- style="width: 100%"
|
|
|
- :header-cell-style="{ background: '#f5f7fa', color: '#333', height: '50px' }"
|
|
|
- :cell-style="{ padding: '12px 8px' }"
|
|
|
- height="70vh"
|
|
|
- :max-height="tableHeight"
|
|
|
- >
|
|
|
- <el-table-column prop="actualTime" label="事件时间" align="center" min-width="150">
|
|
|
- <template #default="{ row }">
|
|
|
- {{ formatDate(row.actualTime) }}
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="accidentGrade" label="事件级别" align="center" />
|
|
|
- <el-table-column prop="accidentType" label="事件类型" align="center" />
|
|
|
- <el-table-column prop="accidentType" label="事件状态" align="center" width="100">
|
|
|
- <template #default="scope">
|
|
|
- <dict-tag :type="DICT_TYPE.ACCIDENT_REPORT_STATUS" :value="scope.row.status" />
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column
|
|
|
- prop="lossSituation"
|
|
|
- label="事件损失情况"
|
|
|
- align="center"
|
|
|
- show-overflow-tooltip
|
|
|
- min-width="150"
|
|
|
- />
|
|
|
-
|
|
|
- <el-table-column
|
|
|
- prop="accidentAddress"
|
|
|
- label="事件地址"
|
|
|
- align="center"
|
|
|
- min-width="150"
|
|
|
- show-overflow-tooltip
|
|
|
- />
|
|
|
- <el-table-column prop="deptName" label="部门名称" align="center" />
|
|
|
- <el-table-column prop="dutyPerson" label="现场负责人" align="center" width="100" />
|
|
|
- <el-table-column prop="actualTime" label="创建时间" align="center" min-width="150">
|
|
|
- <template #default="{ row }">
|
|
|
- {{ formatDate(row.createTime) }}
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
-
|
|
|
- <el-table-column label="操作" align="center" width="150" fixed="right">
|
|
|
- <template #default="{ row }">
|
|
|
- <el-button
|
|
|
- link
|
|
|
- type="primary"
|
|
|
- @click="openForm('detail', row)"
|
|
|
- :icon="View"
|
|
|
- v-hasPermi="['rq:iot-accident-report:query']"
|
|
|
- >详情</el-button
|
|
|
- >
|
|
|
- <el-button link type="primary" @click="openApprovalDialog(row)"> 流转信息 </el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
-
|
|
|
- <!-- 分页 -->
|
|
|
- <div class="mt-2 mb-2 float-right">
|
|
|
- <el-pagination
|
|
|
- v-model:current-page="queryParams.pageNo"
|
|
|
- v-model:page-size="queryParams.pageSize"
|
|
|
- :total="total"
|
|
|
- layout="total, sizes, prev, pager, next"
|
|
|
- @size-change="handleSizeChange"
|
|
|
- @current-change="handleCurrentChange"
|
|
|
- background
|
|
|
- />
|
|
|
- </div>
|
|
|
- </ContentWrap>
|
|
|
-
|
|
|
+ <Dialog :title="dialogTitle" v-model="dialogVisible" style="width: 800px">
|
|
|
<!-- 表单弹窗 -->
|
|
|
- <el-dialog
|
|
|
- :title="title"
|
|
|
- v-model="open"
|
|
|
- width="800px"
|
|
|
- :fullscreen="isMobile"
|
|
|
- append-to-body
|
|
|
- :close-on-click-modal="false"
|
|
|
- destroy-on-close
|
|
|
- custom-class="self-dialog"
|
|
|
- >
|
|
|
- <template #title>
|
|
|
- <div
|
|
|
- style="
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- border-bottom: 1px solid #ebeef5;
|
|
|
- padding-bottom: 20px;
|
|
|
- padding-left: 20px;
|
|
|
- width: 108%;
|
|
|
- margin-left: -15px;
|
|
|
- "
|
|
|
- >
|
|
|
- <span>{{ title }}</span>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- <el-form
|
|
|
- ref="formRef"
|
|
|
- :model="formData"
|
|
|
- :rules="formRules"
|
|
|
- label-width="120px"
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- >
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
- <el-form-item label="事件时间" prop="actualTime">
|
|
|
- <el-date-picker
|
|
|
- v-model="formData.actualTime"
|
|
|
- type="datetime"
|
|
|
- format="YYYY-MM-DD HH:mm:ss"
|
|
|
- value-format="x"
|
|
|
- placeholder="选择事件发生时间"
|
|
|
- style="width: 100%"
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
-
|
|
|
- <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
- <el-form-item label="事件级别" prop="accidentGrade">
|
|
|
- <el-input
|
|
|
- v-model="formData.accidentGrade"
|
|
|
- placeholder="请输入事件级别"
|
|
|
- clearable
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
- <el-form-item label="事件类型" prop="accidentType">
|
|
|
- <el-input
|
|
|
- v-model="formData.accidentType"
|
|
|
- placeholder="请选择事件类型"
|
|
|
- clearable
|
|
|
- style="width: 100%"
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
-
|
|
|
- <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
- <el-form-item label="事件地址" prop="accidentAddress">
|
|
|
- <el-input
|
|
|
- v-model="formData.accidentAddress"
|
|
|
- placeholder="请输入事件地址"
|
|
|
- clearable
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
- <el-form-item label="现场负责人" prop="dutyPerson">
|
|
|
- <el-input
|
|
|
- v-model="formData.dutyPerson"
|
|
|
- placeholder="请输入现场负责人姓名"
|
|
|
- clearable
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="事件损失情况" prop="lossSituation">
|
|
|
- <el-input
|
|
|
- v-model="formData.lossSituation"
|
|
|
- placeholder="请输入事件损失情况"
|
|
|
- clearable
|
|
|
- type="textarea"
|
|
|
- :rows="2"
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="现场采取措施" prop="emergencyMeasure">
|
|
|
- <el-input
|
|
|
- v-model="formData.emergencyMeasure"
|
|
|
- type="textarea"
|
|
|
- :rows="2"
|
|
|
- placeholder="请输入现场采取的应急措施"
|
|
|
- maxlength="500"
|
|
|
- show-word-limit
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="事件简要经过" prop="description">
|
|
|
- <el-input
|
|
|
- v-model="formData.description"
|
|
|
- type="textarea"
|
|
|
- :rows="2"
|
|
|
- placeholder="请输入事件详细经过"
|
|
|
- maxlength="1000"
|
|
|
- show-word-limit
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row :gutter="20">
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="附件/现场图片" prop="pic">
|
|
|
- <UploadImage v-model="formData.pic" width="260px" :disabled="mode === 'detail'" />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
-
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="备注" prop="remark">
|
|
|
- <el-input
|
|
|
- v-model="formData.remark"
|
|
|
- type="textarea"
|
|
|
- :rows="3"
|
|
|
- placeholder="请输入备注信息"
|
|
|
- maxlength="500"
|
|
|
- show-word-limit
|
|
|
- :disabled="mode === 'detail'"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-form>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <div class="dialog-footer" v-if="mode !== 'detail'">
|
|
|
- <el-button @click="cancel">取 消</el-button>
|
|
|
- <el-button type="primary" @click="submitForm" :loading="submitLoading" color="#626aef">
|
|
|
- 确 定
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="dialog-footer" v-else>
|
|
|
- <el-button @click="cancel">关 闭</el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <el-drawer
|
|
|
- :title="approvalDialogTitle"
|
|
|
- v-model="approvalDialogVisible"
|
|
|
- direction="rtl"
|
|
|
- size="650px"
|
|
|
- :with-header="true"
|
|
|
- :close-on-click-modal="false"
|
|
|
- destroy-on-close
|
|
|
+ <el-form
|
|
|
+ ref="formRef"
|
|
|
+ :model="formData"
|
|
|
+ :rules="formRules"
|
|
|
+ label-width="120px"
|
|
|
+ :disabled="disabled"
|
|
|
>
|
|
|
- <template #header>
|
|
|
- <div class="drawer-header">
|
|
|
- <span>{{ approvalDialogTitle }}</span>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
-
|
|
|
- <!-- 专业化的审批流程时间线 -->
|
|
|
- <div class="approval-process-container">
|
|
|
- <el-timeline v-if="approvalProcessList.length > 0">
|
|
|
- <el-timeline-item
|
|
|
- v-for="(item, index) in approvalProcessList"
|
|
|
- :key="index"
|
|
|
- placement="top"
|
|
|
- :color="getNodeStatusColor(item.status)"
|
|
|
- :icon="Check"
|
|
|
- >
|
|
|
- <el-card
|
|
|
- shadow="never"
|
|
|
- class="approval-card"
|
|
|
- :class="{ 'status-completed': item.status === '已完成' || item.status === '已批准' }"
|
|
|
- >
|
|
|
- <div class="card-header">
|
|
|
- <div class="node-info">
|
|
|
- <el-tag :type="getTagTypeByStatus(item.status)" size="small" class="status-tag">
|
|
|
- {{ item.status }}
|
|
|
- </el-tag>
|
|
|
- <span class="node-name">{{ item.nodeName }}</span>
|
|
|
- </div>
|
|
|
- <div class="operator-time">
|
|
|
- <span class="time">{{ formatDate(item.createTime) }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="card-content">
|
|
|
- <div class="opinion-section">
|
|
|
- <span class="label">操作人:</span>
|
|
|
- <span class="opinion">{{ item.operator }}</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="description-section mt-1" v-if="item.description">
|
|
|
- <span class="label">审批意见:</span>
|
|
|
- <span class="description">{{ item.description }}</span>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- class="attachment-section"
|
|
|
- v-if="item.attachments && item.attachments.length > 0"
|
|
|
- >
|
|
|
- <span class="label">附件:</span>
|
|
|
- <div class="attachments">
|
|
|
- <el-link
|
|
|
- v-for="(attachment, idx) in item.attachments"
|
|
|
- :key="idx"
|
|
|
- type="primary"
|
|
|
- :href="attachment.url"
|
|
|
- target="_blank"
|
|
|
- class="attachment-link"
|
|
|
- >
|
|
|
- {{ attachment.name }}
|
|
|
- </el-link>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- </el-timeline-item>
|
|
|
- </el-timeline>
|
|
|
-
|
|
|
- <!-- 无数据提示 -->
|
|
|
- <div v-else class="no-data">
|
|
|
- <el-empty description="暂无审批流程信息" :image-size="100" />
|
|
|
- </div>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
+ <el-form-item label="事件时间" prop="actualTime">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="formData.actualTime"
|
|
|
+ type="datetime"
|
|
|
+ format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ value-format="x"
|
|
|
+ placeholder="选择事件发生时间"
|
|
|
+ style="width: 100%"
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
+ <el-form-item label="事件级别" prop="accidentGrade">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.accidentGrade"
|
|
|
+ placeholder="请输入事件级别"
|
|
|
+ clearable
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
+ <el-form-item label="事件类型" prop="accidentType">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.accidentType"
|
|
|
+ placeholder="请选择事件类型"
|
|
|
+ clearable
|
|
|
+ style="width: 100%"
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
+ <el-form-item label="事件地址" prop="accidentAddress">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.accidentAddress"
|
|
|
+ placeholder="请输入事件地址"
|
|
|
+ clearable
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24" :xs="24" :sm="24" :md="12">
|
|
|
+ <el-form-item label="现场负责人" prop="dutyPerson">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.dutyPerson"
|
|
|
+ placeholder="请输入现场负责人姓名"
|
|
|
+ clearable
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="事件损失情况" prop="lossSituation">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.lossSituation"
|
|
|
+ placeholder="请输入事件损失情况"
|
|
|
+ clearable
|
|
|
+ type="textarea"
|
|
|
+ :rows="2"
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="现场采取措施" prop="emergencyMeasure">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.emergencyMeasure"
|
|
|
+ type="textarea"
|
|
|
+ :rows="2"
|
|
|
+ placeholder="请输入现场采取的应急措施"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="事件简要经过" prop="description">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.description"
|
|
|
+ type="textarea"
|
|
|
+ :rows="2"
|
|
|
+ placeholder="请输入事件详细经过"
|
|
|
+ maxlength="1000"
|
|
|
+ show-word-limit
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="附件/现场图片" prop="pic">
|
|
|
+ <UploadImage v-model="formData.pic" width="260px" :disabled="disabled" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="备注" prop="remark">
|
|
|
+ <el-input
|
|
|
+ v-model="formData.remark"
|
|
|
+ type="textarea"
|
|
|
+ :rows="3"
|
|
|
+ placeholder="请输入备注信息"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ :disabled="disabled"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="submitForm" :loading="submitLoading" color="#626aef">
|
|
|
+ 确 定
|
|
|
+ </el-button>
|
|
|
+ <el-button @click="dialogVisible = false">取 消</el-button>
|
|
|
</div>
|
|
|
- </el-drawer>
|
|
|
- </div>
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, reactive, onMounted, computed } from 'vue'
|
|
|
-import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
-import { Search, Refresh, Plus, Edit, Delete, TopRight, View, Check } from '@element-plus/icons-vue'
|
|
|
-import { defaultProps } from '@/utils/tree'
|
|
|
-import { handleTree } from '@/utils/tree'
|
|
|
-import * as DeptApi from '@/api/system/dept'
|
|
|
+import { ref, reactive } from 'vue'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
import { IotFailureApi } from '@/api/pms/qhse/index'
|
|
|
import UploadImage from '@/components/UploadFile/src/UploadImg.vue'
|
|
|
-import { formatDate } from '@/utils/formatTime'
|
|
|
-import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
|
|
|
-import { IotApprovalApi } from '@/api/pms/qhse/index'
|
|
|
|
|
|
// Data
|
|
|
const loading = ref(false)
|
|
|
const submitLoading = ref(false)
|
|
|
-const list = ref([])
|
|
|
-const total = ref(0)
|
|
|
-const open = ref(false)
|
|
|
-const title = ref('')
|
|
|
+const dialogVisible = ref(false) // 弹窗的是否展示
|
|
|
+const dialogTitle = ref('') // 弹窗的标题
|
|
|
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
|
|
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
|
|
const formRef = ref()
|
|
|
-const mode = ref('') // 'create' or 'update'
|
|
|
-const deptList2 = ref([]) // 树形结构
|
|
|
+const disabled = ref(false)
|
|
|
+const { t } = useI18n() // 国际化
|
|
|
|
|
|
// 表单数据
|
|
|
const formData = ref({
|
|
|
@@ -432,15 +187,6 @@ const formData = ref({
|
|
|
remark: ''
|
|
|
})
|
|
|
|
|
|
-// 查询参数
|
|
|
-const queryParams = ref({
|
|
|
- pageNo: 1,
|
|
|
- pageSize: 10,
|
|
|
- actualTime: [],
|
|
|
- accidentGrade: undefined,
|
|
|
- accidentType: undefined
|
|
|
-})
|
|
|
-
|
|
|
// 表单验证规则
|
|
|
const formRules = reactive({
|
|
|
actualTime: [{ required: true, message: '请选择事件时间', trigger: 'change' }],
|
|
|
@@ -450,128 +196,27 @@ const formRules = reactive({
|
|
|
deptId: [{ required: true, message: '请选择所属部门', trigger: 'change' }],
|
|
|
deptName: [{ required: true, message: '请输入队伍名称', trigger: 'blur' }],
|
|
|
dutyPerson: [{ required: true, message: '请输入现场负责人', trigger: 'blur' }]
|
|
|
- // description: [
|
|
|
- // { required: true, message: '请输入事件简要经过', trigger: 'blur' },
|
|
|
- // { min: 1, max: 1000, message: '事件简要经过长度应在1-1000之间', trigger: 'blur' }
|
|
|
- // ]
|
|
|
-})
|
|
|
-
|
|
|
-// 计算属性
|
|
|
-const isMobile = computed(() => {
|
|
|
- return window.innerWidth < 768
|
|
|
-})
|
|
|
-
|
|
|
-const tableHeight = computed(() => {
|
|
|
- if (isMobile.value) {
|
|
|
- return window.innerHeight - 300 // 为移动端减少高度,考虑其他元素占用空间
|
|
|
- }
|
|
|
- return '70vh'
|
|
|
})
|
|
|
|
|
|
-// Methods
|
|
|
-const getList = async () => {
|
|
|
- loading.value = true
|
|
|
- try {
|
|
|
- const response = await IotFailureApi.getFailureList(queryParams.value)
|
|
|
- list.value = response.list
|
|
|
- total.value = response.total
|
|
|
- loading.value = false
|
|
|
- } catch (error) {
|
|
|
- loading.value = false
|
|
|
- ElMessage.error('获取列表失败')
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const handleSizeChange = (val) => {
|
|
|
- queryParams.value.pageSize = val
|
|
|
- queryParams.value.pageNo = 1 // 重置为第一页
|
|
|
- getList()
|
|
|
-}
|
|
|
-
|
|
|
-const handleCurrentChange = (val) => {
|
|
|
- queryParams.value.pageNo = val
|
|
|
- getList()
|
|
|
-}
|
|
|
-
|
|
|
-const resetQuery = () => {
|
|
|
- // 重置查询参数
|
|
|
- queryParams.value = {
|
|
|
- pageNo: 1,
|
|
|
- pageSize: 10,
|
|
|
- actualTime: [],
|
|
|
- accidentGrade: undefined,
|
|
|
- accidentType: undefined
|
|
|
- }
|
|
|
- handleQuery()
|
|
|
-}
|
|
|
-
|
|
|
-const handleQuery = () => {
|
|
|
- queryParams.value.pageNo = 1
|
|
|
- getList()
|
|
|
-}
|
|
|
-
|
|
|
-// 打开表单 - 支持新增、编辑和详情
|
|
|
-const openForm = async (modeVal, row = {}) => {
|
|
|
+const open = async (type, id, disable) => {
|
|
|
+ disabled.value = disable
|
|
|
+ dialogVisible.value = true
|
|
|
+ dialogTitle.value = t('action.' + type)
|
|
|
+ formType.value = type
|
|
|
reset()
|
|
|
- mode.value = modeVal
|
|
|
-
|
|
|
- if (modeVal === 'create') {
|
|
|
- title.value = '添加事故事件上报'
|
|
|
- open.value = true
|
|
|
- } else if (modeVal === 'update') {
|
|
|
- title.value = '修改事故事件上报'
|
|
|
|
|
|
- // 直接使用列表中的数据,不需要调用详情接口
|
|
|
- formData.value = { ...row }
|
|
|
-
|
|
|
- // 如果是字符串或日期格式的时间,转换为时间戳
|
|
|
- if (typeof row.actualTime === 'string' && row.actualTime) {
|
|
|
- formData.value.actualTime = new Date(row.actualTime).getTime()
|
|
|
- } else if (row.actualTime instanceof Date) {
|
|
|
- formData.value.actualTime = row.actualTime.getTime()
|
|
|
- } else if (typeof row.actualTime === 'number') {
|
|
|
- // 如果已经是时间戳格式,直接使用
|
|
|
- formData.value.actualTime = row.actualTime
|
|
|
- }
|
|
|
-
|
|
|
- open.value = true
|
|
|
- } else if (modeVal === 'detail') {
|
|
|
- title.value = '事故事件上报详情'
|
|
|
-
|
|
|
- // 直接使用列表中的数据
|
|
|
- formData.value = { ...row }
|
|
|
-
|
|
|
- // 如果是字符串或日期格式的时间,转换为时间戳
|
|
|
- if (typeof row.actualTime === 'string' && row.actualTime) {
|
|
|
- formData.value.actualTime = new Date(row.actualTime).getTime()
|
|
|
- } else if (row.actualTime instanceof Date) {
|
|
|
- formData.value.actualTime = row.actualTime.getTime()
|
|
|
- } else if (typeof row.actualTime === 'number') {
|
|
|
- // 如果已经是时间戳格式,直接使用
|
|
|
- formData.value.actualTime = row.actualTime
|
|
|
+ // 修改时,设置数据
|
|
|
+ if (id) {
|
|
|
+ formLoading.value = true
|
|
|
+ try {
|
|
|
+ formData.value = await IotFailureApi.getFailure(id)
|
|
|
+ } finally {
|
|
|
+ formLoading.value = false
|
|
|
}
|
|
|
-
|
|
|
- open.value = true
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const handleDelete = async (row) => {
|
|
|
- const ids = [row.id]
|
|
|
- await ElMessageBox.confirm('是否确认删除选中的故障报告数据项?', '警告', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning'
|
|
|
- })
|
|
|
-
|
|
|
- try {
|
|
|
- // 删除API调用
|
|
|
- await IotFailureApi.deleteFailure(ids)
|
|
|
- ElMessage.success('删除成功')
|
|
|
- getList()
|
|
|
- } catch (error) {
|
|
|
- ElMessage.error('删除失败')
|
|
|
- }
|
|
|
-}
|
|
|
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
|
|
|
|
|
const reset = () => {
|
|
|
formData.value = {
|
|
|
@@ -593,7 +238,8 @@ const reset = () => {
|
|
|
formRef.value.resetFields()
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+/** 提交表单 */
|
|
|
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
|
|
const submitForm = async () => {
|
|
|
if (!formRef.value) return
|
|
|
|
|
|
@@ -604,7 +250,7 @@ const submitForm = async () => {
|
|
|
// 在提交前确保时间是时间戳格式
|
|
|
const submitData = { ...formData.value }
|
|
|
|
|
|
- if (mode.value === 'update' && formData.value.id) {
|
|
|
+ if (formType.value === 'create' && formData.value.id) {
|
|
|
// 更新API调用
|
|
|
submitData.id = formData.value.id
|
|
|
await IotFailureApi.updateFailure(submitData)
|
|
|
@@ -614,8 +260,8 @@ const submitForm = async () => {
|
|
|
await IotFailureApi.createFailure(submitData)
|
|
|
ElMessage.success('新增成功')
|
|
|
}
|
|
|
- open.value = false
|
|
|
- getList()
|
|
|
+ dialogVisible.value = false
|
|
|
+ emit('success')
|
|
|
} catch (error) {
|
|
|
ElMessage.error(error.message || '操作失败')
|
|
|
} finally {
|
|
|
@@ -626,346 +272,4 @@ const submitForm = async () => {
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
-const downloadFile = (response) => {
|
|
|
- // 创建 blob 对象
|
|
|
- const blob = new Blob([response], {
|
|
|
- type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
|
|
|
- })
|
|
|
-
|
|
|
- // 获取文件名
|
|
|
- let fileName = '事故事件上报.xlsx'
|
|
|
- const disposition = response.headers ? response.headers['content-disposition'] : ''
|
|
|
- if (disposition) {
|
|
|
- const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
|
|
|
- const matches = filenameRegex.exec(disposition)
|
|
|
- if (matches != null && matches[1]) {
|
|
|
- fileName = matches[1].replace(/['"]/g, '')
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 创建下载链接
|
|
|
- const url = window.URL.createObjectURL(blob)
|
|
|
- const link = document.createElement('a')
|
|
|
- link.href = url
|
|
|
- link.setAttribute('download', fileName)
|
|
|
-
|
|
|
- // 触发下载
|
|
|
- document.body.appendChild(link)
|
|
|
- link.click()
|
|
|
-
|
|
|
- // 清理
|
|
|
- document.body.removeChild(link)
|
|
|
- window.URL.revokeObjectURL(url)
|
|
|
-}
|
|
|
-
|
|
|
-let exportLoading = ref(false)
|
|
|
-const handleExport = async () => {
|
|
|
- try {
|
|
|
- exportLoading.value = true
|
|
|
- // 调用导出接口
|
|
|
- const response = await IotFailureApi.exportFailure(queryParams.value)
|
|
|
-
|
|
|
- // 下载文件
|
|
|
- downloadFile(response)
|
|
|
- exportLoading.value = false
|
|
|
- } catch (error) {
|
|
|
- ElMessage.error('导出失败,请重试')
|
|
|
- console.error('导出错误:', error)
|
|
|
- } finally {
|
|
|
- exportLoading.value = false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const cancel = () => {
|
|
|
- open.value = false
|
|
|
- reset()
|
|
|
-}
|
|
|
-
|
|
|
-const approvalDialogVisible = ref(false)
|
|
|
-const approvalDialogTitle = ref('审批流程')
|
|
|
-const approvalProcessList = ref([]) // 存储审批流程信息
|
|
|
-const approvalSuggestion = ref('')
|
|
|
-// 根据状态返回标签类型
|
|
|
-const getTagTypeByStatus = (status) => {
|
|
|
- const tagTypeMap = {
|
|
|
- 待处理: 'warning',
|
|
|
- 处理中: 'info',
|
|
|
- 已完成: 'success',
|
|
|
- 已驳回: 'danger',
|
|
|
- 已撤销: 'info',
|
|
|
- 已批准: 'success',
|
|
|
- 审批中: 'primary',
|
|
|
- 上报: 'success',
|
|
|
- 提交上报: 'primary'
|
|
|
- }
|
|
|
- return tagTypeMap[status] || 'info'
|
|
|
-}
|
|
|
-const getNodeStatusColor = (status) => {
|
|
|
- const colorMap = {
|
|
|
- 待处理: '#E6A23C',
|
|
|
- 处理中: '#409EFF',
|
|
|
- 已完成: '#67C23A',
|
|
|
- 已驳回: '#F56C6C',
|
|
|
- 已撤销: '#909399',
|
|
|
- 已批准: '#67C23A',
|
|
|
- 审批中: '#409EFF',
|
|
|
- 上报: '#229242',
|
|
|
- 提交上报: '#409EFF'
|
|
|
- }
|
|
|
- return colorMap[status] || '#90939'
|
|
|
-}
|
|
|
-
|
|
|
-const openApprovalDialog = async (row) => {
|
|
|
- approvalDialogVisible.value = true
|
|
|
- approvalDialogTitle.value = `审批流程详情`
|
|
|
- approvalSuggestion.value = '' // 清空审批建议
|
|
|
-
|
|
|
- try {
|
|
|
- const response = await IotApprovalApi.getApprovalProcess(row.id)
|
|
|
- const processList = response.list || []
|
|
|
-
|
|
|
- // 按 createTime 升序排序(时间正序)
|
|
|
- approvalProcessList.value = processList.sort((a, b) => a.createTime - b.createTime)
|
|
|
-
|
|
|
- // 如果没有数据,添加一条默认的“发起人”记录
|
|
|
- if (approvalProcessList.value.length === 0) {
|
|
|
- approvalProcessList.value.push({
|
|
|
- createTime: Date.now(),
|
|
|
- operator: '系统管理员',
|
|
|
- status: '提交上报',
|
|
|
- description: '发起事故事件上报申请',
|
|
|
- nodeName: '上报发起',
|
|
|
- opinion: ''
|
|
|
- })
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- ElMessage.error('获取审批流程失败')
|
|
|
- // 即使出错也显示一个基本记录
|
|
|
- approvalProcessList.value = [
|
|
|
- {
|
|
|
- createTime: Date.now(),
|
|
|
- operator: '系统',
|
|
|
- status: '错误',
|
|
|
- description: '无法获取审批流程信息',
|
|
|
- nodeName: '系统通知',
|
|
|
- opinion: ''
|
|
|
- }
|
|
|
- ]
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 监听窗口大小变化
|
|
|
-const handleResize = () => {
|
|
|
- // 这里可以添加响应式逻辑
|
|
|
-}
|
|
|
-
|
|
|
-// Lifecycle hooks
|
|
|
-onMounted(async () => {
|
|
|
- window.addEventListener('resize', handleResize)
|
|
|
- getList()
|
|
|
- deptList2.value = handleTree(await DeptApi.getSimpleDeptList())
|
|
|
-})
|
|
|
-
|
|
|
-onUnmounted(() => {
|
|
|
- window.removeEventListener('resize', handleResize)
|
|
|
-})
|
|
|
</script>
|
|
|
-
|
|
|
-<style scoped lang="scss">
|
|
|
-.app-container {
|
|
|
- padding: 15px 10px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 移动端适配 */
|
|
|
-@media (max-width: 768px) {
|
|
|
- .app-container {
|
|
|
- padding: 10px 5px;
|
|
|
- }
|
|
|
-
|
|
|
- .el-form-item__label {
|
|
|
- display: block;
|
|
|
- text-align: left;
|
|
|
- padding-bottom: 5px;
|
|
|
- }
|
|
|
-
|
|
|
- .el-form-item__content {
|
|
|
- margin-left: 0 !important;
|
|
|
- }
|
|
|
-
|
|
|
- .el-button + .el-button {
|
|
|
- margin-left: 5px;
|
|
|
- }
|
|
|
-
|
|
|
- /* 调整表格字体大小 */
|
|
|
- :deep(.el-table .el-table__cell) {
|
|
|
- padding: 8px 0;
|
|
|
- }
|
|
|
-
|
|
|
- :deep(.el-table th.el-table__cell) {
|
|
|
- padding: 10px 0;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* 通用样式 */
|
|
|
-.dialog-footer {
|
|
|
- text-align: right;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-textarea__inner) {
|
|
|
- min-height: 80px !important;
|
|
|
-}
|
|
|
-
|
|
|
-/* 移动端分页样式 */
|
|
|
-.mt-2.flex.justify-right {
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- margin-top: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 移动端按钮样式 */
|
|
|
-@media (max-width: 768px) {
|
|
|
- .el-button {
|
|
|
- margin-bottom: 5px;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .el-button {
|
|
|
- border-radius: 3px;
|
|
|
-}
|
|
|
-
|
|
|
-.drawer-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- border-bottom: 1px solid #ebeef5;
|
|
|
- padding-bottom: 20px;
|
|
|
- padding-left: 20px;
|
|
|
- width: 108%;
|
|
|
- margin-left: -15px;
|
|
|
-}
|
|
|
-
|
|
|
-.approval-process-container {
|
|
|
- padding: 10px 15px;
|
|
|
-
|
|
|
- .no-data {
|
|
|
- text-align: center;
|
|
|
- padding: 40px 0;
|
|
|
- }
|
|
|
-
|
|
|
- .approval-card {
|
|
|
- border: 1px solid #ebeef5;
|
|
|
- border-radius: 6px;
|
|
|
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
- transition: all 0.3s ease;
|
|
|
-
|
|
|
- &.status-completed {
|
|
|
- border-left: 4px solid #67c23a;
|
|
|
- }
|
|
|
-
|
|
|
- &:hover {
|
|
|
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
- }
|
|
|
-
|
|
|
- .card-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- padding-bottom: 12px;
|
|
|
- border-bottom: 1px dashed #ebeef5;
|
|
|
-
|
|
|
- .node-info {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
-
|
|
|
- .status-tag {
|
|
|
- font-weight: bold;
|
|
|
- }
|
|
|
-
|
|
|
- .node-name {
|
|
|
- font-weight: 600;
|
|
|
- color: #303133;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .operator-time {
|
|
|
- .time {
|
|
|
- color: #909399;
|
|
|
- font-size: 13px;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .card-content {
|
|
|
- padding: 12px 0;
|
|
|
-
|
|
|
- .label {
|
|
|
- font-weight: 600;
|
|
|
- color: #606266;
|
|
|
- display: inline-block;
|
|
|
- width: 70px;
|
|
|
- vertical-align: top;
|
|
|
- }
|
|
|
-
|
|
|
- .opinion,
|
|
|
- .description {
|
|
|
- color: #303133;
|
|
|
- line-height: 1.6;
|
|
|
- }
|
|
|
-
|
|
|
- .attachment-section {
|
|
|
- margin-top: 8px;
|
|
|
-
|
|
|
- .attachments {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 5px;
|
|
|
- margin-top: 5px;
|
|
|
-
|
|
|
- .attachment-link {
|
|
|
- display: inline-flex;
|
|
|
- align-items: center;
|
|
|
- padding-left: 70px;
|
|
|
- text-decoration: none;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- text-decoration: underline;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-@media (max-width: 768px) {
|
|
|
- .approval-process-container {
|
|
|
- padding: 5px;
|
|
|
-
|
|
|
- .approval-card {
|
|
|
- .card-header {
|
|
|
- flex-direction: column;
|
|
|
- gap: 8px;
|
|
|
- align-items: flex-start;
|
|
|
-
|
|
|
- .node-info {
|
|
|
- flex-wrap: wrap;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .card-content {
|
|
|
- .label {
|
|
|
- width: auto;
|
|
|
- display: block;
|
|
|
- margin-bottom: 4px;
|
|
|
- }
|
|
|
-
|
|
|
- .attachment-section .attachment-link {
|
|
|
- padding-left: 0;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|