4 files modified
3 files added
| | |
| | | |
| | | this.page.currentPage = 1 |
| | | this.onLoad(this.page, this.query) |
| | | this.handleViewDetail() |
| | | }, |
| | | /** |
| | | * 驳回 |
| | |
| | | <div class="events"> |
| | | <div v-for="(event, index) in getEvents(data.day)" :key="index" class="event-item" :class="event.type" |
| | | @click="jumpcalendar(event, data.day)"> |
| | | <img :src="getEventIcon(event.type)" alt="" /> |
| | | {{ event.name }}<span>{{ event.value }}</span> |
| | | <div> <img :src="getEventIcon(event.type)" alt="" /> |
| | | {{ event.name }}</div> |
| | | <span>{{ event.value }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | |
| | | const getJobEventBar = () => { |
| | | getCalen(params.value).then(res => { |
| | | console.log('re',res.data); |
| | | |
| | | if (res.data.code !== 0) return |
| | | events.value = res.data.data |
| | | const a = res.data.data |
| | | const filteredData = {}; |
| | | for(let date in a) { |
| | | filteredData[date] = a[date].filter(item => item.type !== "work-order"); |
| | | } |
| | | events.value = filteredData; |
| | | // events.value = res.data.data |
| | | }) |
| | | } |
| | | const jumpcalendar = (event, day) => { |
| | |
| | | .event-item { |
| | | font-size: 12px; |
| | | // padding: 2px; |
| | | |
| | | text-align: center; |
| | | border-radius: 3px; |
| | | white-space: nowrap; |
| | | |
| | |
| | | |
| | | span { |
| | | font-weight: 600; |
| | | font-size: 14px; |
| | | font-size: 20px; |
| | | color: #029d36; |
| | | margin-left: 2px; |
| | | } |
| New file |
| | |
| | | <template> |
| | | <div class="flyOrder"> |
| | | <div class="fytitle"> |
| | | <div class="cardtotal"> |
| | | <p>飞行统计</p> |
| | | <img @click="refresh" src="/src/assets/images/workbench/st1.png" alt="" /> |
| | | </div> |
| | | <div class="time-card"> |
| | | <div |
| | | class="card-item" |
| | | :class="item === checked ? 'active' : ''" |
| | | v-for="(item, index) in timeListEnum" |
| | | :key="index" |
| | | @click="timeClick(item, index)" |
| | | > |
| | | {{ timeListStr[index] }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="flycenter"> |
| | | <div class="centerBox"> |
| | | <div class="centerItem" v-for="(itemfly, index) in flyTypeList" :key="index"> |
| | | <div class="flyimg"><img :src="itemfly.img" alt="" />{{ itemfly.name }}</div> |
| | | <div class="flydata"> |
| | | <span>{{ itemfly.value }}</span |
| | | >{{ unitMap[itemfly.name] }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="lineChart"> |
| | | <div class="lineBox" ref="chartRef"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { getJobEventByStatus, getJobEventTotal, getFly, getFlyTime } from '@/api/home/index'; |
| | | import flyImg1 from '@/assets/images/workbench/fy2.svg'; |
| | | import flyImg2 from '@/assets/images/workbench/fy3.svg'; |
| | | import flyImg3 from '@/assets/images/workbench/fy4.svg'; |
| | | import * as echarts from 'echarts'; |
| | | import useEchartsResize from '@/hooks/useEchartsResize'; |
| | | let checked = ref('CURRENT_YEAR'); |
| | | let timeListStr = ['本周', '本月', '本年']; |
| | | let timeListEnum = ['CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR']; |
| | | const dateSelect = ref('CURRENT_YEAR'); |
| | | const params = ref({ |
| | | date_enum: 'CURRENT_YEAR', |
| | | device_sn: '', |
| | | end_date: undefined, |
| | | start_date: undefined, |
| | | }); |
| | | const chartRef = ref(null); |
| | | let { chart: lineChart } = useEchartsResize(chartRef); |
| | | const keyMapping = { |
| | | 飞行时长: 'total_flight_time', |
| | | 飞行里程: 'total_flight_distance', |
| | | // 任务成果: 'event_num', |
| | | }; |
| | | const unitMap = { |
| | | 飞行时长: '小时', |
| | | 飞行里程: '公里', |
| | | // 任务成果: '个', |
| | | }; |
| | | const flyTypeList = ref([ |
| | | { name: '飞行时长', value: 0, img: flyImg1 }, |
| | | { name: '飞行里程', value: 0, img: flyImg2 }, |
| | | // { name: '任务成果', value: 0, img: flyImg3 }, |
| | | ]); |
| | | // 飞行统计 |
| | | const getFlyList = () => { |
| | | getFly(params.value).then(res => { |
| | | flyTypeList.value = flyTypeList.value.map(item => ({ |
| | | ...item, |
| | | value: res.data.data[keyMapping[item.name]] || 0, |
| | | })); |
| | | }); |
| | | }; |
| | | const getFlyTimeList = () => { |
| | | getFlyTime(params.value).then(res => { |
| | | const resList = res?.data?.data || []; |
| | | lineCharts(resList); |
| | | }); |
| | | }; |
| | | let timeClick = (item, index) => { |
| | | checked.value = item; |
| | | params.value.date_enum = item; |
| | | dateSelect.value = item; |
| | | getFlyList(); |
| | | getFlyTimeList(); |
| | | }; |
| | | // 折线/柱状图 |
| | | const lineCharts = bardata => { |
| | | const categories = bardata?.map(item => item.name); // x轴类别 |
| | | const flight_distance = []; |
| | | const flight_time = []; |
| | | const event_num = []; |
| | | // /遍历数据填充各系列 |
| | | bardata?.forEach(period => { |
| | | let hasDuration = false, |
| | | hasDistance = false, |
| | | hasResult = false; |
| | | |
| | | period.data?.forEach(item => { |
| | | switch (item.name) { |
| | | case '飞行时长': |
| | | flight_time.push(parseFloat(item.value) || 0); |
| | | hasDuration = true; |
| | | break; |
| | | case '飞行里程': |
| | | // 转换为万公 (假设原始单位是米) |
| | | // flight_distance.push((parseFloat(item.value) / 10 || 0)); |
| | | flight_distance.push(parseFloat(item.value) || 0); |
| | | hasDistance = true; |
| | | break; |
| | | } |
| | | }); |
| | | |
| | | // 处理可能缺失的数据项 |
| | | if (!hasDuration) flight_time.push(0); |
| | | if (!hasDistance) flight_distance.push(0); |
| | | |
| | | }); |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'item', |
| | | axisPointer: { |
| | | type: 'shadow', |
| | | }, |
| | | }, |
| | | grid: { |
| | | left: '2%', |
| | | right: '4%', |
| | | bottom: '14%', |
| | | top: '16%', |
| | | containLabel: true, |
| | | }, |
| | | legend: { |
| | | data: ['飞行时长', '飞行里程'], |
| | | left: 'center', |
| | | top: '5%', |
| | | color: '#383838', // 直接配置颜色 |
| | | itemWidth: 15, |
| | | itemHeight: 10, |
| | | itemGap: 25, |
| | | fontSize: '1.2rem', |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: categories, |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | interval: 0, |
| | | color: '#383838', |
| | | }, |
| | | }, |
| | | yAxis: [ |
| | | { |
| | | type: 'log', |
| | | name: '单位:小时', |
| | | nameTextStyle: { |
| | | color: '#383838', |
| | | fontSize: '1.2rem', |
| | | }, |
| | | min: 1, |
| | | logBase: 3, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | color: '#cdd5e2', |
| | | width: 1, |
| | | opacity: 0.5, |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | color: '#666666', // 直接配置颜色 |
| | | }, |
| | | }, |
| | | { |
| | | type: 'log', |
| | | name: '单位:公里', |
| | | nameTextStyle: { |
| | | color: '#383838', |
| | | }, |
| | | min: 1, |
| | | logBase: 3, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | color: '#cdd5e2', |
| | | width: 1, |
| | | opacity: 0.5, |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | color: '#383838', // 直接配置颜色 |
| | | }, |
| | | }, |
| | | ], |
| | | series: [ |
| | | { |
| | | name: '飞行时长', |
| | | type: 'bar', |
| | | barWidth: '8px', |
| | | itemStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: '#91C1FF' }, |
| | | { offset: 1, color: '#2970FF' }, |
| | | ]), |
| | | borderRadius: 4, |
| | | }, |
| | | data: flight_time, |
| | | }, |
| | | |
| | | { |
| | | name: '飞行里程', |
| | | type: 'line', |
| | | yAxisIndex: 1, |
| | | smooth: true, |
| | | itemStyle: { |
| | | color: '#01D0A7', |
| | | }, |
| | | lineStyle: { |
| | | width: 2, |
| | | type: 'solid', |
| | | }, |
| | | symbol: 'circle', |
| | | symbolSize: 6, |
| | | lineStyle: { |
| | | color: '#01D0A7', |
| | | }, |
| | | data: flight_distance, |
| | | }, |
| | | ], |
| | | }; |
| | | lineChart.value.setOption(option); |
| | | }; |
| | | onMounted(() => { |
| | | lineCharts(); |
| | | getFlyList(); |
| | | getFlyTimeList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | // 飞行统计 |
| | | .flyOrder { |
| | | border-radius: 8px 8px 8px 8px; |
| | | padding: 4px 14px 0 15px; |
| | | background: #ffffff !important; |
| | | margin-top: 5px; |
| | | height: 100%; |
| | | |
| | | .fytitle { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .cardtotal { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-left: 9px; |
| | | img { |
| | | width: 17px; |
| | | height: 17px; |
| | | margin-left: 6px; |
| | | cursor: pointer; |
| | | } |
| | | p { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #363636; |
| | | } |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .total-number { |
| | | font-family: 'Source Han Sans CN'; |
| | | |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | color: #2a54ff; |
| | | } |
| | | } |
| | | img { |
| | | width: 39px; |
| | | height: 38px; |
| | | } |
| | | |
| | | span { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #363636; |
| | | } |
| | | } |
| | | |
| | | .flycenter { |
| | | margin-top: 13px; |
| | | |
| | | .centerBox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | |
| | | .centerItem { |
| | | padding: 7px 7px 0 15px; |
| | | width: 196px; |
| | | flex: 1; |
| | | // height: 80px; |
| | | height: pxToVh(80); |
| | | background: #f6f8fe; |
| | | box-shadow: 0px 5px 4px 0px #ebf1ff; |
| | | border-radius: 8px 8px 8px 8px; |
| | | border: 1px solid #ffffff; |
| | | margin-right: 16px; |
| | | |
| | | img { |
| | | width: 15px; |
| | | height: 15px; |
| | | margin-right: 5px; |
| | | } |
| | | |
| | | .flyimg { |
| | | display: flex; |
| | | align-items: center; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .flydata { |
| | | margin-top: 10px; |
| | | text-align: right; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | |
| | | span { |
| | | font-weight: bold; |
| | | font-size: 24px; |
| | | color: #343434; |
| | | margin-right: 6px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .lineChart { |
| | | height: 209px; |
| | | width: 100%; |
| | | |
| | | .lineBox { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .time-card { |
| | | text-align: center; |
| | | // height: 30px; |
| | | height: pxToVh(30); |
| | | background: #ffffff; |
| | | |
| | | border: 1px solid #e5e5e5; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | display: flex; |
| | | width: 282px; |
| | | margin-left: 15px; |
| | | border-radius: 4px; |
| | | |
| | | .card-item { |
| | | width: 94px; |
| | | height: 100%; |
| | | line-height: 28px; |
| | | cursor: pointer; |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .card-item:first-child { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | |
| | | .card-item:nth-child(2) { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | |
| | | .card-item.active { |
| | | color: #1441ff; |
| | | border: 1px solid #1c5cff; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <div class="machineNest"> |
| | | <div class="nestTop"> |
| | | <div class="card-title"> |
| | | <img :src="jc1" alt="" /> |
| | | |
| | | <div class="cardtotal"> |
| | | <p>机巢工单数量排名</p> |
| | | <img @click="refresh" src="/src/assets/images/workbench/st1.png" alt="" /> |
| | | </div> |
| | | <div class="time-card"> |
| | | <div |
| | | class="card-item" |
| | | :class="item === checked ? 'active' : ''" |
| | | v-for="(item, index) in timeListEnum" |
| | | :key="index" |
| | | @click="timeClick(item, index)" |
| | | > |
| | | {{ timeListStr[index] }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="nestCenter"> |
| | |
| | | import jc2 from '@/assets/images/workbench/jc2.png'; |
| | | import { industryJobNumPieChart } from '@/api/home/index'; |
| | | import { nextTick } from 'vue'; |
| | | |
| | | let checked = ref('CURRENT_YEAR'); |
| | | let timeListStr = ['本周', '本月', '本年']; |
| | | let timeListEnum = ['CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR']; |
| | | const params = ref({ |
| | | date_enum: 'CURRENT_YEAR', |
| | | device_sn: '', |
| | | end_date: undefined, |
| | | start_date: undefined, |
| | | }); |
| | | const dateSelect = ref('CURRENT_YEAR'); |
| | | const echartsRef = ref(null); |
| | | let { chart: jcchart } = useEchartsResize(echartsRef); |
| | | const jcOrder = ref([]); |
| | |
| | | type: String, |
| | | }, |
| | | }); |
| | | const params = reactive({ |
| | | date_enum: props.dateSelect, |
| | | }); |
| | | const refresh = () => { |
| | | params.value.date_enum = 'CURRENT_YEAR'; |
| | | checked.value = 'CURRENT_YEAR'; |
| | | dateSelect.value = 'CURRENT_YEAR'; |
| | | getIndustryJobNumPieChart(); |
| | | }; |
| | | let timeClick = (item, index) => { |
| | | checked.value = item; |
| | | params.value.date_enum = item; |
| | | dateSelect.value = item; |
| | | getIndustryJobNumPieChart(); |
| | | }; |
| | | // 空数据计算 |
| | | const isEmptyData = computed(() => { |
| | | return jcOrder.value.length === 0 || |
| | |
| | | } |
| | | // 获取机巢事件数据 |
| | | const getIndustryJobNumPieChart = () => { |
| | | industryJobNumPieChart(params).then(res => { |
| | | industryJobNumPieChart(params.value).then(res => { |
| | | const resList = res?.data?.data || []; |
| | | jcOrder.value = resList; |
| | | nextTick(() => { |
| | |
| | | |
| | | <style scoped lang="scss"> |
| | | .machineNest { |
| | | width: 100%; |
| | | width: 93%; |
| | | margin-left: 10px; |
| | | height: pxToVh(355); |
| | | border-radius: 8px 8px 8px 8px; |
| | | padding: 4px 14px 0 15px; |
| | | background: #ffffff !important; |
| | | .custom-text { |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | .nestTop { |
| | | .card-title { |
| | | .card-title { |
| | | display: flex; |
| | | margin-bottom: 10px; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .cardtotal { |
| | | display: flex; |
| | | margin-left: 57px; |
| | | margin-bottom: 15px; |
| | | align-items: center; |
| | | margin-left: 9px; |
| | | img { |
| | | width: 36px; |
| | | height: 40px; |
| | | width: 17px; |
| | | height: 17px; |
| | | margin-left: 6px; |
| | | cursor: pointer; |
| | | } |
| | | p { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #363636; |
| | | } |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .total-number { |
| | | font-family: 'Source Han Sans CN'; |
| | | |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | color: #2a54ff; |
| | | } |
| | | } |
| | | |
| | | img { |
| | | width: 36px; |
| | | height: 40px; |
| | | } |
| | | } |
| | | .cardtotal { |
| | | display: flex; |
| | | align-items: center; |
| | |
| | | .nestCenter { |
| | | width: 100%; |
| | | // height: 600px; |
| | | height: pxToVh(600); |
| | | height: pxToVh(266); |
| | | .chart { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | } |
| | | .time-card { |
| | | text-align: center; |
| | | // height: 30px; |
| | | height: pxToVh(30); |
| | | background: #ffffff; |
| | | |
| | | border: 1px solid #e5e5e5; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | display: flex; |
| | | width: 282px; |
| | | margin-left: 15px; |
| | | border-radius: 4px; |
| | | |
| | | .card-item { |
| | | width: 94px; |
| | | height: 100%; |
| | | line-height: 28px; |
| | | cursor: pointer; |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .card-item:first-child { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | |
| | | .card-item:nth-child(2) { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | |
| | | .card-item.active { |
| | | color: #1441ff; |
| | | border: 1px solid #1c5cff; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="workOrder"> |
| | | <div class="card-title"> |
| | | <div class="cardtotal"> |
| | | <p>工单统计占比</p> |
| | | <img @click="refresh" src="/src/assets/images/workbench/st1.png" alt="" /> |
| | | </div> |
| | | <div class="time-card"> |
| | | <div |
| | | class="card-item" |
| | | :class="item === checked ? 'active' : ''" |
| | | v-for="(item, index) in timeListEnum" |
| | | :key="index" |
| | | @click="timeClick(item, index)" |
| | | > |
| | | {{ timeListStr[index] }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="workorderbox"> |
| | | <div class="card-group"> |
| | | <div class="main-card"> |
| | | <div class="status-grid"> |
| | | <div class="status-item" v-for="(item, index) in eventTypeList" :key="index"> |
| | | <div class="statusCon"> |
| | | <div class="status-label">{{ item.name }}</div> |
| | | <div class="status-value">{{ item.value }}<span>个</span></div> |
| | | <div class="ratio"> |
| | | 占比 |
| | | <span :style="{ color: item.color }" |
| | | >{{ ((item.rate * 100) / 100).toFixed(2) }}%</span |
| | | > |
| | | </div> |
| | | </div> |
| | | <img :src="item.img" alt="" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="charts"> |
| | | <div class="chart" ref="echartsRef"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import useEchartsResize from '@/hooks/useEchartsResize'; |
| | | import { getJobEventByStatus } from '@/api/home/index'; |
| | | import overviewImg2 from '@/assets/images/workbench/tc2.svg'; |
| | | import overviewImg3 from '@/assets/images/workbench/tc3.svg'; |
| | | import overviewImg4 from '@/assets/images/workbench/tc4.svg'; |
| | | import overviewImg5 from '@/assets/images/workbench/tc5.svg'; |
| | | let checked = ref('CURRENT_YEAR'); |
| | | let timeListStr = ['本周', '本月', '本年']; |
| | | let timeListEnum = ['CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR']; |
| | | const params = ref({ |
| | | date_enum: 'CURRENT_YEAR', |
| | | device_sn: '', |
| | | end_date: undefined, |
| | | start_date: undefined, |
| | | }); |
| | | const dateSelect = ref('CURRENT_YEAR'); |
| | | const eventTypeList = ref([ |
| | | { name: '待审核', value: 0, img: overviewImg2, color: '#FF472F', status: '2', rate: 0 }, |
| | | { name: '待处理', value: 0, img: overviewImg3, color: '#FF7411', status: '0', rate: 0 }, |
| | | { name: '处理中', value: 0, img: overviewImg4, color: '#FFC300', status: '3', rate: 0 }, |
| | | { name: '已完成', value: 0, img: overviewImg5, color: '#0291A1', status: '4', rate: 0 }, |
| | | ]); |
| | | // 工单统计 |
| | | const getTypeData = () => { |
| | | getJobEventByStatus(params.value).then(res => { |
| | | const resList = res?.data?.data || []; |
| | | |
| | | resList.forEach(item => { |
| | | eventTypeList.value.forEach(item1 => { |
| | | if (item1.name === item.name) { |
| | | item1.value = item.num; |
| | | item1.rate = item.rate; |
| | | } |
| | | }); |
| | | }); |
| | | initChart(resList); |
| | | }); |
| | | }; |
| | | const refresh = () => { |
| | | params.value.date_enum = 'CURRENT_YEAR'; |
| | | checked.value = 'CURRENT_YEAR'; |
| | | dateSelect.value = 'CURRENT_YEAR'; |
| | | getTypeData(); |
| | | }; |
| | | |
| | | let timeClick = (item, index) => { |
| | | checked.value = item; |
| | | params.value.date_enum = item; |
| | | dateSelect.value = item; |
| | | getTypeData(); |
| | | }; |
| | | // 图表 |
| | | const echartsRef = ref(null); |
| | | let { chart } = useEchartsResize(echartsRef); |
| | | const initChart = val => { |
| | | const totalNum = val.reduce((sum, item) => sum + item.num, 0); |
| | | const data = { |
| | | total: { |
| | | title: '总计', |
| | | figure: totalNum.toString(), // 动态计算总数 |
| | | }, |
| | | data: val.map(item => ({ |
| | | value: item.num, |
| | | name: item.name, |
| | | rate: item.rate, |
| | | })), |
| | | }; |
| | | const containerWidth = chart.value.clientWidth; |
| | | const isSmallScreen = containerWidth < 768; // 移动端判断 |
| | | const echartsOption = { |
| | | color: ['#FF472F', '#FF7411', '#FFC300', '#0291A1'], |
| | | tooltip: { |
| | | trigger: 'item', |
| | | padding: 0, |
| | | borderWidth: 0, |
| | | formatter: params => { |
| | | return `<div style="background-color: rgba($color: #FFFFFF, $alpha: 0.95); |
| | | box-shadow: 0 0.4rem 0.9rem 0 rgba($color: #000000, $alpha: 0.1); |
| | | padding:0 1.2rem; |
| | | display: flex; |
| | | align-items: center; |
| | | border-radius: 0.4rem; |
| | | font-size: 1.2rem;" class="tooltip-area"> |
| | | <p>${params.marker}${params.name}</p> |
| | | <h4 style="margin-left: 1rem;">${params.data.rate || params.percent}%</h4> |
| | | </div>`; |
| | | }, |
| | | }, |
| | | legend: { |
| | | show: false, |
| | | }, |
| | | title: { |
| | | text: data.total.title, |
| | | textStyle: { |
| | | color: 'rgba(28, 31, 35, 0.80)', |
| | | fontSize: '1.2rem', |
| | | fontWeight: 'bold', |
| | | }, |
| | | subtext: data.total.figure, |
| | | subtextStyle: { |
| | | color: '#1C1F23', |
| | | fontSize: '2rem', |
| | | fontWeight: '600', |
| | | }, |
| | | top: '40%', |
| | | left: '48%', |
| | | textAlign: 'center', // 文本对齐 |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '', |
| | | type: 'pie', |
| | | radius: ['55%', '83%'], |
| | | |
| | | label: { |
| | | show: false, |
| | | }, |
| | | labelLine: { |
| | | show: false, |
| | | length: 3, // 调整引导线长度 |
| | | length2: 5, |
| | | lineStyle: { |
| | | cap: 'round', |
| | | }, |
| | | minTurnAngle: 45, // 防止小角度重叠 |
| | | }, |
| | | data: data.data, |
| | | }, |
| | | ], |
| | | }; |
| | | |
| | | chart.value.setOption(echartsOption); |
| | | }; |
| | | onMounted(() => { |
| | | getTypeData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .workOrder { |
| | | border-radius: 8px 8px 8px 8px; |
| | | padding: 4px 14px 0 15px; |
| | | background: #ffffff !important; |
| | | // height: 315px; |
| | | height: pxToVh(355); |
| | | margin-bottom: 10px; |
| | | .card-title { |
| | | display: flex; |
| | | margin-bottom: 10px; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .cardtotal { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-left: 9px; |
| | | img { |
| | | width: 17px; |
| | | height: 17px; |
| | | margin-left: 6px; |
| | | cursor: pointer; |
| | | } |
| | | p { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #363636; |
| | | } |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .total-number { |
| | | font-family: 'Source Han Sans CN'; |
| | | |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | color: #2a54ff; |
| | | } |
| | | } |
| | | |
| | | img { |
| | | width: 36px; |
| | | height: 40px; |
| | | } |
| | | } |
| | | .workorderbox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | .card-group { |
| | | width: 60%; |
| | | |
| | | .status-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(2, 1fr); |
| | | // row-gap: 19px; |
| | | // gap: 10px; |
| | | |
| | | // padding-bottom: 5px; |
| | | |
| | | .status-item { |
| | | display: flex; |
| | | text-align: center; |
| | | justify-content: space-between; |
| | | // height: 97px; |
| | | height: pxToVh(107); |
| | | // max-width: 158px; |
| | | margin-bottom: 19px; |
| | | margin-right: 14px; |
| | | width: 144px; |
| | | background: #f6f8fe; |
| | | border-radius: 8px 8px 8px 8px; |
| | | |
| | | img { |
| | | width: 26px; |
| | | height: 26px; |
| | | padding: 9px 10px 9px 2px; |
| | | } |
| | | |
| | | .statusCon { |
| | | display: flex; |
| | | flex-direction: column; |
| | | // align-items: center; |
| | | padding: 5px 4px 9px 10px; |
| | | text-align: left; |
| | | |
| | | .status-label { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | text-align: left; |
| | | color: #383838; |
| | | } |
| | | |
| | | .ratio { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #363636; |
| | | white-space: nowrap; |
| | | text-align: left; |
| | | } |
| | | |
| | | .status-value { |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: bold; |
| | | font-size: 30px; |
| | | color: #363636; |
| | | // margin: 5px 0; |
| | | // font-style: italic; |
| | | display: inline-block; |
| | | transform: skewX(-5deg); |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .charts { |
| | | margin-top: 20px; |
| | | width: 40%; |
| | | height: auto; |
| | | |
| | | .chart { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .time-card { |
| | | text-align: center; |
| | | // height: 30px; |
| | | height: pxToVh(30); |
| | | background: #ffffff; |
| | | |
| | | border: 1px solid #e5e5e5; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | display: flex; |
| | | width: 282px; |
| | | margin-left: 15px; |
| | | border-radius: 4px; |
| | | |
| | | .card-item { |
| | | width: 94px; |
| | | height: 100%; |
| | | line-height: 28px; |
| | | cursor: pointer; |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .card-item:first-child { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | |
| | | .card-item:nth-child(2) { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | |
| | | .card-item.active { |
| | | color: #1441ff; |
| | | border: 1px solid #1c5cff; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="taskOutcome"> |
| | | <div class="card-title"> |
| | | <div class="cardtotal"> |
| | | <p>任务成果</p> |
| | | <span class="total-number">1856</span> |
| | | <p>个</p> |
| | | <img @click="refresh" src="/src/assets/images/workbench/st1.png" alt="" /> |
| | | </div> |
| | | <div class="time-card"> |
| | | <div |
| | | class="card-item" |
| | | :class="item === checked ? 'active' : ''" |
| | | v-for="(item, index) in timeListEnum" |
| | | :key="index" |
| | | @click="timeClick(item, index)" |
| | | > |
| | | {{ timeListStr[index] }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup > |
| | | let checked = ref('CURRENT_YEAR'); |
| | | let timeListStr = ['本周', '本月', '本年']; |
| | | let timeListEnum = ['CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR']; |
| | | const params = ref({ |
| | | date_enum: 'CURRENT_YEAR', |
| | | device_sn: '', |
| | | end_date: undefined, |
| | | start_date: undefined, |
| | | }); |
| | | const dateSelect = ref('CURRENT_YEAR'); |
| | | |
| | | let timeClick = (item, index) => { |
| | | checked.value = item; |
| | | params.value.date_enum = item; |
| | | dateSelect.value = item; |
| | | |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .taskOutcome { |
| | | border-radius: 8px 8px 8px 8px; |
| | | padding: 4px 14px 0 15px; |
| | | background: #ffffff !important; |
| | | margin-top: 10px; |
| | | margin-left: 10px; |
| | | height: 100%; |
| | | .card-title { |
| | | display: flex; |
| | | margin-bottom: 10px; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .cardtotal { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-left: 9px; |
| | | img { |
| | | width: 17px; |
| | | height: 17px; |
| | | margin-left: 6px; |
| | | cursor: pointer; |
| | | } |
| | | p { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #363636; |
| | | } |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .total-number { |
| | | font-family: 'Source Han Sans CN'; |
| | | |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | color: #2a54ff; |
| | | } |
| | | } |
| | | |
| | | img { |
| | | width: 36px; |
| | | height: 40px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .time-card { |
| | | text-align: center; |
| | | // height: 30px; |
| | | height: pxToVh(30); |
| | | background: #ffffff; |
| | | |
| | | border: 1px solid #e5e5e5; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | display: flex; |
| | | width: 282px; |
| | | margin-left: 15px; |
| | | border-radius: 4px; |
| | | |
| | | .card-item { |
| | | width: 94px; |
| | | height: 100%; |
| | | line-height: 28px; |
| | | cursor: pointer; |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .card-item:first-child { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | |
| | | .card-item:nth-child(2) { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | |
| | | .card-item.active { |
| | | color: #1441ff; |
| | | border: 1px solid #1c5cff; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <!-- 综合统计分析 --> |
| | | <div class="comprehensiveCon"> |
| | | <div class="comprehensive"> |
| | | <div class="title"> |
| | | <div class="name"> |
| | | <span> 综合统计分析</span> |
| | | <img @click="refresh" src="/src/assets/images/workbench/st1.png" alt="" /> |
| | | <div class="time-card"> |
| | | <div class="card-item" :class="item === checked ? 'active' : ''" v-for="(item, index) in timeListEnum" |
| | | :key="index" @click="timeClick(item, index)"> |
| | | {{ timeListStr[index] }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="arrow" @click="jumpshebei"> |
| | | <img src="/src/assets/images/workbench/st2.png" alt="" /> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="center"> |
| | | <div class="centerLeft"> |
| | | <!-- 工单统计 --> |
| | | <div class="workOrder"> |
| | | <div class="card-group"> |
| | | <div class="main-card"> |
| | | <div class="card-title"> |
| | | <img :src="overviewImg1" alt="" /> |
| | | <div class="cardtotal"> |
| | | <p>工单统计占比</p> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="status-grid"> |
| | | <div class="status-item" v-for="(item, index) in eventTypeList" :key="index"> |
| | | <div class="statusCon"> |
| | | <div class="status-label">{{ item.name }}</div> |
| | | <div class="status-value">{{ item.value }}<span>个</span></div> |
| | | <div class="ratio"> |
| | | 占比 |
| | | <span :style="{ color: item.color }">{{ ((item.rate * 100) / 100).toFixed(2) }}%</span> |
| | | </div> |
| | | </div> |
| | | <img :src="item.img" alt="" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="charts"> |
| | | <div class="chart" ref="echartsRef"></div> |
| | | </div> |
| | | </div> |
| | | <proportionStatic></proportionStatic> |
| | | <!-- 飞行统计 --> |
| | | <div class="flyOrder"> |
| | | <div class="fytitle"> |
| | | <img :src="fy1" alt="" /> |
| | | <span>飞行统计</span> |
| | | </div> |
| | | <div class="flycenter"> |
| | | <div class="centerBox"> |
| | | <div class="centerItem" v-for="(itemfly, index) in flyTypeList" :key="index"> |
| | | <div class="flyimg"><img :src="itemfly.img" alt="" />{{ itemfly.name }}</div> |
| | | <div class="flydata"> |
| | | <span>{{ itemfly.value }}</span>{{ unitMap[itemfly.name] }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="lineChart"> |
| | | <div class="lineBox" ref="chartRef"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <flightStatistics></flightStatistics> |
| | | |
| | | </div> |
| | | <div class="centerRight"> |
| | | <flyratio :dateSelect="dateSelect"></flyratio> |
| | | <!-- 机巢工单数量排名(件) --> |
| | | <flyratio></flyratio> |
| | | <!-- 任务成果 --> |
| | | <taskOutcome></taskOutcome> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import taskOutcome from './components/taskOutcome.vue' |
| | | import flightStatistics from './components/flightStatistics.vue' |
| | | import proportionStatic from './components/proportionStatic.vue' |
| | | import flyratio from './components/flyratio.vue' |
| | | import Bocklog from './components/backlog.vue' |
| | | import CalenBox from './components/calendarBox.vue' |
| | |
| | | import { mapGetters } from 'vuex' |
| | | import { getJobEventByStatus, getJobEventTotal, getFly, getFlyTime } from '@/api/home/index' |
| | | import overviewImg1 from '@/assets/images/workbench/tc1.png' |
| | | import overviewImg2 from '@/assets/images/workbench/tc2.svg' |
| | | import overviewImg3 from '@/assets/images/workbench/tc3.svg' |
| | | import overviewImg4 from '@/assets/images/workbench/tc4.svg' |
| | | import overviewImg5 from '@/assets/images/workbench/tc5.svg' |
| | | |
| | | import fy1 from '@/assets/images/workbench/fy1.png' |
| | | import flyImg1 from '@/assets/images/workbench/fy2.svg' |
| | | import flyImg2 from '@/assets/images/workbench/fy3.svg' |
| | | import flyImg3 from '@/assets/images/workbench/fy4.svg' |
| | | |
| | | import statistics from './components/statistics.vue' |
| | | import { ElMessage } from 'element-plus' |
| | | let checked = ref('CURRENT_YEAR') |
| | |
| | | checked.value = item |
| | | params.value.date_enum = item |
| | | dateSelect.value = item |
| | | getTypeData() |
| | | getFlyList() |
| | | getFlyTimeList() |
| | | |
| | | |
| | | |
| | | } |
| | | const refresh = () => { |
| | | params.value.date_enum = 'CURRENT_YEAR' |
| | | checked.value = 'CURRENT_YEAR' |
| | | dateSelect.value = 'CURRENT_YEAR' |
| | | getTypeData() |
| | | getFlyList() |
| | | getFlyTimeList() |
| | | |
| | | |
| | | } |
| | | // 跳转 |
| | | const jumpshebei = () => { |
| | | ElMessage.warning('加急开发中...') |
| | | } |
| | | |
| | | const eventTypeList = ref([ |
| | | { name: '待审核', value: 0, img: overviewImg2, color: '#FF472F', status: '2', rate: 0 }, |
| | | { name: '待处理', value: 0, img: overviewImg3, color: '#FF7411', status: '0', rate: 0 }, |
| | | { name: '处理中', value: 0, img: overviewImg4, color: '#FFC300', status: '3', rate: 0 }, |
| | | { name: '已完成', value: 0, img: overviewImg5, color: '#0291A1', status: '4', rate: 0 }, |
| | | ]) |
| | | const keyMapping = { |
| | | 飞行时长: 'total_flight_time', |
| | | 飞行里程: 'total_flight_distance', |
| | | 任务成果: 'event_num', |
| | | } |
| | | const unitMap = { |
| | | 飞行时长: '时', |
| | | 飞行里程: '千米', |
| | | 任务成果: '个', |
| | | } |
| | | const flyTypeList = ref([ |
| | | { name: '飞行时长', value: 0, img: flyImg1 }, |
| | | { name: '飞行里程', value: 0, img: flyImg2 }, |
| | | { name: '任务成果', value: 0, img: flyImg3 }, |
| | | ]) |
| | | |
| | | const eventTotal = ref(0) |
| | | const data = ref([]) |
| | | // 工单统计 |
| | | const getTypeData = () => { |
| | | getJobEventByStatus(params.value).then(res => { |
| | | const resList = res?.data?.data || [] |
| | | |
| | | resList.forEach(item => { |
| | | eventTypeList.value.forEach(item1 => { |
| | | if (item1.name === item.name) { |
| | | item1.value = item.num |
| | | item1.rate = item.rate |
| | | } |
| | | }) |
| | | }) |
| | | initChart(resList) |
| | | }) |
| | | } |
| | | // 飞行统计 |
| | | const getFlyList = () => { |
| | | getFly(params.value).then(res => { |
| | | flyTypeList.value = flyTypeList.value.map(item => ({ |
| | | ...item, |
| | | value: res.data.data[keyMapping[item.name]] || 0, |
| | | })) |
| | | }) |
| | | } |
| | | const getFlyTimeList = () => { |
| | | getFlyTime(params.value).then(res => { |
| | | const resList = res?.data?.data || [] |
| | | lineCharts(resList) |
| | | }) |
| | | } |
| | | // 图表 |
| | | const echartsRef = ref(null) |
| | | let { chart } = useEchartsResize(echartsRef) |
| | | const chartRef = ref(null) |
| | | let { chart: lineChart } = useEchartsResize(chartRef) |
| | | const initChart = val => { |
| | | const totalNum = val.reduce((sum, item) => sum + item.num, 0) |
| | | const data = { |
| | | total: { |
| | | title: '总计', |
| | | figure: totalNum.toString(), // 动态计算总数 |
| | | }, |
| | | data: val.map(item => ({ |
| | | value: item.num, |
| | | name: item.name, |
| | | rate: item.rate, |
| | | })), |
| | | } |
| | | const containerWidth = chart.value.clientWidth |
| | | const isSmallScreen = containerWidth < 768 // 移动端判断 |
| | | const echartsOption = { |
| | | color: ['#FF472F', '#FF7411', '#FFC300', '#0291A1'], |
| | | tooltip: { |
| | | trigger: 'item', |
| | | padding: 0, |
| | | borderWidth: 0, |
| | | formatter: params => { |
| | | return `<div style="background-color: rgba($color: #FFFFFF, $alpha: 0.95); |
| | | box-shadow: 0 0.4rem 0.9rem 0 rgba($color: #000000, $alpha: 0.1); |
| | | padding:0 1.2rem; |
| | | display: flex; |
| | | align-items: center; |
| | | border-radius: 0.4rem; |
| | | font-size: 1.2rem;" class="tooltip-area"> |
| | | <p>${params.marker}${params.name}</p> |
| | | <h4 style="margin-left: 1rem;">${params.data.rate || params.percent}%</h4> |
| | | </div>` |
| | | }, |
| | | }, |
| | | legend: { |
| | | show: false, |
| | | }, |
| | | title: { |
| | | text: data.total.title, |
| | | textStyle: { |
| | | color: 'rgba(28, 31, 35, 0.80)', |
| | | fontSize: '1.2rem', |
| | | fontWeight: 'bold', |
| | | }, |
| | | subtext: data.total.figure, |
| | | subtextStyle: { |
| | | color: '#1C1F23', |
| | | fontSize: '2rem', |
| | | fontWeight: '600', |
| | | }, |
| | | top: '40%', |
| | | left: '48%', |
| | | textAlign: 'center', // 文本对齐 |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '', |
| | | type: 'pie', |
| | | radius: ['43%', '63%'], |
| | | avoidLabelOverlap: true, |
| | | left: '-2%', |
| | | label: { |
| | | formatter: params => { |
| | | // 使用 b 样式标记包裹百分比数值 |
| | | return `{a|${params.name}}: {b|${params.data.rate}%}` |
| | | }, |
| | | fontSize: isSmallScreen ? '0.8rem' : '1.2rem', |
| | | position: isSmallScreen ? 'outer' : 'outer', |
| | | alignTo: 'labelLine', |
| | | overflow: 'truncate', |
| | | overflow: 'none', // 禁用省略号 |
| | | bleedMargin: 30, // 防止标签被截断 |
| | | rich: { |
| | | a: { |
| | | color: 'rgba(28, 31, 35, 0.80)', |
| | | fontSize: isSmallScreen ? '1rem' : '1.2rem', |
| | | }, |
| | | b: { |
| | | color: '#1C1F23', |
| | | fontSize: isSmallScreen ? '1rem' : '1.3rem', |
| | | fontWeight: 'bold', |
| | | }, |
| | | }, |
| | | }, |
| | | labelLine: { |
| | | show: true, |
| | | length: 3, // 调整引导线长度 |
| | | length2: 5, |
| | | lineStyle: { |
| | | cap: 'round', |
| | | }, |
| | | minTurnAngle: 45, // 防止小角度重叠 |
| | | }, |
| | | data: data.data, |
| | | }, |
| | | ], |
| | | } |
| | | |
| | | chart.value.setOption(echartsOption) |
| | | } |
| | | |
| | | // 折线/柱状图 |
| | | const lineCharts = bardata => { |
| | | const categories = bardata?.map(item => item.name) // x轴类别 |
| | | const flight_distance = [] |
| | | const flight_time = [] |
| | | const event_num = [] |
| | | // /遍历数据填充各系列 |
| | | bardata?.forEach(period => { |
| | | let hasDuration = false, |
| | | hasDistance = false, |
| | | hasResult = false |
| | | |
| | | period.data?.forEach(item => { |
| | | switch (item.name) { |
| | | case '飞行时长': |
| | | flight_time.push(parseFloat(item.value) || 0) |
| | | hasDuration = true |
| | | break |
| | | case '飞行里程': |
| | | // 转换为万公 (假设原始单位是米) |
| | | // flight_distance.push((parseFloat(item.value) / 10 || 0)); |
| | | flight_distance.push(parseFloat(item.value) || 0) |
| | | hasDistance = true |
| | | break |
| | | case '任务成果': |
| | | event_num.push(Number(item.value) || 0) |
| | | hasResult = true |
| | | break |
| | | } |
| | | }) |
| | | |
| | | // 处理可能缺失的数据项 |
| | | if (!hasDuration) flight_time.push(0) |
| | | if (!hasDistance) flight_distance.push(0) |
| | | if (!hasResult) event_num.push(0) |
| | | }) |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'item', |
| | | axisPointer: { |
| | | type: 'shadow', |
| | | }, |
| | | }, |
| | | grid: { |
| | | left: '2%', |
| | | right: '4%', |
| | | bottom: '14%', |
| | | top: '16%', |
| | | containLabel: true, |
| | | }, |
| | | legend: { |
| | | data: ['飞行时长', '飞行里程', '任务成果'], |
| | | left: 'center', |
| | | top: '5%', |
| | | color: '#383838', // 直接配置颜色 |
| | | itemWidth: 15, |
| | | itemHeight: 10, |
| | | itemGap: 25, |
| | | fontSize: '1.2rem' |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: categories, |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | interval: 0, |
| | | color: '#383838', |
| | | }, |
| | | }, |
| | | yAxis: [ |
| | | { |
| | | type: 'log', |
| | | name: '单位:万', |
| | | nameTextStyle: { |
| | | color: '#383838', |
| | | fontSize: '1.2rem' |
| | | }, |
| | | min: 1, |
| | | logBase: 3, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | color: '#cdd5e2', |
| | | width: 1, |
| | | opacity: 0.5, |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | color: '#666666', // 直接配置颜色 |
| | | }, |
| | | }, |
| | | { |
| | | type: 'log', |
| | | name: '', |
| | | nameTextStyle: { |
| | | color: '#383838', |
| | | }, |
| | | min: 1, |
| | | logBase: 3, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | color: '#cdd5e2', |
| | | width: 1, |
| | | opacity: 0.5, |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | color: '#383838', // 直接配置颜色 |
| | | }, |
| | | }, |
| | | ], |
| | | series: [ |
| | | { |
| | | name: '飞行时长', |
| | | type: 'bar', |
| | | barWidth: '8px', |
| | | itemStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: '#29acff' }, |
| | | { offset: 1, color: '#4bdfff' }, |
| | | ]), |
| | | borderRadius: 6, |
| | | }, |
| | | data: flight_time, |
| | | }, |
| | | { |
| | | name: '飞行里程', |
| | | type: 'bar', |
| | | barWidth: '8px', |
| | | itemStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: '#01c871' }, |
| | | { offset: 1, color: '#55f49c' }, |
| | | ]), |
| | | borderRadius: 6, |
| | | }, |
| | | data: flight_distance, |
| | | }, |
| | | |
| | | { |
| | | name: '任务成果', |
| | | type: 'line', |
| | | yAxisIndex: 1, |
| | | smooth: true, |
| | | // itemStyle: { |
| | | // color: '#ffa43a', // 默认状态颜色 |
| | | // borderColor: 'rgba(255, 234, 0, 0.5)', |
| | | // borderWidth: 5, |
| | | // }, |
| | | // emphasis: { |
| | | // // 悬停状态 |
| | | // itemStyle: { |
| | | // color: '#ff8c00', // 悬停时颜色变深 |
| | | // borderWidth: 6, |
| | | // }, |
| | | // }, |
| | | lineStyle: { |
| | | color: 'rgba(52, 146, 242, 1)', |
| | | }, |
| | | data: event_num, |
| | | }, |
| | | ], |
| | | } |
| | | lineChart.value.setOption(option) |
| | | } |
| | | onMounted(() => { |
| | | getJobEventTotal().then(res => { |
| | | eventTotal.value = res?.data?.data || 0 |
| | | }) |
| | | |
| | | |
| | | getTypeData() |
| | | lineCharts() |
| | | getFlyList() |
| | | getFlyTimeList() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | height: 100%; |
| | | |
| | | .comprehensiveCon { |
| | | background: #ffffff !important; |
| | | // background: #ffffff !important; |
| | | height: pxToVh(776); |
| | | border-radius: 8px 8px 8px 8px; |
| | | |
| | | .comprehensive { |
| | | |
| | | padding: 14px 14px 0 21px; |
| | | // padding: 14px 14px 0 21px; |
| | | |
| | | .title { |
| | | display: flex; |
| | |
| | | // 工、单 |
| | | .center { |
| | | display: flex; |
| | | |
| | | .centerLeft { |
| | | width: 60%; |
| | | border-right: 1px solid #dfdfdf; |
| | | width: 50%; |
| | | |
| | | .workOrder { |
| | | margin-top: 11px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | border-bottom: 1px solid #dfdfdf; |
| | | |
| | | .card-group { |
| | | width: 40%; |
| | | |
| | | .card-title { |
| | | display: flex; |
| | | margin-bottom: 10px; |
| | | align-items: center; |
| | | |
| | | img { |
| | | width: 36px; |
| | | height: 40px; |
| | | } |
| | | } |
| | | |
| | | .cardtotal { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-left: 9px; |
| | | |
| | | p { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #363636; |
| | | } |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .total-number { |
| | | font-family: 'Source Han Sans CN'; |
| | | |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | color: #2a54ff; |
| | | } |
| | | } |
| | | |
| | | .status-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(2, 1fr); |
| | | row-gap: 14px; |
| | | gap: 10px; |
| | | padding-bottom: 5px; |
| | | |
| | | .status-item { |
| | | display: flex; |
| | | text-align: center; |
| | | justify-content: space-between; |
| | | height: 97px; |
| | | // height: pxToVh(107); |
| | | max-width: 158px; |
| | | background: #f6f8fe; |
| | | border-radius: 8px 8px 8px 8px; |
| | | |
| | | img { |
| | | width: 26px; |
| | | height: 26px; |
| | | padding: 9px 10px 9px 2px; |
| | | } |
| | | |
| | | .statusCon { |
| | | display: flex; |
| | | flex-direction: column; |
| | | // align-items: center; |
| | | padding: 5px 4px 9px 10px; |
| | | text-align: left; |
| | | |
| | | .status-label { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | text-align: left; |
| | | color: #383838; |
| | | } |
| | | |
| | | .ratio { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #363636; |
| | | white-space: nowrap; |
| | | text-align: left; |
| | | } |
| | | |
| | | .status-value { |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: bold; |
| | | font-size: 30px; |
| | | color: #363636; |
| | | // margin: 5px 0; |
| | | // font-style: italic; |
| | | display: inline-block; |
| | | transform: skewX(-5deg); |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .charts { |
| | | margin-top: 30px; |
| | | width: 100%; |
| | | height: auto; |
| | | |
| | | .chart { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 飞行统计 |
| | | .flyOrder { |
| | | margin-top: 5px; |
| | | |
| | | .fytitle { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | img { |
| | | width: 39px; |
| | | height: 38px; |
| | | } |
| | | |
| | | span { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #363636; |
| | | } |
| | | } |
| | | |
| | | .flycenter { |
| | | margin-top: 13px; |
| | | |
| | | .centerBox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | |
| | | .centerItem { |
| | | padding: 7px 7px 0 15px; |
| | | // width: 196px; |
| | | flex: 1; |
| | | // height: 80px; |
| | | height: pxToVh(80); |
| | | background: #f6f8fe; |
| | | box-shadow: 0px 5px 4px 0px #ebf1ff; |
| | | border-radius: 8px 8px 8px 8px; |
| | | border: 1px solid #ffffff; |
| | | margin-right: 16px; |
| | | |
| | | img { |
| | | width: 15px; |
| | | height: 15px; |
| | | margin-right: 5px; |
| | | } |
| | | |
| | | .flyimg { |
| | | display: flex; |
| | | align-items: center; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | .flydata { |
| | | margin-top: 10px; |
| | | text-align: right; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | |
| | | span { |
| | | font-weight: bold; |
| | | font-size: 24px; |
| | | color: #343434; |
| | | margin-right: 6px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .lineChart { |
| | | height: 209px; |
| | | width: 100%; |
| | | |
| | | .lineBox { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | .centerRight { |
| | | width: 40%; |
| | | width: 50%; |
| | | } |
| | | } |
| | | } |