Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/H5/shehong-vehicle-supervision
| | |
| | | "version": "0.1.0",
|
| | | "private": true,
|
| | | "scripts": {
|
| | | "dev": "vue-cli-service serve",
|
| | | "dev": "vue-cli-service serve --port 8089",
|
| | | "build": "vue-cli-service build",
|
| | | "lint": "vue-cli-service lint"
|
| | | },
|
| | |
| | | "> 1%",
|
| | | "last 2 versions"
|
| | | ]
|
| | | }
|
| | | } |
New file |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog title="订单详情" :visible.sync="dialogVisible" width="50%" :modal-append-to-body="false" |
| | | :close-on-press-escape="false" :close-on-click-modal="false" @close="closeClick"> |
| | | <el-radio-group v-model="tabPosition" style="margin-bottom: 30px;"> |
| | | <el-radio-button label="order">订单信息</el-radio-button> |
| | | <el-radio-button label="track">行程轨迹</el-radio-button> |
| | | <el-radio-button label="monitoring">行程监控</el-radio-button> |
| | | </el-radio-group> |
| | | <!-- 订单信息 --> |
| | | <div v-show="tabPosition == 'order'"> |
| | | <el-descriptions title="" :column="3"> |
| | | <el-descriptions-item label="公司名称">{{ orderData.enterpriseName }}</el-descriptions-item> |
| | | <el-descriptions-item label="发起地区划">{{ orderData.drivingLicenseNumber }}</el-descriptions-item> |
| | | <el-descriptions-item label="订单编号">{{ orderData.code }}</el-descriptions-item> |
| | | <el-descriptions-item label="机动车驾驶证编号">{{ orderData.drivingLicenseNumber }}</el-descriptions-item> |
| | | <el-descriptions-item label="驾驶员手机号">{{ orderData.driverPhone }}</el-descriptions-item> |
| | | <el-descriptions-item label="车辆号牌">{{ orderData.vehicleNumber }}</el-descriptions-item> |
| | | <el-descriptions-item label="派单时间">{{ orderData.orderDeliveryTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="订单发起时间">{{ orderData.orderTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="乘客备注">{{ orderData.remark }}</el-descriptions-item> |
| | | <el-descriptions-item label="出发地点">{{ orderData.orderPlace }}</el-descriptions-item> |
| | | <el-descriptions-item label="下车地点">{{ orderData.dropOffPoint }}</el-descriptions-item> |
| | | <el-descriptions-item label="运价类型编号">{{ orderData.tariffType }}</el-descriptions-item> |
| | | <el-descriptions-item label="订单金额">¥{{ orderData.orderAmount }}</el-descriptions-item> |
| | | <el-descriptions-item label="实付价">¥{{ orderData.paymentAmount }}</el-descriptions-item> |
| | | <el-descriptions-item label="支付方式">{{ orderData.paymentMode }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <!-- 行程轨迹 --> |
| | | <div v-if="tabPosition == 'track'"> |
| | | <div class="mapContainer" id="mapContainers"></div> |
| | | </div> |
| | | <!-- 行程监控 --> |
| | | <div v-if="tabPosition == 'monitoring'"> |
| | | <PlayLive :serverIp="monitoringData.serverIp" :serverPort="monitoringData.serverPort" |
| | | :carId="orderData.carId" /> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import AMapLoader from "@amap/amap-jsapi-loader"; |
| | | export default { |
| | | data() { |
| | | return { |
| | | dialogVisible: false, |
| | | tabPosition: 'order', |
| | | orderData: {}, |
| | | monitoringData: {}, |
| | | travelData: [], |
| | | }; |
| | | }, |
| | | computed: {}, |
| | | watch: { |
| | | tabPosition(val) { |
| | | if (val == 'track') { |
| | | this.$nextTick(() => { |
| | | this.initMap(); |
| | | }) |
| | | return |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | initData(orderData = {}, monitoringData = {}, travelData = []) { |
| | | console.log('////////////////////////'); |
| | | |
| | | this.orderData = orderData |
| | | this.monitoringData = monitoringData |
| | | this.travelData = travelData |
| | | this.dialogVisible = true |
| | | }, |
| | | initMap() { |
| | | window._AMapSecurityConfig = { |
| | | securityJsCode: this.$secretKey, |
| | | }; |
| | | AMapLoader.load({ |
| | | key: this.$mapKey, |
| | | version: "2.0", |
| | | plugins: [ |
| | | "AMap.ToolBar", |
| | | ], |
| | | }) |
| | | .then((AMap) => { |
| | | // 转换 travelData 中的坐标 |
| | | const wgs84Path = this.travelData.map(item => [item.longitude, item.latitude]); |
| | | const batchSize = 40; // 每次转换 40 对坐标 |
| | | const batches = []; |
| | | |
| | | // 分批处理 |
| | | for (let i = 0; i < wgs84Path.length; i += batchSize) { |
| | | batches.push(wgs84Path.slice(i, i + batchSize)); |
| | | } |
| | | |
| | | const gcj02Path = []; |
| | | const promises = batches.map(batch => { |
| | | return new Promise((resolve, reject) => { |
| | | AMap.convertFrom(batch, 'gps', (status, result) => { |
| | | if (status === 'complete' && result.locations) { |
| | | resolve(result.locations); |
| | | } else { |
| | | reject(result); |
| | | } |
| | | }); |
| | | }); |
| | | }); |
| | | |
| | | // 等待所有批次转换完成 |
| | | Promise.all(promises) |
| | | .then(results => { |
| | | results.forEach(batchResult => { |
| | | gcj02Path.push(...batchResult); |
| | | }); |
| | | |
| | | // 开始绘制地图 |
| | | this.map = new AMap.Map("mapContainers", { |
| | | center: gcj02Path[Math.floor(gcj02Path.length / 2)], // 使用转换后的中点坐标 |
| | | zoom: 12, |
| | | }); |
| | | this.map.addControl(new AMap.ToolBar()); |
| | | |
| | | // 添加起点和终点标记 |
| | | const marker = [ |
| | | new AMap.Marker({ |
| | | content: `<div class="custom-content-marker">起点</div>`, |
| | | position: gcj02Path[0], |
| | | offset: new AMap.Pixel(-35, -25), |
| | | }), |
| | | new AMap.Marker({ |
| | | content: `<div class="custom-content-marker-two">终点</div>`, |
| | | position: gcj02Path[gcj02Path.length - 1], |
| | | offset: new AMap.Pixel(-35, -25), |
| | | }), |
| | | ]; |
| | | this.map.add(marker); |
| | | |
| | | // 绘制路径 |
| | | const polyline = new AMap.Polyline({ |
| | | path: gcj02Path, |
| | | strokeWeight: 3, |
| | | strokeColor: "red", |
| | | lineJoin: "round", |
| | | }); |
| | | this.map.add(polyline); |
| | | |
| | | // 强制刷新地图 |
| | | this.$nextTick(() => { |
| | | this.map.resize(); |
| | | }); |
| | | }) |
| | | .catch(error => { |
| | | console.error('坐标转换失败', error); |
| | | }); |
| | | }) |
| | | .catch((e) => { |
| | | console.log(e); |
| | | }); |
| | | }, |
| | | closeClick() { |
| | | this.dialogVisible = false |
| | | this.tabPosition = 'order' |
| | | this.orderData = {} |
| | | this.monitoringData = {} |
| | | this.travelData = [] |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | <style> |
| | | .custom-content-marker { |
| | | width: 50px; |
| | | height: 50px; |
| | | background-color: blue; |
| | | color: #fff; |
| | | border-radius: 50%; |
| | | line-height: 50px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .custom-content-marker-two { |
| | | width: 50px; |
| | | height: 50px; |
| | | background-color: orange; |
| | | color: #fff; |
| | | border-radius: 50%; |
| | | line-height: 50px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .custom-content-marker img { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | </style> |
| | | <style scoped lang="less"> |
| | | ::v-deep .el-descriptions .el-descriptions-item__cell { |
| | | padding-bottom: 25px; |
| | | } |
| | | |
| | | #mapContainers { |
| | | width: 100%; |
| | | height: 500px; |
| | | } |
| | | </style> |
| | |
| | | </div> |
| | | </div> |
| | | <div class="info-right flex2"> |
| | | <video style="width: 100%;height: 100%;" src="../../assets/homeImg/QQ20241223-103023.mp4"></video> |
| | | <div style="position: relative; width: 100%; height: 330px"> |
| | | <div |
| | | style="width: 100%; height: 330px; border-radius: 9px; background: #f5f5f5; display: flex; justify-content: center; align-items: center; flex-direction: column"> |
| | | <video style="width: 100%; height: 330px; border-radius: 9px; display: none" id="monitoringCard" |
| | | ref="monitoringCard" :controls="false" autoPlay width="620"> |
| | | </video> |
| | | <el-empty description="暂无视频信息" :image-size="80"></el-empty> |
| | | </div> |
| | | <canvas id="myCanvas" style="display:none"></canvas> |
| | | <el-button type="default" style="position: absolute; top: 10px;right: 60px;" |
| | | @click="goBack()">查看回放</el-button> |
| | | <div style="position: absolute; right: 11px; top: 10px"> |
| | | <div style="display: flex;flex-direction: column;align-items: center;justify-content: center; |
| | | background: #ffffff; padding: 3px 10px; border-radius: 6px;margin-bottom: 10px;" @click="fullScreen()"> |
| | | <img style="width: 20px; height: 20px" :src="require('../../assets//homeImg/full.png')" /> |
| | | <div |
| | | style="font-size: 12px;font-weight: 400; line-height: 17px; color: rgba(0, 0, 0, 0.88);"> |
| | | 全屏</div> |
| | | </div> |
| | | <div style="display: flex;flex-direction: column;align-items: center; justify-content: center; |
| | | background: #ffffff;padding: 3px 10px;border-radius: 6px;" @click="shotScreen()"> |
| | | <img style="width: 20px; height: 20px" :src="require('../../assets//homeImg/slot.png')" /> |
| | | <div |
| | | style="font-size: 12px; font-weight: 400; line-height: 17px; color: rgba(0, 0, 0, 0.88);"> |
| | | 截屏</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="tab-content ml--100 mr--30"> |
| | |
| | | <el-tab-pane label="订单记录" name="first"> |
| | | <div class="table-box mt--23"> |
| | | <el-table :data="tableData" border stripe style="width: 100%"> |
| | | <el-table-column prop="index" label="序号"></el-table-column> |
| | | <el-table-column type="index" width="80" label="序号"></el-table-column> |
| | | <el-table-column prop="code" label="订单编号"></el-table-column> |
| | | <el-table-column prop="vehicleNumber" label="车牌号"></el-table-column> |
| | | <el-table-column prop="licensePlateColor" label="车牌颜色"></el-table-column> |
| | |
| | | <el-table-column prop="orderAmount" label="订单金额"></el-table-column> |
| | | <el-table-column prop="option" label="操作"> |
| | | <template slot-scope="scope"> |
| | | <el-button type="text" @click="handle(scope.$index, scope.row)">详情</el-button> |
| | | <el-button type="text" @click="showDetails(scope.row)">详情</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | <el-tab-pane label="预警记录" name="second"> |
| | | <div class="table-box mt--23"> |
| | | <el-table :data="tableData" border stripe style="width: 100%"> |
| | | <el-table-column prop="index" label="序号" fixed width="80"></el-table-column> |
| | | <el-table-column type="index" label="序号" fixed width="80"></el-table-column> |
| | | <el-table-column prop="carName" label="车辆名称" width="120" fixed></el-table-column> |
| | | <el-table-column prop="vehicleNumber" label="车牌号码" width="120" fixed></el-table-column> |
| | | <el-table-column prop="keepWarn" label="持续报警" width="120"></el-table-column> |
| | |
| | | <el-form :inline="true" :model="searchForm" class="demo-form-inline"> |
| | | <el-form-item label="选择轨迹时间范围:" prop="level" class="unset_m" |
| | | style="margin-right: 15px;"> |
| | | <el-date-picker :value-format="'yyyy-MM-dd HH:mm'" v-model="searchForm.date" |
| | | <el-date-picker :value-format="'yyyy-MM-dd HH:mm:ss'" v-model="searchForm.date" |
| | | type="datetimerange" range-separator="至" start-placeholder="开始日期" |
| | | end-placeholder="结束日期"> |
| | | </el-date-picker> |
| | |
| | | </el-tabs> |
| | | </div> |
| | | <DetailModal ref="detailModal" :detail="detail" /> |
| | | <DetailOrderModal ref="detailOrder" /> |
| | | <el-drawer :visible.sync="drawer" append-to-body :size="450" @close="closeDrawer"> |
| | | <div class="flex j-between a-center fs--20 pl--15 pr--15"> |
| | | <!-- 使用 Tailwind CSS 的内联十六进制颜色类 --> |
| | | <div>{{ info.vehicleNumber }}<span v-if="info.warnList && info.warnList.length > 0">({{ |
| | | info.warnList.length |
| | | }})</span></div><i @click="closeDrawer" class="el-icon-s-unfold color1 pointer"></i> |
| | | }})</span></div><i @click="closeDrawer" class="el-icon-s-unfold color1 pointer"></i> |
| | | </div> |
| | | <hr class="mt--10" /> |
| | | <div class="pl--15 pr--15"> |
| | |
| | | <script> |
| | | import AMapLoader from "@amap/amap-jsapi-loader"; |
| | | import DetailModal from "./components/detailModal.vue"; |
| | | import { getCarDetail, getCarOrder, getCarWarning, getCarTrack, getCarVideo,getDetail } from './service' |
| | | import DetailOrderModal from "./components/detailOrderModal.vue"; |
| | | import { getCarDetail, getCarOrder, getCarWarning, getCarTrack, getCarVideo, getDetail, getOrderInfo, getOrderTravel, getOrderMonitoring, playDetection, closeRealVideo } from './service' |
| | | import moment from "moment"; |
| | | export default { |
| | | name: "detail", |
| | | components: { DetailModal }, |
| | | components: { DetailModal, DetailOrderModal }, |
| | | data() { |
| | | return { |
| | | id: '', |
| | |
| | | activeName: 'first', |
| | | routeList: [], |
| | | videoObj: {}, |
| | | loading: false, |
| | | drawer: false, |
| | | showWarnDetail: false, |
| | | info: {}, |
| | |
| | | }) |
| | | getCarVideo({ id: this.$route.query.id }).then(res => { |
| | | this.videoObj = res; |
| | | |
| | | this.initVideoPlayer(); |
| | | |
| | | }) |
| | | } |
| | | |
| | | }, |
| | | |
| | | destroyed() { |
| | | this.destroyPlayer(); |
| | | }, |
| | | methods: { |
| | | goBack() { |
| | | this.$router.push('/car-playback?id=' + this.$route.query.id) |
| | | }, |
| | | // 初始化视频播放器 |
| | | initVideoPlayer() { |
| | | // 先销毁之前的播放器 |
| | | if (this.flvPlayer) { |
| | | this.flvPlayer.destroy(); |
| | | this.flvPlayer = null; |
| | | } |
| | | |
| | | // 获取video元素 |
| | | const video = document.getElementById("monitoringCard"); |
| | | if (!video) { |
| | | console.error("Video element not found"); |
| | | return; |
| | | } |
| | | |
| | | // 检查flv.js是否支持 |
| | | if (flvjs.isSupported()) { |
| | | try { |
| | | playDetection(this.carId).then((res) => { |
| | | this.flvPlayer = flvjs.createPlayer({ |
| | | type: "flv", //视频类型 |
| | | isLive: true, //是否为直播 |
| | | cors: true, //是否开启跨域 |
| | | hasAudio: false, //是否开启音频 |
| | | hasVideo: true, //是否开启视频 |
| | | url: `http://${this.videoObj.serverIp}:${this.videoObj.serverPort}/live?port=1935&app=flv&stream=${this.$route.query.id}`, // 后端拿到的视频路径 |
| | | enableWorker: true, //启用 Web Worker 进程来加速视频的解码和处理过程 |
| | | enableStashBuffer: false, // 启用数据缓存机制,提高视频的流畅度和稳定性。 |
| | | stashInitialSize: 1024, // 初始缓存大小。单位:字节。建议针对直播:调整为1024kb |
| | | stashInitialTime: 0.2, // 缓存初始时间。单位:秒。建议针对直播:调整为200毫秒 |
| | | seekType: "range", // 建议将其设置为"range"模式,以便更快地加载视频数据,提高视频的实时性。 |
| | | lazyLoad: false, //关闭懒加载模式,从而提高视频的实时性。建议针对直播:调整为false |
| | | lazyLoadMaxDuration: 0.2, // 懒加载的最大时长。单位:秒。建议针对直播:调整为200毫秒 |
| | | deferLoadAfterSourceOpen: false, // 不预先加载视频数据,在 MSE(Media Source Extensions)打开后立即加载数据,提高视频的实时性。建议针对直播:调整为false |
| | | }); |
| | | let video = document.getElementById("monitoringCard"); |
| | | this.flvPlayer.attachMediaElement(video); // video容器 |
| | | this.flvPlayer.load(); |
| | | this.flvPlayer |
| | | .play() |
| | | .then((res) => { |
| | | // 显示视频元素 |
| | | video.style.display = 'block'; |
| | | // 隐藏空状态 |
| | | const emptyElement = video.parentElement.querySelector('.el-empty'); |
| | | if (emptyElement) { |
| | | emptyElement.style.display = 'none'; |
| | | } |
| | | |
| | | this.videoTimer = setInterval(() => { |
| | | playDetection(this.carId); |
| | | }, 5000); |
| | | }) |
| | | .catch((err) => { |
| | | this.destroyPlayer(); |
| | | }); |
| | | // 错误监听 |
| | | this.flvPlayer.on("error", (err) => { |
| | | this.destroyPlayer(); |
| | | }); |
| | | }); |
| | | } catch (error) { |
| | | console.error("创建播放器失败:", error); |
| | | } |
| | | } else { |
| | | console.error("当前浏览器不支持flv.js"); |
| | | } |
| | | }, |
| | | |
| | | destroyPlayer() { |
| | | // 销毁播放器释放资源 |
| | | if (this.flvPlayer) { |
| | | if (this.videoTimer) clearInterval(this.videoTimer); |
| | | closeRealVideo(this.carId).then((res) => { |
| | | this.flvPlayer.pause(); |
| | | this.flvPlayer.unload(); |
| | | this.flvPlayer.detachMediaElement(); |
| | | this.flvPlayer.destroy(); |
| | | this.flvPlayer = null; |
| | | |
| | | // 恢复空状态的显示 |
| | | const video = document.getElementById("monitoringCard"); |
| | | if (video) { |
| | | video.style.display = 'none'; |
| | | const emptyElement = video.parentElement.querySelector('.el-empty'); |
| | | if (emptyElement) { |
| | | emptyElement.style.display = 'block'; |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | // 处理视频错误 |
| | | handleVideoError(event) { |
| | | console.error("视频加载失败", event); |
| | | if (this.flvPlayer) { |
| | | this.flvPlayer.destroy(); |
| | | this.flvPlayer = null; |
| | | } |
| | | this.infoWindow.setContent( |
| | | '<div style="padding: 20px;text-align: center;color: red;">视频加载失败,请稍后重试</div>' |
| | | ); |
| | | }, |
| | | |
| | | shotScreen() { |
| | | // 获取video和canvas元素 |
| | | const video = document.getElementById("monitoringCard"); |
| | | const canvas = document.getElementById("myCanvas"); |
| | | // 设置canvas的宽度和高度与video相同 |
| | | canvas.width = video.videoWidth; |
| | | canvas.height = video.videoHeight; |
| | | // 获取canvas的2d绘图上下文 |
| | | const context = canvas.getContext("2d"); |
| | | // 将当前video帧绘制到canvas上 |
| | | context.drawImage(video, 0, 0, canvas.width, canvas.height); |
| | | |
| | | setTimeout(() => { |
| | | // 将canvas内容转换为图片 |
| | | let dataURL = canvas.toDataURL("image/png"); |
| | | this.downloadImage(dataURL); |
| | | }, 100); |
| | | }, |
| | | downloadImage(base64) { |
| | | const link = document.createElement("a"); |
| | | link.href = base64; |
| | | link.download = "screenshot.png"; // 你希望下载的文件名 |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | document.body.removeChild(link); |
| | | }, |
| | | fullScreen() { |
| | | const video = document.getElementById("monitoringCard"); |
| | | if (video.requestFullscreen) { |
| | | video.requestFullscreen(); |
| | | } else if (video.mozRequestFullScreen) { |
| | | // Firefox |
| | | video.mozRequestFullScreen(); |
| | | } else if (video.webkitRequestFullscreen) { |
| | | // Chrome, Safari and Opera |
| | | video.webkitRequestFullscreen(); |
| | | } else if (video.msRequestFullscreen) { |
| | | // IE/Edge |
| | | video.msRequestFullscreen(); |
| | | } |
| | | }, |
| | | showDetails(row) { |
| | | this.loading = true |
| | | Promise.all([getOrderInfo(row.id), getOrderTravel({ id: row.id })]).then(res => { |
| | | getOrderMonitoring({ id: row.id }).then(resp => { |
| | | this.$refs.detailOrder.initData(res[0], resp, res[1]) |
| | | this.loading = false |
| | | }).catch(err => { |
| | | this.$refs.detailOrder.initData(res[0], {}, res[1]) |
| | | this.loading = false |
| | | }) |
| | | }).catch(err => { |
| | | this.loading = false |
| | | }) |
| | | }, |
| | | closeDrawer() { |
| | | this.drawer = false |
| | | this.showWarnDetail = false |
| | | |
| | | |
| | | }, |
| | | // 查看详情 |
| | | viewDetail(row) { |
| | |
| | | securityJsCode: this.$secretKey, |
| | | }; |
| | | AMapLoader.load({ |
| | | key:this.$mapKey, |
| | | key: this.$mapKey, |
| | | version: "2.0", |
| | | plugins: [ |
| | | "AMap.ToolBar", |
| | |
| | | pageSize: 10, |
| | | total: 0, |
| | | } |
| | | |
| | | |
| | | this.getList(this.detail.vehicleNumber) |
| | | //销毁地图 |
| | | if (this.map) { |
| | |
| | | pageCurr: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | startTime: this.searchForm.date[0], |
| | | endTime: this.searchForm.date[1], |
| | | startTime: new Date(this.searchForm.date[0]).getTime() / 1000, |
| | | endTime: new Date(this.searchForm.date[1]).getTime() / 1000, |
| | | } |
| | | getCarTrack({ ...this.searchForm, vehicleNumber: this.detail.vehicleNumber }).then(res => { |
| | | this.routeList = res; |
| | |
| | | }, |
| | | reset() { |
| | | this.searchForm = { |
| | | pageCurr: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | date: undefined, |
| | | pageCurr: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | date: undefined, |
| | | } |
| | | }, |
| | | getList(vehicleNumber) { |
| | |
| | | width: 100%; |
| | | height: 600px; |
| | | } |
| | | |
| | | #mapContainers { |
| | | width: 100%; |
| | | height: 500px; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .color1 { |
| | | color: #0E6EFD; |
| | | } |
| | |
| | | <div class="form flex j-between mt--23" style="align-items: end;"> |
| | | <div class="form-left ml--30"> |
| | | <el-form :inline="true" :model="searchForm" class="demo-form-inline"> |
| | | <el-form-item label="车辆号:" prop="carNumber" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.carNumber" placeholder="请输入"></el-input> |
| | | <el-form-item label="车牌号:" prop="vehicleNumber" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.vehicleNumber" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="公司名称:" prop="companyName" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.companyName" placeholder="请输入"></el-input> |
| | | <el-form-item label="公司名称:" prop="enterpriseName" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.enterpriseName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="所属车主:" prop="ownerName" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.ownerName" placeholder="请输入"></el-input> |
| | | <el-form-item label="所属车主:" prop="driverName" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.driverName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="车辆颜色:" prop="carColor" class="unset_m" style="margin-right: 15px;"> |
| | | <el-form-item label="车身颜色:" prop="carColor" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.carColor" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="车辆经营区域:" prop="operationArea" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.operationArea" placeholder="请输入"></el-input> |
| | | <el-form-item label="车辆经营区域:" prop="area" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.area" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="车辆型号:" prop="carModel" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.carModel" placeholder="请输入"></el-input> |
| | | <el-form-item label="车辆型号:" prop="brandModel" class="unset_m" style="margin-right: 15px;"> |
| | | <el-input v-model="searchForm.brandModel" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="核定载客位:" prop="startNum" class="unset_m" style="margin-right: 15px;"> |
| | | <el-form-item prop="startNum" style="margin-right: unset !important;"> |
| | |
| | | <el-input class="w--90" v-model="searchForm.endNum" placeholder="请输入最大值"></el-input> |
| | | </el-form-item> |
| | | </el-form-item> |
| | | <el-form-item label="车辆运营类型:" prop="operationType" class="unset_m" style="margin-right: 15px;"> |
| | | <el-select :popper-append-to-body="false" v-model="searchForm.operationType" placeholder="请选择"> |
| | | <el-option v-for="(item,index) in options" :key="index" :label="item.name" :value="item.id"></el-option> |
| | | <el-form-item label="车辆运营类型:" prop="operateType" class="unset_m" style="margin-right: 15px;"> |
| | | <el-select :popper-append-to-body="false" v-model="searchForm.operateType" placeholder="请选择"> |
| | | <el-option v-for="(item,index) in options" :key="index" :label="item.name" :value="item.name"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="车辆状态:" prop="carStatus" class="unset_m" style="margin-right: 15px;"> |
| | | <el-select :popper-append-to-body="false" v-model="searchForm.carStatus" placeholder="请选择"> |
| | | <el-form-item label="车辆状态:" prop="status" class="unset_m" style="margin-right: 15px;"> |
| | | <el-select :popper-append-to-body="false" v-model="searchForm.status" placeholder="请选择"> |
| | | <el-option label="在线" value="1"></el-option> |
| | | <el-option label="异常" value="2"></el-option> |
| | | <el-option label="离线" value="3"></el-option> |
| | |
| | | <el-table-column prop="status" label="车辆状态"> |
| | | <template slot-scope="scope"> |
| | | <el-tag v-if="scope.row.status == 1" type="success">在线</el-tag> |
| | | <el-tag v-if="scope.row.status == 2" type="warning">异常</el-tag> |
| | | <el-tag v-if="scope.row.status == 4" type="warning">故障</el-tag> |
| | | <el-tag v-if="scope.row.status == 2" type="danger">异常</el-tag> |
| | | <el-tag v-if="scope.row.status == 4" type="danger">故障</el-tag> |
| | | <el-tag v-if="scope.row.status == 3" type="info">离线</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | data() { |
| | | return { |
| | | searchForm: { |
| | | carNumber: '', // 车辆号 |
| | | companyName: '', // 公司名称 |
| | | ownerName: '', // 所属车主 |
| | | vehicleNumber: '', // 车辆号 |
| | | enterpriseName: '', // 公司名称 |
| | | driverName: '', // 所属车主 |
| | | carColor: '', // 车辆颜色 |
| | | operationArea: '', // 车辆经营区域 |
| | | carModel: '', // 车辆型号 |
| | | area: '', // 车辆经营区域 |
| | | brandModel: '', // 车辆型号 |
| | | startNum: '', // 核定载客位最小值 |
| | | endNum: '', // 核定载客位最大值 |
| | | operationType: '', // 车辆运营类型 |
| | | carStatus: '', // 车辆状态 |
| | | operateType: '', // 车辆运营类型 |
| | | status: '', // 车辆状态 |
| | | total: 0, |
| | | pageCurr: 1, |
| | | pageSize: 10 |
| | |
| | | const query = this.$route.query; |
| | | if (query && Object.keys(query).length > 0) { |
| | | if(query.id){ |
| | | this.searchForm.operationType = Number(query.id); |
| | | this.searchForm.operateType = query.id; |
| | | } |
| | | } |
| | | this.getList(); |
| | |
| | | methods: { |
| | | reset() { |
| | | this.searchForm = { |
| | | carNumber: '', |
| | | companyName: '', |
| | | ownerName: '', |
| | | vehicleNumber: '', |
| | | enterpriseName: '', |
| | | driverName: '', |
| | | carColor: '', |
| | | operationArea: '', |
| | | carModel: '', |
| | | area: '', |
| | | brandModel: '', |
| | | minSeats: '', |
| | | maxSeats: '', |
| | | operationType: '', |
| | | carStatus: '', |
| | | operateType: '', |
| | | status: '', |
| | | total: 0, |
| | | pageCurr: 1, |
| | | pageSize: 10 |
| | |
| | | export const getDetail = (params) => { |
| | | console.log(params) |
| | | return axios.get('/system/warn/getCarWarnInfo', {params}) |
| | | } |
| | | } |
| | | |
| | | // 获取订单详情 |
| | | export const getOrderInfo = (id) => { |
| | | return axios.get(`/system/order/getOrderInfo/${id}`) |
| | | } |
| | | |
| | | |
| | | // 获取订单行程轨迹 |
| | | export const getOrderTravel = (params) => { |
| | | return axios.get(`/system/order/getOrderTravel`, { params }) |
| | | } |
| | | |
| | | // 获取订单监控 |
| | | export const getOrderMonitoring = (params) => { |
| | | return axios.get(`/system/order/getOrderMonitoring`, { params }) |
| | | } |
| | |
| | | @click="exportExcell">导出</el-button> |
| | | </div> |
| | | <div class="table-box ml--30 mt--23 mr--30"> |
| | | <el-table :data="tableData" border stripe style="width: 100%" :height="height" :element-loading-text="'正在加载...'"> |
| | | <el-table :data="tableData" border stripe style="width: 100%" :element-loading-text="'正在加载...'"> |
| | | <el-table-column type="index" width="55" label="序号"></el-table-column> |
| | | <el-table-column prop="carName" label="车辆名称"></el-table-column> |
| | | <el-table-column prop="vehicleNumber" label="车牌号码"></el-table-column> |
| | |
| | | <script> |
| | | import { getComplainList } from './service' |
| | | import { exportExcell } from '@/utils/utils' |
| | | import moment from 'moment' |
| | | |
| | | export default { |
| | | data() { |
| | |
| | | let obj = { ...this.searchForm } |
| | | delete obj.total |
| | | if (obj.selectTime) { |
| | | obj.startTime = moment(obj.selectTime[0]).format('YYYY-MM-DD HH-mm-ss') |
| | | obj.endTime = moment(obj.selectTime[1]).format('YYYY-MM-DD HH-mm-ss') |
| | | obj.startTime = moment(obj.selectTime[0]).format('YYYY-MM-DD') + ' 00:00:00' |
| | | obj.endTime = moment(obj.selectTime[1]).format('YYYY-MM-DD') + ' 23:59:59' |
| | | delete obj.selectTime |
| | | } |
| | | exportExcell('投诉记录导出', obj, '/system/complain/exportComplainList') |
| | |
| | | let obj = { ...this.searchForm } |
| | | delete obj.total |
| | | if (obj.selectTime) { |
| | | obj.startTime = moment(obj.selectTime[0]).format('YYYY-MM-DD HH-mm-ss') |
| | | obj.endTime = moment(obj.selectTime[1]).format('YYYY-MM-DD HH-mm-ss') |
| | | obj.startTime = moment(obj.selectTime[0]).format('YYYY-MM-DD') + ' 00:00:00' |
| | | obj.endTime = moment(obj.selectTime[1]).format('YYYY-MM-DD') + ' 23:59:59' |
| | | delete obj.selectTime |
| | | } |
| | | getComplainList(obj).then(res => { |
| | |
| | | class="countCard" |
| | | v-for="(item, index) in carCountData.slice(0, 3)" |
| | | :key="item.id" |
| | | @click="toCarManage(item.id)" |
| | | @click="toCarManage(item.name)" |
| | | > |
| | | <img class="iconImg" :src="imgList[index]" /> |
| | | <div> |
| | |
| | | <div |
| | | class="countCard" |
| | | v-for="(item, index) in carCountData.slice(3, 7)" |
| | | @click="toCarManage(item.id)" |
| | | @click="toCarManage(item.name)" |
| | | :key="item.id" |
| | | > |
| | | <img class="iconImg" :src="imgList[index + 3]" /> |
| | |
| | | </div> |
| | | <!-- 预警情况统计 --> |
| | | <div class="warnCount"> |
| | | <div class="title">预警情况统计</div> |
| | | <div class="title ">预警情况统计</div> |
| | | <div class="countChart" id="countChart"></div> |
| | | <div class="noData" v-if="countList.length == 0"> |
| | | <el-empty description="暂无数据" :image-size="80"></el-empty> |
| | |
| | | </div> |
| | | <!-- 预警排行榜(前10) --> |
| | | <div class="warnRank"> |
| | | <div class="title">预警排行榜(前10)</div> |
| | | <div class="title mt-0">预警排行榜(前10)</div> |
| | | <div class="rankChart" id="rankChart"> |
| | | <div class="rankItem" v-for="(item, index) in rankList" :key="index"> |
| | | <div class="left">{{ item.name }}</div> |
| | |
| | | this.getWarnTop10Data(); |
| | | |
| | | this.initMap(); |
| | | if (this.timer) { |
| | | clearInterval(this.timer); |
| | | } |
| | | // 设置定时器,每分钟刷新一次数据 |
| | | this.timer = setInterval(() => { |
| | | this.getCarCountData(); |
| | |
| | | // 获取预警列表数据 |
| | | async getWarnListData() { |
| | | try { |
| | | const res = await getCarWarnList(); |
| | | const res = await getCarWarnList({pageNum:1,pageSize:100000}); |
| | | this.warnList = res.records; |
| | | } catch (error) { |
| | | this.$message.error("获取预警列表数据失败"); |
| | |
| | | }, |
| | | // 获取视频地址 |
| | | async getVideoUrl(carId) { |
| | | this.carId = carId; |
| | | try { |
| | | const res = await getRealVideo({ id: carId }); |
| | | // 将RTSP流转换为FLV流 |
| | | this.serverIp = res.serverIp; |
| | | this.serverPort = res.serverPort; |
| | | this.carId = carId; |
| | | } catch (error) { |
| | | console.error("获取视频地址失败", error); |
| | | return {}; |
| | |
| | | }, |
| | | |
| | | // 初始化视频播放器 |
| | | initVideoPlayer(videoUrl) { |
| | | initVideoPlayer() { |
| | | console.log('11111',this.serverIp,'2222222222',this.serverPort) |
| | | // 先销毁之前的播放器 |
| | | if (this.flvPlayer) { |
| | |
| | | enableStashBuffer: false, // 启用数据缓存机制,提高视频的流畅度和稳定性。 |
| | | stashInitialSize: 1024, // 初始缓存大小。单位:字节。建议针对直播:调整为1024kb |
| | | stashInitialTime: 0.2, // 缓存初始时间。单位:秒。建议针对直播:调整为200毫秒 |
| | | seekType: "range", // 建议将其设置为“range”模式,以便更快地加载视频数据,提高视频的实时性。 |
| | | seekType: "range", // 建议将其设置为"range"模式,以便更快地加载视频数据,提高视频的实时性。 |
| | | lazyLoad: false, //关闭懒加载模式,从而提高视频的实时性。建议针对直播:调整为false |
| | | lazyLoadMaxDuration: 0.2, // 懒加载的最大时长。单位:秒。建议针对直播:调整为200毫秒 |
| | | deferLoadAfterSourceOpen: false, // 不预先加载视频数据,在 MSE(Media Source Extensions)打开后立即加载数据,提高视频的实时性。建议针对直播:调整为false |
| | |
| | | this.flvPlayer |
| | | .play() |
| | | .then((res) => { |
| | | // 显示视频元素 |
| | | video.style.display = 'block'; |
| | | // 隐藏空状态 |
| | | const emptyElement = video.parentElement.querySelector('.el-empty'); |
| | | if (emptyElement) { |
| | | emptyElement.style.display = 'none'; |
| | | } |
| | | |
| | | this.videoTimer = setInterval(() => { |
| | | playDetection(this.carId); |
| | | }, 5000); |
| | |
| | | this.flvPlayer.detachMediaElement(); |
| | | this.flvPlayer.destroy(); |
| | | this.flvPlayer = null; |
| | | |
| | | // 恢复空状态的显示 |
| | | const video = document.getElementById("monitoringCard"); |
| | | if (video) { |
| | | video.style.display = 'none'; |
| | | const emptyElement = video.parentElement.querySelector('.el-empty'); |
| | | if (emptyElement) { |
| | | emptyElement.style.display = 'block'; |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | |
| | | listRender(record) { |
| | | return `<div style="background: #ffffff; padding: 24px 20px;z-index: 999"> |
| | | <div style="position: relative; width: 460px; height: 330px"> |
| | | |
| | | <video |
| | | <div style="width: 460px; height: 330px; border-radius: 9px; background: #f5f5f5; display: flex; justify-content: center; align-items: center; flex-direction: column"> |
| | | <video |
| | | ref="video" |
| | | style="width: 460px; height: 330px; border-radius: 9px" |
| | | id="monitoringCard" |
| | | ref="monitoringCard" |
| | | :controls="false" |
| | | autoPlay |
| | | width="620"> |
| | | </video> |
| | | style="width: 460px; height: 330px; border-radius: 9px; display: none" |
| | | id="monitoringCard" |
| | | ref="monitoringCard" |
| | | :controls="false" |
| | | autoPlay |
| | | width="620"> |
| | | </video> |
| | | <el-empty description="暂无视频信息" :image-size="80"></el-empty> |
| | | </div> |
| | | <canvas id="myCanvas" style="display:none"></canvas> |
| | | <div style="position: absolute; right: 11px; top: 10px"> |
| | | <div style="display: flex;flex-direction: column;align-items: center;justify-content: center; |
| | |
| | | }, |
| | | axisLabel: { |
| | | color: "rgba(0, 0, 0, 0.45)", |
| | | interval: 0, // 强制显示所有标签 |
| | | width: 60, // 设置标签宽度 |
| | | height: 20, // 设置标签高度 |
| | | overflow: 'truncate', // 截断模式 |
| | | ellipsis: true, // 超出显示省略号 |
| | | rotate: -40, // 可以根据需要调整角度 |
| | | formatter: function(value) { |
| | | if (value.length > 4) { |
| | | return value.substring(0, 4) + '...'; |
| | | } |
| | | return value; |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | |
| | | .leftMap { |
| | | // width: 100%; |
| | | height: 100%; |
| | | flex: 1; |
| | | flex: 3; |
| | | display: flex; |
| | | position: relative; |
| | | |
| | |
| | | right: 513px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | width: calc(100% - 570px); |
| | | width: calc(100% - 770px); |
| | | |
| | | .title { |
| | | font-weight: 600; |
| | |
| | | } |
| | | |
| | | .right { |
| | | width: 493px; |
| | | // width: 493px; |
| | | flex: 1; |
| | | height: calc(100% - 20px); |
| | | margin: 20px 17px 0 20px; |
| | | background: #ffffff; |
| | | box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2); |
| | | border-radius: 10px 10px 0px 0px; |
| | | padding: 20px; |
| | | overflow-y: auto; |
| | | |
| | | .title { |
| | | margin-top: 30px; |
| | |
| | | text-transform: none; |
| | | margin-bottom: 10px; |
| | | } |
| | | .mt-0{ |
| | | margin-top: 0 !important; |
| | | } |
| | | |
| | | .firCard { |
| | | display: flex; |
| | |
| | | |
| | | .companyCard { |
| | | width: 140px; |
| | | height: 90px; |
| | | // height: 90px; |
| | | background: #f4f4ff; |
| | | border-radius: 0px 10px 10px 0px; |
| | | position: relative; |
| | |
| | | left: 0; |
| | | top: 0; |
| | | width: 4px; |
| | | height: 90px; |
| | | // height: 90px; |
| | | background: #0e6efd; |
| | | border-radius: 2px; |
| | | } |
| | |
| | | position: relative; |
| | | |
| | | #countChart { |
| | | width: 453px; |
| | | height: 150px; |
| | | width: 100%; |
| | | height: 180px; |
| | | } |
| | | |
| | | .noData { |
| | |
| | | bottom: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 150px; |
| | | height: 180px; |
| | | } |
| | | } |
| | | |
| | |
| | | position: relative; |
| | | |
| | | .rankChart { |
| | | width: 453px; |
| | | height: 300px; |
| | | width: 100%; |
| | | // height: 300px; |
| | | |
| | | .rankItem { |
| | | display: flex; |
| | |
| | | flex: 2; |
| | | padding-right: 25px; |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | font-size: 13px; |
| | | color: rgba(0, 0, 0, 0.45); |
| | | line-height: 17px; |
| | | text-align: right; |
| | |
| | | } |
| | | // 获取车辆预警列表 |
| | | export const getCarWarnList = (data) => { |
| | | return axios.get('/system/warn/getCarWarnList', data) |
| | | return axios.get('/system/warn/getCarWarnList', {params:data}) |
| | | } |
| | | // 获取车辆预警情况统计 |
| | | export const getWarnGroupCount = (data) => { |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog title="订单详情" :visible.sync="dialogVisible" width="50%" :modal-append-to-body="false" |
| | | @close="closeClick"> |
| | | :close-on-press-escape="false" :close-on-click-modal="false" @close="closeClick"> |
| | | <el-radio-group v-model="tabPosition" style="margin-bottom: 30px;"> |
| | | <el-radio-button label="order">订单信息</el-radio-button> |
| | | <el-radio-button label="track">行程轨迹</el-radio-button> |
| | |
| | | ], |
| | | }) |
| | | .then((AMap) => { |
| | | this.map = new AMap.Map("mapContainer", { |
| | | center: [this.travelData[this.travelData.length / 2].longitude, this.travelData[this.travelData.length / 2].latitude], |
| | | zoom: 12, |
| | | }); |
| | | this.map.addControl(new AMap.ToolBar()); |
| | | let path = this.travelData.map(item => { |
| | | return new AMap.LngLat(item.longitude, item.latitude) |
| | | }) |
| | | const content = `<div class="custom-content-marker"> |
| | | 起点 |
| | | </div>`; |
| | | // 转换 travelData 中的坐标 |
| | | const wgs84Path = this.travelData.map(item => [item.longitude, item.latitude]); |
| | | const batchSize = 40; // 每次转换 40 对坐标 |
| | | const batches = []; |
| | | |
| | | const contentTwo = `<div class="custom-content-marker-two"> |
| | | 终点 |
| | | </div>`; |
| | | const marker = [ |
| | | new AMap.Marker({ |
| | | content: content, //自定义点标记覆盖物内容 |
| | | position: [this.travelData[0].longitude, this.travelData[0].latitude], //基点位置 |
| | | offset: new AMap.Pixel(-35, -25), //相对于基点的偏移位置 |
| | | }), |
| | | new AMap.Marker({ |
| | | content: contentTwo, //自定义点标记覆盖物内容 |
| | | position: [this.travelData[this.travelData.length - 1].longitude, this.travelData[this.travelData.length - 1].latitude], //基点位置 |
| | | offset: new AMap.Pixel(-35, -25), //相对于基点的偏移位置 |
| | | // 分批处理 |
| | | for (let i = 0; i < wgs84Path.length; i += batchSize) { |
| | | batches.push(wgs84Path.slice(i, i + batchSize)); |
| | | } |
| | | |
| | | const gcj02Path = []; |
| | | const promises = batches.map(batch => { |
| | | return new Promise((resolve, reject) => { |
| | | AMap.convertFrom(batch, 'gps', (status, result) => { |
| | | if (status === 'complete' && result.locations) { |
| | | resolve(result.locations); |
| | | } else { |
| | | reject(result); |
| | | } |
| | | }); |
| | | }); |
| | | }); |
| | | |
| | | // 等待所有批次转换完成 |
| | | Promise.all(promises) |
| | | .then(results => { |
| | | results.forEach(batchResult => { |
| | | gcj02Path.push(...batchResult); |
| | | }); |
| | | |
| | | // 开始绘制地图 |
| | | this.map = new AMap.Map("mapContainer", { |
| | | center: gcj02Path[Math.floor(gcj02Path.length / 2)], // 使用转换后的中点坐标 |
| | | zoom: 12, |
| | | }); |
| | | this.map.addControl(new AMap.ToolBar()); |
| | | |
| | | // 添加起点和终点标记 |
| | | const marker = [ |
| | | new AMap.Marker({ |
| | | content: `<div class="custom-content-marker">起点</div>`, |
| | | position: gcj02Path[0], |
| | | offset: new AMap.Pixel(-35, -25), |
| | | }), |
| | | new AMap.Marker({ |
| | | content: `<div class="custom-content-marker-two">终点</div>`, |
| | | position: gcj02Path[gcj02Path.length - 1], |
| | | offset: new AMap.Pixel(-35, -25), |
| | | }), |
| | | ]; |
| | | this.map.add(marker); |
| | | |
| | | // 绘制路径 |
| | | const polyline = new AMap.Polyline({ |
| | | path: gcj02Path, |
| | | strokeWeight: 3, |
| | | strokeColor: "red", |
| | | lineJoin: "round", |
| | | }); |
| | | this.map.add(polyline); |
| | | |
| | | // 强制刷新地图 |
| | | this.$nextTick(() => { |
| | | this.map.resize(); |
| | | }); |
| | | }) |
| | | ] |
| | | this.map.add(marker); |
| | | let polyline = new AMap.Polyline({ |
| | | path: path, |
| | | strokeWeight: 3, //线条宽度 |
| | | strokeColor: "red", //线条颜色 |
| | | lineJoin: "round", //折线拐点连接处样式 |
| | | }); |
| | | this.map.add(polyline); |
| | | // 强制刷新地图 |
| | | this.$nextTick(() => { |
| | | this.map.resize(); |
| | | }); |
| | | .catch(error => { |
| | | console.error('坐标转换失败', error); |
| | | }); |
| | | }) |
| | | .catch((e) => { |
| | | console.log(e); |
| | | }); |
| | | }, |
| | | closeClick() { |
| | |
| | | @click="exportExcell">导出</el-button> |
| | | </div> |
| | | <div class="table-box ml--30 mt--23 mr--30"> |
| | | <el-table :data="tableData" border stripe style="width: 100%" :height="height" |
| | | :element-loading-text="'正在加载...'"> |
| | | <el-table :data="tableData" border stripe style="width: 100%" :element-loading-text="'正在加载...'"> |
| | | <el-table-column type="index" width="55" label="序号" /> |
| | | <el-table-column prop="code" label="订单编号" /> |
| | | <el-table-column prop="vehicleNumber" label="车牌号" /> |
| | |
| | | }, |
| | | showDetail(row) { |
| | | this.loading = true |
| | | Promise.all([getOrderInfo(row.id), getOrderMonitoring({ id: row.id }), getOrderTravel({ id: row.id })]).then(res => { |
| | | // Promise.all([getOrderInfo(row.id), getOrderTravel({ id: row.id })]).then(res => { |
| | | this.$refs.detailModal.initData(res[0], res[1], res[2]) |
| | | this.loading = false |
| | | Promise.all([getOrderInfo(row.id), getOrderTravel({ id: row.id })]).then(res => { |
| | | getOrderMonitoring({ id: row.id }).then(resp => { |
| | | this.$refs.detailModal.initData(res[0], resp, res[1]) |
| | | this.loading = false |
| | | }).catch(err => { |
| | | this.$refs.detailModal.initData(res[0], {}, res[1]) |
| | | this.loading = false |
| | | }) |
| | | }).catch(err => { |
| | | this.loading = false |
| | | }) |
| | |
| | | </div> |
| | | </div> |
| | | <div class="table-box ml--30 mt--23 mr--30"> |
| | | <el-table :data="tableData" border stripe style="width: 100%" :height="height" :element-loading-text="'正在加载...'"> |
| | | <el-table :data="tableData" border stripe style="width: 100%" :element-loading-text="'正在加载...'"> |
| | | <el-table-column type="index" width="55" label="序号"></el-table-column> |
| | | <el-table-column prop="driverName" label="机动车驾驶员姓名"></el-table-column> |
| | | <el-table-column prop="enterpriseName" label="车辆所属公司"></el-table-column> |
| | |
| | | }, |
| | | showDetail(row) { |
| | | getDriverInfo(row.id).then(res=>{ |
| | | |
| | | this.$refs.detailModal.initData(res) |
| | | }) |
| | | }, |
| | | } |
| | |
| | | |
| | | // 获取司机详情 |
| | | export const getDriverInfo = (id) => { |
| | | return axios.get(`/system/driver/getDriverInfo/{id}/${id}`) |
| | | return axios.get(`/system/driver/getDriverInfo/${id}`) |
| | | } |
| | | |
| | | // 获取司机列表 |
| | |
| | | <div class="add_btn"> |
| | | <el-button icon="el-icon-plus" @click="add" type="primary">添加角色</el-button> |
| | | </div> |
| | | <el-table ref="tableSort" v-loading="listLoading" :height="height" stripe :data="data" |
| | | <el-table ref="tableSort" v-loading="listLoading" stripe :data="data" |
| | | :element-loading-text="elementLoadingText"> |
| | | <el-table-column type="index" width="55" label="序号"></el-table-column> |
| | | <el-table-column prop="roleName" label="角色名称"></el-table-column> |
| | |
| | | @click="dialogVisible = true">删除</el-button> --> |
| | | </div> |
| | | <div class="table-box ml--30 mt--23 mr--30"> |
| | | <el-table :data="data" border stripe style="width: 100%" :height="height" :element-loading-text="'正在加载...'"> |
| | | <el-table :data="data" border stripe style="width: 100%" :element-loading-text="'正在加载...'"> |
| | | <el-table-column prop="nickName" label="姓名"></el-table-column> |
| | | <el-table-column prop="phonenumber" label="联系电话"> |
| | | </el-table-column> |