¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-card class="box-card"> |
| | | <div slot="header" class="clearfix"> |
| | | <span>çµè¡¨éé管ç</span> |
| | | <el-button style="float: right; padding: 3px 0" link @click="refreshData"> |
| | | <i class="el-icon-refresh"></i> å·æ° |
| | | </el-button> |
| | | </div> |
| | | |
| | | <!-- æµè¯æé® --> |
| | | <el-row :gutter="20" style="margin-bottom: 15px;"> |
| | | <el-col :span="24"> |
| | | <el-button @click="addTestData" type="primary" size="small">æ·»å æµè¯æ°æ®</el-button> |
| | | <el-button @click="clearData" type="danger" size="small">æ¸
ç©ºæ°æ®</el-button> |
| | | <el-button @click="testChart" type="success" size="small">æµè¯å¾è¡¨</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- æç´¢åºå --> |
| | | <el-row :gutter="20" class="search-row"> |
| | | <el-col :span="6"> |
| | | <el-input |
| | | v-model="searchForm.meterNo" |
| | | placeholder="请è¾å
¥çµè¡¨ç¼å·" |
| | | clearable |
| | | @keyup.enter.native="handleSearch" |
| | | > |
| | | <i slot="prefix" class="el-input__icon el-icon-search"></i> |
| | | </el-input> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-select v-model="searchForm.location" placeholder="è¯·éæ©ä½ç½®" clearable> |
| | | <el-option label="ç产车é´A" value="车é´A"></el-option> |
| | | <el-option label="ç产车é´B" value="车é´B"></el-option> |
| | | <el-option label="åå
¬åºå" value="åå
¬åº"></el-option> |
| | | <el-option label="é
çµå®¤" value="é
çµå®¤"></el-option> |
| | | </el-select> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-date-picker |
| | | v-model="searchForm.dateRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | format="yyyy-MM-dd" |
| | | value-format="yyyy-MM-dd" |
| | | /> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-button type="primary" @click="handleSearch">æç´¢</el-button> |
| | | <el-button @click="resetSearch">éç½®</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- çµè¡¨å表 --> |
| | | <el-table |
| | | :data="meterList" |
| | | style="width: 100%" |
| | | v-loading="loading" |
| | | border |
| | | stripe |
| | | height="calc(100vh - 22em)" |
| | | > |
| | | <el-table-column prop="meterNo" label="çµè¡¨ç¼å·" width="120" /> |
| | | <el-table-column prop="location" label="å®è£
ä½ç½®" width="120" /> |
| | | <el-table-column prop="meterType" label="çµè¡¨ç±»å" width="120" /> |
| | | <el-table-column prop="voltage" label="çµåç级" width="100" /> |
| | | <el-table-column prop="currentReading" label="å½å读æ°(kWh)" width="140" /> |
| | | <el-table-column prop="lastReading" label="䏿¬¡è¯»æ°(kWh)" width="140" /> |
| | | <el-table-column prop="consumption" label="ç¨çµé(kWh)" width="120" /> |
| | | <el-table-column prop="power" label="åç(kW)" width="100" /> |
| | | <el-table-column prop="powerFactor" label="åçå æ°" width="100" /> |
| | | <el-table-column prop="status" label="ç¶æ" width="80"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'æ£å¸¸' ? 'success' : 'danger'"> |
| | | {{ scope.row.status }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="lastUpdateTime" label="æåæ´æ°æ¶é´" width="160" /> |
| | | <el-table-column label="æä½" width="180" fixed="right" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link @click="viewDetails(scope.row)"> |
| | | æ¥ç详æ
|
| | | </el-button> |
| | | <el-button link @click="manualCollection(scope.row)"> |
| | | æå¨éé |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- å页 --> |
| | | <pagination |
| | | :total="pagination.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="pagination.currentPage" |
| | | :limit="pagination.pageSize" |
| | | @pagination="handleCurrentChange" |
| | | /> |
| | | </el-card> |
| | | |
| | | <!-- 详æ
å¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | title="çµè¡¨è¯¦æ
" |
| | | v-model="detailDialogVisible" |
| | | width="60%" |
| | | @opened="onDialogOpened" |
| | | > |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>çµè¡¨ç¼å·:</label> |
| | | <span>{{ currentMeter.meterNo }}</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>å®è£
ä½ç½®:</label> |
| | | <span>{{ currentMeter.location }}</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>çµè¡¨ç±»å:</label> |
| | | <span>{{ currentMeter.meterType }}</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>çµåç级:</label> |
| | | <span>{{ currentMeter.voltage }}</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>å½å读æ°:</label> |
| | | <span>{{ currentMeter.currentReading }} kWh</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>䏿¬¡è¯»æ°:</label> |
| | | <span>{{ currentMeter.lastReading }} kWh</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>ç¨çµé:</label> |
| | | <span>{{ currentMeter.consumption }} kWh</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>åç:</label> |
| | | <span>{{ currentMeter.power }} kW</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>åçå æ°:</label> |
| | | <span>{{ currentMeter.powerFactor }}</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>ç¶æ:</label> |
| | | <el-tag :type="currentMeter.status === 'æ£å¸¸' ? 'success' : 'danger'"> |
| | | {{ currentMeter.status }} |
| | | </el-tag> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="detail-item"> |
| | | <label>æåæ´æ°æ¶é´:</label> |
| | | <span>{{ currentMeter.lastUpdateTime }}</span> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- ç¨çµè¶å¿å¾ --> |
| | | <div style="margin-top: 20px;"> |
| | | <h4>24å°æ¶ç¨çµè¶å¿</h4> |
| | | <div ref="chartContainer" style="height: 300px;"></div> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import * as echarts from 'echarts' |
| | | |
| | | export default { |
| | | name: 'MeterCollection', |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | searchForm: { |
| | | meterNo: '', |
| | | location: '', |
| | | dateRange: [] |
| | | }, |
| | | meterList: [], |
| | | pagination: { |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0 |
| | | }, |
| | | detailDialogVisible: false, |
| | | currentMeter: {}, |
| | | chart: null |
| | | } |
| | | }, |
| | | created() { |
| | | // ç«å³çæä¸äºæµè¯æ°æ® |
| | | this.meterList = [ |
| | | { |
| | | id: 1, |
| | | meterNo: 'M001', |
| | | location: '车é´A', |
| | | meterType: 'æºè½çµè¡¨', |
| | | voltage: '380V', |
| | | currentReading: 8500, |
| | | lastReading: 8400, |
| | | consumption: 100, |
| | | power: '75.5', |
| | | powerFactor: '0.85', |
| | | status: 'æ£å¸¸', |
| | | lastUpdateTime: '2024-01-15 10:30:00' |
| | | }, |
| | | { |
| | | id: 2, |
| | | meterNo: 'M002', |
| | | location: '车é´B', |
| | | meterType: 'å¤åè½çµè¡¨', |
| | | voltage: '220V', |
| | | currentReading: 6200, |
| | | lastReading: 6100, |
| | | consumption: 100, |
| | | power: '45.2', |
| | | powerFactor: '0.92', |
| | | status: 'æ£å¸¸', |
| | | lastUpdateTime: '2024-01-15 10:25:00' |
| | | } |
| | | ] |
| | | this.pagination.total = this.meterList.length |
| | | }, |
| | | mounted() { |
| | | // å»¶è¿ä¸ç¹æ¶é´åè°ç¨ï¼ç¡®ä¿DOMå·²ç»æ¸²æ |
| | | this.$nextTick(() => { |
| | | this.getMeterList() |
| | | }) |
| | | }, |
| | | watch: { |
| | | meterList: { |
| | | handler(newVal) { |
| | | console.log('meterListæ°æ®åå:', newVal) |
| | | }, |
| | | deep: true, |
| | | immediate: true |
| | | } |
| | | }, |
| | | methods: { |
| | | // è·åçµè¡¨å表 |
| | | getMeterList() { |
| | | this.loading = true |
| | | // 模æAPIè°ç¨ |
| | | setTimeout(() => { |
| | | const mockData = this.generateMockData() |
| | | this.meterList = mockData |
| | | this.pagination.total = this.meterList.length |
| | | this.loading = false |
| | | }, 500) |
| | | }, |
| | | |
| | | // çææ¨¡ææ°æ® |
| | | generateMockData() { |
| | | const locations = ['车é´A', '车é´B', 'åå
¬åº', 'é
çµå®¤'] |
| | | const meterTypes = ['æºè½çµè¡¨', 'å¤åè½çµè¡¨', 'æ®éçµè¡¨'] |
| | | const voltages = ['220V', '380V', '10kV'] |
| | | const statuses = ['æ£å¸¸', 'å¼å¸¸'] |
| | | |
| | | const data = [] |
| | | for (let i = 1; i <= 25; i++) { |
| | | const currentReading = Math.floor(Math.random() * 10000) + 5000 |
| | | const lastReading = currentReading - Math.floor(Math.random() * 100) - 10 |
| | | const consumption = currentReading - lastReading |
| | | const power = Math.random() * 100 + 20 |
| | | const powerFactor = (Math.random() * 0.3 + 0.7).toFixed(2) |
| | | |
| | | data.push({ |
| | | id: i, |
| | | meterNo: `M${String(i).padStart(3, '0')}`, |
| | | location: locations[Math.floor(Math.random() * locations.length)], |
| | | meterType: meterTypes[Math.floor(Math.random() * meterTypes.length)], |
| | | voltage: voltages[Math.floor(Math.random() * voltages.length)], |
| | | currentReading: currentReading, |
| | | lastReading: lastReading, |
| | | consumption: consumption, |
| | | power: power.toFixed(2), |
| | | powerFactor: powerFactor, |
| | | status: statuses[Math.floor(Math.random() * statuses.length)], |
| | | lastUpdateTime: this.formatDate(new Date(Date.now() - Math.random() * 86400000)) |
| | | }) |
| | | } |
| | | return data |
| | | }, |
| | | |
| | | // æ ¼å¼åæ¥æ |
| | | formatDate(date) { |
| | | const year = date.getFullYear() |
| | | const month = String(date.getMonth() + 1).padStart(2, '0') |
| | | const day = String(date.getDate()).padStart(2, '0') |
| | | const hours = String(date.getHours()).padStart(2, '0') |
| | | const minutes = String(date.getMinutes()).padStart(2, '0') |
| | | return `${year}-${month}-${day} ${hours}:${minutes}` |
| | | }, |
| | | |
| | | // æç´¢ |
| | | handleSearch() { |
| | | this.pagination.currentPage = 1 |
| | | this.getMeterList() |
| | | }, |
| | | |
| | | // éç½®æç´¢ |
| | | resetSearch() { |
| | | this.searchForm = { |
| | | meterNo: '', |
| | | location: '', |
| | | dateRange: [] |
| | | } |
| | | this.handleSearch() |
| | | }, |
| | | |
| | | // æ¥ç详æ
|
| | | viewDetails(row) { |
| | | this.currentMeter = row |
| | | this.detailDialogVisible = true |
| | | }, |
| | | |
| | | // å¯¹è¯æ¡æå¼ååå§åå¾è¡¨ |
| | | onDialogOpened() { |
| | | this.$nextTick(() => { |
| | | setTimeout(() => { |
| | | this.initChart() |
| | | }, 100) |
| | | }) |
| | | }, |
| | | |
| | | // æå¨éé |
| | | manualCollection(row) { |
| | | this.$message.success(`æ£å¨ééçµè¡¨ ${row.meterNo} çæ°æ®...`) |
| | | // 模æééè¿ç¨ |
| | | setTimeout(() => { |
| | | row.currentReading = Math.floor(Math.random() * 100) + row.currentReading |
| | | row.lastUpdateTime = this.formatDate(new Date()) |
| | | this.$message.success('æ°æ®éé宿') |
| | | }, 1000) |
| | | }, |
| | | |
| | | // å·æ°æ°æ® |
| | | refreshData() { |
| | | this.getMeterList() |
| | | this.$message.success('æ°æ®å·²å·æ°') |
| | | }, |
| | | |
| | | // æ·»å æµè¯æ°æ® |
| | | addTestData() { |
| | | const testData = { |
| | | id: Date.now(), |
| | | meterNo: `M${String(this.meterList.length + 1).padStart(3, '0')}`, |
| | | location: 'æµè¯ä½ç½®', |
| | | meterType: 'æµè¯çµè¡¨', |
| | | voltage: '220V', |
| | | currentReading: Math.floor(Math.random() * 10000) + 1000, |
| | | lastReading: Math.floor(Math.random() * 5000) + 500, |
| | | consumption: Math.floor(Math.random() * 100) + 10, |
| | | power: (Math.random() * 100 + 10).toFixed(2), |
| | | powerFactor: (Math.random() * 0.3 + 0.7).toFixed(2), |
| | | status: 'æ£å¸¸', |
| | | lastUpdateTime: this.formatDate(new Date()) |
| | | } |
| | | this.meterList.push(testData) |
| | | this.pagination.total = this.meterList.length |
| | | this.$message.success('æµè¯æ°æ®å·²æ·»å ') |
| | | }, |
| | | |
| | | // æ¸
ç©ºæ°æ® |
| | | clearData() { |
| | | this.meterList = [] |
| | | this.pagination.total = 0 |
| | | this.$message.success('æ°æ®å·²æ¸
空') |
| | | }, |
| | | |
| | | // æµè¯å¾è¡¨ |
| | | testChart() { |
| | | this.$message.info('å¾è¡¨æµè¯åè½') |
| | | // å建ä¸ä¸ªæµè¯å¯¹è¯æ¡æ¥æµè¯å¾è¡¨ |
| | | this.currentMeter = { |
| | | meterNo: 'TEST001', |
| | | location: 'æµè¯ä½ç½®', |
| | | meterType: 'æµè¯çµè¡¨', |
| | | voltage: '220V', |
| | | currentReading: 1000, |
| | | lastReading: 900, |
| | | consumption: 100, |
| | | power: '50.0', |
| | | powerFactor: '0.85', |
| | | status: 'æ£å¸¸', |
| | | lastUpdateTime: '2024-01-15 12:00:00' |
| | | } |
| | | this.detailDialogVisible = true |
| | | }, |
| | | |
| | | // å页大尿¹å |
| | | handleSizeChange(val) { |
| | | this.pagination.pageSize = val |
| | | this.getMeterList() |
| | | }, |
| | | |
| | | // å½å页æ¹å |
| | | handleCurrentChange(val) { |
| | | this.pagination.pageSize = val.limit |
| | | this.pagination.currentPage = val.page |
| | | this.getMeterList() |
| | | }, |
| | | |
| | | // åå§åå¾è¡¨ |
| | | initChart() { |
| | | try { |
| | | if (this.chart) { |
| | | this.chart.dispose() |
| | | this.chart = null |
| | | } |
| | | |
| | | // ç¡®ä¿DOMå
ç´ åå¨ |
| | | if (!this.$refs.chartContainer) { |
| | | console.error('å¾è¡¨å®¹å¨ä¸åå¨ï¼çå¾
DOMæ´æ°...') |
| | | // 妿容å¨ä¸åå¨ï¼çå¾
ä¸ä¸åè¯ |
| | | setTimeout(() => { |
| | | this.initChart() |
| | | }, 100) |
| | | return |
| | | } |
| | | |
| | | // æ£æ¥å®¹å¨å°ºå¯¸ |
| | | const container = this.$refs.chartContainer |
| | | if (container.offsetWidth === 0 || container.offsetHeight === 0) { |
| | | setTimeout(() => { |
| | | this.initChart() |
| | | }, 100) |
| | | return |
| | | } |
| | | this.chart = echarts.init(container) |
| | | |
| | | // çæ24å°æ¶æ¨¡ææ°æ® |
| | | const hours = [] |
| | | const consumption = [] |
| | | for (let i = 0; i < 24; i++) { |
| | | hours.push(`${i}:00`) |
| | | consumption.push(Math.floor(Math.random() * 50) + 20) |
| | | } |
| | | |
| | | const option = { |
| | | title: { |
| | | text: '24å°æ¶ç¨çµéè¶å¿', |
| | | left: 'center' |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | formatter: '{b}<br/>ç¨çµé: {c} kWh' |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: hours, |
| | | axisLabel: { |
| | | rotate: 45 |
| | | } |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | name: 'ç¨çµé (kWh)' |
| | | }, |
| | | series: [{ |
| | | data: consumption, |
| | | type: 'line', |
| | | smooth: true, |
| | | areaStyle: { |
| | | opacity: 0.3 |
| | | }, |
| | | itemStyle: { |
| | | color: '#409EFF' |
| | | } |
| | | }] |
| | | } |
| | | |
| | | this.chart.setOption(option) |
| | | } catch (error) { |
| | | console.error('å¾è¡¨åå§å失败:', error) |
| | | this.$message.error('å¾è¡¨åå§å失败: ' + error.message) |
| | | } |
| | | } |
| | | }, |
| | | |
| | | beforeUnmount() { |
| | | if (this.chart) { |
| | | try { |
| | | this.chart.dispose() |
| | | this.chart = null |
| | | } catch (error) { |
| | | console.error('æ¸
çå¾è¡¨å¤±è´¥:', error) |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .search-row { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .pagination { |
| | | margin-top: 20px; |
| | | text-align: right; |
| | | } |
| | | |
| | | .el-table { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .detail-item { |
| | | margin-bottom: 15px; |
| | | padding: 10px; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 4px; |
| | | background-color: #fafafa; |
| | | } |
| | | |
| | | .detail-item label { |
| | | font-weight: bold; |
| | | color: #606266; |
| | | margin-right: 10px; |
| | | min-width: 100px; |
| | | display: inline-block; |
| | | } |
| | | |
| | | .detail-item span { |
| | | color: #303133; |
| | | } |
| | | |
| | | .detail-item .el-tag { |
| | | margin-left: 0; |
| | | } |
| | | </style> |