已添加9个文件
已修改7个文件
已删除137个文件
| | |
| | | # 页颿 é¢
|
| | | VITE_APP_TITLE = è¯å¯¼äºï¼ç®¡çä¿¡æ¯ç³»ç»ï¼
|
| | | VITE_APP_TITLE = 设å¤å¨çº¿çæµè¯æå维修系ç»
|
| | |
|
| | | # å¼åç¯å¢é
ç½®
|
| | | VITE_APP_ENV = 'development'
|
| | |
| | | # 页颿 é¢
|
| | | VITE_APP_TITLE = MISï¼ç®¡çä¿¡æ¯ç³»ç»ï¼
|
| | | VITE_APP_TITLE = 设å¤å¨çº¿çæµè¯æå维修系ç»
|
| | |
|
| | | # ç产ç¯å¢é
ç½®
|
| | | VITE_APP_ENV = 'production'
|
| | |
| | | <meta name="renderer" content="webkit">
|
| | | <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
| | | <link rel="icon" href="/favicon.ico">
|
| | | <title>MISï¼ç®¡çä¿¡æ¯ç³»ç»ï¼</title>
|
| | | <title>设å¤å¨çº¿çæµè¯æå维修系ç»</title>
|
| | | <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
|
| | | <style>
|
| | | html,
|
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | |
| | | // æ¥è¯¢æ¥è¦é
ç½®å表 |
| | | export function listAlarmConfig(query) { |
| | | return request({ |
| | | url: '/alarm/config/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | | |
| | | // è·åæ¥è¦é
置详ç»ä¿¡æ¯ |
| | | export function getAlarmConfig(configId) { |
| | | return request({ |
| | | url: '/alarm/config/' + configId, |
| | | method: 'get' |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢æ¥è¦é
ç½® |
| | | export function addAlarmConfig(data) { |
| | | return request({ |
| | | url: '/alarm/config', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹æ¥è¦é
ç½® |
| | | export function updateAlarmConfig(data) { |
| | | return request({ |
| | | url: '/alarm/config', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | // å 餿¥è¦é
ç½® |
| | | export function delAlarmConfig(configIds) { |
| | | return request({ |
| | | url: '/alarm/config/' + configIds, |
| | | method: 'delete' |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹æ¥è¦é
ç½®ç¶æ |
| | | export function changeStatus(configId, status) { |
| | | const data = { |
| | | configId, |
| | | status |
| | | }; |
| | | return request({ |
| | | url: '/alarm/config/changeStatus', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | // å¯¼åºæ¥è¦é
ç½® |
| | | export function exportAlarmConfig(query) { |
| | | return request({ |
| | | url: '/alarm/config/export', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | |
| | | // æ¥è¯¢æ¥è¦åå²å表 |
| | | export function listAlarmHistory(query) { |
| | | return request({ |
| | | url: '/alarm/history/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | | |
| | | // è·åæ¥è¦åå²è¯¦æ
|
| | | export function getAlarmHistoryDetail(alarmId) { |
| | | return request({ |
| | | url: '/alarm/history/detail/' + alarmId, |
| | | method: 'get' |
| | | }); |
| | | } |
| | | |
| | | // å¯¼åºæ¥è¦åå² |
| | | export function exportAlarmHistory(query) { |
| | | return request({ |
| | | url: '/alarm/history/export', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | |
| | | // æ¥è¯¢æ¥è¦çæ§å表 |
| | | export function listAlarmMonitor(query) { |
| | | return request({ |
| | | url: '/alarm/monitor/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | | |
| | | // 确认æ¥è¦ |
| | | export function confirmAlarm(data) { |
| | | return request({ |
| | | url: '/alarm/monitor/confirm', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | // è§£å³æ¥è¦ |
| | | export function resolveAlarm(data) { |
| | | return request({ |
| | | url: '/alarm/monitor/resolve', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | // è·åæ¥è¦è¯¦æ
|
| | | export function getAlarmDetail(alarmId) { |
| | | return request({ |
| | | url: '/alarm/monitor/detail/' + alarmId, |
| | | method: 'get' |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | |
| | | // è·åæ¥è¦ç»è®¡æ°æ® |
| | | export function getAlarmStatistics(query) { |
| | | return request({ |
| | | url: '/alarm/statistics', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | | |
| | | // è·åæ¥è¦ç±»ååå¸ |
| | | export function getAlarmTypeDistribution(query) { |
| | | return request({ |
| | | url: '/alarm/statistics/typeDistribution', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | | |
| | | // è·åæ¥è¦ç级åå¸ |
| | | export function getAlarmLevelDistribution(query) { |
| | | return request({ |
| | | url: '/alarm/statistics/levelDistribution', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | | |
| | | // è·åæ¥è¦è¶å¿åæ |
| | | export function getAlarmTrend(query) { |
| | | return request({ |
| | | url: '/alarm/statistics/trend', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | | |
| | | // è·åè®¾å¤æ¥è¦æè¡æ¦ |
| | | export function getDeviceAlarmRank(query) { |
| | | return request({ |
| | | url: '/alarm/statistics/deviceRank', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | | |
| | | // è·åæ¥è¦å¤çèæ¶ç»è®¡ |
| | | export function getHandleTimeStatistics(query) { |
| | | return request({ |
| | | url: '/alarm/statistics/handleTime', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | } |
| | |
| | | app.config.globalProperties.addDateRange = addDateRange;
|
| | | app.config.globalProperties.selectDictLabel = selectDictLabel;
|
| | | app.config.globalProperties.selectDictLabels = selectDictLabels;
|
| | | app.config.globalProperties.javaApi = "http://114.132.189.42:7004";
|
| | | app.config.globalProperties.javaApi = "http://10.136.12.71:8020";
|
| | | app.config.globalProperties.HaveJson = (val) => {
|
| | | return JSON.parse(JSON.stringify(val));
|
| | | };
|
| | |
| | | }
|
| | | ]
|
| | | },
|
| | | {
|
| | | path: '/main/MobileChat',
|
| | | component: Layout,
|
| | | redirect: '',
|
| | | hidden: true,
|
| | | permissions: ['MobileChat:edit'],
|
| | | children: [
|
| | | {
|
| | | path: '',
|
| | | component: () => import('@/views/chatHome/chatHomeIndex/MobileChat'),
|
| | | name: 'MobileChat',
|
| | | meta: { title: 'AI对è¯', activeMenu: '/chatHome/chatHomeIndex'}
|
| | | }
|
| | | ]
|
| | | },
|
| | | // {
|
| | | // path: '/main/MobileChat',
|
| | | // component: Layout,
|
| | | // redirect: '',
|
| | | // hidden: true,
|
| | | // permissions: ['MobileChat:edit'],
|
| | | // children: [
|
| | | // {
|
| | | // path: '',
|
| | | // component: () => import('@/views/chatHome/chatHomeIndex/MobileChat'),
|
| | | // name: 'MobileChat',
|
| | | // meta: { title: 'AI对è¯', activeMenu: '/chatHome/chatHomeIndex'}
|
| | | // }
|
| | | // ]
|
| | | // },
|
| | | {
|
| | | path: '/system/role-auth',
|
| | | component: Layout,
|
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="dashboard-container"> |
| | | <!-- ç»è®¡å¡ç --> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="6"> |
| | | <el-card class="statistics-card" shadow="hover"> |
| | | <div class="card-content"> |
| | | <div class="card-title">设å¤å¨çº¿ç</div> |
| | | <div class="card-value">{{ onlineRate }}%</div> |
| | | <div class="card-desc">å½åå¨çº¿è®¾å¤æ°ï¼{{ onlineCount }} / {{ totalDevices }}</div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="statistics-card" shadow="hover"> |
| | | <div class="card-content"> |
| | | <div class="card-title">æ
éé¢è¦æ°</div> |
| | | <div class="card-value">{{ warningCount }}</div> |
| | | <div class="card-desc">é«é£é©ï¼{{ highRiskCount }} | ä¸é£é©ï¼{{ mediumRiskCount }} | ä½é£é©ï¼{{ lowRiskCount }}</div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="statistics-card" shadow="hover"> |
| | | <div class="card-content"> |
| | | <div class="card-title">å¾
å¤çç»´ä¿®å</div> |
| | | <div class="card-value">{{ pendingOrders }}</div> |
| | | <div class="card-desc">å¤çä¸ï¼{{ processingOrders }} | 已宿ï¼{{ completedOrders }}</div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="statistics-card" shadow="hover"> |
| | | <div class="card-content"> |
| | | <div class="card-title">éç¹è®¾å¤è¿è¡ç¶æ</div> |
| | | <div class="card-value">{{ normalDevices }} æ£å¸¸</div> |
| | | <div class="card-desc">å¼å¸¸ï¼{{ abnormalDevices }} | æ
éï¼{{ faultDevices }}</div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- å¾è¡¨åºå --> |
| | | <el-row :gutter="20" style="margin-top: 20px;"> |
| | | <!-- 设å¤å¥åº·åº¦è¶å¿å¾ --> |
| | | <el-col :span="12"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>设å¤å¥åº·åº¦è¶å¿å¾</span> |
| | | </div> |
| | | </template> |
| | | <div ref="healthChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | <!-- è¿7æ¥æ
éç±»åç»è®¡ --> |
| | | <el-col :span="12"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>è¿7æ¥æ
éç±»åç»è®¡</span> |
| | | </div> |
| | | </template> |
| | | <div ref="faultChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- éç¹è®¾å¤è¿è¡ç¶æå¡ç --> |
| | | <el-card shadow="hover" style="margin-top: 20px;"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>éç¹è®¾å¤è¿è¡ç¶æ</span> |
| | | </div> |
| | | </template> |
| | | <el-table :data="keyDevices" stripe style="width: 100%"> |
| | | <el-table-column prop="name" label="设å¤åç§°" width="180"></el-table-column> |
| | | <el-table-column prop="model" label="åå·" width="120"></el-table-column> |
| | | <el-table-column prop="ip" label="IPå°å" width="150"></el-table-column> |
| | | <el-table-column prop="status" label="ç¶æ" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'online' ? 'success' : scope.row.status === 'warning' ? 'warning' : 'danger'"> |
| | | {{ scope.row.status === 'online' ? 'å¨çº¿' : scope.row.status === 'warning' ? 'é¢è¦' : 'æ
é' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="temperature" label="温度(â)" width="100"></el-table-column> |
| | | <el-table-column prop="pressure" label="åå(MPa)" width="100"></el-table-column> |
| | | <el-table-column prop="speed" label="转é(rpm)" width="100"></el-table-column> |
| | | <el-table-column prop="health" label="å¥åº·åº¦" width="120"> |
| | | <template #default="scope"> |
| | | <el-progress :percentage="scope.row.health" :stroke-width="10"></el-progress> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, onUnmounted } from 'vue' |
| | | import * as echarts from 'echarts' |
| | | |
| | | // ç»è®¡æ°æ® |
| | | const onlineRate = ref(85) |
| | | const onlineCount = ref(170) |
| | | const totalDevices = ref(200) |
| | | const warningCount = ref(23) |
| | | const highRiskCount = ref(5) |
| | | const mediumRiskCount = ref(12) |
| | | const lowRiskCount = ref(6) |
| | | const pendingOrders = ref(15) |
| | | const processingOrders = ref(8) |
| | | const completedOrders = ref(45) |
| | | const normalDevices = ref(162) |
| | | const abnormalDevices = ref(18) |
| | | const faultDevices = ref(10) |
| | | |
| | | // éç¹è®¾å¤å表 |
| | | const keyDevices = ref([ |
| | | { name: 'ç©ºåæºA-001', model: 'KA-200', ip: '192.168.1.101', status: 'online', temperature: 42, pressure: 0.8, speed: 1450, health: 92 }, |
| | | { name: 'å·å´å¡B-002', model: 'CT-300', ip: '192.168.1.102', status: 'warning', temperature: 58, pressure: 0.6, speed: 980, health: 75 }, |
| | | { name: 'æ°´æ³µC-003', model: 'WP-150', ip: '192.168.1.103', status: 'online', temperature: 38, pressure: 1.2, speed: 1200, health: 88 }, |
| | | { name: 'åçµæºD-004', model: 'GE-500', ip: '192.168.1.104', status: 'danger', temperature: 75, pressure: 0.5, speed: 1500, health: 60 }, |
| | | { name: 'ååå¨E-005', model: 'TR-1000', ip: '192.168.1.105', status: 'online', temperature: 45, pressure: 0, speed: 0, health: 95 } |
| | | ]) |
| | | |
| | | // å¾è¡¨å¼ç¨ |
| | | const healthChartRef = ref(null) |
| | | const faultChartRef = ref(null) |
| | | let healthChart = null |
| | | let faultChart = null |
| | | |
| | | // å¥åº·åº¦è¶å¿æ°æ® |
| | | const healthTrendData = { |
| | | dates: ['12-10', '12-11', '12-12', '12-13', '12-14', '12-15', '12-16'], |
| | | values: [88, 90, 85, 87, 92, 91, 93] |
| | | } |
| | | |
| | | // æ
éç±»åç»è®¡æ°æ® |
| | | const faultTypeData = { |
| | | types: ['温度å¼å¸¸', 'ååè¶
æ ', '转éå¼å¸¸', 'æ¯å¨è¿å¤§', 'å
¶ä»'], |
| | | values: [15, 8, 12, 6, 3] |
| | | } |
| | | |
| | | // åå§åå¥åº·åº¦è¶å¿å¾ |
| | | const initHealthChart = () => { |
| | | if (healthChartRef.value) { |
| | | healthChart = echarts.init(healthChartRef.value) |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'cross', |
| | | label: { |
| | | backgroundColor: '#6a7985' |
| | | } |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | boundaryGap: false, |
| | | data: healthTrendData.dates |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | min: 70, |
| | | max: 100, |
| | | name: 'å¥åº·åº¦(%)' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'å¥åº·åº¦', |
| | | type: 'line', |
| | | stack: 'æ»é', |
| | | areaStyle: {}, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: healthTrendData.values, |
| | | itemStyle: { |
| | | color: '#67c23a' |
| | | }, |
| | | lineStyle: { |
| | | width: 3 |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | healthChart.setOption(option) |
| | | } |
| | | } |
| | | |
| | | // åå§åæ
éç±»åç»è®¡é¥¼å¾ |
| | | const initFaultChart = () => { |
| | | if (faultChartRef.value) { |
| | | faultChart = echarts.init(faultChartRef.value) |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'item' |
| | | }, |
| | | legend: { |
| | | orient: 'vertical', |
| | | left: 'left' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'æ
éç±»å', |
| | | type: 'pie', |
| | | radius: '50%', |
| | | data: faultTypeData.types.map((type, index) => ({ |
| | | name: type, |
| | | value: faultTypeData.values[index] |
| | | })), |
| | | emphasis: { |
| | | itemStyle: { |
| | | shadowBlur: 10, |
| | | shadowOffsetX: 0, |
| | | shadowColor: 'rgba(0, 0, 0, 0.5)' |
| | | } |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | faultChart.setOption(option) |
| | | } |
| | | } |
| | | |
| | | // çå¬çªå£å¤§å°ååï¼è°æ´å¾è¡¨å¤§å° |
| | | const handleResize = () => { |
| | | healthChart?.resize() |
| | | faultChart?.resize() |
| | | } |
| | | |
| | | onMounted(() => { |
| | | initHealthChart() |
| | | initFaultChart() |
| | | window.addEventListener('resize', handleResize) |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | window.removeEventListener('resize', handleResize) |
| | | healthChart?.dispose() |
| | | faultChart?.dispose() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .dashboard-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .statistics-card { |
| | | height: 180px; |
| | | } |
| | | |
| | | .card-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | height: 100%; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | |
| | | .card-title { |
| | | font-size: 16px; |
| | | color: #606266; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .card-value { |
| | | font-size: 32px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .card-desc { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .chart-container { |
| | | width: 100%; |
| | | height: 350px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="device-management-container"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>设å¤ç®¡ç</span> |
| | | <div class="header-buttons"> |
| | | <el-button type="primary" @click="showAddDeviceDialog"> |
| | | <el-icon-plus /> æ·»å è®¾å¤ |
| | | </el-button> |
| | | <el-button @click="exportDevices"> |
| | | <el-icon-download /> å¯¼åº |
| | | </el-button> |
| | | <el-button @click="showImportDialog"> |
| | | <el-icon-upload /> 导å
¥ |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <!-- ç鿡件 --> |
| | | <el-form :inline="true" :model="filterForm" class="device-filter-form"> |
| | | <el-form-item label="设å¤åç§°"> |
| | | <el-input v-model="filterForm.name" placeholder="请è¾å
¥è®¾å¤åç§°" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="åå·"> |
| | | <el-input v-model="filterForm.model" placeholder="请è¾å
¥åå·" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ"> |
| | | <el-select v-model="filterForm.status" placeholder="è¯·éæ©ç¶æ" clearable> |
| | | <el-option label="å¨çº¿" value="online"></el-option> |
| | | <el-option label="离线" value="offline"></el-option> |
| | | <el-option label="æ
é" value="fault"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleFilter">æ¥è¯¢</el-button> |
| | | <el-button @click="resetFilter">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- 设å¤å表 --> |
| | | <el-table :data="filteredDevices" stripe style="width: 100%" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55"></el-table-column> |
| | | <el-table-column prop="id" label="设å¤ID" width="100"></el-table-column> |
| | | <el-table-column prop="name" label="设å¤åç§°" width="180"></el-table-column> |
| | | <el-table-column prop="model" label="åå·" width="120"></el-table-column> |
| | | <el-table-column prop="ip" label="IPå°å" width="150"></el-table-column> |
| | | <el-table-column prop="status" label="ç¶æ" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'online' ? 'success' : scope.row.status === 'offline' ? 'info' : 'danger'"> |
| | | {{ scope.row.status === 'online' ? 'å¨çº¿' : scope.row.status === 'offline' ? '离线' : 'æ
é' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="location" label="å®è£
ä½ç½®" width="180"></el-table-column> |
| | | <el-table-column prop="installDate" label="å®è£
æ¥æ" width="150"></el-table-column> |
| | | <el-table-column prop="manufacturer" label="å¶é å" width="150"></el-table-column> |
| | | <el-table-column label="æä½" width="220" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="text" size="small" @click="showDeviceDetail(scope.row)"> |
| | | 详æ
|
| | | </el-button> |
| | | <el-button type="text" size="small" @click="showEditDeviceDialog(scope.row)"> |
| | | ç¼è¾ |
| | | </el-button> |
| | | <el-button type="text" size="small" @click="handleDelete(scope.row)"> |
| | | å é¤ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å页 --> |
| | | <div class="pagination-container"> |
| | | <el-pagination |
| | | background |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :total="filteredDevices.length" |
| | | :current-page="currentPage" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :page-size="pageSize" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | ></el-pagination> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- æ·»å 设å¤å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="addDeviceDialogVisible" title="æ·»å 设å¤" width="600px"> |
| | | <el-form :model="deviceForm" :rules="deviceRules" ref="deviceFormRef" label-width="100px"> |
| | | <el-form-item label="设å¤åç§°" prop="name"> |
| | | <el-input v-model="deviceForm.name" placeholder="请è¾å
¥è®¾å¤åç§°"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="åå·" prop="model"> |
| | | <el-input v-model="deviceForm.model" placeholder="请è¾å
¥åå·"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="IPå°å" prop="ip"> |
| | | <el-input v-model="deviceForm.ip" placeholder="请è¾å
¥IPå°å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å®è£
ä½ç½®" prop="location"> |
| | | <el-input v-model="deviceForm.location" placeholder="请è¾å
¥å®è£
ä½ç½®"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å¶é å" prop="manufacturer"> |
| | | <el-input v-model="deviceForm.manufacturer" placeholder="请è¾å
¥å¶é å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å®è£
æ¥æ" prop="installDate"> |
| | | <el-date-picker v-model="deviceForm.installDate" type="date" placeholder="éæ©å®è£
æ¥æ" style="width: 100%"></el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="deviceForm.status" placeholder="è¯·éæ©ç¶æ"> |
| | | <el-option label="å¨çº¿" value="online"></el-option> |
| | | <el-option label="离线" value="offline"></el-option> |
| | | <el-option label="æ
é" value="fault"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="addDeviceDialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleAddDevice">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- ç¼è¾è®¾å¤å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="editDeviceDialogVisible" title="ç¼è¾è®¾å¤" width="600px"> |
| | | <el-form :model="deviceForm" :rules="deviceRules" ref="deviceFormRef" label-width="100px"> |
| | | <el-form-item label="设å¤åç§°" prop="name"> |
| | | <el-input v-model="deviceForm.name" placeholder="请è¾å
¥è®¾å¤åç§°"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="åå·" prop="model"> |
| | | <el-input v-model="deviceForm.model" placeholder="请è¾å
¥åå·"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="IPå°å" prop="ip"> |
| | | <el-input v-model="deviceForm.ip" placeholder="请è¾å
¥IPå°å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å®è£
ä½ç½®" prop="location"> |
| | | <el-input v-model="deviceForm.location" placeholder="请è¾å
¥å®è£
ä½ç½®"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å¶é å" prop="manufacturer"> |
| | | <el-input v-model="deviceForm.manufacturer" placeholder="请è¾å
¥å¶é å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å®è£
æ¥æ" prop="installDate"> |
| | | <el-date-picker v-model="deviceForm.installDate" type="date" placeholder="éæ©å®è£
æ¥æ" style="width: 100%"></el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="deviceForm.status" placeholder="è¯·éæ©ç¶æ"> |
| | | <el-option label="å¨çº¿" value="online"></el-option> |
| | | <el-option label="离线" value="offline"></el-option> |
| | | <el-option label="æ
é" value="fault"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="editDeviceDialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleEditDevice">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 设å¤è¯¦æ
å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="deviceDetailDialogVisible" title="设å¤è¯¦æ
" width="600px"> |
| | | <el-descriptions :column="1" border> |
| | | <el-descriptions-item label="设å¤åç§°">{{ selectedDevice.name }}</el-descriptions-item> |
| | | <el-descriptions-item label="设å¤ID">{{ selectedDevice.id }}</el-descriptions-item> |
| | | <el-descriptions-item label="åå·">{{ selectedDevice.model }}</el-descriptions-item> |
| | | <el-descriptions-item label="IPå°å">{{ selectedDevice.ip }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç¶æ"> |
| | | <el-tag :type="selectedDevice.status === 'online' ? 'success' : selectedDevice.status === 'offline' ? 'info' : 'danger'"> |
| | | {{ selectedDevice.status === 'online' ? 'å¨çº¿' : selectedDevice.status === 'offline' ? '离线' : 'æ
é' }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="å®è£
ä½ç½®">{{ selectedDevice.location }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¶é å">{{ selectedDevice.manufacturer }}</el-descriptions-item> |
| | | <el-descriptions-item label="å®è£
æ¥æ">{{ selectedDevice.installDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="å建æ¶é´">{{ selectedDevice.createTime }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="deviceDetailDialogVisible = false">å
³é</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="importDialogVisible" title="导å
¥è®¾å¤" width="400px"> |
| | | <el-upload |
| | | class="upload-demo" |
| | | action="#" |
| | | :on-change="handleFileChange" |
| | | :auto-upload="false" |
| | | accept=".xlsx,.xls" |
| | | > |
| | | <el-button type="primary">éæ©æä»¶</el-button> |
| | | <template #tip> |
| | | <div class="el-upload__tip"> |
| | | åªè½ä¸ä¼ xlsx/xls æä»¶ï¼ä¸ä¸è¶
è¿ 2MB |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="importDialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleImport">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed } from 'vue' |
| | | |
| | | // 设å¤åè¡¨æ°æ® |
| | | const devices = ref([ |
| | | { |
| | | id: 'D001', |
| | | name: 'ç©ºåæºA-001', |
| | | model: 'KA-200', |
| | | ip: '192.168.1.101', |
| | | status: 'online', |
| | | location: '车é´A-1åº', |
| | | manufacturer: 'åº·æ®æ¯', |
| | | installDate: '2023-05-10', |
| | | createTime: '2023-05-10 10:30:00' |
| | | }, |
| | | { |
| | | id: 'D002', |
| | | name: 'å·å´å¡B-002', |
| | | model: 'CT-300', |
| | | ip: '192.168.1.102', |
| | | status: 'warning', |
| | | location: '车é´B-2åº', |
| | | manufacturer: 'è¯æº', |
| | | installDate: '2023-06-15', |
| | | createTime: '2023-06-15 14:20:00' |
| | | }, |
| | | { |
| | | id: 'D003', |
| | | name: 'æ°´æ³µC-003', |
| | | model: 'WP-150', |
| | | ip: '192.168.1.103', |
| | | status: 'online', |
| | | location: '车é´C-3åº', |
| | | manufacturer: 'æ ¼å
°å¯', |
| | | installDate: '2023-07-20', |
| | | createTime: '2023-07-20 09:15:00' |
| | | }, |
| | | { |
| | | id: 'D004', |
| | | name: 'åçµæºD-004', |
| | | model: 'GE-500', |
| | | ip: '192.168.1.104', |
| | | status: 'fault', |
| | | location: 'æºæ¿', |
| | | manufacturer: 'å¡ç¹å½¼å', |
| | | installDate: '2023-08-25', |
| | | createTime: '2023-08-25 16:45:00' |
| | | }, |
| | | { |
| | | id: 'D005', |
| | | name: 'ååå¨E-005', |
| | | model: 'TR-1000', |
| | | ip: '192.168.1.105', |
| | | status: 'online', |
| | | location: 'é
çµæ¿', |
| | | manufacturer: 'ABB', |
| | | installDate: '2023-09-30', |
| | | createTime: '2023-09-30 11:20:00' |
| | | } |
| | | ]) |
| | | |
| | | // çé表å |
| | | const filterForm = ref({ |
| | | name: '', |
| | | model: '', |
| | | status: '' |
| | | }) |
| | | |
| | | // åé¡µæ°æ® |
| | | const currentPage = ref(1) |
| | | const pageSize = ref(10) |
| | | |
| | | // å¯¹è¯æ¡ç¶æ |
| | | const addDeviceDialogVisible = ref(false) |
| | | const editDeviceDialogVisible = ref(false) |
| | | const deviceDetailDialogVisible = ref(false) |
| | | const importDialogVisible = ref(false) |
| | | |
| | | // 设å¤è¡¨åæ°æ® |
| | | const deviceForm = ref({ |
| | | id: '', |
| | | name: '', |
| | | model: '', |
| | | ip: '', |
| | | status: 'online', |
| | | location: '', |
| | | manufacturer: '', |
| | | installDate: '' |
| | | }) |
| | | |
| | | // 表åéªè¯è§å |
| | | const deviceRules = ref({ |
| | | name: [{ required: true, message: '请è¾å
¥è®¾å¤åç§°', trigger: 'blur' }], |
| | | model: [{ required: true, message: '请è¾å
¥åå·', trigger: 'blur' }], |
| | | ip: [{ required: true, message: '请è¾å
¥IPå°å', trigger: 'blur' }], |
| | | location: [{ required: true, message: '请è¾å
¥å®è£
ä½ç½®', trigger: 'blur' }], |
| | | manufacturer: [{ required: true, message: '请è¾å
¥å¶é å', trigger: 'blur' }], |
| | | installDate: [{ required: true, message: 'è¯·éæ©å®è£
æ¥æ', trigger: 'change' }], |
| | | status: [{ required: true, message: 'è¯·éæ©ç¶æ', trigger: 'change' }] |
| | | }) |
| | | |
| | | // 表åå¼ç¨ |
| | | const deviceFormRef = ref(null) |
| | | |
| | | // éä¸çè®¾å¤ |
| | | const selectedDevice = ref({}) |
| | | |
| | | // éä¸ç设å¤å表ï¼ç¨äºæ¹éæä½ï¼ |
| | | const selectedDevices = ref([]) |
| | | |
| | | // 导å
¥çæä»¶ |
| | | const importFile = ref(null) |
| | | |
| | | // è¿æ»¤åç设å¤å表 |
| | | const filteredDevices = computed(() => { |
| | | let result = [...devices.value] |
| | | |
| | | // æåç§°çé |
| | | if (filterForm.value.name) { |
| | | result = result.filter(device => device.name.includes(filterForm.value.name)) |
| | | } |
| | | |
| | | // æåå·çé |
| | | if (filterForm.value.model) { |
| | | result = result.filter(device => device.model.includes(filterForm.value.model)) |
| | | } |
| | | |
| | | // æç¶æçé |
| | | if (filterForm.value.status) { |
| | | result = result.filter(device => device.status === filterForm.value.status) |
| | | } |
| | | |
| | | return result |
| | | }) |
| | | |
| | | // æ¾ç¤ºæ·»å 设å¤å¯¹è¯æ¡ |
| | | const showAddDeviceDialog = () => { |
| | | // é置表å |
| | | deviceForm.value = { |
| | | id: '', |
| | | name: '', |
| | | model: '', |
| | | ip: '', |
| | | status: 'online', |
| | | location: '', |
| | | manufacturer: '', |
| | | installDate: '' |
| | | } |
| | | addDeviceDialogVisible.value = true |
| | | } |
| | | |
| | | // æ¾ç¤ºç¼è¾è®¾å¤å¯¹è¯æ¡ |
| | | const showEditDeviceDialog = (device) => { |
| | | deviceForm.value = { ...device } |
| | | editDeviceDialogVisible.value = true |
| | | } |
| | | |
| | | // æ¾ç¤ºè®¾å¤è¯¦æ
|
| | | const showDeviceDetail = (device) => { |
| | | selectedDevice.value = { ...device } |
| | | deviceDetailDialogVisible.value = true |
| | | } |
| | | |
| | | // æ¾ç¤ºå¯¼å
¥å¯¹è¯æ¡ |
| | | const showImportDialog = () => { |
| | | importDialogVisible.value = true |
| | | } |
| | | |
| | | // å¤çæ·»å è®¾å¤ |
| | | const handleAddDevice = () => { |
| | | // æ¨¡ææ·»å è®¾å¤ |
| | | const newDevice = { |
| | | ...deviceForm.value, |
| | | id: `D${String(devices.value.length + 1).padStart(3, '0')}`, |
| | | createTime: new Date().toLocaleString() |
| | | } |
| | | devices.value.push(newDevice) |
| | | addDeviceDialogVisible.value = false |
| | | ElMessage.success('è®¾å¤æ·»å æå') |
| | | } |
| | | |
| | | // å¤çç¼è¾è®¾å¤ |
| | | const handleEditDevice = () => { |
| | | // 模æç¼è¾è®¾å¤ |
| | | const index = devices.value.findIndex(device => device.id === deviceForm.value.id) |
| | | if (index !== -1) { |
| | | devices.value[index] = { ...deviceForm.value } |
| | | editDeviceDialogVisible.value = false |
| | | ElMessage.success('设å¤ç¼è¾æå') |
| | | } |
| | | } |
| | | |
| | | // å¤çå é¤è®¾å¤ |
| | | const handleDelete = (device) => { |
| | | ElMessageBox.confirm('ç¡®å®è¦å é¤è¯¥è®¾å¤åï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | // 模æå é¤è®¾å¤ |
| | | const index = devices.value.findIndex(item => item.id === device.id) |
| | | if (index !== -1) { |
| | | devices.value.splice(index, 1) |
| | | ElMessage.success('设å¤å 餿å') |
| | | } |
| | | }).catch(() => { |
| | | // åæ¶å é¤ |
| | | }) |
| | | } |
| | | |
| | | // å¤ççé |
| | | const handleFilter = () => { |
| | | // çéé»è¾å·²ç»å¨computedä¸å®ç° |
| | | } |
| | | |
| | | // éç½®ç鿡件 |
| | | const resetFilter = () => { |
| | | filterForm.value = { |
| | | name: '', |
| | | model: '', |
| | | status: '' |
| | | } |
| | | } |
| | | |
| | | // å¤çå页大å°åå |
| | | const handleSizeChange = (size) => { |
| | | pageSize.value = size |
| | | currentPage.value = 1 |
| | | } |
| | | |
| | | // å¤çå½å页åå |
| | | const handleCurrentChange = (current) => { |
| | | currentPage.value = current |
| | | } |
| | | |
| | | // å¤çæä»¶ååï¼å¯¼å
¥ï¼ |
| | | const handleFileChange = (file) => { |
| | | importFile.value = file |
| | | } |
| | | |
| | | // å¤ç导å
¥ |
| | | const handleImport = () => { |
| | | // 模æå¯¼å
¥ |
| | | if (importFile.value) { |
| | | importDialogVisible.value = false |
| | | ElMessage.success('设å¤å¯¼å
¥æå') |
| | | importFile.value = null |
| | | } else { |
| | | ElMessage.warning('è¯·éæ©è¦å¯¼å
¥çæä»¶') |
| | | } |
| | | } |
| | | |
| | | // 导åºè®¾å¤ |
| | | const exportDevices = () => { |
| | | // 模æå¯¼åº |
| | | ElMessage.success('设å¤å¯¼åºæå') |
| | | } |
| | | |
| | | // å¤çéæ©ååï¼ç¨äºæ¹éæä½ï¼ |
| | | const handleSelectionChange = (selection) => { |
| | | selectedDevices.value = selection |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .device-management-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .header-buttons { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .device-filter-form { |
| | | margin-bottom: 20px; |
| | | padding: 10px 0; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | :deep(.el-icon-plus), |
| | | :deep(.el-icon-download), |
| | | :deep(.el-icon-upload) { |
| | | margin-right: 5px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="fault-diagnosis-container"> |
| | | <el-row :gutter="20"> |
| | | <!-- å·¦ä¾§ï¼æ
éé¢è¦å表 --> |
| | | <el-col :span="12"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>æ
éé¢è¦å表</span> |
| | | </div> |
| | | </template> |
| | | <el-table :data="warningList" stripe style="width: 100%" @row-click="handleWarningClick"> |
| | | <el-table-column prop="deviceName" label="设å¤åç§°" width="180"></el-table-column> |
| | | <el-table-column prop="warningType" label="é¢è¦ç±»å" width="120"></el-table-column> |
| | | <el-table-column prop="riskLevel" label="é£é©ç级" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.riskLevel === 'high' ? 'danger' : scope.row.riskLevel === 'medium' ? 'warning' : 'info'"> |
| | | {{ scope.row.riskLevel === 'high' ? 'é«' : scope.row.riskLevel === 'medium' ? 'ä¸' : 'ä½' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="occurTime" label="åçæ¶é´" width="180"></el-table-column> |
| | | <el-table-column prop="status" label="å¤çç¶æ" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'pending' ? 'warning' : 'success'"> |
| | | {{ scope.row.status === 'pending' ? 'å¾
å¤ç' : 'å·²å¤ç' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-card> |
| | | |
| | | <!-- æ
éåå²è®°å½æ¥è¯¢ --> |
| | | <el-card shadow="hover" style="margin-top: 20px;"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>æ
éåå²è®°å½</span> |
| | | </div> |
| | | </template> |
| | | <el-form :inline="true" :model="historyFilterForm" class="history-filter-form"> |
| | | <el-form-item label="设å¤"> |
| | | <el-select v-model="historyFilterForm.deviceId" placeholder="è¯·éæ©è®¾å¤" clearable> |
| | | <el-option |
| | | v-for="device in devices" |
| | | :key="device.id" |
| | | :label="device.name" |
| | | :value="device.id" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ¶é´èå´"> |
| | | <el-date-picker |
| | | v-model="historyTimeRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | ></el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleHistorySearch">æ¥è¯¢</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <el-table :data="historyList" stripe style="width: 100%" size="small"> |
| | | <el-table-column prop="deviceName" label="设å¤åç§°" width="150"></el-table-column> |
| | | <el-table-column prop="faultType" label="æ
éç±»å" width="120"></el-table-column> |
| | | <el-table-column prop="occurTime" label="åçæ¶é´" width="150"></el-table-column> |
| | | <el-table-column prop="dealTime" label="å¤çæ¶é´" width="150"></el-table-column> |
| | | <el-table-column prop="status" label="ç¶æ" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.status }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pagination-container"> |
| | | <el-pagination |
| | | background |
| | | layout="total, prev, pager, next" |
| | | :total="historyList.length" |
| | | :page-size="5" |
| | | size="small" |
| | | ></el-pagination> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | |
| | | <!-- å³ä¾§ï¼æ
éè¯æç»æ --> |
| | | <el-col :span="12"> |
| | | <!-- æ
éè¯æç»æ --> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>æ
éè¯æç»æ</span> |
| | | <el-button type="primary" size="small" @click="handleDiagnosis">éæ°è¯æ</el-button> |
| | | </div> |
| | | </template> |
| | | <div v-if="currentWarning" class="diagnosis-result"> |
| | | <h3>{{ currentWarning.deviceName }} - {{ currentWarning.warningType }}</h3> |
| | | <el-descriptions :column="1" border> |
| | | <el-descriptions-item label="é£é©ç级"> |
| | | <el-tag :type="currentWarning.riskLevel === 'high' ? 'danger' : currentWarning.riskLevel === 'medium' ? 'warning' : 'info'"> |
| | | {{ currentWarning.riskLevel === 'high' ? 'é«' : currentWarning.riskLevel === 'medium' ? 'ä¸' : 'ä½' }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="åçæ¶é´">{{ currentWarning.occurTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="åå æ¨æµ">{{ diagnosisResult.reason }}</el-descriptions-item> |
| | | <el-descriptions-item label="å½±åèå´">{{ diagnosisResult.impact }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¤ç建议">{{ diagnosisResult.suggestion }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <div v-else class="no-selection"> |
| | | <el-empty description="è¯·éæ©ä¸ä¸ªé¢è¦é¡¹æ¥çè¯æç»æ"></el-empty> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 颿µæ§è¯æç»æ --> |
| | | <el-card shadow="hover" style="margin-top: 20px;"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>颿µæ§è¯æç»æï¼æªæ¥7æ¥æ
éé£é©ï¼</span> |
| | | </div> |
| | | </template> |
| | | <div class="prediction-result"> |
| | | <el-timeline> |
| | | <el-timeline-item |
| | | v-for="item in predictionList" |
| | | :key="item.date" |
| | | :timestamp="item.date" |
| | | :type="item.riskLevel === 'high' ? 'danger' : item.riskLevel === 'medium' ? 'warning' : 'success'" |
| | | > |
| | | <div class="timeline-content"> |
| | | <h4>{{ item.deviceName }}</h4> |
| | | <p class="risk-level"> |
| | | é£é©ççº§ï¼ |
| | | <el-tag :type="item.riskLevel === 'high' ? 'danger' : item.riskLevel === 'medium' ? 'warning' : 'success'"> |
| | | {{ item.riskLevel === 'high' ? 'é«' : item.riskLevel === 'medium' ? 'ä¸' : 'ä½' }} |
| | | </el-tag> |
| | | </p> |
| | | <p class="fault-type">å¯è½æ
éç±»åï¼{{ item.possibleFault }}</p> |
| | | <p class="probability">åçæ¦çï¼{{ item.probability }}%</p> |
| | | </div> |
| | | </el-timeline-item> |
| | | </el-timeline> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive } from 'vue' |
| | | |
| | | // 设å¤å表 |
| | | const devices = ref([ |
| | | { id: 'D001', name: 'ç©ºåæºA-001' }, |
| | | { id: 'D002', name: 'å·å´å¡B-002' }, |
| | | { id: 'D003', name: 'æ°´æ³µC-003' }, |
| | | { id: 'D004', name: 'åçµæºD-004' }, |
| | | { id: 'D005', name: 'ååå¨E-005' } |
| | | ]) |
| | | |
| | | // æ
éé¢è¦å表 |
| | | const warningList = ref([ |
| | | { |
| | | id: 1, |
| | | deviceName: 'ç©ºåæºA-001', |
| | | warningType: 'ååå¼å¸¸', |
| | | riskLevel: 'high', |
| | | occurTime: '2024-12-16 14:32:15', |
| | | status: 'pending' |
| | | }, |
| | | { |
| | | id: 2, |
| | | deviceName: 'å·å´å¡B-002', |
| | | warningType: '温度è¿é«', |
| | | riskLevel: 'medium', |
| | | occurTime: '2024-12-16 14:30:45', |
| | | status: 'pending' |
| | | }, |
| | | { |
| | | id: 3, |
| | | deviceName: 'æ°´æ³µC-003', |
| | | warningType: 'æ¯å¨è¿å¤§', |
| | | riskLevel: 'medium', |
| | | occurTime: '2024-12-16 14:28:30', |
| | | status: 'pending' |
| | | }, |
| | | { |
| | | id: 4, |
| | | deviceName: 'åçµæºD-004', |
| | | warningType: 'çµæµå¼å¸¸', |
| | | riskLevel: 'high', |
| | | occurTime: '2024-12-16 14:25:10', |
| | | status: 'pending' |
| | | }, |
| | | { |
| | | id: 5, |
| | | deviceName: 'ååå¨E-005', |
| | | warningType: 'çµåæ³¢å¨', |
| | | riskLevel: 'low', |
| | | occurTime: '2024-12-16 14:20:05', |
| | | status: 'pending' |
| | | } |
| | | ]) |
| | | |
| | | // å½åéä¸çé¢è¦é¡¹ |
| | | const currentWarning = ref(warningList.value[0]) |
| | | |
| | | // æ
éè¯æç»æ |
| | | const diagnosisResult = reactive({ |
| | | reason: 'æ ¹æ®è®¾å¤è¿è¡æ°æ®æ¨æµï¼æ
éåå å¯è½æ¯è®¾å¤å
é¨é¨ä»¶ç£¨æå¯¼è´çååå¼å¸¸ï¼éè¦è¿ä¸æ¥æ£æ¥è®¾å¤çæ´»å¡ç¯åæ°ç¼¸å¥ã', |
| | | impact: '妿ä¸åæ¶å¤çï¼å¯è½å¯¼è´è®¾å¤åæºï¼å½±åçäº§çº¿çæ£å¸¸è¿è¡ï¼é¢è®¡åæºæ¶é´ä¸º4-6å°æ¶ã', |
| | | suggestion: '1. ç«å³å®æç»´ä¿®äººåè¿è¡è®¾å¤æ£æ¥ï¼2. æ£æ¥è®¾å¤çæ´»å¡ç¯åæ°ç¼¸å¥ï¼3. æ´æ¢ç£¨æä¸¥éçé¨ä»¶ï¼4. æ£æ¥è®¾å¤ç润æ»ç³»ç»ï¼ç¡®ä¿æ¶¦æ»æ£å¸¸ã' |
| | | }) |
| | | |
| | | // 颿µæ§è¯æç»æ |
| | | const predictionList = ref([ |
| | | { |
| | | date: '2024-12-17', |
| | | deviceName: 'ç©ºåæºA-001', |
| | | riskLevel: 'medium', |
| | | possibleFault: 'ååå¼å¸¸', |
| | | probability: 65 |
| | | }, |
| | | { |
| | | date: '2024-12-18', |
| | | deviceName: 'å·å´å¡B-002', |
| | | riskLevel: 'high', |
| | | possibleFault: '温度è¿é«', |
| | | probability: 85 |
| | | }, |
| | | { |
| | | date: '2024-12-19', |
| | | deviceName: 'æ°´æ³µC-003', |
| | | riskLevel: 'medium', |
| | | possibleFault: 'æ¯å¨è¿å¤§', |
| | | probability: 70 |
| | | }, |
| | | { |
| | | date: '2024-12-20', |
| | | deviceName: 'åçµæºD-004', |
| | | riskLevel: 'high', |
| | | possibleFault: 'çµæµå¼å¸¸', |
| | | probability: 90 |
| | | }, |
| | | { |
| | | date: '2024-12-21', |
| | | deviceName: 'ååå¨E-005', |
| | | riskLevel: 'low', |
| | | possibleFault: 'çµåæ³¢å¨', |
| | | probability: 45 |
| | | }, |
| | | { |
| | | date: '2024-12-22', |
| | | deviceName: 'ç©ºåæºA-001', |
| | | riskLevel: 'high', |
| | | possibleFault: 'ååå¼å¸¸', |
| | | probability: 80 |
| | | }, |
| | | { |
| | | date: '2024-12-23', |
| | | deviceName: 'å·å´å¡B-002', |
| | | riskLevel: 'medium', |
| | | possibleFault: '温度è¿é«', |
| | | probability: 60 |
| | | } |
| | | ]) |
| | | |
| | | // æ
éåå²è®°å½æ¥è¯¢è¡¨å |
| | | const historyFilterForm = ref({ |
| | | deviceId: '' |
| | | }) |
| | | |
| | | // åå²è®°å½æ¶é´èå´ |
| | | const historyTimeRange = ref([]) |
| | | |
| | | // æ
éåå²è®°å½ |
| | | const historyList = ref([ |
| | | { |
| | | id: 1, |
| | | deviceName: 'ç©ºåæºA-001', |
| | | faultType: 'ååå¼å¸¸', |
| | | occurTime: '2024-12-15 08:30:00', |
| | | dealTime: '2024-12-15 10:45:00', |
| | | status: 'å·²å¤ç' |
| | | }, |
| | | { |
| | | id: 2, |
| | | deviceName: 'å·å´å¡B-002', |
| | | faultType: '温度è¿é«', |
| | | occurTime: '2024-12-14 14:20:00', |
| | | dealTime: '2024-12-14 16:15:00', |
| | | status: 'å·²å¤ç' |
| | | }, |
| | | { |
| | | id: 3, |
| | | deviceName: 'æ°´æ³µC-003', |
| | | faultType: 'æ¯å¨è¿å¤§', |
| | | occurTime: '2024-12-13 09:15:00', |
| | | dealTime: '2024-12-13 11:30:00', |
| | | status: 'å·²å¤ç' |
| | | }, |
| | | { |
| | | id: 4, |
| | | deviceName: 'åçµæºD-004', |
| | | faultType: 'çµæµå¼å¸¸', |
| | | occurTime: '2024-12-12 16:45:00', |
| | | dealTime: '2024-12-12 18:30:00', |
| | | status: 'å·²å¤ç' |
| | | }, |
| | | { |
| | | id: 5, |
| | | deviceName: 'ååå¨E-005', |
| | | faultType: 'çµåæ³¢å¨', |
| | | occurTime: '2024-12-11 11:20:00', |
| | | dealTime: '2024-12-11 13:15:00', |
| | | status: 'å·²å¤ç' |
| | | } |
| | | ]) |
| | | |
| | | // å¤çé¢è¦é¡¹ç¹å» |
| | | const handleWarningClick = (row) => { |
| | | currentWarning.value = row |
| | | } |
| | | |
| | | // éæ°è¯æ |
| | | const handleDiagnosis = () => { |
| | | // 模æéæ°è¯æ |
| | | ElMessage.success('éæ°è¯æå®æ') |
| | | } |
| | | |
| | | // å¤çåå²è®°å½æ¥è¯¢ |
| | | const handleHistorySearch = () => { |
| | | // æ¨¡ææ¥è¯¢åå²è®°å½ |
| | | ElMessage.success('åå²è®°å½æ¥è¯¢æå') |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .fault-diagnosis-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .diagnosis-result h3 { |
| | | margin-bottom: 20px; |
| | | color: #303133; |
| | | } |
| | | |
| | | .no-selection { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | height: 200px; |
| | | } |
| | | |
| | | .prediction-result { |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .timeline-content { |
| | | padding: 10px; |
| | | background-color: #fafafa; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .timeline-content h4 { |
| | | margin-bottom: 10px; |
| | | color: #303133; |
| | | } |
| | | |
| | | .timeline-content p { |
| | | margin: 5px 0; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | |
| | | .risk-level { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 5px; |
| | | } |
| | | |
| | | .fault-type { |
| | | color: #606266; |
| | | } |
| | | |
| | | .probability { |
| | | color: #606266; |
| | | } |
| | | |
| | | .history-filter-form { |
| | | margin-bottom: 20px; |
| | | padding: 10px 0; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 20px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="dashboard"> |
| | | <!-- 顶鍿¨ªå两æ --> |
| | | <div class="dashboard-top"> |
| | | <!-- å·¦ï¼ä¼ä¸ä¿¡æ¯+ä¸å¤§æ°æ®å¡çï¼ä¸ä¸æåï¼ --> |
| | | <div class="top-left"> |
| | | <div class="company-info"> |
| | | <div class="section-title">ç»éä¿¡æ¯</div> |
| | | <div style="display: flex;align-items: center;gap: 20px"> |
| | | <img :src="userStore.avatar" class="avatar" alt=""/> |
| | | <div class="company-card"> |
| | | <div class="company-name">{{userStore.name}}</div> |
| | | <div class="company-meta">{{userStore.roleName}}</div> |
| | | </div> |
| | | <div style="display: flex;align-items: center;gap: 8px"> |
| | | <el-icon color="#5053B5" size="22"><Clock /></el-icon> |
| | | <span>ç»éæ¥æï¼{{userStore.currentLoginTime}}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="data-cards"> |
| | | <div class="data-card sales"> |
| | | <div class="data-title">é宿°æ®</div> |
| | | <div class="data-num"> |
| | | <div> |
| | | <div class="data-desc">æ¬æéå®é¢/å
</div> |
| | | <div class="data-value">{{businessInfo.monthSaleMoney}}</div> |
| | | </div> |
| | | <div> |
| | | <div class="data-desc">æªå¼ç¥¨éé¢/å
</div> |
| | | <div class="data-value">{{businessInfo.monthSaleHaveMoney}}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | <div class="data-card purchase"> |
| | | <div class="data-title">éè´æ°æ®</div> |
| | | <div class="data-num"> |
| | | <div> |
| | | <div class="data-desc">æ¬æéè´é¢/å
</div> |
| | | <div class="data-value">{{businessInfo.monthPurchaseMoney}}</div> |
| | | </div> |
| | | <div> |
| | | <div class="data-desc">å¾
仿¬¾éé¢/å
</div> |
| | | <div class="data-value">{{businessInfo.monthPurchaseHaveMoney}}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="data-card inventory"> |
| | | <div class="data-title">åºåæ°æ®</div> |
| | | <div class="data-num"> |
| | | <div> |
| | | <div class="data-desc">å½ååºåæ»é/ä»¶</div> |
| | | <div class="data-value">{{businessInfo.inventoryNum}}</div> |
| | | </div> |
| | | <div> |
| | | <div class="data-desc">仿¥å
¥åº/ä»¶</div> |
| | | <div class="data-value">{{businessInfo.todayInventoryNum}}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- å³ï¼å¾
åäºé¡¹ --> |
| | | <div class="todo-panel"> |
| | | <div class="section-title">å¾
åäºé¡¹</div> |
| | | <ul class="todo-list" v-if="todoList.length > 0"> |
| | | <li v-for="item in todoList" :key="item.id"> |
| | | <div style="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px"> |
| | | <div style="display: flex;justify-content: space-between;align-items: center;"> |
| | | <div class="todo-title">æµç¨ç¼å·ï¼{{item.approveId}}</div> |
| | | <div class="todo-division">ç³è¯·é¨é¨ï¼{{item.approveDeptName}}</div> |
| | | <div class="todo-time">{{item.approveTime}}</div> |
| | | </div> |
| | | <div class="todo-division">审æ¹äºç±ï¼{{item.approveReason}}</div> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | <div v-else style="text-align: center"> |
| | | ææ æ°æ® |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- ä¸é¨æ¨ªå两æ --> |
| | | <div class="dashboard-row"> |
| | | <div class="main-panel"> |
| | | <div class="section-title">客æ·ååéé¢åæ</div> |
| | | <div class="contract-summary"> |
| | | <div class="contract-info"> |
| | | <img src="../assets/images/khtitle.png" alt="" style="width: 42px"/> |
| | | <div class="contract-card"> |
| | | <div class="contract-name">æ»ååéé¢(å
)</div> |
| | | <div class="contract-meta"> |
| | | <div class="main-amount">{{sum}}</div> |
| | | <div>å¨åæ¯: <span class="up">{{yny}}% </span> æ¥ç¯æ¯: <span class="up">{{chain}}% </span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 180px;margin-top: 20px"> |
| | | <div> |
| | | <Echarts ref="chart" :legend="pieLegend" :chartStyle="chartStylePie" |
| | | :series="materialPieSeries" |
| | | :tooltip="pieTooltip"></Echarts> |
| | | </div> |
| | | <ul class="contract-list"> |
| | | <li v-for="item in materialPieSeries[0].data" :key="item.name"> |
| | | <div style="display: flex;align-items: center;justify-content: space-between;width: 100%"> |
| | | <div class="line" :style="{color: item.itemStyle.color}">â{{item.name}}</div> |
| | | <div style="width: 70px">{{item.rate}}%</div> |
| | | <div>ï¿¥{{item.value}}</div> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | </div> |
| | | <div class="main-panel"> |
| | | <div style="display: flex;justify-content: space-between;"> |
| | | <div class="section-title">åºæ¶åºä»ç»è®¡</div> |
| | | <!-- <el-radio-group v-model="radio1" size="large" @change="statisticsReceivable">--> |
| | | <!-- <el-radio-button label="æå¨" :value="1" />--> |
| | | <!-- <el-radio-button label="ææ" :value="2" />--> |
| | | <!-- <el-radio-button label="æå£åº¦" :value="3" />--> |
| | | <!-- </el-radio-group>--> |
| | | </div> |
| | | <Echarts ref="chart" |
| | | :color="barColors2" |
| | | :chartStyle="chartStyle" |
| | | :grid="grid" |
| | | :series="barSeries" |
| | | :tooltip="tooltip" |
| | | :xAxis="xAxis" |
| | | :yAxis="yAxis" |
| | | style="height: 260px"></Echarts> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- åºé¨æ¨ªå两æ --> |
| | | <div class="dashboard-row"> |
| | | <!-- <div class="main-panel">--> |
| | | <!-- <div class="section-title">è´¨éç»è®¡</div>--> |
| | | <!-- <div class="quality-cards">--> |
| | | <!-- <div class="quality-card one">åææå·²æ£æµæ° <span>{{qualityStatisticsObject.supplierNum}}ä»¶</span></div>--> |
| | | <!-- <div class="quality-card two">è¿ç¨æ£éªæ°é <span>{{qualityStatisticsObject.processNum}}ä»¶</span></div>--> |
| | | <!-- <div class="quality-card three">åºåå·²æ£æ°é <span>{{qualityStatisticsObject.factoryNum}}ä»¶</span></div>--> |
| | | <!-- </div>--> |
| | | <!-- <Echarts ref="chart"--> |
| | | <!-- :chartStyle="chartStyle"--> |
| | | <!-- :grid="grid"--> |
| | | <!-- :legend="barLegend"--> |
| | | <!-- :series="barSeries1"--> |
| | | <!-- :tooltip="tooltip"--> |
| | | <!-- :xAxis="xAxis1"--> |
| | | <!-- :yAxis="yAxis1"--> |
| | | <!-- style="height: 260px"></Echarts>--> |
| | | <!-- </div>--> |
| | | <div class="main-panel"> |
| | | <div class="section-title">忬¾ä¸å¼ç¥¨åæ</div> |
| | | <Echarts ref="chart" :chartStyle="chartStyle" :grid="grid" :legend="lineLegend" :series="lineSeries" |
| | | :tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" style="height: 270px;"></Echarts> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="dashboard-container"> |
| | | <!-- ç»è®¡å¡ç --> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="6"> |
| | | <el-card class="statistics-card" shadow="hover"> |
| | | <div class="card-content"> |
| | | <div class="card-title">设å¤å¨çº¿ç</div> |
| | | <div class="card-value">{{ onlineRate }}%</div> |
| | | <div class="card-desc"> |
| | | å½åå¨çº¿è®¾å¤æ°ï¼{{ onlineCount }} / {{ totalDevices }} |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="statistics-card" shadow="hover"> |
| | | <div class="card-content"> |
| | | <div class="card-title">æ
éé¢è¦æ°</div> |
| | | <div class="card-value">{{ warningCount }}</div> |
| | | <div class="card-desc"> |
| | | é«é£é©ï¼{{ highRiskCount }} | ä¸é£é©ï¼{{ mediumRiskCount }} | |
| | | ä½é£é©ï¼{{ lowRiskCount }} |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="statistics-card" shadow="hover"> |
| | | <div class="card-content"> |
| | | <div class="card-title">å¾
å¤çç»´ä¿®å</div> |
| | | <div class="card-value">{{ pendingOrders }}</div> |
| | | <div class="card-desc"> |
| | | å¤çä¸ï¼{{ processingOrders }} | 已宿ï¼{{ completedOrders }} |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="statistics-card" shadow="hover"> |
| | | <div class="card-content"> |
| | | <div class="card-title">éç¹è®¾å¤è¿è¡ç¶æ</div> |
| | | <div class="card-value">{{ normalDevices }} æ£å¸¸</div> |
| | | <div class="card-desc"> |
| | | å¼å¸¸ï¼{{ abnormalDevices }} | æ
éï¼{{ faultDevices }} |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- å¾è¡¨åºå --> |
| | | <el-row :gutter="20" style="margin-top: 20px"> |
| | | <!-- 设å¤å¥åº·åº¦è¶å¿å¾ --> |
| | | <el-col :span="12"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>设å¤å¥åº·åº¦è¶å¿å¾</span> |
| | | </div> |
| | | </template> |
| | | <div ref="healthChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | <!-- è¿7æ¥æ
éç±»åç»è®¡ --> |
| | | <el-col :span="12"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>è¿7æ¥æ
éç±»åç»è®¡</span> |
| | | </div> |
| | | </template> |
| | | <div ref="faultChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- éç¹è®¾å¤è¿è¡ç¶æå¡ç --> |
| | | <el-card shadow="hover" style="margin-top: 20px"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>éç¹è®¾å¤è¿è¡ç¶æ</span> |
| | | </div> |
| | | </template> |
| | | <el-table :data="keyDevices" stripe style="width: 100%"> |
| | | <el-table-column |
| | | prop="name" |
| | | label="设å¤åç§°" |
| | | width="180" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="model" |
| | | label="åå·" |
| | | width="120" |
| | | ></el-table-column> |
| | | <el-table-column prop="ip" label="IPå°å" width="150"></el-table-column> |
| | | <el-table-column prop="status" label="ç¶æ" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag |
| | | :type=" |
| | | scope.row.status === 'online' |
| | | ? 'success' |
| | | : scope.row.status === 'warning' |
| | | ? 'warning' |
| | | : 'danger' |
| | | " |
| | | > |
| | | {{ |
| | | scope.row.status === "online" |
| | | ? "å¨çº¿" |
| | | : scope.row.status === "warning" |
| | | ? "é¢è¦" |
| | | : "æ
é" |
| | | }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | prop="temperature" |
| | | label="温度(â)" |
| | | width="100" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="pressure" |
| | | label="åå(MPa)" |
| | | width="100" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="speed" |
| | | label="转é(rpm)" |
| | | width="100" |
| | | ></el-table-column> |
| | | <el-table-column prop="health" label="å¥åº·åº¦" width="120"> |
| | | <template #default="scope"> |
| | | <el-progress |
| | | :percentage="scope.row.health" |
| | | :stroke-width="10" |
| | | ></el-progress> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from 'vue' |
| | | import Echarts from "@/components/Echarts/echarts.vue"; |
| | | import * as echarts from 'echarts'; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import { |
| | | analysisCustomerContractAmounts, getAmountHalfYear, |
| | | getBusiness, |
| | | homeTodos, |
| | | qualityStatistics, |
| | | statisticsReceivablePayable |
| | | } from "@/api/viewIndex.js"; |
| | | import { ref, onMounted, onUnmounted } from "vue"; |
| | | import * as echarts from "echarts"; |
| | | |
| | | const userStore = useUserStore() |
| | | // ç»è®¡æ°æ® |
| | | const onlineRate = ref(85); |
| | | const onlineCount = ref(170); |
| | | const totalDevices = ref(200); |
| | | const warningCount = ref(23); |
| | | const highRiskCount = ref(5); |
| | | const mediumRiskCount = ref(12); |
| | | const lowRiskCount = ref(6); |
| | | const pendingOrders = ref(15); |
| | | const processingOrders = ref(8); |
| | | const completedOrders = ref(45); |
| | | const normalDevices = ref(162); |
| | | const abnormalDevices = ref(18); |
| | | const faultDevices = ref(10); |
| | | |
| | | const businessInfo = ref({ |
| | | inventoryNum: 0, |
| | | monthPurchaseHaveMoney: 0, |
| | | monthPurchaseMoney: 0, |
| | | monthSaleHaveMoney: 0, |
| | | monthSaleMoney: 0, |
| | | todayInventoryNum: 0, |
| | | }) |
| | | const qualityStatisticsObject = ref({ |
| | | supplierNum: 0, |
| | | processNum: 0, |
| | | factoryNum: 0, |
| | | }) |
| | | const sum = ref(0) |
| | | const yny = ref(0) |
| | | const chain = ref(0) |
| | | |
| | | const pieLegend = reactive({ |
| | | show: false, |
| | | }) |
| | | const barSeries = ref([ |
| | | { |
| | | type: 'bar', |
| | | data: [], |
| | | label: { |
| | | show: true, |
| | | } |
| | | }, |
| | | ]) |
| | | const barSeries1 = ref([ |
| | | { |
| | | name: 'åææä¸åæ ¼æ°', |
| | | type: 'bar', |
| | | barGap: 0, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: [] |
| | | }, |
| | | { |
| | | name: 'è¿ç¨ä¸åæ ¼æ°', |
| | | type: 'bar', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: [] |
| | | }, |
| | | { |
| | | name: 'åºåä¸åæ ¼æ°', |
| | | type: 'bar', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: [] |
| | | }, |
| | | ]) |
| | | const chartStyle = { |
| | | width: '100%', |
| | | height: '100%' // 设置å¾è¡¨å®¹å¨çé«åº¦ |
| | | } |
| | | const chartStylePie = { |
| | | width: '140%', |
| | | height: '140%' // 设置å¾è¡¨å®¹å¨çé«åº¦ |
| | | } |
| | | const grid = { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | } |
| | | const barLegend = { |
| | | show: true, |
| | | data: ['åææä¸åæ ¼æ°', 'è¿ç¨ä¸åæ ¼æ°', 'åºåä¸åæ ¼æ°'] |
| | | } |
| | | const barLegend1 = { |
| | | show: true, |
| | | data: ['é¢ä»è´¦æ¬¾', 'åºä»è´¦æ¬¾', '颿¶è´¦æ¬¾', 'åºæ¶è´¦æ¬¾'] |
| | | } |
| | | const lineLegend = { |
| | | show: true, |
| | | data: ['å¼ç¥¨', '忬¾'] |
| | | } |
| | | const tooltip = { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | } |
| | | } |
| | | const xAxis = [{ |
| | | type: 'value', |
| | | }] |
| | | const xAxis1 = ref([{ |
| | | type: 'category', |
| | | axisTick: { show: false }, |
| | | data: [] |
| | | }]) |
| | | const yAxis = [{ |
| | | type: 'category', |
| | | data: [ 'åºä»è´¦æ¬¾', 'åºæ¶è´¦æ¬¾',] |
| | | }] |
| | | const yAxis1 = [{ |
| | | type: 'value' |
| | | }] |
| | | const pieTooltip = reactive({ |
| | | trigger: 'item', |
| | | formatter: function (params) { |
| | | // å¨æçææç¤ºä¿¡æ¯ï¼åºäºæ°æ®é¡¹ç name 屿§ |
| | | const description = params.name === 'æ¬æåæ¬¾éé¢' ? 'æ¬æåæ¬¾éé¢' : 'åºæ¶æ¬¾éé¢'; |
| | | return `${description} ${formatNumber(params.value)}å
${params.percent}%`; |
| | | }, |
| | | position: 'right' |
| | | }) |
| | | const materialPieSeries = ref([ |
| | | { |
| | | type: 'pie', |
| | | radius: ['66%', '90%'], |
| | | avoidLabelOverlap: false, |
| | | itemStyle: { |
| | | borderColor: '#fff', |
| | | borderWidth: 2 |
| | | }, |
| | | label: { |
| | | show: false |
| | | }, |
| | | data: [] |
| | | } |
| | | ]) |
| | | const lineSeries = ref([ |
| | | { |
| | | type: 'line', |
| | | data: [], |
| | | label: { |
| | | show: true |
| | | }, |
| | | showSymbol: true, // æ¾ç¤ºåç¹ |
| | | }, |
| | | ]) |
| | | const tooltipLine = { |
| | | trigger: 'axis', |
| | | } |
| | | const yAxis2 = ref([ |
| | | { |
| | | type: 'value', |
| | | } |
| | | ]) |
| | | const xAxis2 = ref([ |
| | | { |
| | | type: 'category', |
| | | data: [], |
| | | axisLabel: { |
| | | interval: 0, |
| | | formatter: function(value) { |
| | | return value.replace(/~/g, '\n'); |
| | | }, |
| | | } |
| | | } |
| | | ]) |
| | | |
| | | // å¾
åäºé¡¹ |
| | | const todoList = ref([]) |
| | | const radio1 = ref(1) |
| | | // éç¹è®¾å¤å表 |
| | | const keyDevices = ref([ |
| | | { |
| | | name: "ç©ºåæºA-001", |
| | | model: "KA-200", |
| | | ip: "192.168.1.101", |
| | | status: "online", |
| | | temperature: 42, |
| | | pressure: 0.8, |
| | | speed: 1450, |
| | | health: 92, |
| | | }, |
| | | { |
| | | name: "å·å´å¡B-002", |
| | | model: "CT-300", |
| | | ip: "192.168.1.102", |
| | | status: "warning", |
| | | temperature: 58, |
| | | pressure: 0.6, |
| | | speed: 980, |
| | | health: 75, |
| | | }, |
| | | { |
| | | name: "æ°´æ³µC-003", |
| | | model: "WP-150", |
| | | ip: "192.168.1.103", |
| | | status: "online", |
| | | temperature: 38, |
| | | pressure: 1.2, |
| | | speed: 1200, |
| | | health: 88, |
| | | }, |
| | | { |
| | | name: "åçµæºD-004", |
| | | model: "GE-500", |
| | | ip: "192.168.1.104", |
| | | status: "danger", |
| | | temperature: 75, |
| | | pressure: 0.5, |
| | | speed: 1500, |
| | | health: 60, |
| | | }, |
| | | { |
| | | name: "ååå¨E-005", |
| | | model: "TR-1000", |
| | | ip: "192.168.1.105", |
| | | status: "online", |
| | | temperature: 45, |
| | | pressure: 0, |
| | | speed: 0, |
| | | health: 95, |
| | | }, |
| | | ]); |
| | | |
| | | // å¾è¡¨å¼ç¨ |
| | | const barChart = ref(null) |
| | | const lineChart = ref(null) |
| | | const barColors2 = ['#5181DB', '#D369E0', '#F2CA6D', '#60CCA8'] |
| | | const healthChartRef = ref(null); |
| | | const faultChartRef = ref(null); |
| | | let healthChart = null; |
| | | let faultChart = null; |
| | | |
| | | // éæºé¢è²çæå½æ° |
| | | const getRandomColor = () => { |
| | | return '#' + Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0'); |
| | | } |
| | | // å¥åº·åº¦è¶å¿æ°æ® |
| | | const healthTrendData = { |
| | | dates: ["12-10", "12-11", "12-12", "12-13", "12-14", "12-15", "12-16"], |
| | | values: [88, 90, 85, 87, 92, 91, 93], |
| | | }; |
| | | |
| | | // æ
éç±»åç»è®¡æ°æ® |
| | | const faultTypeData = { |
| | | types: ["温度å¼å¸¸", "ååè¶
æ ", "转éå¼å¸¸", "æ¯å¨è¿å¤§", "å
¶ä»"], |
| | | values: [15, 8, 12, 6, 3], |
| | | }; |
| | | |
| | | // åå§åå¥åº·åº¦è¶å¿å¾ |
| | | const initHealthChart = () => { |
| | | if (healthChartRef.value) { |
| | | healthChart = echarts.init(healthChartRef.value); |
| | | const option = { |
| | | tooltip: { |
| | | trigger: "axis", |
| | | axisPointer: { |
| | | type: "cross", |
| | | label: { |
| | | backgroundColor: "#6a7985", |
| | | }, |
| | | }, |
| | | }, |
| | | grid: { |
| | | left: "3%", |
| | | right: "4%", |
| | | bottom: "3%", |
| | | containLabel: true, |
| | | }, |
| | | xAxis: { |
| | | type: "category", |
| | | boundaryGap: false, |
| | | data: healthTrendData.dates, |
| | | }, |
| | | yAxis: { |
| | | type: "value", |
| | | min: 70, |
| | | max: 100, |
| | | name: "å¥åº·åº¦(%)", |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "å¥åº·åº¦", |
| | | type: "line", |
| | | stack: "æ»é", |
| | | areaStyle: {}, |
| | | emphasis: { |
| | | focus: "series", |
| | | }, |
| | | data: healthTrendData.values, |
| | | itemStyle: { |
| | | color: "#67c23a", |
| | | }, |
| | | lineStyle: { |
| | | width: 3, |
| | | }, |
| | | }, |
| | | ], |
| | | }; |
| | | healthChart.setOption(option); |
| | | } |
| | | }; |
| | | |
| | | // åå§åæ
éç±»åç»è®¡é¥¼å¾ |
| | | const initFaultChart = () => { |
| | | if (faultChartRef.value) { |
| | | faultChart = echarts.init(faultChartRef.value); |
| | | const option = { |
| | | tooltip: { |
| | | trigger: "item", |
| | | }, |
| | | legend: { |
| | | orient: "vertical", |
| | | left: "left", |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "æ
éç±»å", |
| | | type: "pie", |
| | | radius: "50%", |
| | | data: faultTypeData.types.map((type, index) => ({ |
| | | name: type, |
| | | value: faultTypeData.values[index], |
| | | })), |
| | | emphasis: { |
| | | itemStyle: { |
| | | shadowBlur: 10, |
| | | shadowOffsetX: 0, |
| | | shadowColor: "rgba(0, 0, 0, 0.5)", |
| | | }, |
| | | }, |
| | | }, |
| | | ], |
| | | }; |
| | | faultChart.setOption(option); |
| | | } |
| | | }; |
| | | |
| | | // çå¬çªå£å¤§å°ååï¼è°æ´å¾è¡¨å¤§å° |
| | | const handleResize = () => { |
| | | healthChart?.resize(); |
| | | faultChart?.resize(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getBusinessData() |
| | | analysisCustomer() |
| | | todoInfoS() |
| | | statisticsReceivable() |
| | | qualityStatisticsInfo() |
| | | getAmountHalfYearNum() |
| | | }) |
| | | // æ°æ®ç»è®¡ |
| | | const getBusinessData = () => { |
| | | getBusiness().then((res) => { |
| | | businessInfo.value = {...res.data} |
| | | }) |
| | | } |
| | | // ååéé¢ |
| | | const analysisCustomer = () => { |
| | | analysisCustomerContractAmounts().then((res) => { |
| | | sum.value = res.data.sum |
| | | yny.value = res.data.yny |
| | | chain.value = res.data.chain |
| | | // 为æ¯ä¸ªæ°æ®é¡¹åé
éæºé¢è² |
| | | materialPieSeries.value[0].data = res.data.item.map(item => ({ |
| | | ...item, |
| | | itemStyle: { color: getRandomColor() } |
| | | })) |
| | | }) |
| | | } |
| | | // å¾
åäºé¡¹ |
| | | const todoInfoS = () => { |
| | | homeTodos().then((res) => { |
| | | todoList.value = res.data |
| | | }) |
| | | } |
| | | // åºä»åºæ¶ç»è®¡ |
| | | const statisticsReceivable = (type) => { |
| | | console.log(type) |
| | | statisticsReceivablePayable({type: radio1.value}).then((res) => { |
| | | barSeries.value[0].data = [ |
| | | // { value: res.data.prepayMoney, itemStyle: { color: barColors2[0] } }, |
| | | { value: res.data.payableMoney, itemStyle: { color: barColors2[0] } }, |
| | | // { value: res.data.advanceMoney, itemStyle: { color: barColors2[2] } }, |
| | | { value: res.data.receivableMoney, itemStyle: { color: barColors2[1] } } |
| | | ] |
| | | }) |
| | | } |
| | | // è´¨æ£ç»è®¡ |
| | | const qualityStatisticsInfo = () => { |
| | | qualityStatistics().then((res) => { |
| | | res.data.item.forEach(item => { |
| | | xAxis1.value[0].data.push(item.date) |
| | | barSeries1.value[0].data.push(item.supplierNum) |
| | | barSeries1.value[1].data.push(item.processNum) |
| | | barSeries1.value[2].data.push(item.factoryNum) |
| | | }) |
| | | qualityStatisticsObject.value.supplierNum = res.data.supplierNum |
| | | qualityStatisticsObject.value.processNum = res.data.processNum |
| | | qualityStatisticsObject.value.factoryNum = res.data.factoryNum |
| | | }) |
| | | } |
| | | const getAmountHalfYearNum = async () => { |
| | | const res = await getAmountHalfYear() |
| | | console.log(res) |
| | | const monthName = [] |
| | | const receiptAmount = [] |
| | | const invoiceAmount = [] |
| | | res.data.forEach(item => { |
| | | monthName.push(item.month) |
| | | receiptAmount.push(item.receiptAmount) |
| | | invoiceAmount.push(item.invoiceAmount) |
| | | }) |
| | | // æ£ç¡®ååºå¼èµå¼ï¼å建æ°ç xAxis å series 对象 |
| | | xAxis2.value[0].data = monthName |
| | | xAxis2.value[0].data = monthName.map(item => item.replace(/~/g, '\n~')); |
| | | lineSeries.value = [ |
| | | { |
| | | name: 'å¼ç¥¨', |
| | | type: 'line', |
| | | data: receiptAmount, |
| | | stack: 'Total', |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(131, 207, 255, 1)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(186, 228, 255, 1)' |
| | | } |
| | | ]) |
| | | }, |
| | | itemStyle: { |
| | | color: '#2D99FF', |
| | | borderColor: '#2D99FF' |
| | | }, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | lineStyle: { |
| | | width: 0 |
| | | }, |
| | | showSymbol: true, |
| | | }, |
| | | { |
| | | name: '忬¾', |
| | | type: 'line', |
| | | data: invoiceAmount, |
| | | stack: 'Total', |
| | | lineStyle: { |
| | | width: 0 |
| | | }, |
| | | itemStyle: { |
| | | color: '#83CFFF', |
| | | borderColor: '#83CFFF' |
| | | }, |
| | | showSymbol: true, |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgba(54, 153, 255, 1)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(89, 169, 254, 1)' |
| | | } |
| | | ]) |
| | | }, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | } |
| | | ] |
| | | } |
| | | initHealthChart(); |
| | | initFaultChart(); |
| | | window.addEventListener("resize", handleResize); |
| | | }); |
| | | |
| | | onUnmounted(() => { |
| | | window.removeEventListener("resize", handleResize); |
| | | healthChart?.dispose(); |
| | | faultChart?.dispose(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .dashboard { |
| | | background: #f5f7fa; |
| | | min-height: 100vh; |
| | | padding: 20px; |
| | | box-sizing: border-box; |
| | | } |
| | | .dashboard-top { |
| | | display: flex; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | } |
| | | .company-info { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | padding: 20px; |
| | | min-width: 0; |
| | | background-color: #EFF2FB; /* ä½¿ç¨æå®çèæ¯é¢è² */ |
| | | background-image: url("../assets/images/denglu.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | border-radius: 12px; |
| | | height: 138px; |
| | | } |
| | | .avatar { |
| | | width: 60px; |
| | | height: 60px; |
| | | border-radius: 50%; |
| | | object-fit: contain; |
| | | background: #fff; |
| | | border: 1px solid #eee; |
| | | } |
| | | .company-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | position: relative; |
| | | padding-right: 15px; |
| | | .dashboard-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .company-card::after { |
| | | content: ''; |
| | | position: absolute; |
| | | right: 0; |
| | | top: 0; |
| | | bottom: 0; |
| | | width: 1px; |
| | | background-color: #C9C5C5; |
| | | border-radius: 2px; |
| | | } |
| | | .company-name { |
| | | font-weight: 400; |
| | | font-size: 16px; |
| | | color: #161A9A; |
| | | } |
| | | .company-meta { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #818185; |
| | | } |
| | | .data-cards { |
| | | display: flex; |
| | | gap: 16px; |
| | | justify-content: flex-start; |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | } |
| | | .data-title { |
| | | font-weight: 700; |
| | | font-size: 26px; |
| | | color: #FFFFFF; |
| | | } |
| | | .data-num { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-top: 20px; |
| | | } |
| | | .data-card { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 14px 10px 10px 10px; |
| | | min-width: 160px; |
| | | box-shadow: 0 2px 8px #eee; |
| | | display: flex; |
| | | flex-direction: column; |
| | | width: 32%; |
| | | height: 140px; |
| | | } |
| | | .data-card.sales { |
| | | background-image: url("../assets/images/xioashoushuju.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | .data-card.purchase { |
| | | background-image: url("../assets/images/caigou.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | .data-card.inventory { |
| | | background-image: url("../assets/images/kucun.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | .data-desc { |
| | | font-weight: 500; |
| | | font-size: 13px; |
| | | color: #FFFFFF; |
| | | } |
| | | .data-value { |
| | | font-size: 18px; |
| | | font-weight: 500; |
| | | margin: 10px 0; |
| | | color: #FFFFFF; |
| | | } |
| | | .top-left { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | width: 50%; |
| | | } |
| | | .todo-panel { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | width: 50%; |
| | | } |
| | | .todo-list { |
| | | list-style: none; |
| | | padding: 0; |
| | | margin: 0; |
| | | font-size: 15px; |
| | | overflow-y: auto; |
| | | height: 260px; |
| | | } |
| | | .todo-list li { |
| | | border-radius: 8px; |
| | | margin-bottom: 12px; |
| | | padding: 8px 20px; |
| | | height: 74px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | background: rgba(225,227,250,0.62); |
| | | } |
| | | .todo-title { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | position: relative; |
| | | } |
| | | .todo-title::before { |
| | | content: ''; /* å¿
éï¼è¡¨ç¤ºè¿éæä¸ä¸ªå
容 */ |
| | | position: absolute; |
| | | left: -10px; /* å®ä½å°å·¦ä¾§ */ |
| | | top: 50%; /* åç´å±
ä¸ */ |
| | | transform: translateY(-50%); /* å¾®è°åç´å±
ä¸ */ |
| | | width: 6px; /* åçç´å¾ */ |
| | | height: 6px; /* åçç´å¾ */ |
| | | background: #498CEB; |
| | | border-radius: 50%; /* 让å
¶åæåå½¢ */ |
| | | } |
| | | .todo-division { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | } |
| | | .todo-time { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | } |
| | | .todo-meta { |
| | | color: #888; |
| | | font-size: 13px; |
| | | } |
| | | .dashboard-row { |
| | | display: flex; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | } |
| | | .main-panel { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | flex: 1; |
| | | min-width: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .section-title { |
| | | position: relative; |
| | | font-size: 18px; |
| | | color: #333; |
| | | padding-left: 10px; |
| | | margin-bottom: 10px; |
| | | font-weight: 700; |
| | | .statistics-card { |
| | | height: 180px; |
| | | } |
| | | |
| | | .section-title::before { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 4px; |
| | | content: ''; |
| | | width: 4px; |
| | | height: 18px; |
| | | background-color: #002FA7; |
| | | border-radius: 2px; |
| | | .card-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | height: 100%; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | .contract-info { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 20px; |
| | | height: 90px; |
| | | background: rgba(245,245,245,0.59); |
| | | width: 100%; |
| | | border-radius: 10px; |
| | | padding: 10px 30px; |
| | | |
| | | .card-title { |
| | | font-size: 16px; |
| | | color: #606266; |
| | | margin-bottom: 10px; |
| | | } |
| | | .contract-summary { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 30px; |
| | | |
| | | .card-value { |
| | | font-size: 32px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 8px; |
| | | } |
| | | .contract-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | |
| | | .card-desc { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | .contract-name { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #050505; |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .contract-meta { |
| | | display: flex; |
| | | align-items: center; |
| | | width: 100%; |
| | | gap: 80px; |
| | | |
| | | .chart-container { |
| | | width: 100%; |
| | | height: 350px; |
| | | } |
| | | .main-amount { |
| | | font-size: 24px; |
| | | color: rgba(51,50,50,0.85); |
| | | } |
| | | .up { color: #e57373; } |
| | | .contract-list { |
| | | margin-top: 16px; |
| | | font-size: 14px; |
| | | color: #666; |
| | | list-style: none; |
| | | padding: 0; |
| | | height: 190px; |
| | | overflow-y: auto; |
| | | width: 460px; |
| | | } |
| | | .line { |
| | | position: relative; |
| | | width: 230px; |
| | | } |
| | | .line::after { |
| | | content: ''; |
| | | position: absolute; |
| | | right: 2px; |
| | | top: 0; |
| | | bottom: 0; |
| | | width: 1px; |
| | | background-color: #C9C5C5; |
| | | border-radius: 2px; |
| | | } |
| | | .contract-list li { |
| | | margin-top: 10px; |
| | | } |
| | | .quality-cards { |
| | | display: flex; |
| | | gap: 12px; |
| | | margin-bottom: 12px; |
| | | } |
| | | .quality-card { |
| | | border-radius: 8px; |
| | | padding: 15px 10px 10px 50px; |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: rgba(0,0,0,0.67); |
| | | width: 236px; |
| | | height: 49px; |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | .quality-card.one { |
| | | background-image: url("../assets/images/yuancailiao.png"); |
| | | } |
| | | .quality-card.two { |
| | | background-image: url("../assets/images/guocheng.png"); |
| | | } |
| | | .quality-card.three { |
| | | background-image: url("../assets/images/chuchang.png"); |
| | | |
| | | } |
| | | .quality-card span { |
| | | color: #4fc3f7; |
| | | font-weight: bold; |
| | | margin-left: 6px; |
| | | } |
| | | .chart { |
| | | width: 100%; |
| | | height: 220px; |
| | | margin-top: 10px; |
| | | } |
| | | </style> |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="maintenance-management-container"> |
| | | <!-- 顶鍿使 --> |
| | | <el-card shadow="hover" style="margin-bottom: 20px;"> |
| | | <div class="card-header"> |
| | | <span>维修管ç</span> |
| | | <div class="header-buttons"> |
| | | <el-button type="primary" @click="showCreateWorkOrderDialog"> |
| | | <el-icon-plus /> å建工å |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <el-row :gutter="20"> |
| | | <!-- 左侧ï¼å·¥åå表 --> |
| | | <el-col :span="16"> |
| | | <el-card shadow="hover"> |
| | | <!-- å·¥åç¶ææ ç¾é¡µ --> |
| | | <el-tabs v-model="activeTab" @tab-change="handleTabChange"> |
| | | <el-tab-pane label="å¾
å¤ç" name="pending"></el-tab-pane> |
| | | <el-tab-pane label="å¤çä¸" name="processing"></el-tab-pane> |
| | | <el-tab-pane label="已宿" name="completed"></el-tab-pane> |
| | | </el-tabs> |
| | | |
| | | <!-- å·¥åå表 --> |
| | | <el-table :data="filteredWorkOrders" stripe style="width: 100%" @row-click="handleWorkOrderClick"> |
| | | <el-table-column prop="orderNo" label="å·¥åç¼å·" width="180"></el-table-column> |
| | | <el-table-column prop="deviceName" label="设å¤åç§°" width="150"></el-table-column> |
| | | <el-table-column prop="faultType" label="æ
éç±»å" width="120"></el-table-column> |
| | | <el-table-column prop="createTime" label="å建æ¶é´" width="180"></el-table-column> |
| | | <el-table-column prop="assignee" label="è´è´£äºº" width="120"></el-table-column> |
| | | <el-table-column prop="priority" label="ä¼å
级" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.priority === 'high' ? 'danger' : scope.row.priority === 'medium' ? 'warning' : 'info'"> |
| | | {{ scope.row.priority === 'high' ? 'é«' : scope.row.priority === 'medium' ? 'ä¸' : 'ä½' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="150"> |
| | | <template #default="scope"> |
| | | <el-button size="small" @click="showEditWorkOrderDialog(scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" size="small" @click="handleDeleteWorkOrder(scope.row.id)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å页 --> |
| | | <div class="pagination-container"> |
| | | <el-pagination |
| | | background |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :total="filteredWorkOrders.length" |
| | | :current-page="currentPage" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :page-size="pageSize" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | ></el-pagination> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | |
| | | <!-- å³ä¾§ï¼ç»´ä¿®ç»è®¡åå¤ä»¶æ¨è --> |
| | | <el-col :span="8"> |
| | | <!-- ç»´ä¿®åå²ç»è®¡ --> |
| | | <el-card shadow="hover" style="margin-bottom: 20px;"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>ç»´ä¿®åå²ç»è®¡</span> |
| | | </div> |
| | | </template> |
| | | <div class="statistics-content"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">æ¬æå®æå·¥å</div> |
| | | <div class="stat-value">{{ monthlyCompleted }}</div> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">å¹³åç»´ä¿®æ¶é¿</div> |
| | | <div class="stat-value">{{ averageRepairTime }}å°æ¶</div> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">è®¾å¤æ
éç</div> |
| | | <div class="stat-value">{{ failureRate }}%</div> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">常ç¨ç»´ä¿®è®¾å¤</div> |
| | | <div class="stat-value">{{ commonDevice }}</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 常ç¨å¤ä»¶å
³èæ¨è --> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>常ç¨å¤ä»¶æ¨è</span> |
| | | </div> |
| | | </template> |
| | | <div class="spare-parts-content"> |
| | | <el-table :data="spareParts" stripe style="width: 100%" size="small"> |
| | | <el-table-column prop="name" label="å¤ä»¶åç§°" width="120"></el-table-column> |
| | | <el-table-column prop="model" label="åå·" width="100"></el-table-column> |
| | | <el-table-column prop="stock" label="åºå" width="80"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.stock < 10 ? 'danger' : 'success'"> |
| | | {{ scope.row.stock }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="usageCount" label="ä½¿ç¨æ¬¡æ°" width="80"></el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- å建工åå¯¹è¯æ¡ --> |
| | | <el-dialog v-model="createWorkOrderDialogVisible" title="å建维修工å" width="600px"> |
| | | <el-form :model="workOrderForm" :rules="workOrderRules" ref="workOrderFormRef" label-width="100px"> |
| | | <el-form-item label="设å¤" prop="deviceId"> |
| | | <el-select v-model="workOrderForm.deviceId" placeholder="è¯·éæ©è®¾å¤"> |
| | | <el-option |
| | | v-for="device in devices" |
| | | :key="device.id" |
| | | :label="device.name" |
| | | :value="device.id" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ
éç±»å" prop="faultType"> |
| | | <el-input v-model="workOrderForm.faultType" placeholder="请è¾å
¥æ
éç±»å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æ
éæè¿°" prop="faultDescription"> |
| | | <el-input v-model="workOrderForm.faultDescription" type="textarea" placeholder="è¯·è¯¦ç»æè¿°æ
éæ
åµ" :rows="3"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ä¼å
级" prop="priority"> |
| | | <el-select v-model="workOrderForm.priority" placeholder="è¯·éæ©ä¼å
级"> |
| | | <el-option label="é«" value="high"></el-option> |
| | | <el-option label="ä¸" value="medium"></el-option> |
| | | <el-option label="ä½" value="low"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="createWorkOrderDialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleCreateWorkOrder">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- ç¼è¾å·¥åå¯¹è¯æ¡ --> |
| | | <el-dialog v-model="editWorkOrderDialogVisible" title="ç¼è¾ç»´ä¿®å·¥å" width="600px"> |
| | | <el-form :model="workOrderForm" :rules="workOrderRules" ref="workOrderFormRef" label-width="100px"> |
| | | <el-form-item label="å·¥åç¼å·" disabled> |
| | | <el-input v-model="workOrderForm.orderNo"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="设å¤" disabled> |
| | | <el-input v-model="workOrderForm.deviceName"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æ
éç±»å" disabled> |
| | | <el-input v-model="workOrderForm.faultType"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="è´è´£äºº" prop="assignee"> |
| | | <el-select v-model="workOrderForm.assignee" placeholder="è¯·éæ©è´è´£äºº"> |
| | | <el-option |
| | | v-for="user in users" |
| | | :key="user.id" |
| | | :label="user.name" |
| | | :value="user.name" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç»´ä¿®ç¶æ" prop="status"> |
| | | <el-select v-model="workOrderForm.status" placeholder="è¯·éæ©ç¶æ"> |
| | | <el-option label="å¾
å¤ç" value="pending"></el-option> |
| | | <el-option label="å¤çä¸" value="processing"></el-option> |
| | | <el-option label="已宿" value="completed"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç»´ä¿®ç»æ" prop="repairResult"> |
| | | <el-input v-model="workOrderForm.repairResult" type="textarea" placeholder="请填åç»´ä¿®ç»æ" :rows="3"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å¤ä»¶ä½¿ç¨" prop="usedParts"> |
| | | <el-input v-model="workOrderForm.usedParts" type="textarea" placeholder="请填å使ç¨çå¤ä»¶" :rows="2"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="editWorkOrderDialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleEditWorkOrder">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed } from 'vue' |
| | | |
| | | // 设å¤å表 |
| | | const devices = ref([ |
| | | { id: 'D001', name: 'ç©ºåæºA-001' }, |
| | | { id: 'D002', name: 'å·å´å¡B-002' }, |
| | | { id: 'D003', name: 'æ°´æ³µC-003' }, |
| | | { id: 'D004', name: 'åçµæºD-004' }, |
| | | { id: 'D005', name: 'ååå¨E-005' } |
| | | ]) |
| | | |
| | | // ç¨æ·å表ï¼ç¨äºåé
è´è´£äººï¼ |
| | | const users = ref([ |
| | | { id: 'U001', name: 'å¼ ä¸' }, |
| | | { id: 'U002', name: 'æå' }, |
| | | { id: 'U003', name: 'çäº' }, |
| | | { id: 'U004', name: 'èµµå
' } |
| | | ]) |
| | | |
| | | // å·¥ååè¡¨æ°æ® |
| | | const workOrders = ref([ |
| | | { |
| | | id: 1, |
| | | orderNo: 'WO20241216001', |
| | | deviceId: 'D001', |
| | | deviceName: 'ç©ºåæºA-001', |
| | | faultType: 'ååå¼å¸¸', |
| | | faultDescription: '设å¤è¿è¡æ¶ååè¶
è¿è®¾å®éå¼ï¼ä¼´æå¼å¸¸åªé³', |
| | | priority: 'high', |
| | | assignee: '', |
| | | status: 'pending', |
| | | repairResult: '', |
| | | usedParts: '', |
| | | createTime: '2024-12-16 14:32:15', |
| | | startTime: '', |
| | | endTime: '' |
| | | }, |
| | | { |
| | | id: 2, |
| | | orderNo: 'WO20241216002', |
| | | deviceId: 'D002', |
| | | deviceName: 'å·å´å¡B-002', |
| | | faultType: '温度è¿é«', |
| | | faultDescription: 'å·å´å¡åºæ°´æ¸©åº¦è¶
è¿è®¾å®å¼ï¼å·å´ææä¸ä½³', |
| | | priority: 'medium', |
| | | assignee: 'å¼ ä¸', |
| | | status: 'processing', |
| | | repairResult: '', |
| | | usedParts: '', |
| | | createTime: '2024-12-16 14:30:45', |
| | | startTime: '2024-12-16 15:00:00', |
| | | endTime: '' |
| | | }, |
| | | { |
| | | id: 3, |
| | | orderNo: 'WO20241215001', |
| | | deviceId: 'D003', |
| | | deviceName: 'æ°´æ³µC-003', |
| | | faultType: 'æ¯å¨è¿å¤§', |
| | | faultDescription: 'æ°´æ³µè¿è¡æ¶æ¯å¨å¼è¶
è¿æ åï¼å¯è½å½±å设å¤å¯¿å½', |
| | | priority: 'medium', |
| | | assignee: 'æå', |
| | | status: 'completed', |
| | | repairResult: 'æ´æ¢äºæ°´æ³µè½´æ¿ï¼è°æ´äºèè½´å¨ï¼æ¯å¨å¼æ¢å¤æ£å¸¸', |
| | | usedParts: 'è½´æ¿Ã2ï¼èè½´å¨Ã1', |
| | | createTime: '2024-12-15 08:30:00', |
| | | startTime: '2024-12-15 09:00:00', |
| | | endTime: '2024-12-15 10:45:00' |
| | | }, |
| | | { |
| | | id: 4, |
| | | orderNo: 'WO20241214001', |
| | | deviceId: 'D004', |
| | | deviceName: 'åçµæºD-004', |
| | | faultType: 'çµæµå¼å¸¸', |
| | | faultDescription: 'åçµæºè¿è¡æ¶çµæµæ³¢å¨è¾å¤§ï¼å¯è½åå¨çè·¯é£é©', |
| | | priority: 'high', |
| | | assignee: 'çäº', |
| | | status: 'completed', |
| | | repairResult: 'æ£æ¥å¹¶ä¿®å¤äºåçµæºç»ç»çè·¯é®é¢ï¼çµæµæ¢å¤æ£å¸¸', |
| | | usedParts: 'ç»ç¼ææÃ1ï¼å¯¼çº¿Ã5ç±³', |
| | | createTime: '2024-12-14 14:20:00', |
| | | startTime: '2024-12-14 14:30:00', |
| | | endTime: '2024-12-14 16:15:00' |
| | | }, |
| | | { |
| | | id: 5, |
| | | orderNo: 'WO20241213001', |
| | | deviceId: 'D005', |
| | | deviceName: 'ååå¨E-005', |
| | | faultType: 'çµåæ³¢å¨', |
| | | faultDescription: 'ååå¨è¾åºçµåæ³¢å¨è¾å¤§ï¼å½±å䏿¸¸è®¾å¤è¿è¡', |
| | | priority: 'low', |
| | | assignee: 'èµµå
', |
| | | status: 'completed', |
| | | repairResult: 'è°æ´äºååå¨åæ¥å¼å
³ï¼çµå稳å®å¨æ£å¸¸èå´å
', |
| | | usedParts: '', |
| | | createTime: '2024-12-13 09:15:00', |
| | | startTime: '2024-12-13 10:00:00', |
| | | endTime: '2024-12-13 11:30:00' |
| | | } |
| | | ]) |
| | | |
| | | // å½åæ¿æ´»çæ ç¾é¡µï¼å·¥åç¶æï¼ |
| | | const activeTab = ref('pending') |
| | | |
| | | // åé¡µæ°æ® |
| | | const currentPage = ref(1) |
| | | const pageSize = ref(10) |
| | | |
| | | // å¯¹è¯æ¡ç¶æ |
| | | const createWorkOrderDialogVisible = ref(false) |
| | | const editWorkOrderDialogVisible = ref(false) |
| | | |
| | | // å·¥åè¡¨åæ°æ® |
| | | const workOrderForm = ref({ |
| | | id: '', |
| | | orderNo: '', |
| | | deviceId: '', |
| | | deviceName: '', |
| | | faultType: '', |
| | | faultDescription: '', |
| | | priority: 'medium', |
| | | assignee: '', |
| | | status: 'pending', |
| | | repairResult: '', |
| | | usedParts: '', |
| | | createTime: '', |
| | | startTime: '', |
| | | endTime: '' |
| | | }) |
| | | |
| | | // 表åéªè¯è§å |
| | | const workOrderRules = ref({ |
| | | deviceId: [{ required: true, message: 'è¯·éæ©è®¾å¤', trigger: 'change' }], |
| | | faultType: [{ required: true, message: '请è¾å
¥æ
éç±»å', trigger: 'blur' }], |
| | | faultDescription: [{ required: true, message: 'è¯·è¯¦ç»æè¿°æ
éæ
åµ', trigger: 'blur' }], |
| | | priority: [{ required: true, message: 'è¯·éæ©ä¼å
级', trigger: 'change' }], |
| | | assignee: [{ required: true, message: 'è¯·éæ©è´è´£äºº', trigger: 'change' }], |
| | | status: [{ required: true, message: 'è¯·éæ©ç¶æ', trigger: 'change' }] |
| | | }) |
| | | |
| | | // 表åå¼ç¨ |
| | | const workOrderFormRef = ref(null) |
| | | |
| | | // çéåçå·¥åå表 |
| | | const filteredWorkOrders = computed(() => { |
| | | return workOrders.value.filter(order => order.status === activeTab.value) |
| | | }) |
| | | |
| | | // ç»´ä¿®ç»è®¡æ°æ® |
| | | const monthlyCompleted = ref(28) |
| | | const averageRepairTime = ref(2.5) |
| | | const failureRate = ref(3.2) |
| | | const commonDevice = ref('ç©ºåæºA-001') |
| | | |
| | | // 常ç¨å¤ä»¶æ¨è |
| | | const spareParts = ref([ |
| | | { id: 1, name: 'è½´æ¿', model: '6308', stock: 15, usageCount: 23 }, |
| | | { id: 2, name: 'å¯å°ä»¶', model: 'MS-25', stock: 8, usageCount: 18 }, |
| | | { id: 3, name: 'èè½´å¨', model: 'CL-50', stock: 5, usageCount: 12 }, |
| | | { id: 4, name: 'ä¼ æå¨', model: 'TS-100', stock: 3, usageCount: 15 }, |
| | | { id: 5, name: 'æ¶¦æ»æ²¹', model: 'L-46', stock: 20, usageCount: 30 } |
| | | ]) |
| | | |
| | | // æ¾ç¤ºå建工åå¯¹è¯æ¡ |
| | | const showCreateWorkOrderDialog = () => { |
| | | // é置表å |
| | | workOrderForm.value = { |
| | | id: '', |
| | | orderNo: '', |
| | | deviceId: '', |
| | | deviceName: '', |
| | | faultType: '', |
| | | faultDescription: '', |
| | | priority: 'medium', |
| | | assignee: '', |
| | | status: 'pending', |
| | | repairResult: '', |
| | | usedParts: '', |
| | | createTime: '', |
| | | startTime: '', |
| | | endTime: '' |
| | | } |
| | | createWorkOrderDialogVisible.value = true |
| | | } |
| | | |
| | | // æ¾ç¤ºç¼è¾å·¥åå¯¹è¯æ¡ |
| | | const showEditWorkOrderDialog = (order) => { |
| | | workOrderForm.value = { ...order } |
| | | editWorkOrderDialogVisible.value = true |
| | | } |
| | | |
| | | // å¤çå·¥åç¹å» |
| | | const handleWorkOrderClick = (row) => { |
| | | // å¯ä»¥å¨è¿éæ·»å æ¥çå·¥å详æ
çé»è¾ |
| | | } |
| | | |
| | | // å¤çæ ç¾é¡µåæ¢ |
| | | const handleTabChange = (tab) => { |
| | | activeTab.value = tab |
| | | currentPage.value = 1 // 忢æ ç¾é¡µæ¶é置页ç |
| | | } |
| | | |
| | | // å¤çå建工å |
| | | const handleCreateWorkOrder = () => { |
| | | // 模æå建工å |
| | | const newOrder = { |
| | | ...workOrderForm.value, |
| | | id: workOrders.value.length + 1, |
| | | orderNo: `WO${new Date().getFullYear()}${String(new Date().getMonth() + 1).padStart(2, '0')}${String(new Date().getDate()).padStart(2, '0')}${String(workOrders.value.length + 1).padStart(3, '0')}`, |
| | | deviceName: devices.value.find(d => d.id === workOrderForm.value.deviceId)?.name || '', |
| | | createTime: new Date().toLocaleString(), |
| | | status: 'pending' |
| | | } |
| | | workOrders.value.unshift(newOrder) |
| | | createWorkOrderDialogVisible.value = false |
| | | ElMessage.success('å·¥åå建æå') |
| | | } |
| | | |
| | | // å¤çç¼è¾å·¥å |
| | | const handleEditWorkOrder = () => { |
| | | // 模æç¼è¾å·¥å |
| | | const index = workOrders.value.findIndex(order => order.id === workOrderForm.value.id) |
| | | if (index !== -1) { |
| | | // å¦æç¶æä»å¾
å¤çå为å¤çä¸ï¼è®¾ç½®å¼å§æ¶é´ |
| | | if (workOrders.value[index].status === 'pending' && workOrderForm.value.status === 'processing') { |
| | | workOrderForm.value.startTime = new Date().toLocaleString() |
| | | } |
| | | // å¦æç¶æä»å¤çä¸åä¸ºå·²å®æï¼è®¾ç½®ç»ææ¶é´ |
| | | if (workOrders.value[index].status === 'processing' && workOrderForm.value.status === 'completed') { |
| | | workOrderForm.value.endTime = new Date().toLocaleString() |
| | | } |
| | | workOrders.value[index] = { ...workOrderForm.value } |
| | | editWorkOrderDialogVisible.value = false |
| | | ElMessage.success('å·¥åç¼è¾æå') |
| | | } |
| | | } |
| | | |
| | | // å¤çå é¤å·¥å |
| | | const handleDeleteWorkOrder = (id) => { |
| | | ElMessageBox.confirm('ç¡®å®è¦å é¤è¯¥å·¥ååï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | // 模æå é¤å·¥å |
| | | const index = workOrders.value.findIndex(order => order.id === id) |
| | | if (index !== -1) { |
| | | workOrders.value.splice(index, 1) |
| | | ElMessage.success('å·¥åå 餿å') |
| | | } |
| | | }).catch(() => { |
| | | // åæ¶å é¤ |
| | | }) |
| | | } |
| | | |
| | | // å¤çå页大å°åå |
| | | const handleSizeChange = (size) => { |
| | | pageSize.value = size |
| | | currentPage.value = 1 |
| | | } |
| | | |
| | | // å¤çå½å页åå |
| | | const handleCurrentChange = (current) => { |
| | | currentPage.value = current |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .maintenance-management-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .header-buttons { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .statistics-content { |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 20px; |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .stat-item { |
| | | text-align: center; |
| | | padding: 15px; |
| | | background-color: #fafafa; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .stat-label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .stat-value { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | |
| | | .spare-parts-content { |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | :deep(.el-icon-plus) { |
| | | margin-right: 5px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="real-time-monitoring-container"> |
| | | <!-- 设å¤éæ© --> |
| | | <el-card shadow="hover" style="margin-bottom: 20px;"> |
| | | <el-form :inline="true" :model="deviceSelectForm" class="device-select-form"> |
| | | <el-form-item label="设å¤"> |
| | | <el-select v-model="deviceSelectForm.deviceId" placeholder="è¯·éæ©è®¾å¤" @change="handleDeviceChange"> |
| | | <el-option |
| | | v-for="device in devices" |
| | | :key="device.id" |
| | | :label="device.name" |
| | | :value="device.id" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ¶é´èå´"> |
| | | <el-date-picker |
| | | v-model="timeRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | :default-time="['00:00:00', '23:59:59']" |
| | | ></el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleHistoryQuery">æ¥è¯¢å岿°æ®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | |
| | | <!-- 宿¶åæ°å¡ç --> |
| | | <el-row :gutter="20" style="margin-bottom: 20px;"> |
| | | <el-col :span="8" v-for="param in realTimeParams" :key="param.name"> |
| | | <el-card class="param-card" :shadow="param.isAlarm ? 'always' : 'hover'" :class="{ 'alarm-card': param.isAlarm }"> |
| | | <div class="param-content"> |
| | | <div class="param-title"> |
| | | <span>{{ param.name }}</span> |
| | | <el-tag v-if="param.isAlarm" type="danger">åè¦</el-tag> |
| | | </div> |
| | | <div class="param-value">{{ param.value }} {{ param.unit }}</div> |
| | | <div class="param-range"> |
| | | æ£å¸¸èå´ï¼{{ param.min }} - {{ param.max }} {{ param.unit }} |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- åè¦æç¤º --> |
| | | <el-card shadow="hover" v-if="alarmList.length > 0" style="margin-bottom: 20px;"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>åè¦æç¤º</span> |
| | | </div> |
| | | </template> |
| | | <el-scrollbar height="200px"> |
| | | <div class="alarm-item" v-for="alarm in alarmList" :key="alarm.id"> |
| | | <el-alert |
| | | :title="alarm.message" |
| | | :type="alarm.level === 'high' ? 'error' : alarm.level === 'medium' ? 'warning' : 'info'" |
| | | show-icon |
| | | closable |
| | | @close="handleAlarmClose(alarm.id)" |
| | | > |
| | | <template #default> |
| | | <div class="alarm-detail"> |
| | | <span>设å¤ï¼{{ alarm.deviceName }}</span> |
| | | <span>æ¶é´ï¼{{ alarm.time }}</span> |
| | | </div> |
| | | </template> |
| | | </el-alert> |
| | | </div> |
| | | </el-scrollbar> |
| | | </el-card> |
| | | |
| | | <!-- å岿°æ®è¶å¿å¾ --> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>å岿°æ®è¶å¿</span> |
| | | <div class="param-tabs"> |
| | | <el-radio-group v-model="activeParam" size="small" @change="handleParamChange"> |
| | | <el-radio-button v-for="param in historyParams" :key="param" :label="param"> |
| | | {{ param }} |
| | | </el-radio-button> |
| | | </el-radio-group> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <div ref="historyChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | |
| | | <!-- å设å¤åæ°è¯¦æ
页 --> |
| | | <el-dialog v-model="deviceDetailVisible" title="设å¤åæ°è¯¦æ
" width="800px"> |
| | | <div class="device-detail-content"> |
| | | <h3>{{ selectedDevice.name }} - 宿¶åæ°</h3> |
| | | <el-row :gutter="20" style="margin-bottom: 20px;"> |
| | | <el-col :span="12" v-for="param in realTimeParams" :key="param.name"> |
| | | <div class="detail-param-item"> |
| | | <span class="param-label">{{ param.name }}ï¼</span> |
| | | <span class="param-value" :class="{ 'alarm-value': param.isAlarm }"> |
| | | {{ param.value }} {{ param.unit }} |
| | | </span> |
| | | <span class="param-range"> |
| | | ï¼{{ param.min }} - {{ param.max }} {{ param.unit }}ï¼ |
| | | </span> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <h3>åæ°éå¼è®¾ç½®</h3> |
| | | <el-form :model="thresholdForm" label-width="100px" style="margin-top: 20px;"> |
| | | <el-form-item v-for="param in realTimeParams" :key="param.name" :label="param.name"> |
| | | <el-input-number |
| | | v-model="thresholdForm[param.name + 'Min']" |
| | | :min="0" |
| | | :max="1000" |
| | | size="small" |
| | | style="width: 120px; margin-right: 10px;" |
| | | placeholder="æå°å¼" |
| | | ></el-input-number> |
| | | <span style="margin: 0 10px;">-</span> |
| | | <el-input-number |
| | | v-model="thresholdForm[param.name + 'Max']" |
| | | :min="0" |
| | | :max="1000" |
| | | size="small" |
| | | style="width: 120px; margin-right: 10px;" |
| | | placeholder="æå¤§å¼" |
| | | ></el-input-number> |
| | | <span>{{ param.unit }}</span> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="deviceDetailVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="saveThresholds">ä¿å设置</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, onUnmounted, computed } from 'vue' |
| | | import * as echarts from 'echarts' |
| | | |
| | | // 设å¤å表 |
| | | const devices = ref([ |
| | | { id: 'D001', name: 'ç©ºåæºA-001' }, |
| | | { id: 'D002', name: 'å·å´å¡B-002' }, |
| | | { id: 'D003', name: 'æ°´æ³µC-003' }, |
| | | { id: 'D004', name: 'åçµæºD-004' }, |
| | | { id: 'D005', name: 'ååå¨E-005' } |
| | | ]) |
| | | |
| | | // 设å¤éæ©è¡¨å |
| | | const deviceSelectForm = ref({ |
| | | deviceId: 'D001' // é»è®¤éæ©ç¬¬ä¸ä¸ªè®¾å¤ |
| | | }) |
| | | |
| | | // æ¶é´èå´ |
| | | const timeRange = ref([]) |
| | | |
| | | // å½åéä¸çè®¾å¤ |
| | | const selectedDevice = ref(devices.value[0]) |
| | | |
| | | // 宿¶åæ°æ°æ® |
| | | const realTimeParams = ref([ |
| | | { name: '温度', value: 45, unit: 'â', min: 0, max: 60, isAlarm: false }, |
| | | { name: 'åå', value: 0.85, unit: 'MPa', min: 0.5, max: 0.8, isAlarm: true }, |
| | | { name: '转é', value: 1450, unit: 'rpm', min: 1000, max: 1500, isAlarm: false }, |
| | | { name: 'æ¯å¨', value: 3.2, unit: 'mm/s', min: 0, max: 2.5, isAlarm: true }, |
| | | { name: 'çµæµ', value: 25.6, unit: 'A', min: 0, max: 30, isAlarm: false }, |
| | | { name: 'çµå', value: 380, unit: 'V', min: 360, max: 400, isAlarm: false } |
| | | ]) |
| | | |
| | | // åè¦å表 |
| | | const alarmList = ref([ |
| | | { id: 1, deviceName: 'ç©ºåæºA-001', message: 'ååè¶
æ ', level: 'high', time: '2024-12-16 14:32:15' }, |
| | | { id: 2, deviceName: 'ç©ºåæºA-001', message: 'æ¯å¨è¿å¤§', level: 'medium', time: '2024-12-16 14:30:45' }, |
| | | { id: 3, deviceName: 'å·å´å¡B-002', message: '温度å¼å¸¸', level: 'warning', time: '2024-12-16 14:28:30' } |
| | | ]) |
| | | |
| | | // åå²åæ°é项 |
| | | const historyParams = ref(['温度', 'åå', '转é', 'æ¯å¨', 'çµæµ', 'çµå']) |
| | | const activeParam = ref('温度') |
| | | |
| | | // å岿°æ® |
| | | const historyData = ref({ |
| | | dates: [], |
| | | values: [] |
| | | }) |
| | | |
| | | // å¾è¡¨å¼ç¨ |
| | | const historyChartRef = ref(null) |
| | | let historyChart = null |
| | | |
| | | // 设å¤è¯¦æ
å¯¹è¯æ¡ |
| | | const deviceDetailVisible = ref(false) |
| | | |
| | | // éå¼è®¾ç½®è¡¨å |
| | | const thresholdForm = ref({}) |
| | | |
| | | // åå§åéå¼è¡¨å |
| | | const initThresholdForm = () => { |
| | | const form = {} |
| | | realTimeParams.value.forEach(param => { |
| | | form[param.name + 'Min'] = param.min |
| | | form[param.name + 'Max'] = param.max |
| | | }) |
| | | thresholdForm.value = form |
| | | } |
| | | |
| | | // å¤ç设å¤åæ´ |
| | | const handleDeviceChange = (deviceId) => { |
| | | selectedDevice.value = devices.value.find(device => device.id === deviceId) || devices.value[0] |
| | | // 模æåæ¢è®¾å¤åæ´æ°å®æ¶åæ° |
| | | updateRealTimeParams() |
| | | // å·æ°å岿°æ®å¾è¡¨ |
| | | initHistoryChart() |
| | | } |
| | | |
| | | // æ´æ°å®æ¶åæ°ï¼æ¨¡æï¼ |
| | | const updateRealTimeParams = () => { |
| | | realTimeParams.value = realTimeParams.value.map(param => { |
| | | // çæéæºå¼ï¼é¨ååæ°å¯è½è§¦ååè¦ |
| | | const randomFactor = Math.random() * 0.2 - 0.1 // -0.1 å° 0.1 ä¹é´çéæºæ° |
| | | const baseValue = (param.min + param.max) / 2 |
| | | const newValue = baseValue + baseValue * randomFactor |
| | | const isAlarm = newValue < param.min || newValue > param.max |
| | | |
| | | return { |
| | | ...param, |
| | | value: Number(newValue.toFixed(2)), |
| | | isAlarm |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // å¤çå岿°æ®æ¥è¯¢ |
| | | const handleHistoryQuery = () => { |
| | | // æ¨¡ææ¥è¯¢å岿°æ® |
| | | generateHistoryData() |
| | | initHistoryChart() |
| | | ElMessage.success('å岿°æ®æ¥è¯¢æå') |
| | | } |
| | | |
| | | // çæå岿°æ®ï¼æ¨¡æï¼ |
| | | const generateHistoryData = () => { |
| | | const dates = [] |
| | | const values = [] |
| | | |
| | | // çæè¿å»7å¤©çæ¥æåå¯¹åºæ°æ® |
| | | for (let i = 6; i >= 0; i--) { |
| | | const date = new Date() |
| | | date.setDate(date.getDate() - i) |
| | | dates.push(date.toLocaleDateString()) |
| | | |
| | | // çæéæºå¼ |
| | | const baseValue = (realTimeParams.value.find(p => p.name === activeParam.value).min + |
| | | realTimeParams.value.find(p => p.name === activeParam.value).max) / 2 |
| | | const randomValue = baseValue + (Math.random() - 0.5) * baseValue * 0.4 |
| | | values.push(Number(randomValue.toFixed(2))) |
| | | } |
| | | |
| | | historyData.value = { |
| | | dates, |
| | | values |
| | | } |
| | | } |
| | | |
| | | // åå§åå岿°æ®è¶å¿å¾ |
| | | const initHistoryChart = () => { |
| | | if (historyChartRef.value) { |
| | | historyChart = echarts.init(historyChartRef.value) |
| | | |
| | | // å¦ææ²¡æå岿°æ®ï¼çææ¨¡ææ°æ® |
| | | if (historyData.value.dates.length === 0) { |
| | | generateHistoryData() |
| | | } |
| | | |
| | | const paramConfig = realTimeParams.value.find(p => p.name === activeParam.value) |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'cross', |
| | | label: { |
| | | backgroundColor: '#6a7985' |
| | | } |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | boundaryGap: false, |
| | | data: historyData.value.dates |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | name: `${activeParam.value}(${paramConfig.unit})`, |
| | | min: paramConfig.min * 0.9, |
| | | max: paramConfig.max * 1.1 |
| | | }, |
| | | series: [ |
| | | { |
| | | name: activeParam.value, |
| | | type: 'line', |
| | | stack: 'æ»é', |
| | | areaStyle: {}, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | data: historyData.value.values, |
| | | itemStyle: { |
| | | color: '#409eff' |
| | | }, |
| | | lineStyle: { |
| | | width: 3 |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | historyChart.setOption(option) |
| | | } |
| | | } |
| | | |
| | | // å¤ç忰忢 |
| | | const handleParamChange = () => { |
| | | // çææ°åæ°çå岿°æ® |
| | | generateHistoryData() |
| | | initHistoryChart() |
| | | } |
| | | |
| | | // å¤çåè¦å
³é |
| | | const handleAlarmClose = (alarmId) => { |
| | | const index = alarmList.value.findIndex(alarm => alarm.id === alarmId) |
| | | if (index !== -1) { |
| | | alarmList.value.splice(index, 1) |
| | | } |
| | | } |
| | | |
| | | // æå¼è®¾å¤è¯¦æ
页 |
| | | const openDeviceDetail = () => { |
| | | initThresholdForm() |
| | | deviceDetailVisible.value = true |
| | | } |
| | | |
| | | // ä¿åéå¼è®¾ç½® |
| | | const saveThresholds = () => { |
| | | // 模æä¿åéå¼ |
| | | realTimeParams.value = realTimeParams.value.map(param => { |
| | | return { |
| | | ...param, |
| | | min: thresholdForm.value[param.name + 'Min'], |
| | | max: thresholdForm.value[param.name + 'Max'] |
| | | } |
| | | }) |
| | | deviceDetailVisible.value = false |
| | | ElMessage.success('éå¼è®¾ç½®ä¿åæå') |
| | | } |
| | | |
| | | // çå¬çªå£å¤§å°ååï¼è°æ´å¾è¡¨å¤§å° |
| | | const handleResize = () => { |
| | | historyChart?.resize() |
| | | } |
| | | |
| | | // æ¯5ç§æ´æ°ä¸æ¬¡å®æ¶åæ°ï¼æ¨¡æï¼ |
| | | let updateTimer = null |
| | | const startRealTimeUpdate = () => { |
| | | updateTimer = setInterval(() => { |
| | | updateRealTimeParams() |
| | | }, 5000) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | // åå§åå¾è¡¨ |
| | | initHistoryChart() |
| | | // åå§åéå¼è¡¨å |
| | | initThresholdForm() |
| | | // å¼å§å®æ¶æ´æ° |
| | | startRealTimeUpdate() |
| | | // çå¬çªå£å¤§å°åå |
| | | window.addEventListener('resize', handleResize) |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | // æ¸
é¤å®æ¶å¨ |
| | | if (updateTimer) { |
| | | clearInterval(updateTimer) |
| | | } |
| | | // 鿝å¾è¡¨ |
| | | historyChart?.dispose() |
| | | // ç§»é¤äºä»¶çå¬ |
| | | window.removeEventListener('resize', handleResize) |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .real-time-monitoring-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .device-select-form { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .param-tabs { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .param-card { |
| | | transition: all 0.3s; |
| | | } |
| | | |
| | | .alarm-card { |
| | | border-left: 4px solid #f56c6c; |
| | | box-shadow: 0 2px 12px 0 rgba(245, 108, 108, 0.1); |
| | | } |
| | | |
| | | .param-content { |
| | | text-align: center; |
| | | } |
| | | |
| | | .param-title { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | gap: 10px; |
| | | font-size: 16px; |
| | | color: #606266; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .param-value { |
| | | font-size: 32px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 10px; |
| | | display: block; |
| | | } |
| | | |
| | | .alarm-value { |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .param-range { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .alarm-item { |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .alarm-detail { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-top: 5px; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | |
| | | .chart-container { |
| | | width: 100%; |
| | | height: 400px; |
| | | } |
| | | |
| | | .device-detail-content { |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .device-detail-content h3 { |
| | | margin-bottom: 20px; |
| | | color: #303133; |
| | | } |
| | | |
| | | .detail-param-item { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 15px; |
| | | padding: 10px; |
| | | background-color: #fafafa; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .param-label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | width: 80px; |
| | | } |
| | | |
| | | .param-range { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-left: 10px; |
| | | } |
| | | </style> |
| | |
| | | const { VITE_APP_ENV } = env;
|
| | | const baseUrl =
|
| | | VITE_APP_ENV == "development"
|
| | | ? "http://192.168.1.147:7003" // å¼åç¯å¢å端æ¥å£
|
| | | : "http://10.136.12.71:7003"; // ç产ç¯å¢å端æ¥å£
|
| | | ? "http://127.0.0.1:8020" // å¼åç¯å¢å端æ¥å£
|
| | | : "http://10.136.12.71:8020"; // ç产ç¯å¢å端æ¥å£
|
| | |
|
| | | return {
|
| | | // é¨ç½²ç产ç¯å¢åå¼åç¯å¢ä¸çURLã
|