| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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' |
| | | // 注éæAPI导å
¥ï¼ä½¿ç¨åæ°æ® |
| | | 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, |
| | | total: 0 |
| | | }) |
| | | |
| | | // æç´¢è¡¨å |
| | | 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(`æ£å¨å¤ç卿°ç½ ${currentWarningTank.value.tankName} ç缺æ°é®é¢`) |
| | | shortageWarningVisible.value = false |
| | | // è¿éå¯ä»¥è°ç¨å¤çAPI |
| | | } |
| | | // å¤ç缺æ°é¢è¦ |
| | | const closeShortageWarning = () => { |
| | | // ElMessage.success(`æ£å¨å¤ç卿°ç½ ${currentWarningTank.value.tankName} ç缺æ°é®é¢`) |
| | | shortageWarningVisible.value = false |
| | | // è¿éå¯ä»¥è°ç¨å¤çAPI |
| | | } |
| | | |
| | | // è·ååè¡¨æ°æ® |
| | | const getList = async () => { |
| | | tableLoading.value = true |
| | | getStockWarningPage(page, searchForm) |
| | | .then(res => { |
| | | |
| | | tableData.value = res.data.records |
| | | page.value.total = res.data.total; |
| | | tableLoading.value = false; |
| | | // æ£æ¥ç¼ºæ°é¢è¦ |
| | | checkShortageWarnings() |
| | | }).catch(err => { |
| | | 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(`æ£å¨å¤çé¢è¦ï¼${row.tankName}`) |
| | | // getList() |
| | | } catch (error) { |
| | | ElMessage.error('å¤çé¢è¦å¤±è´¥') |
| | | } |
| | | } |
| | | |
| | | // å é¤ |
| | | const handleDelete = async (row) => { |
| | | try { |
| | | await ElMessageBox.confirm(`ç¡®å®è¦å é¤é¢è¦è§åï¼${row.tankName}åï¼`, 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }) |
| | | let ids = []; |
| | | ids.push(row.id); |
| | | deleteStockWarning(ids).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("å 餿å"); |
| | | ids.value = []; |
| | | getList(); |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | // // 模æ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 () => { |
| | | // if (selectedRows.value.length === 0) { |
| | | // exportStockWarning().then(res => { |
| | | // // // å建ä¸è½½é¾æ¥ |
| | | // // const blob = new Blob([res.data], { 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) |
| | | // }).catch(err => { |
| | | // ElMessage.error(err.msg); |
| | | // }) |
| | | // }else{ |
| | | // let ids = []; |
| | | // selectedRows.value.forEach(item => { |
| | | // ids.push(item.id); |
| | | // }) |
| | | // exportStockWarning(ids).then(res => { |
| | | // // // å建ä¸è½½é¾æ¥ |
| | | // // const blob = new Blob([res.data], { 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) |
| | | // }).catch(err => { |
| | | // ElMessage.error(err.msg); |
| | | // }) |
| | | // } |
| | | |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/gasTankWarning/export", {ids: selectedRows.value.map(item => item.id)}, "卿°ç½é¢è¦.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | } |
| | | |
| | | |
| | | |
| | | // // å¯ç¨ç¶æåå |
| | | const handleEnableChange = async (row) => { |
| | | |
| | | try { |
| | | updateStockWarning(row).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success(`${row.tankName} çå¯ç¨ç¶æå·²æ´æ°`); |
| | | getList(); |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | } 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') { |
| | | addStockWarning(form).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("æ·»å æå"); |
| | | dialogFormVisible.value = false |
| | | getList() |
| | | resetForm() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | |
| | | // ElMessage.success('æ°å¢æå') |
| | | } else { |
| | | updateStockWarning(form).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("æ´æ°æå"); |
| | | dialogFormVisible.value = false |
| | | getList() |
| | | resetForm() |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | // 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> |