| | |
| | | }) |
| | | } |
| | | // å页æ¥è¯¢ |
| | | export function findPayablePage(query) { |
| | | export function findPayablePage(data) { |
| | | return request({ |
| | | url: '/duePayable/list', |
| | | method: 'get', |
| | | params: query |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-card class="box-card"> |
| | | <!-- æç´¢åºå --> |
| | | <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> |
| | | <el-form-item label="ç
¤ç§åç§°" prop="coalName"> |
| | | <el-input |
| | | v-model="queryParams.coalName" |
| | | placeholder="请è¾å
¥ç
¤ç§åç§°" |
| | | clearable |
| | | size="small" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="éä»ç¶æ" prop="lockStatus"> |
| | | <el-select v-model="queryParams.lockStatus" placeholder="è¯·éæ©éä»ç¶æ" clearable size="small"> |
| | | <el-option label="å·²éå®" value="locked" /> |
| | | <el-option label="é¨åéå®" value="partial" /> |
| | | <el-option label="æªéå®" value="unlocked" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ä¾åºå" prop="supplierName"> |
| | | <el-input |
| | | v-model="queryParams.supplierName" |
| | | placeholder="请è¾å
¥ä¾åºååç§°" |
| | | clearable |
| | | size="small" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="é仿¥æ" prop="lockDateRange"> |
| | | <el-date-picker |
| | | v-model="queryParams.lockDateRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | size="small" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" size="small" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" size="small" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- æä½æé®åºå --> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | icon="Plus" |
| | | size="small" |
| | | @click="handleAdd" |
| | | v-hasPermi="['coalLock:add']" |
| | | >æ°å¢éä»</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="success" |
| | | plain |
| | | icon="Edit" |
| | | size="small" |
| | | :disabled="single" |
| | | @click="handleUpdate" |
| | | v-hasPermi="['coalLock:edit']" |
| | | >ä¿®æ¹éä»</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="danger" |
| | | plain |
| | | icon="Delete" |
| | | size="small" |
| | | :disabled="multiple" |
| | | @click="handleDelete" |
| | | v-hasPermi="['coalLock:remove']" |
| | | >å é¤éä»</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="warning" |
| | | plain |
| | | icon="Unlock" |
| | | size="small" |
| | | :disabled="single" |
| | | @click="handleUnlock" |
| | | v-hasPermi="['coalLock:unlock']" |
| | | >è§£é¤éä»</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="info" |
| | | plain |
| | | icon="View" |
| | | size="small" |
| | | :disabled="single" |
| | | @click="handleView" |
| | | v-hasPermi="['coalLock:query']" |
| | | >æ¥ç详æ
</el-button> |
| | | </el-col> |
| | | <!-- <el-col :span="1.5"> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | icon="Download" |
| | | size="small" |
| | | @click="handleExport" |
| | | v-hasPermi="['coalLock:export']" |
| | | >导åº</el-button> |
| | | </el-col> --> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | </el-row> |
| | | |
| | | <!-- æ°æ®è¡¨æ ¼ --> |
| | | <el-table v-loading="loading" :data="lockList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="éä»ç¼å·" align="center" prop="lockCode" width="180" /> |
| | | <el-table-column label="ç
¤ç§åç§°" align="center" prop="coalName" min-width="120" /> |
| | | <el-table-column label="ä¾åºå" align="center" prop="supplierName" min-width="120" /> |
| | | <el-table-column label="æ»åºåé(å¨)" align="center" prop="totalInventory" width="120" /> |
| | | <el-table-column label="é仿°é(å¨)" align="center" prop="lockQuantity" width="120" /> |
| | | <el-table-column label="å¯ç¨æ°é(å¨)" align="center" prop="availableQuantity" width="120" /> |
| | | <el-table-column label="éä»ç¶æ" align="center" prop="lockStatus" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getLockStatusType(scope.row.lockStatus)"> |
| | | {{ getLockStatusText(scope.row.lockStatus) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="éä»åå " align="center" prop="lockReason" min-width="150" show-overflow-tooltip /> |
| | | <el-table-column label="éä»äºº" align="center" prop="lockUser" width="100" /> |
| | | <el-table-column label="é仿¶é´" align="center" prop="lockTime" width="180" /> |
| | | <el-table-column label="é¢è®¡è§£éæ¶é´" align="center" prop="expectedUnlockTime" width="180" /> |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width" width="200"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | size="small" |
| | | type="text" |
| | | icon="Edit" |
| | | @click="handleUpdate(scope.row)" |
| | | v-hasPermi="['coalLock:edit']" |
| | | >ä¿®æ¹</el-button> |
| | | <el-button |
| | | size="small" |
| | | type="text" |
| | | icon="Unlock" |
| | | @click="handleUnlock(scope.row)" |
| | | v-hasPermi="['coalLock:unlock']" |
| | | >è§£é</el-button> |
| | | <el-button |
| | | size="small" |
| | | type="text" |
| | | icon="Delete" |
| | | @click="handleDelete(scope.row)" |
| | | v-hasPermi="['coalLock:remove']" |
| | | >å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å页ç»ä»¶ --> |
| | | <pagination |
| | | v-show="total > 0" |
| | | :total="total" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | </el-card> |
| | | |
| | | <!-- æ·»å æä¿®æ¹éä»å¯¹è¯æ¡ --> |
| | | <el-dialog :title="title" v-model="open" width="800px" append-to-body> |
| | | <el-form ref="lockFormRef" :model="form" :rules="rules" label-width="120px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç
¤ç§åç§°" prop="coalName"> |
| | | <el-select |
| | | v-model="form.coalId" |
| | | placeholder="è¯·éæ©ç
¤ç§" |
| | | filterable |
| | | clearable |
| | | @change="handleCoalChange" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="coal in coalOptions" |
| | | :key="coal.value" |
| | | :label="coal.label" |
| | | :value="coal.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºå" prop="supplierId"> |
| | | <el-select |
| | | v-model="form.supplierId" |
| | | placeholder="è¯·éæ©ä¾åºå" |
| | | filterable |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="supplier in supplierOptions" |
| | | :key="supplier.value" |
| | | :label="supplier.label" |
| | | :value="supplier.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ»åºåé(å¨)" prop="totalInventory"> |
| | | <el-input v-model="form.totalInventory" placeholder="请è¾å
¥æ»åºåé" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="é仿°é(å¨)" prop="lockQuantity"> |
| | | <el-input |
| | | v-model="form.lockQuantity" |
| | | placeholder="请è¾å
¥é仿°é" |
| | | type="number" |
| | | :max="form.totalInventory" |
| | | @input="handleLockQuantityChange" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¯ç¨æ°é(å¨)" prop="availableQuantity"> |
| | | <el-input v-model="form.availableQuantity" placeholder="å¯ç¨æ°é" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éä»ç¶æ" prop="lockStatus"> |
| | | <el-select v-model="form.lockStatus" placeholder="è¯·éæ©éä»ç¶æ" style="width: 100%"> |
| | | <el-option label="å·²éå®" value="locked" /> |
| | | <el-option label="é¨åéå®" value="partial" /> |
| | | <el-option label="æªéå®" value="unlocked" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="é仿¶é´" prop="lockTime"> |
| | | <el-date-picker |
| | | v-model="form.lockTime" |
| | | type="datetime" |
| | | placeholder="éæ©é仿¶é´" |
| | | style="width: 100%" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="é¢è®¡è§£éæ¶é´" prop="expectedUnlockTime"> |
| | | <el-date-picker |
| | | v-model="form.expectedUnlockTime" |
| | | type="datetime" |
| | | placeholder="éæ©é¢è®¡è§£éæ¶é´" |
| | | style="width: 100%" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éä»åå " prop="lockReason"> |
| | | <el-input |
| | | v-model="form.lockReason" |
| | | type="textarea" |
| | | placeholder="请è¾å
¥éä»åå " |
| | | :rows="3" |
| | | maxlength="500" |
| | | show-word-limit |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨" prop="remarks"> |
| | | <el-input |
| | | v-model="form.remarks" |
| | | type="textarea" |
| | | placeholder="请è¾å
¥å¤æ³¨ä¿¡æ¯" |
| | | :rows="2" |
| | | maxlength="200" |
| | | show-word-limit |
| | | /> |
| | | </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="cancel">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- æ¥ç详æ
å¯¹è¯æ¡ --> |
| | | <el-dialog title="éä»è¯¦æ
" v-model="viewOpen" width="800px" append-to-body> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="éä»ç¼å·">{{ form.lockCode }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç
¤ç§åç§°">{{ form.coalName }}</el-descriptions-item> |
| | | <el-descriptions-item label="ä¾åºå">{{ form.supplierName }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ»åºåé">{{ form.totalInventory }}å¨</el-descriptions-item> |
| | | <el-descriptions-item label="é仿°é">{{ form.lockQuantity }}å¨</el-descriptions-item> |
| | | <el-descriptions-item label="å¯ç¨æ°é">{{ form.availableQuantity }}å¨</el-descriptions-item> |
| | | <el-descriptions-item label="éä»ç¶æ"> |
| | | <el-tag :type="getLockStatusType(form.lockStatus)"> |
| | | {{ getLockStatusText(form.lockStatus) }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="éä»äºº">{{ form.lockUser }}</el-descriptions-item> |
| | | <el-descriptions-item label="é仿¶é´">{{ form.lockTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="é¢è®¡è§£éæ¶é´">{{ form.expectedUnlockTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="éä»åå " :span="2">{{ form.lockReason }}</el-descriptions-item> |
| | | <el-descriptions-item label="夿³¨" :span="2">{{ form.remarks }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="viewOpen = false">å
³ é</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed, onMounted } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Search, Plus, Edit, Delete, Unlock, View, Download, Refresh } from '@element-plus/icons-vue' |
| | | |
| | | // ååºå¼æ°æ® |
| | | const loading = ref(false) |
| | | const showSearch = ref(true) |
| | | const open = ref(false) |
| | | const viewOpen = ref(false) |
| | | const single = ref(true) |
| | | const multiple = ref(true) |
| | | const total = ref(0) |
| | | const lockList = ref([]) |
| | | const coalOptions = ref([]) |
| | | const supplierOptions = ref([]) |
| | | |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = reactive({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | coalName: '', |
| | | lockStatus: '', |
| | | supplierName: '', |
| | | lockDateRange: [] |
| | | }) |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = reactive({ |
| | | id: undefined, |
| | | lockCode: '', |
| | | coalId: '', |
| | | coalName: '', |
| | | supplierId: '', |
| | | supplierName: '', |
| | | totalInventory: 0, |
| | | lockQuantity: 0, |
| | | availableQuantity: 0, |
| | | lockStatus: 'locked', |
| | | lockReason: '', |
| | | lockUser: '', |
| | | lockTime: '', |
| | | expectedUnlockTime: '', |
| | | remarks: '' |
| | | }) |
| | | |
| | | // 表åéªè¯è§å |
| | | const rules = reactive({ |
| | | coalId: [ |
| | | { required: true, message: 'è¯·éæ©ç
¤ç§', trigger: 'change' } |
| | | ], |
| | | supplierId: [ |
| | | { required: true, message: 'è¯·éæ©ä¾åºå', trigger: 'change' } |
| | | ], |
| | | lockQuantity: [ |
| | | { required: true, message: '请è¾å
¥é仿°é', trigger: 'blur' }, |
| | | { type: 'number', min: 0, message: 'é仿°éä¸è½å°äº0', trigger: 'blur' } |
| | | ], |
| | | lockStatus: [ |
| | | { required: true, message: 'è¯·éæ©éä»ç¶æ', trigger: 'change' } |
| | | ], |
| | | lockReason: [ |
| | | { required: true, message: '请è¾å
¥éä»åå ', trigger: 'blur' } |
| | | ], |
| | | lockTime: [ |
| | | { required: true, message: 'è¯·éæ©é仿¶é´', trigger: 'change' } |
| | | ] |
| | | }) |
| | | |
| | | // 计ç®å±æ§ |
| | | const title = computed(() => { |
| | | return form.id ? 'ä¿®æ¹éä»' : 'æ°å¢éä»' |
| | | }) |
| | | |
| | | // 表åå¼ç¨ |
| | | const lockFormRef = ref() |
| | | const queryForm = ref() |
| | | |
| | | // åå§åæ°æ® |
| | | onMounted(() => { |
| | | getList() |
| | | initOptions() |
| | | }) |
| | | |
| | | // åå§åéé¡¹æ°æ® |
| | | const initOptions = () => { |
| | | // 模æç
¤ç§æ°æ® |
| | | coalOptions.value = [ |
| | | { value: '1', label: 'æ çç
¤' }, |
| | | { value: '2', label: 'çç
¤' }, |
| | | { value: '3', label: 'è¤ç
¤' }, |
| | | { value: '4', label: 'ç¦ç
¤' }, |
| | | { value: '5', label: 'æ°ç
¤' } |
| | | ] |
| | | |
| | | // 模æä¾åºåæ°æ® |
| | | supplierOptions.value = [ |
| | | { value: '1', label: '山西ç
¤çéå¢' }, |
| | | { value: '2', label: 'å
èå¤ç
¤çå
¬å¸' }, |
| | | { value: '3', label: 'é西ç
¤çå·¥ä¸' }, |
| | | { value: '4', label: 'æ²³åç
¤çéå¢' }, |
| | | { value: '5', label: 'æ²³åç
¤çå
¬å¸' } |
| | | ] |
| | | |
| | | // 模æéä»åè¡¨æ°æ® |
| | | lockList.value = [ |
| | | { |
| | | id: '1', |
| | | lockCode: 'LK20241201001', |
| | | coalId: '1', |
| | | coalName: 'æ çç
¤', |
| | | supplierId: '1', |
| | | supplierName: '山西ç
¤çéå¢', |
| | | totalInventory: 1000, |
| | | lockQuantity: 300, |
| | | availableQuantity: 700, |
| | | lockStatus: 'partial', |
| | | lockReason: 'ç产计åé¢ç', |
| | | lockUser: 'å¼ ä¸', |
| | | lockTime: '2024-12-01 09:00:00', |
| | | expectedUnlockTime: '2024-12-31 18:00:00' |
| | | }, |
| | | { |
| | | id: '2', |
| | | lockCode: 'LK20241201002', |
| | | coalId: '2', |
| | | coalName: 'çç
¤', |
| | | supplierId: '2', |
| | | supplierName: 'å
èå¤ç
¤çå
¬å¸', |
| | | totalInventory: 800, |
| | | lockQuantity: 800, |
| | | availableQuantity: 0, |
| | | lockStatus: 'locked', |
| | | lockReason: 'è´¨éæ£æµä¸', |
| | | lockUser: 'æå', |
| | | lockTime: '2024-12-01 10:00:00', |
| | | expectedUnlockTime: '2024-12-15 18:00:00' |
| | | }, |
| | | { |
| | | id: '3', |
| | | lockCode: 'LK20241201003', |
| | | coalId: '4', |
| | | coalName: 'ç¦ç
¤', |
| | | supplierId: '3', |
| | | supplierName: 'é西ç
¤çå·¥ä¸', |
| | | totalInventory: 1200, |
| | | lockQuantity: 0, |
| | | availableQuantity: 1200, |
| | | lockStatus: 'unlocked', |
| | | lockReason: '', |
| | | lockUser: '', |
| | | lockTime: '', |
| | | expectedUnlockTime: '' |
| | | } |
| | | ] |
| | | total.value = lockList.value.length |
| | | } |
| | | |
| | | // è·åéä»ç¶æç±»å |
| | | const getLockStatusType = (status) => { |
| | | const statusMap = { |
| | | 'locked': 'danger', |
| | | 'partial': 'warning', |
| | | 'unlocked': 'success' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | // è·åéä»ç¶æææ¬ |
| | | const getLockStatusText = (status) => { |
| | | const statusMap = { |
| | | 'locked': 'å·²éå®', |
| | | 'partial': 'é¨åéå®', |
| | | 'unlocked': 'æªéå®' |
| | | } |
| | | return statusMap[status] || 'æªç¥' |
| | | } |
| | | |
| | | // ç
¤ç§éæ©ååå¤ç |
| | | const handleCoalChange = (coalId) => { |
| | | const selectedCoal = coalOptions.value.find(item => item.value === coalId) |
| | | if (selectedCoal) { |
| | | form.coalName = selectedCoal.label |
| | | // 模æè®¾ç½®åºåæ°æ® |
| | | form.totalInventory = Math.floor(Math.random() * 1000) + 500 |
| | | form.availableQuantity = form.totalInventory - form.lockQuantity |
| | | } |
| | | } |
| | | |
| | | // é仿°éååå¤ç |
| | | const handleLockQuantityChange = () => { |
| | | if (form.lockQuantity > form.totalInventory) { |
| | | form.lockQuantity = form.totalInventory |
| | | } |
| | | form.availableQuantity = form.totalInventory - form.lockQuantity |
| | | |
| | | // æ´æ°éä»ç¶æ |
| | | if (form.lockQuantity === 0) { |
| | | form.lockStatus = 'unlocked' |
| | | } else if (form.lockQuantity === form.totalInventory) { |
| | | form.lockStatus = 'locked' |
| | | } else { |
| | | form.lockStatus = 'partial' |
| | | } |
| | | } |
| | | |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | loading.value = true |
| | | // 模æAPIè°ç¨å»¶è¿ |
| | | setTimeout(() => { |
| | | loading.value = false |
| | | }, 500) |
| | | } |
| | | |
| | | // æç´¢ |
| | | const handleQuery = () => { |
| | | queryParams.pageNum = 1 |
| | | getList() |
| | | } |
| | | |
| | | // éç½®æç´¢ |
| | | const resetQuery = () => { |
| | | queryParams.coalName = '' |
| | | queryParams.lockStatus = '' |
| | | queryParams.supplierName = '' |
| | | queryParams.lockDateRange = [] |
| | | handleQuery() |
| | | } |
| | | |
| | | // éæ©ååå¤ç |
| | | const handleSelectionChange = (selection) => { |
| | | single.value = selection.length !== 1 |
| | | multiple.value = !selection.length |
| | | } |
| | | |
| | | // æ°å¢éä» |
| | | const handleAdd = () => { |
| | | reset() |
| | | open.value = true |
| | | } |
| | | |
| | | // ä¿®æ¹éä» |
| | | const handleUpdate = (row) => { |
| | | reset() |
| | | const id = row.id || row |
| | | const lockData = lockList.value.find(item => item.id === id) |
| | | if (lockData) { |
| | | Object.assign(form, lockData) |
| | | } |
| | | open.value = true |
| | | } |
| | | |
| | | // æ¥ç详æ
|
| | | const handleView = (row) => { |
| | | reset() |
| | | const id = row.id || row |
| | | const lockData = lockList.value.find(item => item.id === id) |
| | | if (lockData) { |
| | | Object.assign(form, lockData) |
| | | } |
| | | viewOpen.value = true |
| | | } |
| | | |
| | | // å é¤éä» |
| | | const handleDelete = (row) => { |
| | | const ids = row.id || row |
| | | ElMessageBox.confirm('确认å é¤éä¸çéä»è®°å½åï¼', 'è¦å', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | ElMessage.success('å 餿å') |
| | | getList() |
| | | }) |
| | | } |
| | | |
| | | // è§£é¤éä» |
| | | const handleUnlock = (row) => { |
| | | const id = row.id || row |
| | | ElMessageBox.confirm('确认解é¤è¯¥ç
¤ç§çéä»åï¼', 'è¦å', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | const lockData = lockList.value.find(item => item.id === id) |
| | | if (lockData) { |
| | | lockData.lockQuantity = 0 |
| | | lockData.availableQuantity = lockData.totalInventory |
| | | lockData.lockStatus = 'unlocked' |
| | | lockData.lockReason = '' |
| | | lockData.lockUser = '' |
| | | lockData.lockTime = '' |
| | | lockData.expectedUnlockTime = '' |
| | | } |
| | | ElMessage.success('è§£éæå') |
| | | getList() |
| | | }) |
| | | } |
| | | |
| | | // å¯¼åº |
| | | const handleExport = () => { |
| | | ElMessage.success('导åºåè½å¼åä¸...') |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | lockFormRef.value.validate((valid) => { |
| | | if (valid) { |
| | | if (form.id) { |
| | | // ä¿®æ¹ |
| | | const index = lockList.value.findIndex(item => item.id === form.id) |
| | | if (index !== -1) { |
| | | Object.assign(lockList.value[index], form) |
| | | } |
| | | ElMessage.success('ä¿®æ¹æå') |
| | | } else { |
| | | // æ°å¢ |
| | | const newLock = { |
| | | ...form, |
| | | id: Date.now().toString(), |
| | | lockCode: `LK${new Date().toISOString().slice(0, 10).replace(/-/g, '')}${String(lockList.value.length + 1).padStart(3, '0')}`, |
| | | lockUser: 'å½åç¨æ·' |
| | | } |
| | | lockList.value.unshift(newLock) |
| | | total.value = lockList.value.length |
| | | ElMessage.success('æ°å¢æå') |
| | | } |
| | | open.value = false |
| | | getList() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // åæ¶ |
| | | const cancel = () => { |
| | | open.value = false |
| | | reset() |
| | | } |
| | | |
| | | // é置表å |
| | | const reset = () => { |
| | | Object.assign(form, { |
| | | id: undefined, |
| | | lockCode: '', |
| | | coalId: '', |
| | | coalName: '', |
| | | supplierId: '', |
| | | supplierName: '', |
| | | totalInventory: 0, |
| | | lockQuantity: 0, |
| | | availableQuantity: 0, |
| | | lockStatus: 'locked', |
| | | lockReason: '', |
| | | lockUser: '', |
| | | lockTime: '', |
| | | expectedUnlockTime: '', |
| | | remarks: '' |
| | | }) |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .box-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .mb8 { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | |
| | | .el-descriptions { |
| | | margin: 20px 0; |
| | | } |
| | | </style> |
| | |
| | | total: 0, |
| | | // æ¥è¯¢åæ° |
| | | queryParams: { |
| | | searchAll: "", |
| | | search: "", |
| | | }, |
| | | }); |
| | | const userInfo = ref({}); |
| | |
| | | let resp = await findPayablePage( |
| | | { |
| | | current: state.current, |
| | | pageSize: state.current |
| | | size: state.pageSize |
| | | , ...state.queryParams |
| | | }) |
| | | tableData.value = resp.data.records |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <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 |
| | | }) |
| | | |
| | | // æç´¢è¡¨å |
| | | 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 generateMockData = () => { |
| | | const mockData = [ |
| | | { |
| | | id: 1, |
| | | tankCode: 'TANK001', |
| | | tankName: 'æ¶²åæ°å¨ç½A', |
| | | 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: 'å缩æ°å¨ç½B', |
| | | 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: 'å¤©ç¶æ°å¨ç½C', |
| | | 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: 'æ¶²åæ°å¨ç½E', |
| | | 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: 'å缩æ°å¨ç½F', |
| | | 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: 'å¤©ç¶æ°å¨ç½G', |
| | | 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(`æ£å¨å¤çé¢è¦ï¼${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-top: 20px; |
| | | 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> |
| | |
| | | style="width: 100%; height: calc(100vh - 30em)" |
| | | show-summary |
| | | :summary-method="summarizeChildrenTable" |
| | | :row-class-name="tableRowClassName" |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column |
| | |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // æ·»å 夿è¡ç±»åç彿° |
| | | const tableRowClassName = (row) => { |
| | | if (activeTab.value === 'officialInventory' && row.row.inventoryQuantity < 3) { |
| | | return 'low-inventory-row'; |
| | | } |
| | | return ''; |
| | | }; |
| | | // å
³éå®¡æ ¸å¼¹æ¡ |
| | | const cancelReview = () => { |
| | | proxy.$refs.formRef.resetFields(); |
| | |
| | | :deep(.el-table) { |
| | | margin: 20px 0; |
| | | } |
| | | |
| | | :deep(.low-inventory-row) { |
| | | background-color: #ffcccc; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <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 |
| | | }) |
| | | |
| | | // æç´¢è¡¨å |
| | | 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 generateMockData = () => { |
| | | const mockData = [ |
| | | { |
| | | id: 1, |
| | | tankCode: 'TANK001', |
| | | tankName: 'æ¶²åæ°å¨ç½A', |
| | | 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: 'å缩æ°å¨ç½B', |
| | | 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: 'å¤©ç¶æ°å¨ç½C', |
| | | 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: 'æ¶²åæ°å¨ç½E', |
| | | 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: 'å缩æ°å¨ç½F', |
| | | 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: 'å¤©ç¶æ°å¨ç½G', |
| | | 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(`æ£å¨å¤çé¢è¦ï¼${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-top: 20px; |
| | | 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> |