Browse Source

<feat>:提交部分代码

master
黄潇军 3 months ago
parent
commit
01a42a1e62
  1. 168
      packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/MapComponent copy.vue
  2. 22
      packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/MapComponent.vue
  3. 52
      packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/components/BlockTitle.vue
  4. BIN
      packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/images/block-title.png
  5. 149
      packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/index.vue

168
packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/MapComponent copy.vue

@ -0,0 +1,168 @@
<template>
<div id="map" style="height: 100%; width: 100%; overflow: hidden"></div>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
/**
* props.rectangles: Array<{ id, name, status, geomWkt }>
* - geomWkt: "POLYGON((lng lat,lng lat,...))"
* - status: 施工中 | 已施工 | 未施工 | 故障 | 运行中 | 停机
*/
const STATUS_STYLE = {
施工中: { stroke: 'rgba(41,169,253,1)', fill: 'rgba(41,169,253,0.45)' },
已施工: { stroke: 'rgba(82,196,26,1)', fill: 'rgba(82,196,26,0.45)' },
未施工: { stroke: 'rgba(250,173,20,1)', fill: 'rgba(250,173,20,0.45)' },
故障: { stroke: 'rgba(219,77,77,1)', fill: 'rgba(219,77,77,0.6)' },
运行中: { stroke: 'rgba(19,194,194,1)', fill: 'rgba(19,194,194,0.45)' },
停机: { stroke: 'rgba(99,99,99,1)', fill: 'rgba(0,0,0,0.45)' }
};
export default {
name: 'TaskMapPolygon',
props: {
rectangles: {
type: Array,
default: () => []
}
},
data() {
return {
map: null,
AMapIns: null,
polygons: [],
texts: [],
pointAll: { lng: [], lat: [] }
};
},
watch: {
rectangles: {
immediate: true,
deep: true,
handler(val) {
if (this.map && val?.length) {
this.clearLayers();
this.formatData(val);
}
}
}
},
mounted() {
this.initAMap();
},
beforeUnmount() {
this.map?.destroy();
},
methods: {
initAMap() {
const map_center = JSON.parse(this.$storage.get('map_center') || 'null');
let defaultCenterPoint = [121.5563, 32.107];
if (map_center) {
defaultCenterPoint = map_center.find((el) => el.key == 'default')?.value || defaultCenterPoint;
}
window._AMapSecurityConfig = { securityJsCode: '5869fe06ab3640b49006f4ec5e595e9f' };
AMapLoader.load({
key: '3758e4530242ba6282c77f96ea69262d',
version: '2.0',
plugins: ['AMap.MouseTool', 'AMap.Scale', 'AMap.Text']
})
.then((AMap) => {
this.AMapIns = AMap;
this.map = new AMap.Map('map', {
viewMode: '2D',
zoom: 12,
center: defaultCenterPoint
});
if (this.rectangles?.length) {
this.formatData(this.rectangles);
}
})
.catch(console.error);
},
clearLayers() {
if (!this.map) return;
this.map.remove(this.polygons);
this.map.remove(this.texts);
this.polygons = [];
this.texts = [];
this.pointAll = { lng: [], lat: [] };
},
formatData(data = []) {
// WKT -> AMap path使
const list = (data || []).map((item, index) => {
const raw = (item.geomWkt || '')
.replace(/POLYGON\(\(/i, '')
.replace(/\)\)$/i, '')
.trim();
const points = raw.split(',');
const path = [];
for (let i = 0; i < points.length; i++) {
const parts = points[i].trim().split(/\s+/);
const lng = Number(parts[0]);
const lat = Number(parts[1]);
if (isNaN(lng) || isNaN(lat)) continue;
this.pointAll.lng.push(lng);
this.pointAll.lat.push(lat);
path.push([lng, lat]);
}
return { ...item, path, index };
});
list.forEach((it) => this.createPolygon(it));
//
if (this.polygons.length) {
// padding: [top, right, bottom, left]
this.map.setFitView(this.polygons, false, [60, 60, 60, 60]);
}
},
createPolygon(item) {
const { path, status, name } = item;
const style = STATUS_STYLE[status] || STATUS_STYLE['未施工'];
const polygon = new this.AMapIns.Polygon({
path,
strokeColor: style.stroke,
strokeWeight: 2,
strokeOpacity: 1,
strokeStyle: 'solid',
fillColor: style.fill,
fillOpacity: 0.45,
cursor: 'pointer',
zIndex: 50
});
console.log(polygon, 'polygon');
this.map.add(polygon);
this.polygons.push(polygon);
//
const text = new this.AMapIns.Text({
text: name || '',
anchor: 'center',
style: { 'background-color': 'transparent', border: 'none', color: '#ffffff', 'font-size': '12px' }
});
//
const mid = path[Math.floor(path.length / 2)] || path[0];
if (mid) text.setPosition(mid);
text.setMap(this.map);
this.texts.push(text);
// hover
polygon.on('mouseover', () => {
polygon.setOptions({ fillOpacity: 0.55 });
});
polygon.on('mouseout', () => {
polygon.setOptions({ fillOpacity: 0.35 });
});
}
}
};
</script>
<style scoped lang="scss">
#map {
width: 100%;
height: 100%;
}
</style>

22
packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/MapComponent.vue

@ -1,5 +1,8 @@
<template> <template>
<div style="position: relative; height: 100%; width: 100%; overflow: hidden">
<div id="map" style="height: 100%; width: 100%; overflow: hidden"></div> <div id="map" style="height: 100%; width: 100%; overflow: hidden"></div>
<div v-if="darkMask" class="dark-mask"></div>
</div>
</template> </template>
<script> <script>
@ -25,6 +28,11 @@ export default {
rectangles: { rectangles: {
type: Array, type: Array,
default: () => [] default: () => []
},
//
darkMask: {
type: Boolean,
default: true
} }
}, },
data() { data() {
@ -70,10 +78,13 @@ export default {
}) })
.then((AMap) => { .then((AMap) => {
this.AMapIns = AMap; this.AMapIns = AMap;
// 使线
const satellite = new AMap.TileLayer.Satellite();
this.map = new AMap.Map('map', { this.map = new AMap.Map('map', {
viewMode: '2D', viewMode: '2D',
zoom: 12, zoom: 12,
center: defaultCenterPoint center: defaultCenterPoint,
layers: [satellite]
}); });
if (this.rectangles?.length) { if (this.rectangles?.length) {
this.formatData(this.rectangles); this.formatData(this.rectangles);
@ -165,4 +176,13 @@ export default {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.dark-mask {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: rgba(0, 10, 26, 0.25);
pointer-events: none;
}
</style> </style>

52
packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/components/BlockTitle.vue

@ -0,0 +1,52 @@
<template>
<div class="block-title">
<div class="title-left">
<img src="../images/block-title.png" alt="logo" />
<div class="title-text">{{ title }}</div>
</div>
<div class="title-more">
<slot name="more"> </slot>
</div>
</div>
</template>
<script>
export default {
name: 'BlockTitle',
props: {
title: {
type: String,
default: ''
}
}
};
</script>
<style lang="scss" scoped>
.block-title {
display: flex;
justify-content: space-between;
align-items: center;
height: 28px;
img {
height: 26px;
width: auto;
margin-right: 8px;
}
.title-left {
display: flex;
align-items: center;
}
.title-text {
font-family: PingFang SC, PingFang SC;
font-weight: 600;
font-size: 20px;
color: #333333;
}
.title-more {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #4886e0;
}
}
</style>

BIN
packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/images/block-title.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

149
packages/robot-system/src/modules/RobotSystemManage/ScreenViewManage/TaskScreenView/index.vue

@ -1,6 +1,6 @@
<template> <template>
<div class="task-screen"> <div class="task-screen">
<div class="map-wrap"> <!-- <div class="map-wrap">
<MapComponent :rectangles="rectangles" /> <MapComponent :rectangles="rectangles" />
<div class="legend"> <div class="legend">
<div class="legend-item" v-for="(item, i) in legends" :key="i"> <div class="legend-item" v-for="(item, i) in legends" :key="i">
@ -8,22 +8,20 @@
<span class="text">{{ item.label }}</span> <span class="text">{{ item.label }}</span>
</div> </div>
</div> </div>
</div> </div> -->
<div class="side left"> <div class="side left">
<div class="panel"> <div class="panel">
<div class="panel-title"> <BlockTitle title="工区统计">
<img class="titleIcon" :src="titleIcon" /> <template #right>
<span>工区统计</span> <span>更多</span>
<span class="more">更多</span> </template>
</div> </BlockTitle>
<div class="progress-group"> <div class="progress-group">
<div class="progress-row"> <div class="progress-row">
<div class="label">工区总进度</div> <div class="label">工区总进度</div>
<div class="value">{{ areaProgress }}%</div> <div class="value">{{ areaProgress }}%</div>
</div> </div>
<fks-progress :percentage="areaProgress" :stroke-width="8" color="#4dabf7" />
<div class="progress-sub"> <div class="progress-sub">
<div class="sub-row" v-for="(p, pi) in subProgress" :key="pi"> <div class="sub-row" v-for="(p, pi) in subProgress" :key="pi">
<div class="name">{{ p.name }}</div> <div class="name">{{ p.name }}</div>
@ -33,24 +31,21 @@
<div class="num">{{ p.value }}</div> <div class="num">{{ p.value }}</div>
</div> </div>
</div> </div>
</div> <fks-table :data="areaTable" border height="220">
<fks-table-column prop="name" label="工区名称" min-width="74" />
<fks-table :data="areaTable" border height="280"> <fks-table-column prop="pile" label="桩条安装进度(%)" width="90" />
<fks-table-column type="index" label="#" width="50" /> <fks-table-column prop="module" label="组件安装进度(%)" width="90" />
<fks-table-column prop="name" label="工区名称" min-width="90" /> <fks-table-column prop="year" label="10号车" width="74" />
<fks-table-column prop="pile" label="桩条安装进度(%)" width="140" />
<fks-table-column prop="module" label="组件安装进度(%)" width="140" />
<fks-table-column prop="owner" label="负责安环" width="90" />
<fks-table-column prop="year" label="10号车" width="80" />
</fks-table> </fks-table>
</div> </div>
</div>
<div class="panel"> <div class="panel">
<div class="panel-title"> <BlockTitle title="材料统计">
<img class="titleIcon" :src="titleIcon" /> <template #right>
<span>材料统计</span> <span>更多</span>
<span class="more">更多</span> </template>
</div> </BlockTitle>
<fks-table :data="materialTable" border height="300"> <fks-table :data="materialTable" border height="300">
<fks-table-column prop="name" label="材料名称" min-width="100" /> <fks-table-column prop="name" label="材料名称" min-width="100" />
<fks-table-column prop="used" label="当日消耗量" width="120" /> <fks-table-column prop="used" label="当日消耗量" width="120" />
@ -61,12 +56,11 @@
<div class="side right"> <div class="side right">
<div class="panel"> <div class="panel">
<div class="panel-title"> <BlockTitle title="设备信息">
<img class="titleIcon" :src="titleIcon" /> <template #right>
<span>设备信息</span> <span>更多</span>
<span class="more">更多</span> </template>
</div> </BlockTitle>
<div class="kpibox"> <div class="kpibox">
<div class="kpi"> <div class="kpi">
<div class="kpi-label">当前设备在线数量</div> <div class="kpi-label">当前设备在线数量</div>
@ -115,11 +109,12 @@
<script> <script>
import Mix from '@/mixins/module'; import Mix from '@/mixins/module';
import MapComponent from './MapComponent.vue'; import MapComponent from './MapComponent.vue';
import BlockTitle from './components/BlockTitle.vue';
export default { export default {
name: 'TaskScreenView', name: 'TaskScreenView',
mixins: [Mix], mixins: [Mix],
components: { MapComponent }, components: { MapComponent, BlockTitle },
data() { data() {
return { return {
titleIcon: require('@/assets/img/Automated/titleIcon1.png'), titleIcon: require('@/assets/img/Automated/titleIcon1.png'),
@ -165,17 +160,17 @@ export default {
], ],
rectangles: [ rectangles: [
// 西 // 西
{ id: '1', name: '西湖区', status: '施工中', geomWkt: 'POLYGON((120.0000 30.1500,120.2500 30.1500,120.2500 30.3700,120.0000 30.3700,120.0000 30.1500))' }, { id: '1', name: '西湖区', status: '施工中', geomWkt: 'POLYGON((120.0000 30.1500,120.2500 30.1500,120.2500 30.3700,120.0000 30.3700,120.0000 30.1500))' }
// //
{ id: '2', name: '拱墅区', status: '已施工', geomWkt: 'POLYGON((120.0900 30.3000,120.2300 30.3000,120.2300 30.4200,120.0900 30.4200,120.0900 30.3000))' }, // { id: '2', name: '', status: '', geomWkt: 'POLYGON((120.0900 30.3000,120.2300 30.3000,120.2300 30.4200,120.0900 30.4200,120.0900 30.3000))' },
// // //
{ id: '3', name: '上城区', status: '未施工', geomWkt: 'POLYGON((120.1400 30.2000,120.2600 30.2000,120.2600 30.3100,120.1400 30.3100,120.1400 30.2000))' }, // { id: '3', name: '', status: '', geomWkt: 'POLYGON((120.1400 30.2000,120.2600 30.2000,120.2600 30.3100,120.1400 30.3100,120.1400 30.2000))' },
// // //
{ id: '4', name: '滨江区', status: '故障', geomWkt: 'POLYGON((120.0900 30.1400,120.2700 30.1400,120.2700 30.2400,120.0900 30.2400,120.0900 30.1400))' }, // { id: '4', name: '', status: '', geomWkt: 'POLYGON((120.0900 30.1400,120.2700 30.1400,120.2700 30.2400,120.0900 30.2400,120.0900 30.1400))' },
// // //
{ id: '5', name: '萧山区', status: '运行中', geomWkt: 'POLYGON((120.1800 30.0200,120.5300 30.0200,120.5300 30.3300,120.1800 30.3300,120.1800 30.0200))' }, // { id: '5', name: '', status: '', geomWkt: 'POLYGON((120.1800 30.0200,120.5300 30.0200,120.5300 30.3300,120.1800 30.3300,120.1800 30.0200))' },
// // //
{ id: '6', name: '余杭区', status: '停机', geomWkt: 'POLYGON((119.8000 30.1800,120.1000 30.1800,120.1000 30.5000,119.8000 30.5000,119.8000 30.1800))' } // { id: '6', name: '', status: '', geomWkt: 'POLYGON((119.8000 30.1800,120.1000 30.1800,120.1000 30.5000,119.8000 30.5000,119.8000 30.1800))' }
], ],
legends: [ legends: [
{ label: '施工中', color: '#3fa7ff' }, { label: '施工中', color: '#3fa7ff' },
@ -191,12 +186,27 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
//
* {
box-sizing: border-box;
color: #333333;
}
::v-deep .fks-table {
table {
th {
font-size: 12px !important;
padding: 4px 0 !important;
color: #999 !important;
background: #f9f9f9 !important;
}
}
}
//
.task-screen { .task-screen {
position: relative; position: relative;
display: flex; display: flex;
height: 100%; height: 100%;
width: 100%; width: 100%;
background: #0b1535;
} }
.map-wrap { .map-wrap {
position: relative; position: relative;
@ -225,18 +235,19 @@ export default {
margin-right: 6px; margin-right: 6px;
} }
.text { .text {
color: #cfe6ff;
font-size: 12px; font-size: 12px;
} }
} }
} }
.side { .side {
width: 360px; width: 392px;
padding: 12px; padding: 24px;
box-sizing: border-box; box-sizing: border-box;
box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.1);
border-radius: 4px;
.panel + .panel { .panel + .panel {
margin-top: 12px; margin-top: 20px;
} }
} }
.left { .left {
@ -255,15 +266,13 @@ export default {
} }
.panel { .panel {
background: rgba(0, 12, 32, 0.7); .block-title {
border: 1px solid rgba(91, 166, 255, 0.35); margin-bottom: 10px;
border-radius: 8px; }
padding: 12px;
.panel-title { .panel-title {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
color: #cfe6ff;
font-size: 14px; font-size: 14px;
margin-bottom: 10px; margin-bottom: 10px;
.titleIcon { .titleIcon {
@ -275,44 +284,52 @@ export default {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
} }
.more {
color: #6bb1ff;
cursor: pointer;
font-size: 12px;
}
} }
} }
.progress-group { .progress-group {
margin-bottom: 12px; background: linear-gradient(180deg, #ffffff 0%, rgba(242, 249, 255, 0.5) 100%);
border-radius: 8px 8px 8px 8px;
border: 1px solid #dcedff;
.progress-row { .progress-row {
height: 34px;
background: linear-gradient(90deg, #e6f5ff 0%, #d3eeff 100%), linear-gradient(90deg, #e6f5ff 0%, #d8efff 75%, rgba(214, 238, 255, 0.89) 79%, rgba(211, 238, 255, 0.58) 100%);
margin-bottom: 12px;
display: flex; display: flex;
justify-content: space-between; align-items: center;
color: #cfe6ff; justify-content: center;
margin-bottom: 6px; gap: 0 8px;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 14px;
.label { .label {
font-size: 13px; color: #333333;
} }
.value { .value {
font-size: 13px; color: #4886e0;
} }
} }
.progress-sub { .progress-sub {
margin-top: 8px; margin-top: 8px;
padding: 12px;
.sub-row { .sub-row {
display: grid; display: grid;
grid-template-columns: 120px 1fr 36px; grid-template-columns: 92px 1fr 18px;
align-items: center; align-items: center;
color: #cfe6ff;
font-size: 12px;
margin-bottom: 6px; margin-bottom: 6px;
gap: 0 16px;
.name { .name {
opacity: 0.85; font-size: 12px;
color: #999;
} }
.bar { .bar {
padding: 0 8px; padding: 0 8px;
} }
.num { .num {
font-family: DIN, DIN;
font-weight: bold;
font-size: 16px;
color: #4886e0;
text-align: right; text-align: right;
} }
} }
@ -330,7 +347,6 @@ export default {
border-radius: 6px; border-radius: 6px;
padding: 10px 8px; padding: 10px 8px;
.kpi-label { .kpi-label {
color: #94b8ff;
font-size: 12px; font-size: 12px;
margin-bottom: 4px; margin-bottom: 4px;
white-space: nowrap; white-space: nowrap;
@ -338,7 +354,6 @@ export default {
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.kpi-value { .kpi-value {
color: #e8f3ff;
font-weight: 600; font-weight: 600;
font-size: 18px; font-size: 18px;
line-height: 1.2; line-height: 1.2;

Loading…
Cancel
Save