zouyu
4 天以前 69250232abffb8b578d9b94c20f4d560492efa02
Merge branch 'dev_tide_gybjyhglxt' into dev_tide_gybjyhglxt_xindao

# Conflicts:
# src/store/modules/user.js
# vite.config.js
已添加2个文件
已修改2个文件
已删除3个文件
1934 ■■■■ 文件已修改
src/views/alarmManagement/alarmAnalysis/alarmTrend.vue 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/alarmManagement/alarmConfig/Form.vue 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/alarmManagement/alarmConfig/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/alarmManagement/alarmConfig/alarmRule.vue 355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/alarmManagement/alarmKnowledge/alarmHandle.vue 652 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/alarmManagement/alarmMonitor/realTimeAlarm.vue 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/alarmManagement/alarmReport/alarmStats.vue 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/alarmManagement/alarmAnalysis/alarmTrend.vue
ÎļþÒÑɾ³ý
src/views/alarmManagement/alarmConfig/Form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,151 @@
<template>
  <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
    <el-row :gutter="20">
      <el-col :span="12">
        <el-form-item label="规则名称" prop="deviceName">
          <el-input v-model="form.deviceName" placeholder="请输入规则名称" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="设备类型" prop="deviceModel">
          <el-input v-model="form.deviceModel" placeholder="请输入设备类型" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="监控参数" prop="supplierName">
          <el-input v-model="form.supplierName" placeholder="请输入监控参数" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="报警级别" prop="unit">
          <el-input v-model="form.unit" placeholder="请输入报警级别" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="是否启用" prop="status">
          <el-switch
              v-model="form.status"
              :active-value="1"
              :inactive-value="0"
          />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="创建日期" prop="createTime">
          <el-date-picker
            style="width: 100%"
            v-model="form.createTime"
            format="YYYY-MM-DD"
            value-format="YYYY-MM-DD HH:mm:ss"
            type="date"
            placeholder="请选择录入日期"
            clearable
          />
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>
<script setup>
import useFormData from "@/hooks/useFormData.js";
// import useUserStore from "@/store/modules/user";
import { getLedgerById } from "@/api/equipmentManagement/ledger.js";
import dayjs from "dayjs";
import {
  calculateTaxIncludeTotalPrice,
  calculateTaxExclusiveTotalPrice,
} from "@/utils/summarizeTable.js";
import { ElMessage } from "element-plus";
import {ref} from "vue";
defineOptions({
  name: "设备台账表单",
});
const formRef = ref(null);
const operationType = ref('');
const formRules = {
    deviceName: [{ required: true, trigger: "blur", message: "请输入" }],
    deviceModel: [{ required: true, trigger: "blur", message: "请输入" }],
    supplierName: [{ required: true, trigger: "blur", message: "请输入" }],
    unit: [{ required: true, trigger: "blur", message: "请输入" }],
    taxRate: [{ required: true, trigger: "change", message: "请选择" }],
}
const { form, resetForm } = useFormData({
  deviceName: undefined, // è®¾å¤‡åç§°
  deviceModel: undefined, // è§„格型号
  deviceBrand: undefined, // è®¾å¤‡å“ç‰Œ
  supplierName: undefined, // ä¾›åº”商
  storageLocation: undefined, // å­˜æ”¾ä½ç½®
  enableDepreciation: false, // æ˜¯å¦å¯ç”¨æŠ˜æ—§
  unit: undefined, // å•位
  number: 1, // æ•°é‡
  taxIncludingPriceUnit: undefined, // å«ç¨Žå•ä»·
  taxIncludingPriceTotal: undefined, // å«ç¨Žæ€»ä»·
  taxRate: undefined, // ç¨Žçއ
  unTaxIncludingPriceTotal: undefined, // ä¸å«ç¨Žæ€»ä»·
  // createUser: useUserStore().nickName, // å½•入人
  createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // å½•入日期
    planRuntimeTime: dayjs().format("YYYY-MM-DD"), // å½•入日期
});
const loadForm = async (id) => {
    if (id) {
        operationType.value = 'edit'
    }
  const { code, data } = await getLedgerById(id);
  if (code == 200) {
    form.deviceName = data.deviceName;
    form.deviceModel = data.deviceModel;
    form.deviceBrand = data.deviceBrand;
    form.supplierName = data.supplierName;
    form.storageLocation = data.storageLocation;
    form.enableDepreciation = data.enableDepreciation;
    form.unit = data.unit;
    form.number = 1;
    form.taxIncludingPriceUnit = data.taxIncludingPriceUnit;
    form.taxIncludingPriceTotal = data.taxIncludingPriceTotal;
    form.taxRate = data.taxRate;
    form.unTaxIncludingPriceTotal = data.unTaxIncludingPriceTotal;
    form.createTime = data.createTime;
  }
};
const mathNum = () => {
  if (!form.taxIncludingPriceUnit) {
    ElMessage.error("请输入单价");
    return;
  }
  form.taxIncludingPriceTotal = calculateTaxIncludeTotalPrice(
    form.taxIncludingPriceUnit,
    form.number
  );
  if (form.taxRate) {
    form.unTaxIncludingPriceTotal = calculateTaxExclusiveTotalPrice(
      form.taxIncludingPriceTotal,
      form.taxRate
    );
  }
};
// æ¸…除表单校验状态
const clearValidate = () => {
  formRef.value?.clearValidate();
};
// é‡ç½®è¡¨å•数据和校验状态
const resetFormAndValidate = () => {
  resetForm();
  clearValidate();
};
defineExpose({
  form,
  loadForm,
  resetForm,
  clearValidate,
  resetFormAndValidate,
    formRef,
});
</script>
src/views/alarmManagement/alarmConfig/Modal.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
<template>
  <el-dialog :title="modalOptions.title" v-model="visible" @close="close">
    <Form ref="formRef"></Form>
    <template #footer>
            <el-button type="primary" @click="sendForm" :loading="loading">
                {{ modalOptions.confirmText }}
            </el-button>
      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import { useModal } from "@/hooks/useModal.js";
import { addLedger, editLedger } from "@/api/equipmentManagement/ledger.js";
import Form from "./Form.vue";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance()
defineOptions({
  name: "设备台账新增编辑",
});
const emits = defineEmits(["success"]);
const formRef = ref();
const {
  id,
  visible,
  loading,
  openModal,
  modalOptions,
  handleConfirm,
  closeModal,
} = useModal({ title: "设备台账" });
const sendForm = () => {
    proxy.$refs.formRef.$refs.formRef.validate(async valid => {
        if (valid) {
            const {code} = id.value
                ? await editLedger({id: id.value, ...formRef.value.form})
                : await addLedger(formRef.value.form);
            if (code == 200) {
                emits("success");
                ElMessage({message: "操作成功", type: "success"});
                close();
            } else {
                loading.value = false;
            }
        }
    })
};
const close = () => {
    formRef.value.resetFormAndValidate();
  closeModal();
};
const loadForm = async (id) => {
  openModal(id);
  await nextTick();
  formRef.value.loadForm(id);
};
defineExpose({
  openModal,
  loadForm,
});
</script>
src/views/alarmManagement/alarmConfig/alarmRule.vue
@@ -1,173 +1,222 @@
<template>
  <div class="alarm-rule-config">
    <el-card shadow="never" class="search-card">
      <el-form :inline="true" :model="searchForm" class="demo-form-inline">
        <el-form-item label="规则名称">
          <el-input v-model="searchForm.ruleName" placeholder="请输入规则名称" />
        </el-form-item>
        <el-form-item label="设备类型">
          <el-select v-model="searchForm.equipmentType" placeholder="请选择设备类型">
            <el-option label="工艺设备" value="工艺设备" />
            <el-option label="检测设备" value="检测设备" />
            <el-option label="其他设备" value="其他设备" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
          <el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <el-card shadow="never" class="table-card">
      <template #header>
        <div class="card-header">
          <span>报警规则配置</span>
          <el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增规则</el-button>
        </div>
      </template>
      <el-table :data="ruleList" style="width: 100%" :header-cell-style="{textAlign: 'center'}" :cell-style="{textAlign: 'center'}">
        <el-table-column type="index" label="序号" width="80" />
        <el-table-column prop="ruleName" label="规则名称" />
        <el-table-column prop="equipmentType" label="设备类型" />
        <el-table-column prop="parameter" label="监控参数" />
        <el-table-column prop="alarmLevel" label="报警级别" />
        <el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip/>
        <el-table-column prop="status" label="状态" width="150">
          <template #default="scope">
            <el-switch v-model="scope.row.status" active-text="启用" inactive-text="禁用" />
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150" fixed="right">
          <template #default="scope">
            <el-button size="small" type="text" @click="handleEdit(scope.row)">编辑</el-button>
            <el-button size="small" type="text" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <div class="pagination">
        <el-pagination
          layout="total, sizes, prev, pager, next, jumper"
          :total="ruleList.length"
          :page-size="10"
          :page-sizes="[10, 20, 30, 50]"
  <div class="app-container">
    <el-form :model="filters" :inline="true">
      <el-form-item label="规则名称">
        <el-input
          v-model="filters.deviceName"
          style="width: 240px"
          placeholder="请输入规则名称"
          clearable
          @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="设备类型">
        <el-input
            v-model="filters.deviceModel"
            style="width: 240px"
            placeholder="请输入设备类型"
            clearable
            @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="监控参数">
        <el-input
            v-model="filters.supplierName"
            style="width: 240px"
            placeholder="请输入监控参数"
            clearable
            @change="getTableData"
        />
      </el-form-item>
    </el-form>
    <div class="table_list">
      <div class="actions">
        <div></div>
        <div>
          <el-button type="primary" @click="add" icon="Plus"> æ–°å¢ž </el-button>
          <el-button
            type="danger"
            icon="Delete"
            :disabled="multipleList.length <= 0"
            @click="deleteRow(multipleList.map((item) => item.id))"
          >
            æ‰¹é‡åˆ é™¤
          </el-button>
        </div>
      </div>
    </el-card>
      <PIMTable
        rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
        :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
      </PIMTable>
    </div>
    <Modal ref="modalRef" @success="getTableData"></Modal>
    <el-dialog v-model="qrDialogVisible" title="二维码" width="300px">
      <div style="text-align:center;">
        <img :src="qrCodeUrl" alt="二维码" style="width:200px;height:200px;" />
        <div style="margin:10px 0;">
          <el-button type="primary" @click="downloadQRCode">下载二维码图片</el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: 'AlarmRule',
  data() {
    return {
      searchForm: {
        ruleName: '',
        equipmentType: ''
      },
      ruleList: [
        {
          id: 1,
          ruleName: '温度过高报警',
          equipmentType: '工艺设备',
          parameter: '温度',
          alarmLevel: '严重',
          createTime: '2025-12-01 10:30:00',
          status: true
        },
        {
          id: 2,
          ruleName: '压力异常报警',
          equipmentType: '工艺设备',
          parameter: '压力',
          alarmLevel: '中等',
          createTime: '2025-12-02 14:20:00',
          status: true
        },
        {
          id: 3,
          ruleName: '流量过低报警',
          equipmentType: '检测设备',
          parameter: '流量',
          alarmLevel: '轻微',
          createTime: '2025-12-03 09:15:00',
          status: false
        },
        {
          id: 4,
          ruleName: '电压不稳定报警',
          equipmentType: '其他设备',
          parameter: '电压',
          alarmLevel: '中等',
          createTime: '2025-12-04 16:45:00',
          status: true
        },
        {
          id: 5,
          ruleName: '液位异常报警',
          equipmentType: '工艺设备',
          parameter: '液位',
          alarmLevel: '严重',
          createTime: '2025-12-05 11:20:00',
          status: true
        }
      ]
    }
<script setup>
import { usePaginationApi } from "../../../hooks/usePaginationApi.jsx";
import { getLedgerPage, delLedger } from "../../..//api/equipmentManagement/ledger.js";
import { onMounted, getCurrentInstance } from "vue";
import Modal from "./Modal.vue";
import { ElMessageBox, ElMessage } from "element-plus";
import dayjs from "dayjs";
import { ref } from "vue";
defineOptions({
  name: "设备台账",
});
// è¡¨æ ¼å¤šé€‰æ¡†é€‰ä¸­é¡¹
const multipleList = ref([]);
const { proxy } = getCurrentInstance();
const modalRef = ref();
const qrDialogVisible = ref(false);
const qrCodeUrl = ref("");
const qrRowData = ref(null);
const {
  filters,
  columns,
  dataList,
  pagination,
  getTableData,
  resetFilters,
  onCurrentChange,
} = usePaginationApi(
  getLedgerPage,
  {
    deviceName: undefined,
    deviceModel: undefined,
    supplierName: undefined,
    unit: undefined,
    entryDateStart: undefined,
    entryDateEnd: undefined,
  },
  methods: {
    handleSearch() {
      console.log('搜索', this.searchForm)
  [
    {
      label: "规则名称",
      align: "center",
      prop: "deviceName",
    },
    handleReset() {
      this.searchForm = {
        ruleName: '',
        equipmentType: ''
      }
    {
      label: "设备类型",
      align: "center",
      prop: "deviceModel",
    },
    handleAdd() {
      console.log('新增规则')
    {
      label: "监控参数",
      align: "center",
      prop: "supplierName",
    },
    handleEdit(row) {
      console.log('编辑规则', row)
    {
      label: "报警级别",
      align: "center",
      prop: "unit",
    },
    handleDelete(row) {
      console.log('删除规则', row)
    {
      label: "创建时间",
      align: "center",
      prop: "createTime",
    },
    {
      label: "是否启用",
      align: "center",
      prop: "status",
    },
        {
            dataType: "action",
            label: "操作",
            align: "center",
            fixed: 'right',
            width: 150,
            operation: [
                {
                    name: "编辑",
                    type: "text",
                    clickFun: (row) => {
                        edit(row.id)
                    },
                },
            ],
        },
  ]
);
// å¤šé€‰åŽåšä»€ä¹ˆ
const handleSelectionChange = (selectionList) => {
  multipleList.value = selectionList;
};
const add = () => {
  modalRef.value.openModal();
};
const edit = (id) => {
  modalRef.value.loadForm(id);
};
const changePage = ({ page, limit }) => {
  pagination.currentPage = page;
    pagination.pageSize = limit;
  onCurrentChange(page);
};
const deleteRow = (id) => {
  ElMessageBox.confirm("此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(async () => {
    const { code } = await delLedger(id);
    if (code == 200) {
      ElMessage({
        type: "success",
        message: "删除成功",
      });
      getTableData();
    }
  });
};
const changeDaterange = (value) => {
  if (value) {
    filters.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
    filters.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
  } else {
    filters.entryDateStart = undefined;
    filters.entryDateEnd = undefined;
  }
}
  getTableData();
};
onMounted(() => {
  getTableData();
});
</script>
<style scoped>
.alarm-rule-config {
  padding: 16px;
  background-color: #f0f2f5;
  min-height: 100vh;
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
.search-card {
  margin-bottom: 16px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.table-card {
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.card-header {
.actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20px;
  margin-bottom: 10px;
}
.pagination {
  margin-top: 16px;
  display: flex;
  justify-content: flex-end;
  padding-right: 20px;
}
</style>
src/views/alarmManagement/alarmKnowledge/alarmHandle.vue
@@ -1,180 +1,498 @@
<template>
  <div class="alarm-handle-knowledge">
    <el-card shadow="never" class="search-card">
      <el-form :inline="true" :model="searchForm" class="demo-form-inline">
        <el-form-item label="知识库标题">
          <el-input v-model="searchForm.title" placeholder="请输入知识库标题" />
        </el-form-item>
        <el-form-item label="报警类型">
          <el-select v-model="searchForm.alarmType" placeholder="请选择报警类型" clearable>
            <el-option label="温度报警" value="温度报警" />
            <el-option label="压力报警" value="压力报警" />
            <el-option label="振动报警" value="振动报警" />
            <el-option label="液位报警" value="液位报警" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
          <el-button icon="el-icon-plus" @click="handleAdd">新增</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <el-card shadow="never" class="table-card" >
      <el-table :data="knowledgeList" style="width: 100%" :header-cell-style="{textAlign: 'center'}" :cell-style="{textAlign: 'center'}">
        <el-table-column type="index" label="序号" width="80" />
        <el-table-column prop="title" label="知识库标题" min-width="200" />
        <el-table-column prop="alarmType" label="报警类型" width="120" />
        <el-table-column prop="alarmLevel" label="报警级别" width="100">
          <template #default="scope">
            <el-tag :type="getAlarmLevelType(scope.row.alarmLevel)">
              {{ scope.row.alarmLevel }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" width="180" />
        <el-table-column prop="creator" label="创建人" width="100" />
        <el-table-column prop="status" label="状态" width="100">
          <template #default="scope">
            <el-tag :type="scope.row.status === '启用' ? 'success' : 'info'">
              {{ scope.row.status }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="250" fixed="right">
          <template #default="scope">
            <el-button size="small" type="text" icon="el-icon-view" @click="handleView(scope.row)">查看</el-button>
            <el-button size="small" type="text" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
            <el-button size="small" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <div class="pagination">
        <el-pagination
          layout="total, sizes, prev, pager, next, jumper"
          :total="knowledgeList.length"
          :page-size="10"
          :page-sizes="[10, 20, 30, 50]"
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">知识库标题:</span>
        <el-input
          v-model="searchForm.customerName"
          style="width: 240px"
          placeholder="请输入"
          @change="handleQuery"
          clearable
          :prefix-icon="Search"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
          >搜索</el-button
        >
      </div>
    </el-card>
      <div>
        <el-button type="primary" @click="openForm('add')">新增知识库</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
    </div>
    <div class="table_list">
      <PIMTable
        rowKey="id"
        :column="tableColumn"
        :tableData="tableData"
        :page="page"
        :isSelection="true"
        @selection-change="handleSelectionChange"
        :tableLoading="tableLoading"
        @pagination="pagination"
      ></PIMTable>
    </div>
    <el-dialog
      v-model="dialogFormVisible"
      :title="operationType === 'add' ? '新增知识库' : '编辑知识库'"
      width="70%"
      @close="closeDia"
    >
      <el-form
        :model="form"
        label-width="140px"
        label-position="top"
        :rules="rules"
        ref="formRef"
      >
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="知识库标题:" prop="customerName">
              <el-input
                v-model="form.customerName"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item
              label="报警类型:"
              prop="taxpayerIdentificationNumber"
            >
              <el-input
                v-model="form.taxpayerIdentificationNumber"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="报警级别:" prop="companyAddress">
              <el-select
                  v-model="form.companyAddress"
                  placeholder="请选择报警级别"
                  clearable
                  style="width: 100%"
              >
                <el-option label="一般" value="一般" />
                <el-option label="轻微" value="轻微" />
                <el-option label="严重" value="严重" />
              </el-select>
            </el-form-item>
          </el-col>
                    <el-col :span="12">
                        <el-form-item label="联系人:" prop="companyPhone">
                            <el-input v-model="form.companyPhone" placeholder="请输入" clearable  />
                        </el-form-item>
                    </el-col>
                </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确认</el-button>
          <el-button @click="closeDia">取消</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- ç”¨æˆ·å¯¼å…¥å¯¹è¯æ¡† -->
    <el-dialog
      :title="upload.title"
      v-model="upload.open"
      width="400px"
      append-to-body
    >
      <el-upload
        ref="uploadRef"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="upload.headers"
        :action="upload.url + '?updateSupport=' + upload.updateSupport"
        :disabled="upload.isUploading"
        :before-upload="upload.beforeUpload"
        :on-progress="upload.onProgress"
        :on-success="upload.onSuccess"
        :on-error="upload.onError"
        :on-change="upload.onChange"
        :auto-upload="false"
        drag
      >
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <template #tip>
          <div class="el-upload__tip text-center">
            <span>仅允许导入xls、xlsx格式文件。</span>
            <el-link
              type="primary"
              :underline="false"
              style="font-size: 12px; vertical-align: baseline"
              @click="importTemplate"
              >下载模板</el-link
            >
          </div>
        </template>
      </el-upload>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitFileForm">ç¡® å®š</el-button>
          <el-button @click="upload.open = false">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: 'AlarmHandleKnowledge',
  data() {
    return {
      searchForm: {
        title: '',
        alarmType: ''
      },
      knowledgeList: [
        {
          id: 1,
          title: '反应釜温度过高报警处理流程',
          alarmType: '温度报警',
          alarmLevel: '严重',
          createTime: '2025-12-01 14:30:00',
          creator: '管理员',
          status: '启用'
        },
        {
          id: 2,
          title: '离心泵振动异常报警处理指南',
          alarmType: '振动报警',
          alarmLevel: '中等',
          createTime: '2025-12-02 09:15:00',
          creator: '设备工程师',
          status: '启用'
        },
        {
          id: 3,
          title: '储罐液位过低报警处理方法',
          alarmType: '液位报警',
          alarmLevel: '轻微',
          createTime: '2025-12-03 16:45:00',
          creator: '工艺工程师',
          status: '启用'
        },
        {
          id: 4,
          title: '压缩机压力过高报警应急预案',
          alarmType: '压力报警',
          alarmLevel: '严重',
          createTime: '2025-12-04 11:20:00',
          creator: '安全主管',
          status: '启用'
        },
        {
          id: 5,
          title: '干燥机湿度异常报警处理流程',
          alarmType: '湿度报警',
          alarmLevel: '中等',
          createTime: '2025-12-05 15:10:00',
          creator: '工艺工程师',
          status: '禁用'
        }
      ]
<script setup>
import {onMounted, ref} from "vue";
import { Search } from "@element-plus/icons-vue";
import {
  addCustomer,
  delCustomer,
  getCustomer,
  listCustomer,
  updateCustomer,
} from "@/api/basicData/customerFile.js";
import { ElMessageBox } from "element-plus";
import { userListNoPage } from "@/api/system/user.js";
import useUserStore from "@/store/modules/user";
import { getToken } from "@/utils/auth.js";
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const tableColumn = ref([
  {
    label: "知识库标题",
    prop: "customerName",
    width: 220,
  },
  {
    label: "报警类型",
    prop: "taxpayerIdentificationNumber",
    width: 220,
  },
  {
    label: "报警级别",
    prop: "companyAddress",
    width: 250,
    formatter: (row, column, cellValue) => {
      const levelMap = {
        '一般': '一般',
        '轻微': '轻微',
        '严重': '严重'
      };
      return levelMap[cellValue] || cellValue;
    }
  },
  methods: {
    getAlarmLevelType(level) {
      switch (level) {
        case '严重':
          return 'danger'
        case '中等':
          return 'warning'
        case '轻微':
          return 'info'
        default:
          return 'info'
      }
    },
    handleSearch() {
      console.log('搜索知识库', this.searchForm)
    },
    handleAdd() {
      console.log('新增知识库')
    },
    handleView(row) {
      console.log('查看知识库详情', row)
    },
    handleEdit(row) {
      console.log('编辑知识库', row)
    },
    handleDelete(row) {
      console.log('删除知识库', row)
  {
    label: "联系人",
    prop: "companyPhone",
  },
  {
    label: "创建时间",
    prop: "maintenanceTime",
    width: 100,
  },
  {
    dataType: "action",
    label: "操作",
    align: "center",
        fixed: 'right',
    operation: [
      {
        name: "编辑",
        type: "text",
        clickFun: (row) => {
          openForm("edit", row);
        }
      },
    ],
  },
]);
const tableData = ref([]);
const selectedRows = ref([]);
const userList = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 100,
  total: 0,
});
const total = ref(0);
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref("");
const dialogFormVisible = ref(false);
const formYYs = ref({    // å…¶ä»–字段...
  contactList: [
    {
      contactPerson: "",
      contactPhone: ""
    }
  ]
});
const data = reactive({
  searchForm: {
    customerName: "",
  },
  form: {
    customerName: "",
    taxpayerIdentificationNumber: "",
    companyAddress: "",
    addressPhone: "",
    contactPerson: "",
    contactPhone: "",
    maintainer: "",
    maintenanceTime: "",
    basicBankAccount: "",
    bankAccount: "",
    bankCode: "",
  },
  rules: {
    customerName: [{ required: true, message: "请输入", trigger: "blur" }],
    taxpayerIdentificationNumber: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    companyAddress: [{ required: true, message: "请输入", trigger: "blur" }],
    companyPhone: [{ required: true, message: "请输入", trigger: "blur" }],
    // contactPerson: [{ required: true, message: "请输入", trigger: "blur" }],
    // contactPhone: [{ required: true, message: "请输入", trigger: "blur" }],
    maintainer: [{ required: false, message: "请选择", trigger: "change" }],
    maintenanceTime: [
      { required: false, message: "请选择", trigger: "change" },
    ],
    basicBankAccount: [{ required: true, message: "请输入", trigger: "blur" }],
    bankAccount: [{ required: true, message: "请输入", trigger: "blur" }],
    bankCode: [{ required: true, message: "请输入", trigger: "blur" }],
  },
});
const upload = reactive({
  // æ˜¯å¦æ˜¾ç¤ºå¼¹å‡ºå±‚(客户导入)
  open: false,
  // å¼¹å‡ºå±‚标题(客户导入)
  title: "",
  // æ˜¯å¦ç¦ç”¨ä¸Šä¼ 
  isUploading: false,
  // è®¾ç½®ä¸Šä¼ çš„请求头部
  headers: { Authorization: "Bearer " + getToken() },
  // ä¸Šä¼ çš„地址
  url: import.meta.env.VITE_APP_BASE_API + "/basic/customer/importData",
  // æ–‡ä»¶ä¸Šä¼ å‰çš„回调
  beforeUpload: (file) => {
    console.log('文件即将上传', file);
    // å¯ä»¥åœ¨æ­¤å¤„做文件类型或大小校验
    const isValid = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
    if (!isValid) {
      proxy.$modal.msgError("只能上传 Excel æ–‡ä»¶");
    }
    return isValid;
  },
  // æ–‡ä»¶çŠ¶æ€æ”¹å˜æ—¶çš„å›žè°ƒ
  onChange: (file, fileList) => {
    console.log('文件状态改变', file, fileList);
  },
  // æ–‡ä»¶ä¸Šä¼ æˆåŠŸæ—¶çš„å›žè°ƒ
  onSuccess: (response, file, fileList) => {
    console.log('上传成功', response, file, fileList);
    upload.isUploading = false;
    if(response.code === 200){
      proxy.$modal.msgSuccess("文件上传成功");
      upload.open = false;
      proxy.$refs["uploadRef"].clearFiles();
      getList();
    }else if(response.code === 500){
      proxy.$modal.msgError(response.msg);
    }else{
      proxy.$modal.msgWarning(response.msg);
    }
  },
  // æ–‡ä»¶ä¸Šä¼ å¤±è´¥æ—¶çš„回调
  onError: (error, file, fileList) => {
    console.error('上传失败', error, file, fileList);
    upload.isUploading = false;
    proxy.$modal.msgError("文件上传失败");
  },
  // æ–‡ä»¶ä¸Šä¼ è¿›åº¦å›žè°ƒ
  onProgress: (event, file, fileList) => {
    console.log('上传中...', event.percent);
  }
});
const { searchForm, form, rules } = toRefs(data);
const addNewContact = () => {
  formYYs.value.contactList.push({
    contactPerson: "",
    contactPhone: ""
  });
};
const removeContact = (index) => {
  if (formYYs.value.contactList.length > 1) {
    formYYs.value.contactList.splice(index, 1);
  }
};
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1;
  getList();
};
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList();
};
const getList = () => {
  tableLoading.value = true;
  listCustomer({ ...searchForm.value, ...page }).then((res) => {
    tableLoading.value = false;
    tableData.value = res.records;
    page.total = res.total;
  });
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection;
};
/** æäº¤ä¸Šä¼ æ–‡ä»¶ */
function submitFileForm() {
  upload.isUploading = true;
  proxy.$refs["uploadRef"].submit();
}
/** å¯¼å…¥æŒ‰é’®æ“ä½œ */
function handleImport() {
  upload.title = "客户导入";
  upload.open = true;
}
/** ä¸‹è½½æ¨¡æ¿ */
function importTemplate() {
  proxy.download("/basic/customer/downloadTemplate", {}, "客户导入模板.xlsx");
}
// æ‰“开弹框
const openForm = (type, row) => {
  operationType.value = type;
  form.value = {};
  form.value.maintainer = userStore.nickName;
  formYYs.value.contactList = [
    {
      contactPerson: "",
      contactPhone: ""
    }
  ];
  form.value.maintenanceTime = getCurrentDate();
  userListNoPage().then((res) => {
    userList.value = res.data;
  });
  if (type === "edit") {
    getCustomer(row.id).then((res) => {
      form.value = { ...res.data };
      formYYs.value.contactList = res.data.contactPerson.split(",").map((item, index) => {
        return {
          contactPerson: item,
          contactPhone: res.data.contactPhone.split(",")[index]
        }
      });
    });
  }
  dialogFormVisible.value = true;
};
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      if (operationType.value === "edit") {
        submitEdit();
      } else {
        submitAdd();
      }
    }
  });
};
// æäº¤æ–°å¢ž
const submitAdd = () => {
  if(formYYs.value.contactList.length < 1){
    return proxy.$modal.msgWarning("请至少添加一个联系人");
  }
  form.value.contactPerson = formYYs.value.contactList.map(item => item.contactPerson).join(",");
  form.value.contactPhone = formYYs.value.contactList.map(item => item.contactPhone).join(",");
  addCustomer(form.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeDia();
    getList();
  });
};
// æäº¤ä¿®æ”¹
const submitEdit = () => {
    form.value.contactPerson = formYYs.value.contactList.map(item => item.contactPerson).join(",");
    form.value.contactPhone = formYYs.value.contactList.map(item => item.contactPhone).join(",");
  updateCustomer(form.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeDia();
    getList();
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
};
// å¯¼å‡º
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download("/basic/customer/export", {}, "客户档案.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// åˆ é™¤
const handleDelete = () => {
  let ids = [];
  if (selectedRows.value.length > 0) {
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      tableLoading.value = true;
      delCustomer(ids)
        .then((res) => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
        })
        .finally(() => {
          tableLoading.value = false;
        });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// èŽ·å–å½“å‰æ—¥æœŸå¹¶æ ¼å¼åŒ–ä¸º YYYY-MM-DD
function getCurrentDate() {
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, "0"); // æœˆä»½ä»Ž0开始
  const day = String(today.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
onMounted(() => {
    getList();
});
</script>
<style scoped>
.alarm-handle-knowledge {
  padding: 16px;
  background-color: #f0f2f5;
  min-height: 100vh;
}
.search-card {
  margin-bottom: 16px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.table-card {
  margin-top: 16px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.pagination {
  margin-top: 16px;
  display: flex;
  justify-content: flex-end;
  padding-right: 20px;
}
</style>
<style scoped lang="scss"></style>
src/views/alarmManagement/alarmMonitor/realTimeAlarm.vue
ÎļþÒÑɾ³ý
src/views/alarmManagement/alarmReport/alarmStats.vue
ÎļþÒÑɾ³ý