Sfoglia il codice sorgente

Merge branch 'master' of http://1.94.244.160:3000/shuzhihua/pms-iot-vue

Zimo 1 giorno fa
parent
commit
65f5ef6924

+ 1 - 1
src/views/pms/qhse/index.vue

@@ -171,7 +171,7 @@
           <el-form-item label="分类" prop="classify">
             <el-select
               v-model="formData.classify"
-              placeholder="请选择平台"
+              placeholder="请选择分类"
               clearable
               class="!w-240px"
             >

+ 4 - 3
src/views/pms/qhse/iotmeasuredetect/IotMeasureDetectForm.vue

@@ -77,7 +77,7 @@
           </el-form-item>
         </el-col>
 
-        <el-col :span="12">
+        <!-- <el-col :span="12">
           <el-form-item label="部门" prop="deptId">
             <el-tree-select
               style="width: 100%"
@@ -91,7 +91,7 @@
               placeholder="请选择所在部门"
             />
           </el-form-item>
-        </el-col>
+        </el-col> -->
       </el-row>
 
       <el-row :gutter="20">
@@ -156,7 +156,7 @@
             {{ scope.$index + 1 }}
           </template>
         </el-table-column>
-        <el-table-column label="单位" align="center" prop="measureUnit" />
+        <el-table-column label="计量单位" align="center" prop="measureUnit" />
         <el-table-column label="名称" align="center" prop="measureName" />
         <el-table-column label="责任人" align="center" prop="dutyPerson" />
         <el-table-column label="品牌" align="center" prop="brand" />
@@ -371,6 +371,7 @@ const confirmSelectMeasure = () => {
   // 将选中的仪器信息填入表单
   formData.value.measureId = selectedMeasure.value.id
   formData.value.measureName = selectedMeasure.value.measureName
+  formData.value.deptId = selectedMeasure.value.deptId
 
   // 关闭选择仪器对话框
   measureDialogVisible.value = false

+ 0 - 1
src/views/pms/qhse/iotmeasuredetect/index.vue

@@ -103,7 +103,6 @@
 </template>
 
 <script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotMeasureDetectApi, IotMeasureDetectVO } from '@/api/pms/qhse/index'
 import IotMeasureDetectForm from './IotMeasureDetectForm.vue'

+ 640 - 0
src/views/pms/qhse/safety/index.vue

@@ -0,0 +1,640 @@
+<template>
+  <div class="safety-inspect-container">
+    <ContentWrap style="border: 0">
+      <!-- 搜索栏 -->
+      <el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
+        <el-form-item label="隐患等级" prop="dangerLevel">
+          <el-select
+            v-model="queryParams.dangerLevel"
+            placeholder="请选择隐患等级"
+            clearable
+            style="width: 200px"
+          >
+            <el-option
+              v-for="dict in getStrDictOptions(DICT_TYPE.DANGER_GRADE)"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="排查状态" prop="inspectStatus">
+          <el-select
+            v-model="queryParams.inspectStatus"
+            placeholder="请选择排查状态"
+            clearable
+            style="width: 200px"
+          >
+            <el-option label="待排查" value="0" />
+            <el-option label="已排查" value="1" />
+            <el-option label="整改中" value="2" />
+            <el-option label="已完成" value="3" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+          <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+          <el-button type="primary" @click="openForm('create')" color="#626aef">
+            <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-form>
+    </ContentWrap>
+
+    <ContentWrap style="border: 0">
+      <el-table
+        v-loading="loading"
+        :data="tableData"
+        border
+        style="width: 100%"
+        :header-cell-style="{ background: '#f5f7fa', color: '#333' }"
+        :cell-style="{ padding: '12px 8px' }"
+        height="70vh"
+      >
+        <el-table-column label="序号" width="70" align="center">
+          <template #default="scope">
+            {{ (pagination.pageNo - 1) * pagination.pageSize + scope.$index + 1 }}
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          prop="inspectArea"
+          label="排查区域"
+          width="150"
+          align="center"
+          fixed="left"
+        />
+
+        <el-table-column
+          prop="hazardDesc"
+          label="隐患描述"
+          min-width="200"
+          show-overflow-tooltip
+          align="center"
+        />
+
+        <el-table-column
+          prop="maybeAccident"
+          label="可能导致的事故"
+          min-width="180"
+          show-overflow-tooltip
+          align="center"
+        />
+
+        <el-table-column label="风险评价" width="280" align="center">
+          <el-table-column prop="possibility" label="可能性 (L)" width="70" align="center">
+            <template #default="{ row }">
+              {{ row.possibility }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="severity" label="严重性 (S)" width="70" align="center">
+            <template #default="{ row }">
+              {{ row.severity }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="riskValue" label="风险值 (R)" width="70" align="center">
+            <template #default="{ row }">
+              {{ row.riskValue }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="dangerLevel" label="隐患等级" width="90" align="center">
+            <template #default="scope">
+              <span v-if="scope.row.dangerLevel === 'low'" class="text-blue-600">低风险</span>
+              <span v-else-if="scope.row.dangerLevel === 'normal'" class="text-yellow-600"
+                >一般风险</span
+              >
+              <span v-else-if="scope.row.dangerLevel === 'big'" class="text-orange-600"
+                >较大风险</span
+              >
+              <span v-else class="text-red-600">重大风险</span>
+            </template>
+          </el-table-column>
+        </el-table-column>
+
+        <el-table-column
+          prop="rectifyMeasure"
+          label="整改措施"
+          min-width="200"
+          show-overflow-tooltip
+          align="center"
+        />
+
+        <el-table-column prop="responsiblePerson" label="责任人" width="120" align="center" />
+
+        <el-table-column prop="inspectStatus" label="排查状态" width="100" align="center">
+          <template #default="scope">
+            <el-tag v-if="scope.row.inspectStatus === '0'" type="info">待排查</el-tag>
+            <el-tag v-else-if="scope.row.inspectStatus === '1'" type="success">已排查</el-tag>
+            <el-tag v-else-if="scope.row.inspectStatus === '2'" type="warning">整改中</el-tag>
+            <el-tag v-else-if="scope.row.inspectStatus === '3'" type="success">已完成</el-tag>
+          </template>
+        </el-table-column>
+
+        <el-table-column prop="inspectTime" label="排查时间" width="160" align="center">
+          <template #default="scope">
+            {{ formatDate(scope.row.inspectTime) }}
+          </template>
+        </el-table-column>
+
+        <el-table-column label="操作" width="180" align="center" fixed="right">
+          <template #default="{ row }">
+            <div class="flex gap-3 justify-center">
+              <el-button link type="primary" @click="openForm('edit', row)"> 编辑 </el-button>
+              <el-button link type="success" @click="openForm('detail', row)"> 详情 </el-button>
+              <el-button link type="danger" @click="deleteRow(row)"> 删除 </el-button>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页 -->
+      <div class="mt-2 flex justify-right">
+        <el-pagination
+          v-model:current-page="pagination.pageNo"
+          v-model:page-size="pagination.pageSize"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          background
+        />
+      </div>
+    </ContentWrap>
+
+    <!-- 新增/编辑/详情弹窗 -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      :width="isMobile ? '100%' : '50%'"
+      :fullscreen="isMobile"
+      @close="resetForm"
+    >
+      <el-form
+        ref="formRef"
+        :model="formData"
+        :rules="formRules"
+        label-width="140px"
+        :disabled="viewMode"
+      >
+        <el-row :gutter="20">
+          <!-- 第一行:排查区域 + 隐患描述 -->
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="排查区域" prop="inspectArea">
+              <el-input
+                v-model="formData.inspectArea"
+                placeholder="请输入排查区域"
+                :required="!viewMode"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="隐患描述" prop="hazardDesc">
+              <el-input
+                v-model="formData.hazardDesc"
+                placeholder="请输入隐患描述"
+                :required="!viewMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <!-- 第二行:可能导致的事故 + 可能性 -->
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="可能导致的事故" prop="maybeAccident">
+              <el-input
+                v-model="formData.maybeAccident"
+                placeholder="请输入可能导致的事故"
+                type="textarea"
+                :rows="2"
+                :required="!viewMode"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="可能性 (L)" prop="possibility">
+              <el-input-number
+                v-model="formData.possibility"
+                controls-position="right"
+                :min="1"
+                :max="10"
+                style="width: 100%"
+                :disabled="viewMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <!-- 第三行:严重性 + 风险值 -->
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="严重性 (S)" prop="severity">
+              <el-input-number
+                v-model="formData.severity"
+                controls-position="right"
+                :min="1"
+                :max="10"
+                style="width: 100%"
+                :disabled="viewMode"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="风险值 (R)" prop="riskValue">
+              <el-input-number v-model="formData.riskValue" disabled style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <!-- 第四行:隐患等级 + 排查状态 -->
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="隐患等级" prop="dangerLevel">
+              <el-select
+                v-model="formData.dangerLevel"
+                placeholder="请选择隐患等级"
+                clearable
+                style="width: 100%"
+                :disabled="viewMode"
+              >
+                <el-option label="低风险" value="low" />
+                <el-option label="一般风险" value="normal" />
+                <el-option label="较大风险" value="big" />
+                <el-option label="重大风险" value="major" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="排查状态" prop="inspectStatus">
+              <el-select
+                v-model="formData.inspectStatus"
+                placeholder="请选择排查状态"
+                clearable
+                style="width: 100%"
+                :disabled="viewMode"
+              >
+                <el-option label="待排查" value="0" />
+                <el-option label="已排查" value="1" />
+                <el-option label="整改中" value="2" />
+                <el-option label="已完成" value="3" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <!-- 第五行:责任人 + 排查时间 -->
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="责任人" prop="responsiblePerson">
+              <el-input
+                v-model="formData.responsiblePerson"
+                placeholder="请输入责任人"
+                :required="!viewMode"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="排查时间" prop="inspectTime">
+              <el-date-picker
+                v-model="formData.inspectTime"
+                type="datetime"
+                placeholder="选择排查时间"
+                format="YYYY-MM-DD HH:mm:ss"
+                value-format="x"
+                style="width: 100%"
+                :disabled="viewMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <!-- 第六行:备注 -->
+          <el-col :xs="24" :sm="12">
+            <el-form-item label="备注" prop="remark">
+              <el-input
+                v-model="formData.remark"
+                type="textarea"
+                placeholder="请输入备注"
+                :rows="2"
+                :disabled="viewMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 整改措施单独一行(占满) -->
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="整改措施" prop="rectifyMeasure">
+              <el-input
+                v-model="formData.rectifyMeasure"
+                type="textarea"
+                :rows="4"
+                placeholder="请输入整改措施"
+                :required="!viewMode"
+                :disabled="viewMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <template #footer v-if="!viewMode">
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitForm">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, watch, onMounted, computed } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { IotDangerApi } from '@/api/pms/qhse/index'
+import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
+import { formatDate } from '@/utils/formatTime'
+
+// 查询参数
+const queryParams = reactive({
+  dangerLevel: '',
+  inspectStatus: ''
+})
+
+// 表格数据
+const tableData = ref([])
+const loading = ref(false)
+const total = ref(0)
+const exportLoading = ref(false)
+
+// 分页
+const pagination = reactive({
+  pageNo: 1,
+  pageSize: 10
+})
+
+// 弹窗控制
+const dialogVisible = ref(false)
+const dialogTitle = ref('')
+const viewMode = ref(false)
+const formRef = ref()
+const queryFormRef = ref()
+
+// 表单数据
+const formData = reactive({
+  id: null,
+  inspectArea: '', // 排查区域
+  hazardDesc: '', // 隐患描述
+  maybeAccident: '', // 可能导致的事故
+  possibility: 1, // 可能性
+  severity: 1, // 严重性
+  riskValue: 1, // 风险值(自动计算)
+  dangerLevel: '', // 隐患等级
+  rectifyMeasure: '', // 整改措施
+  responsiblePerson: '', // 责任人
+  inspectStatus: '', // 排查状态
+  inspectTime: null as number | null, // 排查时间
+  remark: '' // 备注
+})
+
+// 表单验证规则
+const formRules = reactive({
+  inspectArea: [{ required: true, message: '请输入排查区域', trigger: 'blur' }],
+  hazardDesc: [{ required: true, message: '请输入隐患描述', trigger: 'blur' }],
+  maybeAccident: [{ required: true, message: '请输入可能导致的事故', trigger: 'blur' }],
+  possibility: [{ required: true, message: '请输入可能性', trigger: 'change' }],
+  severity: [{ required: true, message: '请输入严重性', trigger: 'change' }],
+  dangerLevel: [{ required: true, message: '请选择隐患等级', trigger: 'change' }],
+  rectifyMeasure: [{ required: true, message: '请输入整改措施', trigger: 'blur' }],
+  responsiblePerson: [{ required: true, message: '请输入责任人', trigger: 'blur' }],
+  inspectStatus: [{ required: true, message: '请选择排查状态', trigger: 'change' }]
+})
+
+// 计算属性:移动端判断
+const isMobile = computed(() => {
+  return window.innerWidth < 768
+})
+
+// 监听可能性和严重性,自动计算风险值
+watch(
+  () => [formData.possibility, formData.severity],
+  ([possibility, severity]) => {
+    if (possibility && severity) {
+      formData.riskValue = possibility * severity
+    }
+  },
+  { immediate: true }
+)
+
+// 加载数据
+const loadTableData = async () => {
+  loading.value = true
+  try {
+    const params = {
+      pageNo: pagination.pageNo,
+      pageSize: pagination.pageSize,
+      ...queryParams
+    }
+    const res = await IotDangerApi.getDangerList(params)
+    tableData.value = res.list || []
+    total.value = res.total || 0
+  } catch (error) {
+    ElMessage.error('加载列表失败')
+    console.error('加载错误:', error)
+  } finally {
+    loading.value = false
+  }
+}
+
+// 搜索
+const handleQuery = () => {
+  pagination.pageNo = 1
+  loadTableData()
+}
+
+// 重置查询
+const resetQuery = () => {
+  queryFormRef.value?.resetFields()
+  pagination.pageNo = 1
+  loadTableData()
+}
+
+// 每页数量变化
+const handleSizeChange = (val: number) => {
+  pagination.pageSize = val
+  pagination.pageNo = 1
+  loadTableData()
+}
+
+// 当前页变化
+const handleCurrentChange = (val: number) => {
+  pagination.pageNo = val
+  loadTableData()
+}
+
+// 删除确认
+const deleteRow = async (row: any) => {
+  try {
+    await ElMessageBox.confirm(`确认删除 "${row.hazardDesc}" 吗?`, '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning'
+    })
+
+    await IotDangerApi.deleteDanger(row.id)
+    ElMessage.success('删除成功')
+    loadTableData()
+  } catch (error: any) {
+    if (error !== 'cancel') {
+      ElMessage.error('删除失败')
+    }
+  }
+}
+
+// 打开表单
+const openForm = async (type: string, row: any = null) => {
+  dialogVisible.value = true
+  viewMode.value = type === 'detail'
+
+  if (type === 'create') {
+    dialogTitle.value = '新增隐患排查'
+    resetForm()
+  } else if (type === 'edit') {
+    dialogTitle.value = '编辑隐患排查'
+    Object.assign(formData, row)
+    // 确保数值类型正确
+    formData.possibility = Number(row.possibility) || 1
+    formData.severity = Number(row.severity) || 1
+    formData.riskValue = Number(row.riskValue) || 1
+  } else if (type === 'detail') {
+    dialogTitle.value = '隐患排查详情'
+    Object.assign(formData, row)
+    formData.possibility = Number(row.possibility) || 1
+    formData.severity = Number(row.severity) || 1
+    formData.riskValue = Number(row.riskValue) || 1
+  }
+}
+
+// 重置表单
+const resetForm = () => {
+  Object.keys(formData).forEach((key: string) => {
+    formData[key] =
+      key === 'id' ? null : ['possibility', 'severity', 'riskValue'].includes(key) ? 1 : ''
+  })
+  formRef.value?.clearValidate()
+  viewMode.value = false
+}
+
+// 提交表单
+const submitForm = async () => {
+  if (!formRef.value) return
+
+  await formRef.value.validate()
+
+  try {
+    const data = {
+      ...formData,
+      possibility: Number(formData.possibility),
+      severity: Number(formData.severity),
+      riskValue: Number(formData.riskValue)
+    }
+
+    if (dialogTitle.value === '新增隐患排查') {
+      await IotDangerApi.createDanger(data)
+      ElMessage.success('新增成功')
+    } else {
+      await IotDangerApi.updateDanger(data)
+      ElMessage.success('修改成功')
+    }
+
+    dialogVisible.value = false
+    loadTableData()
+  } catch (error) {
+    ElMessage.error('提交失败')
+    console.error('提交错误:', error)
+  }
+}
+
+// 导出
+const downloadFile = (response: any) => {
+  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)
+}
+
+const handleExport = async () => {
+  try {
+    exportLoading.value = true
+    const response = await IotDangerApi.exportDanger(queryParams)
+    downloadFile(response)
+    ElMessage.success('导出成功')
+  } catch (error) {
+    ElMessage.error('导出失败,请重试')
+    console.error('导出错误:', error)
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+// 页面挂载后加载数据
+onMounted(() => {
+  loadTableData()
+})
+</script>
+
+<style scoped lang="scss">
+.safety-inspect-container {
+  margin: 20px;
+  margin-top: 10px;
+}
+
+::v-deep .el-button {
+  border-radius: 0;
+}
+
+::v-deep .el-select__wrapper {
+  border-radius: 0 !important;
+  height: 26px;
+}
+
+::v-deep(.el-dialog__body) {
+  max-height: 70vh;
+  overflow-y: auto;
+  padding-right: 10px;
+}
+
+// 移动端适配
+@media (max-width: 768px) {
+  .safety-inspect-container {
+    margin: 10px;
+  }
+
+  ::v-deep .el-form-item__label {
+    width: 100px !important;
+  }
+}
+</style>