From 386375a8e04f72a8bc17553b649a38b5535e21ba Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 11 八月 2025 09:26:52 +0800
Subject: [PATCH] 1.添加用水管理页面
---
src/views/equipmentManagement/gasTank/simple.vue | 566 +++++++++++
src/api/inventoryManagement/stockWarning.js | 81 +
src/views/energyManagement/waterManagement/index.vue | 312 ++++++
src/views/energyManagement/waterManagement/waterTrends.vue | 118 ++
src/views/energyManagement/waterManagement/components/formDia.vue | 221 ++++
src/views/energyManagement/waterManagement/waterBill.vue | 181 +++
src/views/energyManagement/waterManagement/components/waterBillForm.vue | 210 ++++
src/views/inventoryManagement/stockWarning/index.vue | 1137 +++++++++++++++++++++++
src/api/energyManagement/waterManagement.js | 91 +
9 files changed, 2,917 insertions(+), 0 deletions(-)
diff --git a/src/api/energyManagement/waterManagement.js b/src/api/energyManagement/waterManagement.js
new file mode 100644
index 0000000..aef7465
--- /dev/null
+++ b/src/api/energyManagement/waterManagement.js
@@ -0,0 +1,91 @@
+// 鐢ㄦ按绠$悊
+import request from "@/utils/request";
+
+// 鐢ㄦ按璁惧-鍒嗛〉鏌ヨ
+export function waterEquipmentListPage(query) {
+ return request({
+ url: '/waterEquipmentConsumption/listPage',
+ method: 'get',
+ params: query,
+ })
+}
+
+// 鐢ㄦ按瓒嬪娍-鍒嗛〉鏌ヨ
+export function listPageByWaterTrend(query) {
+ return request({
+ url: '/waterEquipmentConsumption/listPageByTrend',
+ method: 'get',
+ params: query,
+ })
+}
+
+// 鐢ㄦ按璁惧-鍒犻櫎
+export function waterEquipmentDelete(query) {
+ return request({
+ url: '/waterEquipmentConsumption/delete',
+ method: 'delete',
+ data: query,
+ })
+}
+
+// 鐢ㄦ按璁惧-鏂板
+export function waterEquipmentAdd(query) {
+ return request({
+ url: '/waterEquipmentConsumption/add',
+ method: 'post',
+ data: query,
+ })
+}
+
+// 鐢ㄦ按璁惧-淇敼
+export function waterEquipmentUpdate(query) {
+ return request({
+ url: '/waterEquipmentConsumption/update',
+ method: 'post',
+ data: query,
+ })
+}
+
+// 鐢ㄦ按璁惧涓嬫媺妗嗘煡璇�
+export function waterDeviceList(query) {
+ return request({
+ url: '/waterEquipmentConsumption/deviceList',
+ method: 'get',
+ })
+}
+
+// 姘磋垂绠$悊-鍒嗛〉鏌ヨ
+export function waterBillListPage(query) {
+ return request({
+ url: '/waterBill/listPage',
+ method: 'get',
+ params: query,
+ })
+}
+
+// 姘磋垂绠$悊-鏂板
+export function waterBillAdd(query) {
+ return request({
+ url: '/waterBill/add',
+ method: 'post',
+ data: query,
+ })
+}
+
+// 姘磋垂绠$悊-淇敼
+export function waterBillUpdate(query) {
+ return request({
+ url: '/waterBill/update',
+ method: 'post',
+ data: query,
+ })
+}
+
+// 姘磋垂绠$悊-鍒犻櫎
+export function waterBillDelete(query) {
+ return request({
+ url: '/waterBill/delete',
+ method: 'delete',
+ data: query,
+ })
+}
diff --git a/src/api/inventoryManagement/stockWarning.js b/src/api/inventoryManagement/stockWarning.js
new file mode 100644
index 0000000..092fb80
--- /dev/null
+++ b/src/api/inventoryManagement/stockWarning.js
@@ -0,0 +1,81 @@
+import request from "@/utils/request";
+
+// 鏌ヨ鍌ㄦ皵缃愰璀﹀垪琛�
+export const getStockWarningPage = (params) => {
+ return request({
+ url: "/gasTankWarning/listPage",
+ method: "get",
+ params,
+ });
+};
+
+// 鏂板鍌ㄦ皵缃愰璀﹁鍒�
+export const addStockWarning = (data) => {
+ return request({
+ url: "/gasTankWarning/add",
+ method: "post",
+ data,
+ });
+};
+
+// 淇敼鍌ㄦ皵缃愰璀﹁鍒�
+export const updateStockWarning = (data) => {
+ return request({
+ url: "/gasTankWarning/update",
+ method: "put",
+ data,
+ });
+};
+
+// 鍒犻櫎鍌ㄦ皵缃愰璀﹁鍒�
+export const deleteStockWarning = (ids) => {
+ return request({
+ url: "/gasTankWarning/delete",
+ method: "delete",
+ data: { ids },
+ });
+};
+
+// 鎵归噺澶勭悊鍌ㄦ皵缃愰璀�
+export const batchProcessStockWarning = (data) => {
+ return request({
+ url: "/gasTankWarning/batchProcess",
+ method: "post",
+ data,
+ });
+};
+
+// 瀵煎嚭鍌ㄦ皵缃愰璀︽暟鎹�
+export const exportStockWarning = (params) => {
+ return request({
+ url: "/gasTankWarning/export",
+ method: "get",
+ params,
+ responseType: "blob",
+ });
+};
+
+// 鏍规嵁ID鑾峰彇鍌ㄦ皵缃愰璀﹁鎯�
+export const getStockWarningById = (id) => {
+ return request({
+ url: `/gasTankWarning/${id}`,
+ method: "get",
+ });
+};
+
+// 鍚敤/绂佺敤棰勮瑙勫垯
+export const toggleStockWarningStatus = (data) => {
+ return request({
+ url: "/gasTankWarning/toggleStatus",
+ method: "put",
+ data,
+ });
+};
+
+// 鑾峰彇棰勮缁熻淇℃伅
+export const getStockWarningStatistics = () => {
+ return request({
+ url: "/gasTankWarning/statistics",
+ method: "get",
+ });
+};
diff --git a/src/views/energyManagement/waterManagement/components/formDia.vue b/src/views/energyManagement/waterManagement/components/formDia.vue
new file mode 100644
index 0000000..a692b95
--- /dev/null
+++ b/src/views/energyManagement/waterManagement/components/formDia.vue
@@ -0,0 +1,221 @@
+<template>
+ <div>
+ <el-dialog
+ v-model="dialogFormVisible"
+ title="鐢ㄦ按璁惧"
+ 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="code">
+ <el-select
+ v-model="form.code"
+ placeholder="璇烽�夋嫨"
+ clearable
+ @change="setName"
+ :disabled="operationType !== 'add'"
+ >
+ <el-option
+ v-for="item in codeList"
+ :key="item.deviceModel"
+ :label="item.deviceName"
+ :value="item.deviceModel"
+ >
+ {{item.deviceName + '--' + item.deviceModel}}
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="姣忔棩闄愬埗姘撮噺锛�" prop="everyNum">
+ <el-input
+ v-model="form.everyNum"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="棰濆畾娴侀噺锛�" prop="flowRating">
+ <el-input
+ v-model="form.flowRating"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="瀹為檯娴侀噺锛�" prop="flowActual">
+ <el-input
+ v-model="form.flowActual"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="杩愯鏃堕棿锛�" prop="runDate">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.runDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="褰撴棩鐢ㄦ按閲忥細" prop="dayNum">
+ <el-input
+ v-model="form.dayNum"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="姘磋垂鍗曚环锛�" prop="waterPrice">
+ <el-input
+ v-model="form.waterPrice"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鐢ㄦ按绫诲瀷锛�" prop="waterType">
+ <el-select
+ v-model="form.waterType"
+ placeholder="璇烽�夋嫨"
+ clearable
+ >
+ <el-option label="宸ヤ笟鐢ㄦ按" value="industrial" />
+ <el-option label="鐢熸椿鐢ㄦ按" value="domestic" />
+ <el-option label="娑堥槻鐢ㄦ按" value="fire" />
+ <el-option label="缁垮寲鐢ㄦ按" value="greening" />
+ </el-select>
+ </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>
+ </div>
+</template>
+
+<script setup>
+import {ref, reactive, nextTick} from "vue";
+import useUserStore from "@/store/modules/user.js";
+import {waterDeviceList, waterEquipmentAdd, waterEquipmentUpdate} from "@/api/energyManagement/waterManagement.js";
+const { proxy } = getCurrentInstance()
+const emit = defineEmits(['close'])
+const dialogFormVisible = ref(false);
+const operationType = ref('')
+const userStore = useUserStore();
+
+const data = reactive({
+ form: {
+ name: "",
+ code: "",
+ everyNum: "",
+ flowRating: "",
+ flowActual: "",
+ runDate: "",
+ dayNum: "",
+ waterPrice: "",
+ waterType: "",
+ },
+ rules: {
+ code: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ runDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ everyNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ flowRating: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ flowActual: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ dayNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ waterPrice: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ waterType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ },
+})
+const { form, rules } = toRefs(data);
+const codeList = ref([])
+
+// 鎵撳紑寮规
+const openDialog = (type, row) => {
+ operationType.value = type;
+ dialogFormVisible.value = true;
+ form.value = {}
+ proxy.resetForm("formRef");
+ waterDeviceList().then((res) => {
+ codeList.value = res.data;
+ });
+ if (type === "edit") {
+ form.value = {...row}
+ }
+}
+const setName = (code) => {
+ const index = codeList.value.findIndex(item => item.deviceModel === code);
+ if (index > -1) {
+ console.log(codeList)
+ form.value.name = codeList.value[index].deviceName;
+ }
+}
+const submitForm = () => {
+ proxy.$refs["formRef"].validate(valid => {
+ if (valid) {
+ if (operationType.value === "add") {
+ waterEquipmentAdd(form.value).then(response => {
+ proxy.$modal.msgSuccess("鏂板鎴愬姛")
+ closeDia()
+ })
+ } else {
+ waterEquipmentUpdate(form.value).then(response => {
+ proxy.$modal.msgSuccess("淇敼鎴愬姛")
+ closeDia()
+ })
+ }
+ }
+ })
+}
+// 鍏抽棴寮规
+const closeDia = () => {
+ proxy.resetForm("formRef");
+ dialogFormVisible.value = false;
+ emit('close')
+};
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� 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}`;
+}
+defineExpose({
+ openDialog,
+});
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/energyManagement/waterManagement/components/waterBillForm.vue b/src/views/energyManagement/waterManagement/components/waterBillForm.vue
new file mode 100644
index 0000000..a132041
--- /dev/null
+++ b/src/views/energyManagement/waterManagement/components/waterBillForm.vue
@@ -0,0 +1,210 @@
+<template>
+ <div>
+ <el-dialog
+ v-model="dialogFormVisible"
+ title="姘磋垂绠$悊"
+ 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="code">
+ <el-select
+ v-model="form.code"
+ placeholder="璇烽�夋嫨"
+ clearable
+ @change="setName"
+ :disabled="operationType !== 'add'"
+ >
+ <el-option
+ v-for="item in codeList"
+ :key="item.deviceModel"
+ :label="item.deviceName"
+ :value="item.deviceModel"
+ >
+ {{item.deviceName + '--' + item.deviceModel}}
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鐢ㄦ按閲忥細" prop="waterConsumption">
+ <el-input
+ v-model="form.waterConsumption"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="姘磋垂鍗曚环锛�" prop="waterPrice">
+ <el-input
+ v-model="form.waterPrice"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="姘磋垂閲戦锛�" prop="waterBill">
+ <el-input
+ v-model="form.waterBill"
+ placeholder="鑷姩璁$畻"
+ clearable
+ disabled
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="璁¤垂鏃ユ湡锛�" prop="billDate">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.billDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鐢ㄦ按绫诲瀷锛�" prop="waterType">
+ <el-select
+ v-model="form.waterType"
+ placeholder="璇烽�夋嫨"
+ clearable
+ >
+ <el-option label="宸ヤ笟鐢ㄦ按" value="industrial" />
+ <el-option label="鐢熸椿鐢ㄦ按" value="domestic" />
+ <el-option label="娑堥槻鐢ㄦ按" value="fire" />
+ <el-option label="缁垮寲鐢ㄦ按" value="greening" />
+ </el-select>
+ </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>
+ </div>
+</template>
+
+<script setup>
+import {ref, reactive, nextTick, watch} from "vue";
+import useUserStore from "@/store/modules/user.js";
+import {waterDeviceList, waterBillAdd, waterBillUpdate} from "@/api/energyManagement/waterManagement.js";
+const { proxy } = getCurrentInstance()
+const emit = defineEmits(['close'])
+const dialogFormVisible = ref(false);
+const operationType = ref('')
+const userStore = useUserStore();
+
+const data = reactive({
+ form: {
+ name: "",
+ code: "",
+ waterConsumption: "",
+ waterPrice: "",
+ waterBill: "",
+ billDate: "",
+ waterType: "",
+ },
+ rules: {
+ code: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ waterConsumption: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ waterPrice: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ billDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ waterType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ },
+})
+const { form, rules } = toRefs(data);
+const codeList = ref([])
+
+// 鎵撳紑寮规
+const openDialog = (type, row) => {
+ operationType.value = type;
+ dialogFormVisible.value = true;
+ form.value = {}
+ proxy.resetForm("formRef");
+ waterDeviceList().then((res) => {
+ codeList.value = res.data;
+ });
+ if (type === "edit") {
+ form.value = {...row}
+ }
+}
+const setName = (code) => {
+ const index = codeList.value.findIndex(item => item.deviceModel === code);
+ if (index > -1) {
+ console.log(codeList)
+ form.value.name = codeList.value[index].deviceName;
+ }
+}
+
+// 璁$畻姘磋垂閲戦
+const calculateWaterBill = () => {
+ if (form.value.waterConsumption && form.value.waterPrice) {
+ form.value.waterBill = (parseFloat(form.value.waterConsumption) * parseFloat(form.value.waterPrice)).toFixed(2);
+ }
+}
+
+// 鐩戝惉鐢ㄦ按閲忓拰姘磋垂鍗曚环鍙樺寲
+watch([() => form.value.waterConsumption, () => form.value.waterPrice], () => {
+ calculateWaterBill();
+});
+
+const submitForm = () => {
+ proxy.$refs["formRef"].validate(valid => {
+ if (valid) {
+ if (operationType.value === "add") {
+ waterBillAdd(form.value).then(response => {
+ proxy.$modal.msgSuccess("鏂板鎴愬姛")
+ closeDia()
+ })
+ } else {
+ waterBillUpdate(form.value).then(response => {
+ proxy.$modal.msgSuccess("淇敼鎴愬姛")
+ closeDia()
+ })
+ }
+ }
+ })
+}
+// 鍏抽棴寮规
+const closeDia = () => {
+ proxy.resetForm("formRef");
+ dialogFormVisible.value = false;
+ emit('close')
+};
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� 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}`;
+}
+defineExpose({
+ openDialog,
+});
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/energyManagement/waterManagement/index.vue b/src/views/energyManagement/waterManagement/index.vue
new file mode 100644
index 0000000..848a945
--- /dev/null
+++ b/src/views/energyManagement/waterManagement/index.vue
@@ -0,0 +1,312 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <div>
+ <span class="search_title">璁惧鍚嶇О锛�</span>
+ <el-input
+ v-model="searchForm.name"
+ style="width: 240px"
+ placeholder="璇疯緭鍏�"
+ @change="handleQuery"
+ clearable
+ :prefix-icon="Search"
+ />
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+ >鎼滅储</el-button
+ >
+ </div>
+ <div>
+ <el-button type="primary" @click="openForm('add')">鏂板</el-button>
+ <el-button type="info" plain icon="Upload" @click="handleImport">瀵煎叆</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>
+ <form-dia ref="formDia" @close="handleQuery"></form-dia>
+ <el-dialog
+ :title="upload.title"
+ v-model="upload.open"
+ width="400px"
+ append-to-body
+ @close="handleDialogClose"
+ >
+ <el-upload
+ ref="uploadRef"
+ :limit="1"
+ accept=".xlsx, .xls"
+ :headers="upload.headers"
+ :action="upload.url"
+ :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>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</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 setup>
+import {Search} from "@element-plus/icons-vue";
+import {onMounted, ref, reactive, nextTick} from "vue";
+import FormDia from "@/views/energyManagement/waterManagement/components/formDia.vue";
+import {ElMessageBox} from "element-plus";
+import {getToken} from "@/utils/auth.js";
+import {waterEquipmentDelete, waterEquipmentListPage} from "@/api/energyManagement/waterManagement.js";
+const { proxy } = getCurrentInstance();
+
+const data = reactive({
+ searchForm: {
+ name: "",
+ },
+});
+const { searchForm } = toRefs(data);
+
+const selectedRows = ref([]);
+const tableColumn = ref([
+ {
+ label: "璁惧鍚嶇О",
+ prop: "name",
+ width: 200,
+ },
+ {
+ label: "瑙勬牸鍨嬪彿",
+ prop: "code",
+ width: 200,
+ },
+ {
+ label: "棰濆畾娴侀噺",
+ prop: "flowRating",
+ },
+ {
+ label: "瀹為檯娴侀噺",
+ prop: "flowActual",
+ },
+ {
+ label: "杩愯鏃堕棿",
+ prop: "runDate",
+ width:150
+ },
+ {
+ label: "褰撴棩鐢ㄦ按閲�",
+ prop: "dayNum",
+ width: 150,
+ },
+ {
+ label: "姣忔棩闄愬埗姘撮噺",
+ prop: "everyNum",
+ width:220
+ },
+ {
+ label: "姘磋垂鍗曚环",
+ prop: "waterPrice",
+ width: 120,
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: 'right',
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openForm("edit", row);
+ },
+ },
+ ],
+ },
+]);
+const tableData = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+ current: 1,
+ size: 100,
+ total: 0,
+});
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+const formDia = ref()
+const upload = reactive({
+ // 鏄惁鏄剧ず寮瑰嚭灞傦紙瀹㈡埛瀵煎叆锛�
+ open: false,
+ // 寮瑰嚭灞傛爣棰橈紙瀹㈡埛瀵煎叆锛�
+ title: "",
+ // 鏄惁绂佺敤涓婁紶
+ isUploading: false,
+ // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+ headers: { Authorization: "Bearer " + getToken() },
+ // 涓婁紶鐨勫湴鍧�
+ url: import.meta.env.VITE_APP_BASE_API + "/waterEquipmentConsumption/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);
+ if(response.code === 200){
+ proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+ }else if(response.code === 500){
+ proxy.$modal.msgError(response.msg);
+ }else{
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+ }
+ upload.open = false;
+ getList();
+ },
+ // 鏂囦欢涓婁紶澶辫触鏃剁殑鍥炶皟
+ onError: (error, file, fileList) => {
+ console.log('涓婁紶澶辫触', error, file, fileList);
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+ upload.open = false;
+ },
+ // 鏂囦欢涓婁紶杩涘害鏀瑰彉鏃剁殑鍥炶皟
+ onProgress: (event, file, fileList) => {
+ console.log('涓婁紶杩涘害', event, file, fileList);
+ upload.isUploading = true;
+ },
+});
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+const pagination = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+
+const getList = () => {
+ tableLoading.value = true;
+ waterEquipmentListPage({ ...searchForm.value, ...page }).then((res) => {
+ tableLoading.value = false;
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ }).catch(() => {
+ tableLoading.value = false;
+ })
+};
+
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+ nextTick(() => {
+ formDia.value?.openDialog(type, row)
+ })
+};
+
+/** 瀵煎叆鎸夐挳鎿嶄綔 */
+function handleImport() {
+ upload.title = "鐢ㄦ按璁惧";
+ upload.open = true;
+ // 娓呯┖涓婃涓婁紶鐨勬枃浠跺垪琛�
+ nextTick(() => {
+ proxy.$refs["uploadRef"]?.clearFiles();
+ });
+}
+function importTemplate() {
+ proxy.download(
+ "/waterEquipmentConsumption/export",
+ {},
+ '鐢ㄦ按璁惧瀵煎叆妯$増.xlsx'
+ );
+}
+/** 鎻愪氦涓婁紶鏂囦欢 */
+function submitFileForm() {
+ proxy.$refs["uploadRef"].submit();
+}
+
+/** 寮规鍏抽棴鏃舵竻绌烘枃浠跺垪琛� */
+function handleDialogClose() {
+ nextTick(() => {
+ proxy.$refs["uploadRef"]?.clearFiles();
+ });
+}
+
+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;
+ waterEquipmentDelete(ids)
+ .then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+onMounted(() => {
+ getList();
+});
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/energyManagement/waterManagement/waterBill.vue b/src/views/energyManagement/waterManagement/waterBill.vue
new file mode 100644
index 0000000..ea382f0
--- /dev/null
+++ b/src/views/energyManagement/waterManagement/waterBill.vue
@@ -0,0 +1,181 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <div>
+ <span class="search_title">璁惧鍚嶇О锛�</span>
+ <el-input
+ v-model="searchForm.name"
+ style="width: 240px"
+ placeholder="璇疯緭鍏�"
+ @change="handleQuery"
+ clearable
+ :prefix-icon="Search"
+ />
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+ >鎼滅储</el-button
+ >
+ </div>
+ <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>
+ <form-dia ref="formDia" @close="handleQuery"></form-dia>
+ </div>
+</template>
+
+<script setup>
+import {Search} from "@element-plus/icons-vue";
+import {onMounted, ref, reactive, nextTick} from "vue";
+import FormDia from "@/views/energyManagement/waterManagement/components/waterBillForm.vue";
+import {ElMessageBox} from "element-plus";
+import {waterBillDelete, waterBillListPage} from "@/api/energyManagement/waterManagement.js";
+const { proxy } = getCurrentInstance();
+
+const data = reactive({
+ searchForm: {
+ name: "",
+ },
+});
+const { searchForm } = toRefs(data);
+
+const selectedRows = ref([]);
+const tableColumn = ref([
+ {
+ label: "璁惧鍚嶇О",
+ prop: "name",
+ width: 200,
+ },
+ {
+ label: "瑙勬牸鍨嬪彿",
+ prop: "code",
+ width: 200,
+ },
+ {
+ label: "鐢ㄦ按閲�",
+ prop: "waterConsumption",
+ },
+ {
+ label: "姘磋垂鍗曚环",
+ prop: "waterPrice",
+ },
+ {
+ label: "姘磋垂閲戦",
+ prop: "waterBill",
+ width:150
+ },
+ {
+ label: "璁¤垂鏃ユ湡",
+ prop: "billDate",
+ width: 150,
+ },
+ {
+ label: "鐢ㄦ按绫诲瀷",
+ prop: "waterType",
+ width:120
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: 'right',
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openForm("edit", row);
+ },
+ },
+ ],
+ },
+]);
+const tableData = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+ current: 1,
+ size: 100,
+ total: 0,
+});
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+const formDia = ref()
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+const pagination = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+
+const getList = () => {
+ tableLoading.value = true;
+ waterBillListPage({ ...searchForm.value, ...page }).then((res) => {
+ tableLoading.value = false;
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ });
+};
+
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+ nextTick(() => {
+ formDia.value?.openDialog(type, row)
+ })
+};
+
+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;
+ waterBillDelete(ids)
+ .then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+onMounted(() => {
+ getList();
+});
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/energyManagement/waterManagement/waterTrends.vue b/src/views/energyManagement/waterManagement/waterTrends.vue
new file mode 100644
index 0000000..12e45fc
--- /dev/null
+++ b/src/views/energyManagement/waterManagement/waterTrends.vue
@@ -0,0 +1,118 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <div>
+ <span class="search_title">璁惧鍚嶇О锛�</span>
+ <el-input
+ v-model="searchForm.name"
+ style="width: 240px"
+ placeholder="璇疯緭鍏�"
+ @change="handleQuery"
+ clearable
+ :prefix-icon="Search"
+ />
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+ >鎼滅储</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>
+ </div>
+</template>
+
+<script setup>
+import {Search} from "@element-plus/icons-vue";
+import {onMounted, ref, reactive} from "vue";
+import {listPageByWaterTrend} from "@/api/energyManagement/waterManagement.js";
+
+const data = reactive({
+ searchForm: {
+ name: "",
+ },
+});
+const { searchForm } = toRefs(data);
+
+const selectedRows = ref([]);
+const tableColumn = ref([
+ {
+ label: "璁惧鍚嶇О",
+ prop: "name",
+ width: 220,
+ },
+ {
+ label: "瑙勬牸鍨嬪彿",
+ prop: "code",
+ width: 220,
+ },
+ {
+ label: "杩愯鏃堕棿",
+ prop: "runDate",
+ width: 250,
+ },
+ {
+ label: "鏄ㄦ棩鐢ㄦ按閲�",
+ prop: "toDayNum",
+ },
+ {
+ label: "鏈湀骞冲潎姘撮噺",
+ prop: "avgNum",
+ width:150
+ },
+ {
+ label: "瓒嬪娍",
+ prop: "trend",
+ width: 220,
+ },
+]);
+const tableData = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+ current: 1,
+ size: 100,
+ total: 0,
+});
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+const pagination = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+
+const getList = () => {
+ tableLoading.value = true;
+ listPageByWaterTrend({ ...searchForm.value, ...page }).then((res) => {
+ tableLoading.value = false;
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ });
+};
+
+onMounted(() => {
+ getList();
+});
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/equipmentManagement/gasTank/simple.vue b/src/views/equipmentManagement/gasTank/simple.vue
new file mode 100644
index 0000000..92e88df
--- /dev/null
+++ b/src/views/equipmentManagement/gasTank/simple.vue
@@ -0,0 +1,566 @@
+<template>
+ <div class="app-container">
+ <!-- 椤甸潰鏍囬 -->
+ <div class="page-header">
+ <h2>閲嶅瀷缃愬紡璐ц溅鐩戞帶</h2>
+ <div class="header-actions">
+<!-- <el-button type="primary" @click="addTank">鏂板鍌ㄧ綈</el-button>-->
+<!-- <el-button @click="exportData">瀵煎嚭鏁版嵁</el-button>-->
+ </div>
+ </div>
+
+ <!-- 鍥涗釜涓昏妯″潡 -->
+ <div class="modules-container">
+ <!-- 1. 鍩烘湰淇℃伅妯″潡 -->
+ <el-card class="module-card">
+ <template #header>
+ <div class="card-header">
+ <span>1. 鍩烘湰淇℃伅</span>
+ <el-button type="text" @click="handleEditBasicInfo">缂栬緫</el-button>
+ </div>
+ </template>
+ <div class="info-grid">
+ <div class="info-item">
+ <label>鍌ㄧ綈缂栧彿锛�</label>
+ <span>{{ basicInfo.tankCode }}</span>
+ </div>
+ <div class="info-item">
+ <label>鍌ㄧ綈鍚嶇О锛�</label>
+ <span>{{ basicInfo.tankName }}</span>
+ </div>
+ <div class="info-item">
+ <label>鍌ㄧ綈绫诲瀷锛�</label>
+ <span>{{ basicInfo.tankType }}</span>
+ </div>
+ <div class="info-item">
+ <label>璁捐鍘嬪姏锛�</label>
+ <span>{{ basicInfo.designPressure }} MPa</span>
+ </div>
+ <div class="info-item">
+ <label>宸ヤ綔鍘嬪姏锛�</label>
+ <span>{{ basicInfo.workingPressure }} MPa</span>
+ </div>
+ <div class="info-item">
+ <label>瀹圭Н锛�</label>
+ <span>{{ basicInfo.volume }} m鲁</span>
+ </div>
+ </div>
+ </el-card>
+
+ <!-- 2. 鐩戞祴鍙傛暟妯″潡 -->
+ <el-card class="module-card">
+ <template #header>
+ <div class="card-header">
+ <span>2. 鐩戞祴鍙傛暟</span>
+ <el-button type="text" @click="refreshMonitoring">鍒锋柊</el-button>
+ </div>
+ </template>
+ <div class="monitoring-grid">
+ <div class="monitor-item">
+ <div class="monitor-label">鍘嬪姏</div>
+ <div class="monitor-value" :class="getStatusClass(monitoringData.pressureStatus)">
+ {{ monitoringData.pressure }} MPa
+ </div>
+ <div class="monitor-status">{{ monitoringData.pressureStatus === 'normal' ? '姝e父' : '寮傚父' }}</div>
+ </div>
+ <div class="monitor-item">
+ <div class="monitor-label">娓╁害</div>
+ <div class="monitor-value" :class="getStatusClass(monitoringData.temperatureStatus)">
+ {{ monitoringData.temperature }} 鈩�
+ </div>
+ <div class="monitor-status">{{ monitoringData.temperatureStatus === 'normal' ? '姝e父' : '寮傚父' }}</div>
+ </div>
+ <div class="monitor-item">
+ <div class="monitor-label">姘斾綋娴撳害</div>
+ <div class="monitor-value" :class="getStatusClass(monitoringData.gasStatus)">
+ {{ monitoringData.gasConcentration }} ppm
+ </div>
+ <div class="monitor-status">{{ monitoringData.gasStatus === 'normal' ? '姝e父' : '寮傚父' }}</div>
+ </div>
+ <div class="monitor-item">
+ <div class="monitor-label">娴侀噺</div>
+ <div class="monitor-value" :class="getStatusClass(monitoringData.flowStatus)">
+ {{ monitoringData.flow }} m鲁/h
+ </div>
+ <div class="monitor-status">{{ monitoringData.flowStatus === 'normal' ? '姝e父' : '寮傚父' }}</div>
+ </div>
+ </div>
+ </el-card>
+
+ <!-- 3. 瀹夊叏瑁呯疆妯″潡 -->
+ <el-card class="module-card">
+ <template #header>
+ <div class="card-header">
+ <span>3. 瀹夊叏瑁呯疆</span>
+ <el-button type="text" @click="checkSafetyDevices">妫�鏌�</el-button>
+ </div>
+ </template>
+ <div class="safety-grid">
+ <div class="safety-item" v-for="device in safetyDevices" :key="device.name">
+
+ <div class="device-info">
+ <div class="device-name">{{ device.name }}</div>
+ <div class="device-status" :class="device.status">
+ {{ device.status === 'normal' ? '姝e父' : '寮傚父' }}
+ </div>
+ </div>
+ </div>
+ </div>
+ </el-card>
+
+ <!-- 4. 缁存姢璁板綍妯″潡 -->
+ <el-card class="module-card">
+ <template #header>
+ <div class="card-header">
+ <span>4. 缁存姢璁板綍</span>
+ <el-button type="text" @click="addMaintenanceRecord">娣诲姞璁板綍</el-button>
+ </div>
+ </template>
+ <div class="maintenance-list">
+ <div class="maintenance-item" v-for="record in maintenanceRecords" :key="record.id">
+ <div class="record-header">
+ <span class="record-date">{{ record.date }}</span>
+ <el-tag :type="record.type === 'inspection' ? 'primary' : 'success'" size="small">
+ {{ record.type === 'inspection' ? '妫�楠�' : '缁存姢' }}
+ </el-tag>
+ </div>
+ <div class="record-content">
+ <div class="record-title">{{ record.title }}</div>
+ <div class="record-desc">{{ record.description }}</div>
+ <div class="record-operator">鎿嶄綔浜猴細{{ record.operator }}</div>
+ </div>
+ </div>
+ </div>
+ </el-card>
+ </div>
+
+ <!-- 缂栬緫鍩烘湰淇℃伅寮圭獥 -->
+ <el-dialog v-model="basicInfoDialogVisible" title="缂栬緫鍩烘湰淇℃伅" width="600px">
+ <el-form :model="editBasicInfo" label-width="120px">
+ <el-form-item label="鍌ㄧ綈缂栧彿">
+ <el-input v-model="editBasicInfo.tankCode" />
+ </el-form-item>
+ <el-form-item label="鍌ㄧ綈鍚嶇О">
+ <el-input v-model="editBasicInfo.tankName" />
+ </el-form-item>
+ <el-form-item label="鍌ㄧ綈绫诲瀷">
+ <el-select v-model="editBasicInfo.tankType" style="width: 100%">
+ <el-option label="娑插寲姘斾綋鍌ㄧ綈" value="娑插寲姘斾綋鍌ㄧ綈" />
+ <el-option label="鍘嬪姏瀹瑰櫒" value="鍘嬪姏瀹瑰櫒" />
+ <el-option label="甯稿帇鍌ㄧ綈" value="甯稿帇鍌ㄧ綈" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="璁捐鍘嬪姏">
+ <el-input-number v-model="editBasicInfo.designPressure" :precision="2" style="width: 100%" />
+ </el-form-item>
+ <el-form-item label="宸ヤ綔鍘嬪姏">
+ <el-input-number v-model="editBasicInfo.workingPressure" :precision="2" style="width: 100%" />
+ </el-form-item>
+ <el-form-item label="瀹圭Н">
+ <el-input-number v-model="editBasicInfo.volume" :precision="2" style="width: 100%" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <el-button @click="basicInfoDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="saveBasicInfo">淇濆瓨</el-button>
+ </template>
+ </el-dialog>
+
+ <!-- 娣诲姞缁存姢璁板綍寮圭獥 -->
+ <el-dialog v-model="maintenanceDialogVisible" title="娣诲姞缁存姢璁板綍" width="600px">
+ <el-form :model="newMaintenanceRecord" label-width="120px">
+ <el-form-item label="璁板綍绫诲瀷">
+ <el-select v-model="newMaintenanceRecord.type" style="width: 100%">
+ <el-option label="妫�楠�" value="inspection" />
+ <el-option label="缁存姢" value="maintenance" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鏍囬">
+ <el-input v-model="newMaintenanceRecord.title" />
+ </el-form-item>
+ <el-form-item label="鎻忚堪">
+ <el-input type="textarea" v-model="newMaintenanceRecord.description" :rows="3" />
+ </el-form-item>
+ <el-form-item label="鎿嶄綔浜�">
+ <el-input v-model="newMaintenanceRecord.operator" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <el-button @click="maintenanceDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="saveMaintenanceRecord">淇濆瓨</el-button>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import { ElMessage } from 'element-plus'
+
+// 鍩烘湰淇℃伅
+const basicInfo = reactive({
+ tankCode: 'GT001',
+ tankName: '娑插寲姘斿偍缃怉',
+ tankType: '娑插寲姘斾綋鍌ㄧ綈',
+ designPressure: 1.6,
+ workingPressure: 0.8,
+ volume: 100.5
+})
+
+// 鐩戞祴鍙傛暟
+const monitoringData = reactive({
+ pressure: 0.8,
+ pressureStatus: 'normal',
+ temperature: 25.5,
+ temperatureStatus: 'normal',
+ gasConcentration: 0.1,
+ gasStatus: 'normal',
+ flow: 15.2,
+ flowStatus: 'normal'
+})
+
+// 瀹夊叏瑁呯疆
+const safetyDevices = ref([
+ { name: '瀹夊叏闃�', status: 'normal' },
+ { name: '鍘嬪姏浼犳劅鍣�', status: 'normal' },
+ { name: '娓╁害浼犳劅鍣�', status: 'normal' },
+ { name: '姘斾綋妫�娴嬪櫒', status: 'normal' },
+ { name: '鐖嗙牬鐗�', status: 'normal' },
+ { name: '娉勫帇瑁呯疆', status: 'normal' }
+])
+
+// 缁存姢璁板綍
+const maintenanceRecords = ref([
+ {
+ id: 1,
+ date: '2024-01-15',
+ type: 'inspection',
+ title: '骞村害妫�楠�',
+ description: '鎸夌収TSG 21-2016鏍囧噯杩涜骞村害妫�楠岋紝璁惧鐘舵�佽壇濂�',
+ operator: '寮犲伐绋嬪笀'
+ },
+ {
+ id: 2,
+ date: '2024-02-20',
+ type: 'maintenance',
+ title: '瀹夊叏闃�缁存姢',
+ description: '鏇存崲瀹夊叏闃�瀵嗗皝鍦堬紝鏍″噯鍘嬪姏璁惧畾鍊�',
+ operator: '鏉庢妧甯�'
+ },
+ {
+ id: 3,
+ date: '2024-03-10',
+ type: 'inspection',
+ title: '鍘嬪姏娴嬭瘯',
+ description: '杩涜鍘嬪姏瀹瑰櫒姘村帇璇曢獙锛岀鍚堣璁¤姹�',
+ operator: '鐜嬫楠屽憳'
+ }
+])
+
+// 寮圭獥鎺у埗
+const basicInfoDialogVisible = ref(false)
+const maintenanceDialogVisible = ref(false)
+
+// 缂栬緫琛ㄥ崟鏁版嵁
+const editBasicInfo = reactive({ ...basicInfo })
+const newMaintenanceRecord = reactive({
+ type: 'inspection',
+ title: '',
+ description: '',
+ operator: ''
+})
+
+// 鑾峰彇鐘舵�佹牱寮忕被
+const getStatusClass = (status) => {
+ return status === 'normal' ? 'status-normal' : 'status-warning'
+}
+
+// 鏂板鍌ㄧ綈
+const addTank = () => {
+ ElMessage.success('鏂板鍌ㄧ綈鍔熻兘')
+}
+
+// 瀵煎嚭鏁版嵁
+const exportData = () => {
+ ElMessage.success('瀵煎嚭鎴愬姛')
+}
+
+// 缂栬緫鍩烘湰淇℃伅
+const handleEditBasicInfo = () => {
+ Object.assign(editBasicInfo, basicInfo)
+ basicInfoDialogVisible.value = true
+}
+
+// 淇濆瓨鍩烘湰淇℃伅
+const saveBasicInfo = () => {
+ Object.assign(basicInfo, editBasicInfo)
+ basicInfoDialogVisible.value = false
+ ElMessage.success('淇濆瓨鎴愬姛')
+}
+
+// 鍒锋柊鐩戞祴鏁版嵁
+const refreshMonitoring = () => {
+ // 妯℃嫙鏁版嵁鏇存柊
+ monitoringData.pressure = (Math.random() * 0.5 + 0.6).toFixed(2)
+ monitoringData.temperature = (Math.random() * 10 + 20).toFixed(1)
+ monitoringData.gasConcentration = (Math.random() * 0.2).toFixed(2)
+ monitoringData.flow = (Math.random() * 10 + 10).toFixed(1)
+ ElMessage.success('鏁版嵁宸插埛鏂�')
+}
+
+// 妫�鏌ュ畨鍏ㄨ缃�
+const checkSafetyDevices = () => {
+ // 妯℃嫙妫�鏌ヨ繃绋�
+ safetyDevices.value.forEach(device => {
+ device.status = Math.random() > 0.1 ? 'normal' : 'warning'
+ })
+ ElMessage.success('瀹夊叏瑁呯疆妫�鏌ュ畬鎴�')
+}
+
+// 娣诲姞缁存姢璁板綍
+const addMaintenanceRecord = () => {
+ newMaintenanceRecord.type = 'inspection'
+ newMaintenanceRecord.title = ''
+ newMaintenanceRecord.description = ''
+ newMaintenanceRecord.operator = ''
+ maintenanceDialogVisible.value = true
+}
+
+// 淇濆瓨缁存姢璁板綍
+const saveMaintenanceRecord = () => {
+ const record = {
+ id: Date.now(),
+ date: new Date().toISOString().split('T')[0],
+ ...newMaintenanceRecord
+ }
+ maintenanceRecords.value.unshift(record)
+ maintenanceDialogVisible.value = false
+ ElMessage.success('璁板綍娣诲姞鎴愬姛')
+}
+
+// 妯℃嫙瀹炴椂鏁版嵁鏇存柊
+onMounted(() => {
+ setInterval(() => {
+ monitoringData.pressure = (Math.random() * 0.5 + 0.6).toFixed(2)
+ monitoringData.temperature = (Math.random() * 10 + 20).toFixed(1)
+ monitoringData.gasConcentration = (Math.random() * 0.2).toFixed(2)
+ monitoringData.flow = (Math.random() * 10 + 10).toFixed(1)
+ }, 5000)
+})
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+ padding: 20px;
+ background: #f5f5f5;
+ min-height: 100vh;
+}
+
+.page-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+ padding: 20px;
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+
+ h2 {
+ margin: 0;
+ color: #303133;
+ }
+
+ .header-actions {
+ display: flex;
+ gap: 10px;
+ }
+}
+
+.modules-container {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 20px;
+}
+
+.module-card {
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-weight: bold;
+ color: #303133;
+ }
+}
+
+.info-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 15px;
+
+ .info-item {
+ display: flex;
+ justify-content: space-between;
+ padding: 10px;
+ background: #f8f9fa;
+ border-radius: 4px;
+
+ label {
+ font-weight: bold;
+ color: #606266;
+ }
+
+ span {
+ color: #303133;
+ }
+ }
+}
+
+.monitoring-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 15px;
+
+ .monitor-item {
+ text-align: center;
+ padding: 15px;
+ background: #f8f9fa;
+ border-radius: 8px;
+ border: 2px solid transparent;
+
+ .monitor-label {
+ font-size: 14px;
+ color: #606266;
+ margin-bottom: 8px;
+ }
+
+ .monitor-value {
+ font-size: 20px;
+ font-weight: bold;
+ margin-bottom: 5px;
+
+ &.status-normal {
+ color: #67c23a;
+ }
+
+ &.status-warning {
+ color: #e6a23c;
+ }
+ }
+
+ .monitor-status {
+ font-size: 12px;
+ color: #909399;
+ }
+ }
+}
+
+.safety-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 15px;
+
+ .safety-item {
+ display: flex;
+ align-items: center;
+ padding: 15px;
+ background: #f8f9fa;
+ border-radius: 8px;
+ border: 2px solid transparent;
+
+ .device-icon {
+ margin-right: 15px;
+ }
+
+ .device-info {
+ flex: 1;
+
+ .device-name {
+ font-weight: bold;
+ color: #303133;
+ margin-bottom: 5px;
+ }
+
+ .device-status {
+ font-size: 12px;
+ padding: 2px 8px;
+ border-radius: 10px;
+ display: inline-block;
+
+ &.normal {
+ background: #f0f9ff;
+ color: #409eff;
+ }
+
+ &.warning {
+ background: #fef7e0;
+ color: #e6a23c;
+ }
+ }
+ }
+ }
+}
+
+.maintenance-list {
+ max-height: 300px;
+ overflow-y: auto;
+
+ .maintenance-item {
+ padding: 15px;
+ border-bottom: 1px solid #ebeef5;
+ margin-bottom: 10px;
+
+ &:last-child {
+ border-bottom: none;
+ margin-bottom: 0;
+ }
+
+ .record-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 8px;
+
+ .record-date {
+ font-size: 14px;
+ color: #909399;
+ }
+ }
+
+ .record-content {
+ .record-title {
+ font-weight: bold;
+ color: #303133;
+ margin-bottom: 5px;
+ }
+
+ .record-desc {
+ font-size: 14px;
+ color: #606266;
+ margin-bottom: 5px;
+ line-height: 1.4;
+ }
+
+ .record-operator {
+ font-size: 12px;
+ color: #909399;
+ }
+ }
+ }
+}
+
+// 鍝嶅簲寮忚璁�
+@media (max-width: 1200px) {
+ .modules-container {
+ grid-template-columns: 1fr;
+ }
+}
+
+@media (max-width: 768px) {
+ .info-grid,
+ .monitoring-grid,
+ .safety-grid {
+ grid-template-columns: 1fr;
+ }
+}
+</style>
diff --git a/src/views/inventoryManagement/stockWarning/index.vue b/src/views/inventoryManagement/stockWarning/index.vue
new file mode 100644
index 0000000..3694265
--- /dev/null
+++ b/src/views/inventoryManagement/stockWarning/index.vue
@@ -0,0 +1,1137 @@
+<template>
+ <div class="app-container">
+ <!-- 鎼滅储琛ㄥ崟 -->
+ <div class="search_form">
+ <el-form :model="searchForm" :inline="true">
+ <el-form-item label="鍌ㄦ皵缃愬悕绉帮細">
+ <el-input v-model="searchForm.tankName" placeholder="璇疯緭鍏ュ偍姘旂綈鍚嶇О" clearable style="width: 200px" />
+ </el-form-item>
+ <el-form-item label="鍌ㄦ皵缃愮被鍨嬶細">
+ <el-select v-model="searchForm.tankType" placeholder="璇烽�夋嫨鍌ㄦ皵缃愮被鍨�" clearable style="width: 200px">
+ <el-option label="娑插寲姘斿偍缃�" value="娑插寲姘斿偍缃�" />
+ <el-option label="鍘嬬缉姘斿偍缃�" value="鍘嬬缉姘斿偍缃�" />
+ <el-option label="澶╃劧姘斿偍缃�" value="澶╃劧姘斿偍缃�" />
+ <el-option label="姘ф皵鍌ㄧ綈" value="姘ф皵鍌ㄧ綈" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="棰勮绫诲瀷锛�">
+ <el-select v-model="searchForm.warningType" placeholder="璇烽�夋嫨棰勮绫诲瀷" clearable style="width: 200px">
+ <el-option label="姘斾綋涓嶈冻" value="姘斾綋涓嶈冻" />
+ <el-option label="鍘嬪姏寮傚父" value="鍘嬪姏寮傚父" />
+ <el-option label="娓╁害寮傚父" value="娓╁害寮傚父" />
+ <el-option label="娉勬紡棰勮" value="娉勬紡棰勮" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="棰勮绾у埆锛�">
+ <el-select v-model="searchForm.warningLevel" placeholder="璇烽�夋嫨棰勮绾у埆" clearable style="width: 200px">
+ <el-option label="绱ф��" value="绱ф��" />
+ <el-option label="閲嶈" value="閲嶈" />
+ <el-option label="涓�鑸�" value="涓�鑸�" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery">鎼滅储</el-button>
+ <el-button @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <!-- 鏁版嵁琛ㄦ牸 -->
+ <div class="table_list">
+ <!-- 鎿嶄綔鎸夐挳 -->
+ <div class="table-operations">
+ <el-button type="primary" @click="handleAdd">鏂板棰勮瑙勫垯</el-button>
+ <el-button type="success" @click="handleBatchProcess">鎵归噺澶勭悊</el-button>
+ <el-button @click="handleExport">瀵煎嚭</el-button>
+ </div>
+ <el-table
+ :data="tableData"
+ border
+ v-loading="tableLoading"
+ @selection-change="handleSelectionChange"
+ style="width: 100%"
+ height="calc(100vh - 280px)"
+ >
+ <el-table-column align="center" type="selection" width="55" />
+ <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+
+ <!-- 鍩虹淇℃伅瀛楁 -->
+ <el-table-column label="鍌ㄦ皵缃愮紪鐮�" prop="tankCode" width="120" show-overflow-tooltip />
+ <el-table-column label="鍌ㄦ皵缃愬悕绉�" prop="tankName" width="200" show-overflow-tooltip />
+ <el-table-column label="鍌ㄦ皵缃愮被鍨�" prop="tankType" width="120" show-overflow-tooltip />
+ <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" width="150" show-overflow-tooltip />
+ <el-table-column label="瀹圭Н(m鲁)" prop="volume" width="100" show-overflow-tooltip />
+
+ <!-- 搴撳瓨鐩稿叧瀛楁 -->
+ <el-table-column label="褰撳墠姘斾綋閲�" prop="currentGasLevel" width="120" show-overflow-tooltip>
+ <template #default="scope">
+ <span :class="getGasLevelClass(scope.row)">{{ scope.row.currentGasLevel }}%</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="瀹夊叏姘斾綋閲�" prop="safetyGasLevel" width="120" show-overflow-tooltip />
+ <el-table-column label="鏈�浣庢皵浣撻噺" prop="minGasLevel" width="120" show-overflow-tooltip />
+ <el-table-column label="鏈�楂樻皵浣撻噺" prop="maxGasLevel" width="120" show-overflow-tooltip />
+ <el-table-column label="褰撳墠鍘嬪姏(MPa)" prop="currentPressure" width="140" show-overflow-tooltip />
+
+ <!-- 棰勮瑙勫垯瀛楁 -->
+ <el-table-column label="棰勮绫诲瀷" prop="warningType" width="100" show-overflow-tooltip>
+ <template #default="scope">
+ <el-tag :type="getWarningTypeTag(scope.row.warningType)">
+ {{ scope.row.warningType }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="棰勮绾у埆" prop="warningLevel" width="100" show-overflow-tooltip>
+ <template #default="scope">
+ <el-tag :type="getWarningLevelTag(scope.row.warningLevel)">
+ {{ scope.row.warningLevel }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="棰勮闃堝��" prop="warningThreshold" width="100" show-overflow-tooltip />
+ <el-table-column label="鏄惁鍚敤" prop="isEnabled" width="100" show-overflow-tooltip>
+ <template #default="scope">
+ <el-switch v-model="scope.row.isEnabled" @change="handleEnableChange(scope.row)" />
+ </template>
+ </el-table-column>
+
+ <!-- 鏃堕棿鐩稿叧瀛楁 -->
+ <el-table-column label="棰勮鏃堕棿" prop="warningTime" width="150" show-overflow-tooltip />
+ <el-table-column label="棰勮鎸佺画澶╂暟" prop="warningDuration" width="120" show-overflow-tooltip />
+ <el-table-column label="鏈�鍚庢洿鏂版椂闂�" prop="lastUpdateTime" width="150" show-overflow-tooltip />
+ <el-table-column label="棰勮鍏呰鏃堕棿" prop="expectedRefillTime" width="150" show-overflow-tooltip />
+ <el-table-column label="棰勮缂烘皵鏃堕棿" prop="expectedShortageTime" width="150" show-overflow-tooltip>
+ <template #default="scope">
+ <div v-if="scope.row.expectedShortageTime">
+ <div v-if="getCountdown(scope.row.expectedShortageTime).isExpired" class="countdown-expired">
+ <el-tag type="danger">宸茬己姘�</el-tag>
+ </div>
+ <div v-else class="countdown-timer">
+ <span :class="getCountdownClass(scope.row.expectedShortageTime)">
+ {{ getCountdown(scope.row.expectedShortageTime).text }}
+ </span>
+ </div>
+ </div>
+ <span v-else>-</span>
+ </template>
+ </el-table-column>
+
+ <!-- 鎿嶄綔鍒� -->
+ <el-table-column fixed="right" label="鎿嶄綔" width="200" align="center">
+ <template #default="scope">
+ <el-button link type="primary" size="small" @click="handleEdit(scope.row)">缂栬緫</el-button>
+ <el-button link type="success" size="small" @click="handleProcess(scope.row)">澶勭悊</el-button>
+ <el-button link type="danger" size="small" @click="handleDelete(scope.row)">鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <pagination
+ v-show="total > 0"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ :page="page.current"
+ :limit="page.size"
+ @pagination="paginationChange"
+ />
+ </div>
+
+ <!-- 鏂板/缂栬緫棰勮瑙勫垯寮圭獥 -->
+ <el-dialog
+ v-model="dialogFormVisible"
+ :title="operationType === 'add' ? '鏂板棰勮瑙勫垯' : '缂栬緫棰勮瑙勫垯'"
+ width="50%"
+ @close="closeDialog"
+ >
+ <el-form :model="form" :rules="rules" ref="formRef" label-width="140px">
+ <el-row :gutter="20">
+ <!-- 鍩虹淇℃伅 -->
+ <el-col :span="12">
+ <el-form-item label="鍌ㄦ皵缃愮紪鐮侊細" prop="tankCode">
+ <el-input v-model="form.tankCode" placeholder="璇疯緭鍏ュ偍姘旂綈缂栫爜" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍌ㄦ皵缃愬悕绉帮細" prop="tankName">
+ <el-input v-model="form.tankName" placeholder="璇疯緭鍏ュ偍姘旂綈鍚嶇О" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鍌ㄦ皵缃愮被鍨嬶細" prop="tankType">
+ <el-select v-model="form.tankType" placeholder="璇烽�夋嫨鍌ㄦ皵缃愮被鍨�" style="width: 100%">
+ <el-option label="娑插寲姘斿偍缃�" value="娑插寲姘斿偍缃�" />
+ <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="specificationModel">
+ <el-input v-model="form.specificationModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="瀹圭Н(m鲁)锛�" prop="volume">
+ <el-input-number v-model="form.volume" :min="0" :precision="2" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="褰撳墠姘斾綋閲�(%)锛�" prop="currentGasLevel">
+ <el-input-number v-model="form.currentGasLevel" :min="0" :max="100" :precision="1" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <!-- 搴撳瓨鐩稿叧 -->
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="瀹夊叏姘斾綋閲�(%)锛�" prop="safetyGasLevel">
+ <el-input-number v-model="form.safetyGasLevel" :min="0" :max="100" :precision="1" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鏈�浣庢皵浣撻噺(%)锛�" prop="minGasLevel">
+ <el-input-number v-model="form.minGasLevel" :min="0" :max="100" :precision="1" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鏈�楂樻皵浣撻噺(%)锛�" prop="maxGasLevel">
+ <el-input-number v-model="form.maxGasLevel" :min="0" :max="100" :precision="1" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="褰撳墠鍘嬪姏(MPa)锛�" prop="currentPressure">
+ <el-input-number v-model="form.currentPressure" :min="0" :precision="2" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <!-- 棰勮瑙勫垯 -->
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="棰勮绫诲瀷锛�" prop="warningType">
+ <el-select v-model="form.warningType" placeholder="璇烽�夋嫨棰勮绫诲瀷" style="width: 100%">
+ <el-option label="姘斾綋涓嶈冻" value="姘斾綋涓嶈冻" />
+ <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="warningLevel">
+ <el-select v-model="form.warningLevel" placeholder="璇烽�夋嫨棰勮绾у埆" style="width: 100%">
+ <el-option label="绱ф��" value="绱ф��" />
+ <el-option label="閲嶈" value="閲嶈" />
+ <el-option label="涓�鑸�" value="涓�鑸�" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="棰勮闃堝�硷細" prop="warningThreshold">
+ <el-input-number v-model="form.warningThreshold" :min="0" :precision="2" style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鏄惁鍚敤锛�" prop="isEnabled">
+ <el-switch v-model="form.isEnabled" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <!-- 鏃堕棿鐩稿叧 -->
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="棰勮鏃堕棿锛�" prop="warningTime">
+ <el-date-picker
+ v-model="form.warningTime"
+ type="datetime"
+ placeholder="璇烽�夋嫨棰勮鏃堕棿"
+ style="width: 100%"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="棰勮鍏呰鏃堕棿锛�" prop="expectedRefillTime">
+ <el-date-picker
+ v-model="form.expectedRefillTime"
+ type="datetime"
+ placeholder="璇烽�夋嫨棰勮鍏呰鏃堕棿"
+ style="width: 100%"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="棰勮缂烘皵鏃堕棿锛�" prop="expectedShortageTime">
+ <el-date-picker
+ v-model="form.expectedShortageTime"
+ type="datetime"
+ placeholder="璇烽�夋嫨棰勮缂烘皵鏃堕棿"
+ style="width: 100%"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="棰勮瑙勫垯鎻忚堪锛�" prop="warningRule">
+ <el-input
+ v-model="form.warningRule"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ラ璀﹁鍒欐弿杩�"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button @click="closeDialog">鍙栨秷</el-button>
+ <el-button type="primary" @click="submitForm">纭</el-button>
+ </div>
+ </template>
+ </el-dialog>
+
+ <!-- 缂烘皵棰勮寮规 -->
+ <el-dialog
+ v-model="shortageWarningVisible"
+ title="鈿狅笍 缂烘皵棰勮"
+ width="400px"
+ :close-on-click-modal="false"
+ :close-on-press-escape="false"
+ :show-close="false"
+ >
+ <div class="shortage-warning-content">
+ <div class="warning-icon">
+ <el-icon size="48" color="#f56c6c"><WarningFilled /></el-icon>
+ </div>
+ <div class="warning-message">
+ <h3>{{ currentWarningTank.tankName }}</h3>
+ <p>鍌ㄦ皵缃愬凡缂烘皵锛岃鍙婃椂澶勭悊锛�</p>
+ <p class="warning-details">
+ 鍌ㄦ皵缃愮紪鐮侊細{{ currentWarningTank.tankCode }}<br>
+ 鍌ㄦ皵缃愮被鍨嬶細{{ currentWarningTank.tankType }}<br>
+ 褰撳墠姘斾綋閲忥細{{ currentWarningTank.currentGasLevel }}%
+ </p>
+ </div>
+ </div>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="handleShortageWarning">绔嬪嵆澶勭悊</el-button>
+ <el-button @click="closeShortageWarning">绋嶅悗澶勭悊</el-button>
+ </div>
+ </template>
+ </el-dialog>
+
+ <!-- 缂烘皵棰勮寮规 -->
+ <el-dialog
+ v-model="shortageWarningVisible"
+ title="鈿狅笍 缂烘皵棰勮"
+ width="400px"
+ :close-on-click-modal="false"
+ :close-on-press-escape="false"
+ :show-close="false"
+ >
+ <div class="shortage-warning-content">
+ <div class="warning-icon">
+ <el-icon size="48" color="#f56c6c"><WarningFilled /></el-icon>
+ </div>
+ <div class="warning-message">
+ <h3>{{ currentWarningTank.tankName }}</h3>
+ <p>鍌ㄦ皵缃愬凡缂烘皵锛岃鍙婃椂澶勭悊锛�</p>
+ <p class="warning-details">
+ 鍌ㄦ皵缃愮紪鐮侊細{{ currentWarningTank.tankCode }}<br>
+ 鍌ㄦ皵缃愮被鍨嬶細{{ currentWarningTank.tankType }}<br>
+ 褰撳墠姘斾綋閲忥細{{ currentWarningTank.currentGasLevel }}%
+ </p>
+ </div>
+ </div>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="handleShortageWarning">绔嬪嵆澶勭悊</el-button>
+ <el-button @click="closeShortageWarning">绋嶅悗澶勭悊</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, onUnmounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { WarningFilled } from '@element-plus/icons-vue'
+import pagination from '@/components/PIMTable/Pagination.vue'
+// 娉ㄩ噴鎺堿PI瀵煎叆锛屼娇鐢ㄥ亣鏁版嵁
+// import {
+// getStockWarningPage,
+// addStockWarning,
+// updateStockWarning,
+// deleteStockWarning,
+// batchProcessStockWarning,
+// exportStockWarning,
+// toggleStockWarningStatus
+// } from '@/api/inventoryManagement/stockWarning.js'
+
+const { proxy } = getCurrentInstance()
+
+// 鍝嶅簲寮忔暟鎹�
+const tableData = ref([])
+const tableLoading = ref(false)
+const selectedRows = ref([])
+const dialogFormVisible = ref(false)
+const operationType = ref('add')
+const total = ref(0)
+
+// 缂烘皵棰勮鐩稿叧
+const shortageWarningVisible = ref(false)
+const currentWarningTank = ref({})
+const countdownTimer = ref(null)
+
+// 鍒嗛〉鍙傛暟
+const page = reactive({
+ current: 1,
+ size: 10
+})
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+ tankName: '',
+ tankType: '',
+ warningType: '',
+ warningLevel: ''
+})
+
+// 琛ㄥ崟鏁版嵁
+const form = reactive({
+ id: null,
+ tankCode: '',
+ tankName: '',
+ tankType: '',
+ specificationModel: '',
+ volume: 0,
+ currentGasLevel: 0,
+ safetyGasLevel: 0,
+ minGasLevel: 0,
+ maxGasLevel: 0,
+ currentPressure: 0,
+ warningType: '',
+ warningLevel: '',
+ warningThreshold: 0,
+ isEnabled: true,
+ warningTime: '',
+ warningDuration: 0,
+ lastUpdateTime: '',
+ expectedRefillTime: '',
+ expectedShortageTime: '',
+ warningRule: ''
+})
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const rules = {
+ tankCode: [{ required: true, message: '璇疯緭鍏ュ偍姘旂綈缂栫爜', trigger: 'blur' }],
+ tankName: [{ required: true, message: '璇疯緭鍏ュ偍姘旂綈鍚嶇О', trigger: 'blur' }],
+ tankType: [{ required: true, message: '璇烽�夋嫨鍌ㄦ皵缃愮被鍨�', trigger: 'change' }],
+ warningType: [{ required: true, message: '璇烽�夋嫨棰勮绫诲瀷', trigger: 'change' }],
+ warningLevel: [{ required: true, message: '璇烽�夋嫨棰勮绾у埆', trigger: 'change' }],
+ warningThreshold: [{ required: true, message: '璇疯緭鍏ラ璀﹂槇鍊�', trigger: 'blur' }]
+}
+
+// 鑾峰彇鍊掕鏃朵俊鎭�
+const getCountdown = (expectedTime) => {
+ if (!expectedTime) return { text: '-', isExpired: false }
+
+ const now = new Date().getTime()
+ const expected = new Date(expectedTime).getTime()
+ const diff = expected - now
+
+ if (diff <= 0) {
+ return { text: '宸茬己姘�', isExpired: true }
+ }
+
+ const days = Math.floor(diff / (1000 * 60 * 60 * 24))
+ const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
+ const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
+
+ if (days > 0) {
+ return { text: `${days}澶�${hours}灏忔椂`, isExpired: false }
+ } else if (hours > 0) {
+ return { text: `${hours}灏忔椂${minutes}鍒嗛挓`, isExpired: false }
+ } else {
+ return { text: `${minutes}鍒嗛挓`, isExpired: false }
+ }
+}
+
+// 鑾峰彇鍊掕鏃舵牱寮忕被
+const getCountdownClass = (expectedTime) => {
+ if (!expectedTime) return ''
+
+ const now = new Date().getTime()
+ const expected = new Date(expectedTime).getTime()
+ const diff = expected - now
+
+ if (diff <= 0) {
+ return 'countdown-expired'
+ } else if (diff <= 24 * 60 * 60 * 1000) { // 24灏忔椂鍐�
+ return 'countdown-urgent'
+ } else if (diff <= 7 * 24 * 60 * 60 * 1000) { // 7澶╁唴
+ return 'countdown-warning'
+ } else {
+ return 'countdown-normal'
+ }
+}
+
+// 妫�鏌ョ己姘旈璀�
+const checkShortageWarnings = () => {
+ tableData.value.forEach(tank => {
+ if (tank.expectedShortageTime) {
+ const countdown = getCountdown(tank.expectedShortageTime)
+ if (countdown.isExpired && !tank.warningShown) {
+ // 鏍囪宸叉樉绀洪璀︼紝閬垮厤閲嶅寮规
+ tank.warningShown = true
+ showShortageWarning(tank)
+ }
+ }
+ })
+}
+
+// 鏄剧ず缂烘皵棰勮寮规
+const showShortageWarning = (tank) => {
+ currentWarningTank.value = tank
+ shortageWarningVisible.value = true
+
+ // 鎾斁鎻愮ず闊筹紙鍙�夛級
+ // const audio = new Audio('/path/to/warning-sound.mp3')
+ // audio.play()
+}
+
+// 澶勭悊缂烘皵棰勮
+const handleShortageWarning = () => {
+ ElMessage.success(`姝e湪澶勭悊鍌ㄦ皵缃� ${currentWarningTank.value.tankName} 鐨勭己姘旈棶棰榒)
+ shortageWarningVisible.value = false
+ // 杩欓噷鍙互璋冪敤澶勭悊API
+}
+// 澶勭悊缂烘皵棰勮
+const closeShortageWarning = () => {
+ // ElMessage.success(`姝e湪澶勭悊鍌ㄦ皵缃� ${currentWarningTank.value.tankName} 鐨勭己姘旈棶棰榒)
+ shortageWarningVisible.value = false
+ // 杩欓噷鍙互璋冪敤澶勭悊API
+}
+
+
+
+// 鐢熸垚鍋囨暟鎹�
+const generateMockData = () => {
+ const mockData = [
+ {
+ id: 1,
+ tankCode: 'TANK001',
+ tankName: '娑插寲姘斿偍缃怉',
+ tankType: '娑插寲姘斿偍缃�',
+ specificationModel: 'LPG-5000L',
+ volume: 5000,
+ currentGasLevel: 15,
+ safetyGasLevel: 30,
+ minGasLevel: 10,
+ maxGasLevel: 95,
+ currentPressure: 2.5,
+ warningType: '姘斾綋涓嶈冻',
+ warningLevel: '绱ф��',
+ warningThreshold: 20,
+ isEnabled: true,
+ warningTime: '2024-01-15 08:30:00',
+ warningDuration: 3,
+ lastUpdateTime: '2024-01-15 10:00:00',
+ expectedRefillTime: '2024-01-16 14:00:00',
+ expectedShortageTime: '2024-01-15 18:30:00', // 浠婂ぉ涓嬪崍6:30缂烘皵
+ warningRule: '褰撴皵浣撻噺浣庝簬20%鏃惰Е鍙戦璀�'
+ },
+ {
+ id: 2,
+ tankCode: 'TANK002',
+ tankName: '鍘嬬缉姘斿偍缃怋',
+ tankType: '鍘嬬缉姘斿偍缃�',
+ specificationModel: 'COMP-3000L',
+ volume: 3000,
+ currentGasLevel: 45,
+ safetyGasLevel: 25,
+ minGasLevel: 15,
+ maxGasLevel: 90,
+ currentPressure: 8.2,
+ warningType: '鍘嬪姏寮傚父',
+ warningLevel: '閲嶈',
+ warningThreshold: 10,
+ isEnabled: true,
+ warningTime: '2024-01-14 16:20:00',
+ warningDuration: 2,
+ lastUpdateTime: '2024-01-15 09:15:00',
+ expectedRefillTime: '2024-01-17 09:00:00',
+ expectedShortageTime: '2024-01-18 12:00:00', // 3澶╁悗缂烘皵
+ warningRule: '褰撳帇鍔涜秴杩�8MPa鏃惰Е鍙戦璀�'
+ },
+ {
+ id: 3,
+ tankCode: 'TANK003',
+ tankName: '澶╃劧姘斿偍缃怌',
+ tankType: '澶╃劧姘斿偍缃�',
+ specificationModel: 'NG-8000L',
+ volume: 8000,
+ currentGasLevel: 75,
+ safetyGasLevel: 20,
+ minGasLevel: 10,
+ maxGasLevel: 95,
+ currentPressure: 4.8,
+ warningType: '娓╁害寮傚父',
+ warningLevel: '涓�鑸�',
+ warningThreshold: 5,
+ isEnabled: true,
+ warningTime: '2024-01-13 11:45:00',
+ warningDuration: 1,
+ lastUpdateTime: '2024-01-15 08:45:00',
+ expectedRefillTime: '2024-01-20 10:00:00',
+ expectedShortageTime: '2024-01-22 15:30:00', // 7澶╁悗缂烘皵
+ warningRule: '褰撴俯搴﹁秴杩�60掳C鏃惰Е鍙戦璀�'
+ },
+ {
+ id: 4,
+ tankCode: 'TANK004',
+ tankName: '姘ф皵鍌ㄧ綈D',
+ tankType: '姘ф皵鍌ㄧ綈',
+ specificationModel: 'O2-2000L',
+ volume: 2000,
+ currentGasLevel: 8,
+ safetyGasLevel: 25,
+ minGasLevel: 5,
+ maxGasLevel: 90,
+ currentPressure: 6.5,
+ warningType: '娉勬紡棰勮',
+ warningLevel: '绱ф��',
+ warningThreshold: 15,
+ isEnabled: true,
+ warningTime: '2024-01-15 07:15:00',
+ warningDuration: 4,
+ lastUpdateTime: '2024-01-15 11:30:00',
+ expectedRefillTime: '2024-01-15 16:00:00',
+ expectedShortageTime: '2024-01-15 14:00:00', // 浠婂ぉ涓嬪崍2鐐圭己姘�
+ warningRule: '褰撴娴嬪埌姘斾綋娉勬紡鏃惰Е鍙戦璀�'
+ },
+ {
+ id: 5,
+ tankCode: 'TANK005',
+ tankName: '娑插寲姘斿偍缃怑',
+ tankType: '娑插寲姘斿偍缃�',
+ specificationModel: 'LPG-6000L',
+ volume: 6000,
+ currentGasLevel: 35,
+ safetyGasLevel: 30,
+ minGasLevel: 15,
+ maxGasLevel: 95,
+ currentPressure: 3.2,
+ warningType: '姘斾綋涓嶈冻',
+ warningLevel: '閲嶈',
+ warningThreshold: 20,
+ isEnabled: false,
+ warningTime: '2024-01-14 14:30:00',
+ warningDuration: 2,
+ lastUpdateTime: '2024-01-15 09:00:00',
+ expectedRefillTime: '2024-01-19 08:00:00',
+ expectedShortageTime: '2024-01-21 10:00:00', // 6澶╁悗缂烘皵
+ warningRule: '褰撴皵浣撻噺浣庝簬20%鏃惰Е鍙戦璀�'
+ },
+ {
+ id: 6,
+ tankCode: 'TANK006',
+ tankName: '鍘嬬缉姘斿偍缃怓',
+ tankType: '鍘嬬缉姘斿偍缃�',
+ specificationModel: 'COMP-4000L',
+ volume: 4000,
+ currentGasLevel: 85,
+ safetyGasLevel: 20,
+ minGasLevel: 10,
+ maxGasLevel: 90,
+ currentPressure: 7.8,
+ warningType: '鍘嬪姏寮傚父',
+ warningLevel: '涓�鑸�',
+ warningThreshold: 8,
+ isEnabled: true,
+ warningTime: '2024-01-12 09:20:00',
+ warningDuration: 1,
+ lastUpdateTime: '2024-01-15 08:30:00',
+ expectedRefillTime: '2024-01-25 14:00:00',
+ expectedShortageTime: '2024-01-28 16:00:00', // 13澶╁悗缂烘皵
+ warningRule: '褰撳帇鍔涜秴杩�8MPa鏃惰Е鍙戦璀�'
+ },
+ {
+ id: 7,
+ tankCode: 'TANK007',
+ tankName: '澶╃劧姘斿偍缃怗',
+ tankType: '澶╃劧姘斿偍缃�',
+ specificationModel: 'NG-10000L',
+ volume: 10000,
+ currentGasLevel: 92,
+ safetyGasLevel: 15,
+ minGasLevel: 8,
+ maxGasLevel: 95,
+ currentPressure: 5.2,
+ warningType: '娓╁害寮傚父',
+ warningLevel: '閲嶈',
+ warningThreshold: 6,
+ isEnabled: true,
+ warningTime: '2024-01-11 16:45:00',
+ warningDuration: 1,
+ lastUpdateTime: '2024-01-15 07:45:00',
+ expectedRefillTime: '2024-01-30 09:00:00',
+ expectedShortageTime: '2024-02-05 12:00:00', // 21澶╁悗缂烘皵
+ warningRule: '褰撴俯搴﹁秴杩�60掳C鏃惰Е鍙戦璀�'
+ },
+ {
+ id: 8,
+ tankCode: 'TANK008',
+ tankName: '姘ф皵鍌ㄧ綈H',
+ tankType: '姘ф皵鍌ㄧ綈',
+ specificationModel: 'O2-1500L',
+ volume: 1500,
+ currentGasLevel: 12,
+ safetyGasLevel: 30,
+ minGasLevel: 8,
+ maxGasLevel: 90,
+ currentPressure: 4.5,
+ warningType: '娉勬紡棰勮',
+ warningLevel: '绱ф��',
+ warningThreshold: 12,
+ isEnabled: true,
+ warningTime: '2024-01-15 06:30:00',
+ warningDuration: 5,
+ lastUpdateTime: '2024-01-15 12:15:00',
+ expectedRefillTime: '2024-01-15 20:00:00',
+ expectedShortageTime: '2024-01-15 17:30:00', // 浠婂ぉ涓嬪崍5:30缂烘皵
+ warningRule: '褰撴娴嬪埌姘斾綋娉勬紡鏃惰Е鍙戦璀�'
+ }
+ ]
+
+ // 鏍规嵁鎼滅储鏉′欢杩囨护鏁版嵁
+ let filteredData = mockData.filter(item => {
+ if (searchForm.tankName && !item.tankName.includes(searchForm.tankName)) return false
+ if (searchForm.tankType && item.tankType !== searchForm.tankType) return false
+ if (searchForm.warningType && item.warningType !== searchForm.warningType) return false
+ if (searchForm.warningLevel && item.warningLevel !== searchForm.warningLevel) return false
+ return true
+ })
+
+ // 鍒嗛〉澶勭悊
+ const start = (page.current - 1) * page.size
+ const end = start + page.size
+ const paginatedData = filteredData.slice(start, end)
+
+ return {
+ records: paginatedData,
+ total: filteredData.length
+ }
+}
+
+// 鑾峰彇鍒楄〃鏁版嵁
+const getList = async () => {
+ tableLoading.value = true
+ try {
+ // 妯℃嫙缃戠粶寤惰繜
+ await new Promise(resolve => setTimeout(resolve, 500))
+
+ const result = generateMockData()
+ tableData.value = result.records
+ total.value = result.total
+
+ // 妫�鏌ョ己姘旈璀�
+ checkShortageWarnings()
+ } catch (error) {
+ console.error('鑾峰彇鍒楄〃澶辫触:', error)
+ ElMessage.error('鑾峰彇鍒楄〃澶辫触')
+ } finally {
+ tableLoading.value = false
+ }
+}
+
+// 鎼滅储
+const handleQuery = () => {
+ page.current = 1
+ getList()
+}
+
+// 閲嶇疆鎼滅储
+const resetQuery = () => {
+ Object.keys(searchForm).forEach(key => {
+ searchForm[key] = ''
+ })
+ handleQuery()
+}
+
+// 鍒嗛〉鍙樺寲
+const paginationChange = (obj) => {
+ page.current = obj.page
+ page.size = obj.limit
+ getList()
+}
+
+// 琛ㄦ牸閫夋嫨鍙樺寲
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection
+}
+
+// 鏂板
+const handleAdd = () => {
+ operationType.value = 'add'
+ resetForm()
+ dialogFormVisible.value = true
+}
+
+// 缂栬緫
+const handleEdit = (row) => {
+ operationType.value = 'edit'
+ Object.assign(form, row)
+ dialogFormVisible.value = true
+}
+
+// 澶勭悊棰勮
+const handleProcess = async (row) => {
+ try {
+ // 妯℃嫙API璋冪敤寤惰繜
+ await new Promise(resolve => setTimeout(resolve, 300))
+ ElMessage.success(`姝e湪澶勭悊棰勮锛�${row.tankName}`)
+ getList()
+ } catch (error) {
+ ElMessage.error('澶勭悊棰勮澶辫触')
+ }
+}
+
+// 鍒犻櫎
+const handleDelete = async (row) => {
+ try {
+ await ElMessageBox.confirm(`纭畾瑕佸垹闄ら璀﹁鍒欙細${row.tankName}鍚楋紵`, '鎻愮ず', {
+ confirmButtonText: '纭畾',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning'
+ })
+
+ // 妯℃嫙API璋冪敤寤惰繜
+ await new Promise(resolve => setTimeout(resolve, 300))
+ ElMessage.success('鍒犻櫎鎴愬姛')
+ getList()
+ } catch (error) {
+ if (error !== 'cancel') {
+ ElMessage.error('鍒犻櫎澶辫触')
+ }
+ }
+}
+
+// 鎵归噺澶勭悊
+const handleBatchProcess = async () => {
+ if (selectedRows.value.length === 0) {
+ ElMessage.warning('璇烽�夋嫨瑕佸鐞嗙殑棰勮')
+ return
+ }
+
+ try {
+ // 妯℃嫙API璋冪敤寤惰繜
+ await new Promise(resolve => setTimeout(resolve, 500))
+ ElMessage.success(`鎵归噺澶勭悊浜� ${selectedRows.value.length} 鏉¢璀)
+ getList()
+ } catch (error) {
+ ElMessage.error('鎵归噺澶勭悊澶辫触')
+ }
+}
+
+// 瀵煎嚭
+const handleExport = async () => {
+ try {
+ // 妯℃嫙API璋冪敤寤惰繜
+ await new Promise(resolve => setTimeout(resolve, 800))
+
+ // 鐢熸垚瀵煎嚭鏁版嵁
+ const exportData = generateMockData().records
+ const csvContent = generateCSV(exportData)
+
+ // 鍒涘缓涓嬭浇閾炬帴
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
+ const url = window.URL.createObjectURL(blob)
+ const link = document.createElement('a')
+ link.href = url
+ link.download = `鍌ㄦ皵缃愰璀︽暟鎹甠${new Date().getTime()}.csv`
+ link.click()
+ window.URL.revokeObjectURL(url)
+
+ ElMessage.success('瀵煎嚭鎴愬姛')
+ } catch (error) {
+ ElMessage.error('瀵煎嚭澶辫触')
+ }
+}
+
+// 鐢熸垚CSV鍐呭
+const generateCSV = (data) => {
+ const headers = [
+ '鍌ㄦ皵缃愮紪鐮�', '鍌ㄦ皵缃愬悕绉�', '鍌ㄦ皵缃愮被鍨�', '瑙勬牸鍨嬪彿', '瀹圭Н(m鲁)',
+ '褰撳墠姘斾綋閲�(%)', '瀹夊叏姘斾綋閲�(%)', '鏈�浣庢皵浣撻噺(%)', '鏈�楂樻皵浣撻噺(%)',
+ '褰撳墠鍘嬪姏(MPa)', '棰勮绫诲瀷', '棰勮绾у埆', '棰勮闃堝��', '鏄惁鍚敤',
+ '棰勮鏃堕棿', '棰勮鎸佺画澶╂暟', '鏈�鍚庢洿鏂版椂闂�', '棰勮鍏呰鏃堕棿', '棰勮缂烘皵鏃堕棿', '棰勮瑙勫垯鎻忚堪'
+ ]
+
+ const csvRows = [headers.join(',')]
+
+ data.forEach(item => {
+ const row = [
+ item.tankCode,
+ item.tankName,
+ item.tankType,
+ item.specificationModel,
+ item.volume,
+ item.currentGasLevel,
+ item.safetyGasLevel,
+ item.minGasLevel,
+ item.maxGasLevel,
+ item.currentPressure,
+ item.warningType,
+ item.warningLevel,
+ item.warningThreshold,
+ item.isEnabled ? '鏄�' : '鍚�',
+ item.warningTime,
+ item.warningDuration,
+ item.lastUpdateTime,
+ item.expectedRefillTime,
+ item.expectedShortageTime,
+ item.warningRule
+ ]
+ csvRows.push(row.join(','))
+ })
+
+ return csvRows.join('\n')
+}
+
+// 鍚敤鐘舵�佸彉鍖�
+const handleEnableChange = async (row) => {
+ try {
+ // 妯℃嫙API璋冪敤寤惰繜
+ await new Promise(resolve => setTimeout(resolve, 200))
+ ElMessage.success(`${row.tankName} 鐨勫惎鐢ㄧ姸鎬佸凡鏇存柊`)
+ } catch (error) {
+ ElMessage.error('鐘舵�佹洿鏂板け璐�')
+ // 鎭㈠鍘熺姸鎬�
+ row.isEnabled = !row.isEnabled
+ }
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = async () => {
+ try {
+ await proxy.$refs.formRef.validate()
+
+ // 妯℃嫙API璋冪敤寤惰繜
+ await new Promise(resolve => setTimeout(resolve, 500))
+
+ if (operationType.value === 'add') {
+ ElMessage.success('鏂板鎴愬姛')
+ } else {
+ ElMessage.success('缂栬緫鎴愬姛')
+ }
+
+ closeDialog()
+ getList()
+ } catch (error) {
+ if (!error.errors) {
+ ElMessage.error(operationType.value === 'add' ? '鏂板澶辫触' : '缂栬緫澶辫触')
+ }
+ }
+}
+
+// 鍏抽棴寮圭獥
+const closeDialog = () => {
+ dialogFormVisible.value = false
+ resetForm()
+}
+
+// 閲嶇疆琛ㄥ崟
+const resetForm = () => {
+ Object.keys(form).forEach(key => {
+ if (key === 'isEnabled') {
+ form[key] = true
+ } else if (typeof form[key] === 'number') {
+ form[key] = 0
+ } else {
+ form[key] = ''
+ }
+ })
+ proxy.$refs.formRef?.resetFields()
+}
+
+// 鑾峰彇姘斾綋閲忔牱寮忕被
+const getGasLevelClass = (row) => {
+ if (row.currentGasLevel < row.minGasLevel) {
+ return 'text-danger'
+ } else if (row.currentGasLevel > row.maxGasLevel) {
+ return 'text-warning'
+ }
+ return 'text-success'
+}
+
+// 鑾峰彇棰勮绫诲瀷鏍囩鏍峰紡
+const getWarningTypeTag = (type) => {
+ const typeMap = {
+ '姘斾綋涓嶈冻': 'danger',
+ '鍘嬪姏寮傚父': 'warning',
+ '娓╁害寮傚父': 'info',
+ '娉勬紡棰勮': 'danger'
+ }
+ return typeMap[type] || 'info'
+}
+
+// 鑾峰彇棰勮绾у埆鏍囩鏍峰紡
+const getWarningLevelTag = (level) => {
+ const levelMap = {
+ '绱ф��': 'danger',
+ '閲嶈': 'warning',
+ '涓�鑸�': 'info'
+ }
+ return levelMap[level] || 'info'
+}
+
+// 鍚姩鍊掕鏃跺畾鏃跺櫒
+const startCountdownTimer = () => {
+ countdownTimer.value = setInterval(() => {
+ checkShortageWarnings()
+ }, 60000) // 姣忓垎閽熸鏌ヤ竴娆�
+}
+
+// 鍋滄鍊掕鏃跺畾鏃跺櫒
+const stopCountdownTimer = () => {
+ if (countdownTimer.value) {
+ clearInterval(countdownTimer.value)
+ countdownTimer.value = null
+ }
+}
+
+// 椤甸潰鍔犺浇
+onMounted(() => {
+ getList()
+ startCountdownTimer()
+})
+
+// 椤甸潰鍗歌浇
+onUnmounted(() => {
+ stopCountdownTimer()
+})
+</script>
+
+<style scoped lang="scss">
+.app-container {
+ padding: 20px;
+
+ .table-operations {
+ text-align: right;
+ margin-bottom: 20px;
+
+ .el-button {
+ margin-right: 10px;
+ }
+ }
+
+ .table_list {
+ background: #fff;
+ border-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
+
+ .text-danger {
+ color: #f56c6c;
+ font-weight: bold;
+ }
+
+ .text-warning {
+ color: #e6a23c;
+ font-weight: bold;
+ }
+
+ .text-success {
+ color: #67c23a;
+ font-weight: bold;
+ }
+
+ .dialog-footer {
+ text-align: right;
+ }
+
+ // 鍊掕鏃舵牱寮�
+ .countdown-timer {
+ font-weight: bold;
+ }
+
+ .countdown-normal {
+ color: #67c23a;
+ }
+
+ .countdown-warning {
+ color: #e6a23c;
+ }
+
+ .countdown-urgent {
+ color: #f56c6c;
+ animation: blink 1s infinite;
+ }
+
+ .countdown-expired {
+ color: #f56c6c;
+ font-weight: bold;
+ }
+
+ @keyframes blink {
+ 0%, 50% { opacity: 1; }
+ 51%, 100% { opacity: 0.5; }
+ }
+
+ // 缂烘皵棰勮寮规鏍峰紡
+ .shortage-warning-content {
+ text-align: center;
+ padding: 20px 0;
+
+ .warning-icon {
+ margin-bottom: 20px;
+ }
+
+ .warning-message {
+ h3 {
+ color: #f56c6c;
+ margin-bottom: 10px;
+ }
+
+ p {
+ margin-bottom: 10px;
+ color: #606266;
+ }
+
+ .warning-details {
+ background: #f5f7fa;
+ padding: 15px;
+ border-radius: 4px;
+ text-align: left;
+ font-size: 14px;
+ line-height: 1.6;
+ }
+ }
+ }
+}
+</style>
--
Gitblit v1.9.3