yanghao 1 天之前
父節點
當前提交
3436220f5f
共有 3 個文件被更改,包括 229 次插入1097 次删除
  1. 1 1
      .env.local
  2. 176 872
      src/views/pms/qhse/faultReport/QhseFaultReportForm.vue
  3. 52 224
      src/views/pms/qhse/faultReport/index.vue

+ 1 - 1
.env.local

@@ -4,7 +4,7 @@ NODE_ENV=development
 VITE_DEV=true
 
 # 请求路径  http://192.168.188.149:48080  https://iot.deepoil.cc  http://172.26.0.56:48080
-VITE_BASE_URL='https://iot.deepoil.cc'
+VITE_BASE_URL='http://172.26.0.56:48080'
 
 # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
 VITE_UPLOAD_TYPE=server

+ 176 - 872
src/views/pms/qhse/faultReport/QhseFaultReportForm.vue

@@ -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>

+ 52 - 224
src/views/pms/qhse/faultReport/index.vue

@@ -36,7 +36,7 @@
               <el-button @click="resetQuery" :icon="Refresh">重置</el-button>
               <el-button
                 type="primary"
-                @click="openForm('create')"
+                @click="openForm('create', undefined, false)"
                 color="#626aef"
                 v-hasPermi="['rq:iot-accident-report:create']"
               >
@@ -103,7 +103,7 @@
             <el-button
               link
               type="primary"
-              @click="openForm('detail', row)"
+              @click="openForm('detail', row.id, true)"
               :icon="View"
               v-hasPermi="['rq:iot-accident-report:query']"
               >详情</el-button
@@ -128,186 +128,8 @@
     </ContentWrap>
 
     <!-- 表单弹窗 -->
-    <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>
+    <!-- 表单弹窗:添加/修改 -->
+    <QhseFaultReportForm ref="formRef" @success="getList" />
 
     <el-drawer
       :title="approvalDialogTitle"
@@ -405,6 +227,7 @@ 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'
+import QhseFaultReportForm from './QhseFaultReportForm.vue'
 
 // Data
 const loading = ref(false)
@@ -511,48 +334,53 @@ const handleQuery = () => {
 }
 
 // 打开表单 - 支持新增、编辑和详情
-const openForm = async (modeVal, row = {}) => {
-  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
-    }
-
-    open.value = true
-  }
+// const openForm = async (modeVal, row = {}) => {
+//   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
+//     }
+
+//     open.value = true
+//   }
+// }
+
+/** 添加/修改操作 */
+const openForm = (type, id, disable) => {
+  formRef.value.open(type, id, disable)
 }
 
 const handleDelete = async (row) => {