10 files modified
1 files added
| | |
| | | import request from '@/axios' |
| | | import request from '@/axios'; |
| | | |
| | | export const getList = (data) => { |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/eventPage', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 修改创建工单的方法 |
| | | export const createTicket = (data, file) => { |
| | | const formData = new FormData() |
| | | |
| | | const formData = new FormData(); |
| | | |
| | | // 创建 eventDto 对象,不显式设置 file 字段 |
| | | const eventDto = { |
| | | ...data // 直接使用传入的 data,不添加 file: null |
| | | } |
| | | }; |
| | | |
| | | // 添加所有字段到 FormData |
| | | Object.entries(eventDto).forEach(([key, value]) => { |
| | | formData.append(key, value) |
| | | }) |
| | | |
| | | formData.append(key, value); |
| | | }); |
| | | |
| | | // 只有当 file 存在时才添加文件 |
| | | if (file) { |
| | | formData.append("file", file) |
| | | formData.append("file", file); |
| | | } |
| | | |
| | | return request({ |
| | |
| | | headers: { |
| | | 'Content-Type': 'multipart/form-data' |
| | | } |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 新增接口:获取工单详细信息 |
| | | export const getTicketInfo = (id) => { |
| | |
| | | url: '/drone-device-core/jobEvent/getTicketInfo', |
| | | method: 'get', |
| | | params: { id }, // 使用工单 ID 查询 |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 修改接口:处理待审核状态,动态构建 FormData 提交 |
| | | export const flowEvent = (data, file) => { |
| | | const formData = new FormData() |
| | | const formData = new FormData(); |
| | | |
| | | // 动态添加非空字段到 FormData |
| | | Object.entries(data).forEach(([key, value]) => { |
| | | if (value !== undefined && value !== null) { |
| | | formData.append(key, value) |
| | | formData.append(key, value); |
| | | } |
| | | }) |
| | | }); |
| | | |
| | | // 如果 file 存在,则添加到 FormData |
| | | if (file) { |
| | | formData.append('file', file) |
| | | formData.append('file', file); |
| | | } |
| | | |
| | | return request({ |
| | |
| | | headers: { |
| | | 'Content-Type': 'multipart/form-data', // 设置为表单数据格式 |
| | | }, |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 新增接口:获取状态统计数据 |
| | | export const getstatusCount = (params) => { |
| | |
| | | url: '/drone-device-core/jobEvent/getstatusCount', |
| | | method: 'get', |
| | | params, |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | export const getStepInfo = (eventNum) => { |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/getStepInfo', |
| | | method: 'get', |
| | | params: { eventNum } |
| | | }) |
| | | } |
| | | |
| | | // 人工复核接口 |
| | | export const getReviewById = (id) => { |
| | | return request({ |
| | | url: `/drone-device-core/jobEvent/reviewById/${id}`, |
| | | method: 'get', |
| | | }) |
| | | } |
| | | |
| | | // 下发任务 |
| | | export const getCreateEventJob = (id) => { |
| | | return request({ |
| | | url: `/drone-device-core/wayline/waylineJobInfo/createEventJob/${id}`, |
| | | method: 'post', |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | |
| | | }, |
| | | fistPage: { |
| | | name: '事件工单', |
| | | // path: '/wel/index', |
| | | path: '/tickets/ticket', |
| | | path: '/wel/index', |
| | | // path: '/tickets/ticket', |
| | | |
| | | }, |
| | | //配置菜单的属性 |
| | |
| | | isAuth: false, |
| | | }, |
| | | }, |
| | | // { |
| | | // path: '/', |
| | | // name: '主页', |
| | | // // redirect: '/wel', |
| | | // redirect:'/tickets/ticket', |
| | | // }, |
| | | { |
| | | path: '/', |
| | | name: '主页', |
| | | redirect: '/tickets/ticket', |
| | | }, |
| | | path: '/', |
| | | name: '主页', |
| | | redirect: '/wel', |
| | | |
| | | }, |
| | | // { |
| | | // path: '/', |
| | | // name: '主页', |
| | | // redirect: '/tickets/ticket', |
| | | // }, |
| | | ]; |
| | |
| | | ], |
| | | }, |
| | | // 事件工单 |
| | | { |
| | | path: '/tickets', |
| | | component: () => |
| | | Store.getters.isMacOs ? import('@/mac/index.vue') : import('@/page/index/index.vue'), |
| | | redirect: '/tickets/ticket', |
| | | children: [ |
| | | { |
| | | path: 'ticket', |
| | | name: '事件工单', |
| | | meta: { |
| | | i18n: 'dashboard', |
| | | }, |
| | | component: () => import(/* webpackChunkName: "views" */ '@/views/tickets/ticket.vue'), |
| | | }, |
| | | ], |
| | | }, |
| | | // { |
| | | // path: '/tickets', |
| | | // component: () => |
| | | // Store.getters.isMacOs ? import('@/mac/index.vue') : import('@/page/index/index.vue'), |
| | | // redirect: '/tickets/ticket', |
| | | // children: [ |
| | | // { |
| | | // path: 'ticket', |
| | | // name: '事件工单', |
| | | // meta: { |
| | | // i18n: 'dashboard', |
| | | // }, |
| | | // component: () => import(/* webpackChunkName: "views" */ '@/views/tickets/ticket.vue'), |
| | | // }, |
| | | // ], |
| | | // }, |
| | | |
| | | { |
| | | path: '/test', |
| | |
| | | flex: 1; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | background: #f0f2f5; |
| | | // background: #f0f2f5; |
| | | background: linear-gradient( 180deg, #EEF3FE 0%, #F8F9FB 100%); |
| | | } |
| | | |
| | | #avue-view { |
| | |
| | | |
| | | <template #menu="{ row }"> |
| | | <div class="menu-custom-box"> |
| | | <template v-if="row.status == 1"> |
| | | <el-button v-if="hasPaddingBtnPermission()" type="text" icon="el-icon-view" |
| | | <div v-if="row.status == 1"> |
| | | <el-button class="audit-btn" v-if="hasPaddingBtnPermission()" type="text" icon="el-icon-view" |
| | | @click="handleCheckDetail(row)">审核</el-button> |
| | | </template> |
| | | </div> |
| | | |
| | | <template v-if=" |
| | | <div v-if=" |
| | | (userInfo.user_id == row.create_user || hasRecallPaddingBtnPermission()) && |
| | | row.status == 1 |
| | | "> |
| | | <!--待审核状态--> |
| | | <el-button type="text" icon="el-icon-warning" @click="orderLogRecall(row.id)">撤回</el-button> |
| | | </template> |
| | | <el-button class="withdraw-btn" type="text" icon="el-icon-warning" |
| | | @click="orderLogRecall(row.id)">撤回</el-button> |
| | | </div> |
| | | <!--已驳回--> |
| | | <template v-if="row.status == 2"> |
| | | <el-button type="text" icon="el-icon-warning" @click="rejectDetail(row.id)">驳回原因</el-button> |
| | | </template> |
| | | <div v-if="row.status == 2"> |
| | | <el-button class="reject-reason-btn" type="text" icon="el-icon-warning" |
| | | @click="rejectDetail(row.id)">驳回原因</el-button> |
| | | </div> |
| | | <!--草稿--> |
| | | <el-button type="text" icon="el-icon-edit" @click="handleViewDetail(row)">编辑</el-button> |
| | | <el-button type="text" icon="el-icon-position" @click="userPublishPush(row.id)">发起</el-button> |
| | | <el-button type="text" icon="el-icon-delete" @click="deleteOrderLog(row.id)">删除</el-button> |
| | | <template v-if="row.status == 3 || row.status == 1 || row.status == 2"> |
| | | <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情</el-button> |
| | | </template> |
| | | <div> |
| | | <el-button class="edit-btn" type="text" icon="el-icon-edit" |
| | | @click="handleViewDetail(row)">编辑</el-button> |
| | | <el-button class="publish-btn" type="text" icon="el-icon-position" |
| | | @click="userPublishPush(row.id)">发布</el-button> |
| | | <el-button class="delete-btn" type="text" icon="el-icon-delete" |
| | | @click="deleteOrderLog(row.id)">删除</el-button> |
| | | </div> |
| | | <div v-if="row.status == 3 || row.status == 1 || row.status == 2"> |
| | | <el-button class="detail-btn" type="text" icon="el-icon-view" |
| | | @click="handleViewDetail(row)">详情</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <template #status="{ row }"> |
| | |
| | | .menu-custom-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | flex-wrap: wrap; |
| | | |
| | | &> ::v-deep(.el-button) { |
| | | &>div { |
| | | flex: 1; |
| | | max-width: 44px; |
| | | } |
| | | |
| | | &:nth-child(4n) { |
| | | margin-left: 0; |
| | | } |
| | | .audit-btn { |
| | | color: #1ba0ff; |
| | | } |
| | | |
| | | .withdraw-btn { |
| | | color: #ff5d9e; |
| | | } |
| | | |
| | | .reject-reason-btn { |
| | | color: #ff6a00; |
| | | } |
| | | |
| | | .edit-btn { |
| | | color: #00b187; |
| | | } |
| | | |
| | | .publish-btn { |
| | | color: #5e00ff; |
| | | } |
| | | |
| | | .delete-btn { |
| | | color: #fe0202; |
| | | } |
| | | |
| | | .detail-btn { |
| | | color: #1f4aff; |
| | | } |
| | | } |
| | | } |
| | |
| | | <el-button type="text" icon="el-icon-delete" class="danger-button" |
| | | @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | |
| | | <template v-else> |
| | | <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情</el-button> |
| | | </template> |
| | | |
| | | <el-button v-if="row.status === 4 && row.isReview !== 1" type="text" icon="el-icon-check" |
| | | @click="reCheck(row)">复核</el-button> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <span :style="getStatusTagType(row.status) ? 'color:' + getStatusTagType(row.status) : ''"> |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 复核弹出层 --> |
| | | |
| | | <el-dialog v-model="reCheckDialog" title="工单复核" width="30%" append-to-body custom-class="re-check-dialog" |
| | | @close="reCheckDialog = false"> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="reCheckConfirm(1)">人工复核</el-button> |
| | | <el-button type="primary" @click="reCheckConfirm(2)">机器复核</el-button> |
| | | </div> |
| | | </el-dialog> |
| | | </basic-container> |
| | | </template> |
| | | |
| | | <script> |
| | | import { ElMessageBox, ElLoading } from 'element-plus' |
| | | import { calculateDefaultRange } from '@/utils/util' |
| | | import { gcj02ToWgs84, wgs84ToGcj02 } from '@/utils/coordinateTransformation' |
| | | import { |
| | | getList, |
| | | createTicket, |
| | | getTicketInfo, |
| | | flowEvent, |
| | | getstatusCount, |
| | | getStepInfo, |
| | | getReviewById, |
| | | getCreateEventJob |
| | | } from '@/api/tickets/ticket' |
| | | import { getList, createTicket, getTicketInfo, flowEvent, getstatusCount, getStepInfo } from '@/api/tickets/ticket' |
| | | import { export_json_to_excel } from '@/utils/exportExcel' |
| | | import geoJson from '@/assets/geoJson.json' |
| | | |
| | |
| | | |
| | | // 配置时间选择器默认配置 |
| | | datePickerDefaultVal: calculateDefaultRange(), |
| | | |
| | | // 复核弹窗 |
| | | reCheckDialog: false, |
| | | } |
| | | }, |
| | | created () { |
| | |
| | | |
| | | showIsReviewText () { |
| | | return (row) => { |
| | | console.log(row, 111111) |
| | | |
| | | if (['4', '5'].includes(String(row.status))) return row.isReview === 1 ? '是' : '否' |
| | | |
| | | return '/' |
| | |
| | | } |
| | | |
| | | return [String(lng), String(lat)] |
| | | }, |
| | | |
| | | // 复核按钮 |
| | | reCheck (row) { |
| | | this.reCheckData = row |
| | | this.reCheckDialog = true |
| | | }, |
| | | |
| | | // 复核确认框按钮事件 |
| | | reCheckConfirm (key) { |
| | | const that = this |
| | | if (key == 1) { |
| | | getReviewById(this.reCheckData.id).then(res => { |
| | | this.reCheckDialog = false |
| | | this.page.currentPage = 1 |
| | | this.fetchTableData() |
| | | this.fetchTabCounts() |
| | | }) |
| | | } else { |
| | | |
| | | const loading = ElLoading.service({ |
| | | lock: true, |
| | | text: '复核任务创建中……', |
| | | background: 'rgba(0, 0, 0, 0.7)', |
| | | }) |
| | | |
| | | // 获取时间的接口 |
| | | getCreateEventJob(that.reCheckData.id).then(res => { |
| | | loading.close() |
| | | |
| | | ElMessageBox.confirm(`预计复核执行时间为${res.data.data}`, '提示', { |
| | | confirmButtonText: '确定', |
| | | showCancelButton: false, // 关键配置 |
| | | type: 'warning' |
| | | }).then(() => { |
| | | this.reCheckDialog = false |
| | | this.page.currentPage = 1 |
| | | this.fetchTableData() |
| | | this.fetchTabCounts() |
| | | }) |
| | | }) |
| | | } |
| | | } |
| | | }, |
| | | } |
| | |
| | | |
| | | // 添加新的样式 |
| | | .review-dialog { |
| | | :deep(.el-dialog__body) { |
| | | padding: 0; |
| | | background-color: #f5f7fa; |
| | | } |
| | | } |
| | | |
| | | .re-check-dialog { |
| | | :deep(.el-dialog__body) { |
| | | padding: 0; |
| | | background-color: #f5f7fa; |
| | |
| | | } |
| | | |
| | | if (newV && oldV) { |
| | | const newDate = dayjs(newV); |
| | | const newDate = dayjs(newV); |
| | | const oldDate = dayjs(oldV); |
| | | |
| | | // 格式化为 YYYY-MM-DD HH:mm:ss |
| | | const newDateStr = newDate.format('YYYY-MM-DD HH:mm:ss'); |
| | | const oldDateStr = oldDate.format('YYYY-MM-DD HH:mm:ss'); |
| | | params. |
| | | console.log('新日期:', newDateStr, '旧日期:', oldDateStr); |
| | | |
| | | if (newDate.isBefore(oldDate, 'month')) { |
| | | console.log('点击了上个月',newDateStr); |
| | | console.log('点击了上个月'); |
| | | } else if (newDate.isAfter(oldDate, 'month')) { |
| | | console.log('点击了下个月',newDateStr); |
| | | console.log('点击了下个月'); |
| | | } |
| | | } |
| | | }, |
| | |
| | | }; |
| | | // 获取对应日期的事件 |
| | | const getEvents = dateString => { |
| | | // console.log('000',dateString); |
| | | // console.log('000',dateString); |
| | | |
| | | return events.value[dateString] || []; |
| | | }; |
| | |
| | | // 获取机巢事件数据 |
| | | const getIndustryJobNumPieChart = value => { |
| | | industryJobNumPieChart(value).then(res => { |
| | | console.log('ppp', res); |
| | | |
| | | const resList = res?.data?.data || []; |
| | | jcOrder.value = resList; |
| | | pieInit(resList); |
| | |
| | | <template> |
| | | <div> |
| | | 个人工作台 |
| | | <div class="workbench"> |
| | | <div class="workleft"> |
| | | <!-- 设备统计 --> |
| | | <statistics></statistics> |
| | | <!-- 综合统计分析 --> |
| | | <div class="comprehensiveCon"> |
| | | <div class="comprehensive"> |
| | | <div class="title"> |
| | | <div class="name"> |
| | | <span> 综合统计分析</span> |
| | | <img 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"> |
| | | <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 class="total-number">{{ eventTotal }}</div> |
| | | <span>个</span> --> |
| | | </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 :style="{ color: item.color }" class="status-value"> |
| | | {{ item.value }}<span>个</span> |
| | | </div> |
| | | <div class="ratio"> |
| | | 占比 |
| | | <span :style="{ color: item.color }" |
| | | >{{ (item.rate / 100) * 100 }}%</span |
| | | > |
| | | </div> |
| | | </div> |
| | | <img :src="item.img" alt="" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="charts"> |
| | | <div class="chart" ref="echartsRef"></div> |
| | | </div> |
| | | </div> |
| | | <!-- 飞行统计 --> |
| | | <div class="flyOrder"> |
| | | <div class="fytitle"> |
| | | <img src="@/assets/images/workbench/fy1.png" alt="" /> |
| | | <span>飞行统计</span> |
| | | </div> |
| | | <div class="flycenter"> |
| | | <div class="centerBox"> |
| | | <div class="centerItem" v-for="(item, index) in 3" :key="index"> |
| | | <div><img src="@/assets/images/workbench/fy2.png" alt="" />飞行时长</div> |
| | | <div class="flydata"><span>5421.56</span>时</div> |
| | | </div> |
| | | </div> |
| | | <div class="lineChart"> |
| | | <div class="lineBox" ref="chartRef"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="centerRight"> |
| | | <flyratio></flyratio> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="workright"> |
| | | <Bocklog></Bocklog> |
| | | <CalenBox></CalenBox> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | <script setup> |
| | | import flyratio from './components/flyratio.vue'; |
| | | import Bocklog from './components/backlog.vue'; |
| | | import CalenBox from './components/calendarBox.vue'; |
| | | import * as echarts from 'echarts'; |
| | | import useEchartsResize from '@/hooks/useEchartsResize'; |
| | | import { mapGetters } from 'vuex'; |
| | | |
| | | export default { |
| | | name: 'wel', |
| | | data() { |
| | | return { |
| | | activeNames: ['1', '2', '3', '5'], |
| | | logActiveNames: ['37'], |
| | | }; |
| | | }, |
| | | computed: { |
| | | ...mapGetters(['userInfo']), |
| | | }, |
| | | methods: { |
| | | handleChange(val) { |
| | | window.console.log(val); |
| | | }, |
| | | }, |
| | | import { ref } from 'vue'; |
| | | import overviewImg1 from '@/assets/images/workbench/tc1.png'; |
| | | import overviewImg2 from '@/assets/images/workbench/tc2.png'; |
| | | import overviewImg3 from '@/assets/images/workbench/tc3.png'; |
| | | import overviewImg4 from '@/assets/images/workbench/tc4.png'; |
| | | import overviewImg5 from '@/assets/images/workbench/tc5.png'; |
| | | import overviewImg6 from '@/assets/images/workbench/tc6.png'; |
| | | import flyImg1 from '@/assets/images/workbench/fy2.png'; |
| | | import statistics from './components/statistics.vue'; |
| | | import { getJobEventByStatus, getJobEventTotal } from '@/api/home/index'; |
| | | // const value = ref(new Date()); |
| | | let checked = ref('CURRENT_WEEK'); |
| | | let timeListStr = ['本周', '本月', '本年']; |
| | | let timeListEnum = ['CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR']; |
| | | let timeClick = (item, index) => { |
| | | checked.value = item; |
| | | params.value.date_enum = item; |
| | | console.log('日期选择', params.value.date_enum); |
| | | getTypeData(); |
| | | }; |
| | | const eventTypeList = ref([ |
| | | { name: '待审核', value: 0, img: overviewImg2, color: '#FF6560', status: '2', rate: 0 }, |
| | | { name: '待处理', value: 0, img: overviewImg3, color: '#5D77FB', status: '0', rate: 0 }, |
| | | { name: '处理中', value: 0, img: overviewImg4, color: '#FF8B26', status: '3', rate: 0 }, |
| | | { name: '已完成', value: 0, img: overviewImg5, color: '#0291A1', status: '4', rate: 0 }, |
| | | ]); |
| | | const flyTypeList = ref([ |
| | | { name: '飞行时长', value: 0, img: overviewImg2 }, |
| | | { name: '飞行里程', value: 0, img: overviewImg3 }, |
| | | { name: '任务成功', value: 0, img: overviewImg4 }, |
| | | ]); |
| | | const params = ref({ |
| | | date_enum: 'CURRENT_WEEK', |
| | | device_sn: '', |
| | | end_date: undefined, |
| | | start_date: undefined, |
| | | }); |
| | | const eventTotal = ref(0); |
| | | const data = ref([]); |
| | | // 工单统计 |
| | | const getTypeData = () => { |
| | | getJobEventByStatus(params.value).then(res => { |
| | | const resList = res?.data?.data || []; |
| | | console.log('工单统计', 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 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 echartsOption = { |
| | | color: ['#FF6560', '#5D77FB', '#FF8B26', '#0291A1'], |
| | | tooltip: { |
| | | trigger: 'item', |
| | | padding: 0, |
| | | borderWidth: 0, |
| | | formatter: params => { |
| | | return `<div style="background-color: rgba($color: #FFFFFF, $alpha: 0.95); |
| | | box-shadow: 0 4px 9px 0 rgba($color: #000000, $alpha: 0.1); |
| | | padding:0 12px; |
| | | display: flex; |
| | | align-items: center; |
| | | border-radius: 4px; |
| | | font-size: 12px;" class="tooltip-area"> |
| | | <p>${params.marker}${params.name}</p> |
| | | <h4 style="margin-left: 30px;">${params.data.rate || params.percent}%</h4> |
| | | </div>`; |
| | | }, |
| | | }, |
| | | legend: { |
| | | show: false, |
| | | }, |
| | | title: { |
| | | text: data.total.title, |
| | | textStyle: { |
| | | color: 'rgba(28, 31, 35, 0.80)', |
| | | fontSize: '12px', |
| | | fontWeight: 'normal', |
| | | }, |
| | | subtext: data.total.figure, |
| | | subtextStyle: { |
| | | color: '#1C1F23', |
| | | fontSize: '20px', |
| | | fontWeight: '600', |
| | | }, |
| | | top: '40%', |
| | | left: 'center', |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '', |
| | | type: 'pie', |
| | | radius: ['30%', '45%'], |
| | | avoidLabelOverlap: true, |
| | | // avoidLabelOverlap: false, |
| | | label: { |
| | | formatter: `{a|{b}}: {b|{d}%}`, |
| | | alignTo: 'labelLine', |
| | | rich: { |
| | | a: { |
| | | color: 'rgba(28, 31, 35, 0.80)', |
| | | fontSize: '12px', |
| | | }, |
| | | b: { |
| | | color: '#1C1F23', |
| | | fontSize: '14px', |
| | | fontWeight: '600', |
| | | }, |
| | | }, |
| | | }, |
| | | labelLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | cap: 'round', |
| | | }, |
| | | }, |
| | | data: data.data, |
| | | }, |
| | | ], |
| | | }; |
| | | |
| | | chart.value.setOption(echartsOption); |
| | | }; |
| | | |
| | | // 柱状图 |
| | | const lineCharts = () => { |
| | | 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%', |
| | | textStyle: { |
| | | color: '#666666', |
| | | }, |
| | | itemWidth: 15, |
| | | itemHeight: 10, |
| | | itemGap: 25, |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | |
| | | axisLabel: { |
| | | interval: 0, |
| | | textStyle: { |
| | | color: '#666666', |
| | | }, |
| | | }, |
| | | }, |
| | | yAxis: [ |
| | | // 只保留第一个y轴 |
| | | { |
| | | type: 'log', |
| | | name: '单位:万套', |
| | | nameTextStyle: { |
| | | color: '#666666', |
| | | }, |
| | | min: 1, |
| | | logBase: 3, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | |
| | | splitLine: { |
| | | show: true, // 显示分割线 |
| | | lineStyle: { |
| | | type: 'dashed', // 设置为虚线 |
| | | color: '#cdd5e2', // 颜色与轴线一致 |
| | | width: 1, // 线宽 |
| | | opacity: 0.5, // 透明度 |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | textStyle: { |
| | | color: '#666666', |
| | | }, |
| | | }, |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | }, |
| | | // 移除第二个y轴配置 |
| | | ], |
| | | series: [ |
| | | { |
| | | name: '飞行时长', |
| | | type: 'bar', |
| | | barWidth: '12px', |
| | | itemStyle: { |
| | | normal: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: '#29acff', |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: '#4bdfff', |
| | | }, |
| | | ]), |
| | | barBorderRadius: 6, |
| | | }, |
| | | }, |
| | | data: [11, 14, 133, 4, 10, 14, 116, 12, 12, 58, 15, 12], |
| | | }, |
| | | { |
| | | name: '飞行里程', |
| | | type: 'bar', |
| | | barWidth: '12px', |
| | | itemStyle: { |
| | | normal: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: '#01c871', |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: '#55f49c', |
| | | }, |
| | | ]), |
| | | barBorderRadius: 6, |
| | | }, |
| | | }, |
| | | data: [0, 1, 9, 0, 5, 3, 0, 2, 0, 0, 1, 0], |
| | | }, |
| | | { |
| | | name: '任务成果', |
| | | type: 'line', |
| | | yAxisIndex: 0, // 改为使用第一个y轴 |
| | | smooth: true, |
| | | // symbol: 'circle', |
| | | // symbolSize: 8, |
| | | // itemStyle: { |
| | | // normal: { |
| | | // color: '#ffa43a', |
| | | // borderColor: 'rgba(255, 234, 0, 0.5)', |
| | | // borderWidth: 5, |
| | | // }, |
| | | // }, |
| | | lineStyle: { |
| | | color: 'rgba(52, 146, 242, 1)', |
| | | }, |
| | | data: [1, 7, 6, 30, 20, 21.43, 11, 16.67, 22, 88, 6.67, 10], |
| | | }, |
| | | ], |
| | | }; |
| | | lineChart.value.setOption(option); |
| | | }; |
| | | onMounted(() => { |
| | | getJobEventTotal().then(res => { |
| | | eventTotal.value = res?.data?.data || 0; |
| | | }); |
| | | |
| | | getTypeData(); |
| | | lineCharts(); |
| | | }); |
| | | </script> |
| | | |
| | | <style> |
| | |
| | | font-size: 14px; |
| | | } |
| | | </style> |
| | | <style scoped lang="scss"> |
| | | // 开始 |
| | | .workbench { |
| | | padding: 0px 20px 0 20px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | } |
| | | .workleft { |
| | | width: 68%; |
| | | margin-right: 10px; |
| | | // 综合 |
| | | .comprehensiveCon { |
| | | // height: 736px; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 8px 8px; |
| | | .comprehensive { |
| | | padding: 14px 14px 0 21px; |
| | | .title { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | .name { |
| | | display: flex; |
| | | align-items: center; |
| | | span { |
| | | margin-right: 4px; |
| | | } |
| | | } |
| | | .arrow { |
| | | cursor: pointer; |
| | | } |
| | | .time-card { |
| | | text-align: center; |
| | | height: 30px; |
| | | background: #ffffff; |
| | | border-radius: 4px 0px 0px 4px; |
| | | border: 1px solid #e5e5e5; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | display: flex; |
| | | width: 282px; |
| | | margin-left: 15px; |
| | | .card-item { |
| | | width: 94px; |
| | | height: 100%; |
| | | line-height: 32px; |
| | | cursor: pointer; |
| | | } |
| | | .card-item:first-child { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | .card-item:nth-child(2) { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | .active { |
| | | color: #1441ff; |
| | | } |
| | | } |
| | | } |
| | | // 工、单 |
| | | .center { |
| | | display: flex; |
| | | .centerLeft { |
| | | width: 60%; |
| | | border-right: 1px solid #dfdfdf; |
| | | .workOrder { |
| | | margin-top: 21px; |
| | | display: flex; |
| | | 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: 'YouSheBiaoTiHei'; |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | color: #2a54ff; |
| | | } |
| | | } |
| | | .status-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(2, 1fr); |
| | | row-gap: 14px; |
| | | gap: 10px; |
| | | .status-item { |
| | | display: flex; |
| | | text-align: center; |
| | | height: 97px; |
| | | background: #f6f8fe; |
| | | border-radius: 8px 8px 8px 8px; |
| | | img { |
| | | width: 26px; |
| | | height: 26px; |
| | | padding: 9px 2px; |
| | | } |
| | | .statusCon { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | padding: 9px 4px 0 4px; |
| | | .status-label { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #383838; |
| | | } |
| | | .ratio { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #363636; |
| | | white-space: nowrap; |
| | | } |
| | | .status-value { |
| | | font-family: 'YouSheBiaoTiHei'; |
| | | font-weight: bold; |
| | | font-size: 24px; |
| | | margin: 5px 0; |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .charts { |
| | | margin-top: 30px; |
| | | width: 348px; |
| | | height: 242px; |
| | | .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; |
| | | .centerItem { |
| | | padding: 7px 7px 0 15px; |
| | | // width: 196px; |
| | | flex: 1; |
| | | height: 80px; |
| | | background: #f6f8fe; |
| | | box-shadow: 0px 5px 4px 0px #ebf1ff; |
| | | border-radius: 8px 8px 8px 8px; |
| | | border: 1px solid #ffffff; |
| | | margin-right: 16px; |
| | | .flydata { |
| | | margin-top: 15px; |
| | | 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%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .workright { |
| | | width: 32%; |
| | | } |
| | | </style> |