Browse Source

代码提交

wangqin
Joe 11 months ago
parent
commit
83d9e5ad03
  1. 50
      ruoyi-ui/src/views/JiHeExpressway/components/FormConfig/components/FormSelect.vue
  2. 47
      ruoyi-ui/src/views/JiHeExpressway/components/Popover/index.vue
  3. 4
      ruoyi-ui/src/views/JiHeExpressway/components/Scrollbar/BlackBar.vue
  4. 113
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/CrowdnessIndicatorRankings/index.vue
  5. 220
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/DisposalPlan/index.vue
  6. 202
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/DisposalPlan/utils.js
  7. 2
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/index.vue
  8. 42
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/dispatch/EventDetailDialog/index.vue
  9. 9
      ruoyi-ui/vue.config.js

50
ruoyi-ui/src/views/JiHeExpressway/components/FormConfig/components/FormSelect.vue

@ -0,0 +1,50 @@
<template>
<ElSelect class='FormSelect' v-bind="$attrs" v-on="$listeners">
<ElOption v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
<slot></slot>
</ElOption>
</ElSelect>
</template>
<script>
export default {
name: 'FormSelect',
props: {
// options: {
// /**
// * {
// * value: any;
// * label: any;
// * }[]
// */
// type: Array,
// default: () => []
// }
},
data() {
return {
options: [{
value: '选项1',
label: '黄金糕'
}, {
value: '选项2',
label: '双皮奶'
}, {
value: '选项3',
label: '蚵仔煎'
}, {
value: '选项4',
label: '龙须面'
}, {
value: '选项5',
label: '北京烤鸭'
}],
value: ''
}
}
}
</script>
<style lang='scss' scoped>
.FormSelect {}
</style>

47
ruoyi-ui/src/views/JiHeExpressway/components/Popover/index.vue

@ -0,0 +1,47 @@
<template>
<ElPopover class='Popover' v-bind="getBind" v-on="$listeners">
<slot />
<template #reference>
<slot name="reference" />
</template>
</ElPopover>
</template>
<script>
export default {
name: 'Popover',
computed: {
getBind() {
return {
trigger: 'hover',
placement: "left",
...this.$attrs,
popperClass: "Popover-Scope-Screen"
}
}
}
}
</script>
<style lang='scss'>
div.el-popper.Popover-Scope-Screen {
background: linear-gradient(180deg, #005C79 0%, #009BCC 100%);
border: 0;
color: #fff;
font-size: 14px;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
color: #FFFFFF;
div.popper__arrow {
border-left-color: #00799f;
&::after {
border-left-color: #00799f;
}
}
}
</style>
<style lang='scss' scoped>
.Popover {}
</style>

4
ruoyi-ui/src/views/JiHeExpressway/components/Scrollbar/BlackBar.vue

@ -18,7 +18,9 @@ export default {
height: 100%;
overflow: hidden;
padding: 6px;
background: #000000;
// background: #000000;
border: 1px solid;
border-image: linear-gradient(72deg, rgba(55, 231, 255, .6), rgba(55, 231, 255, 0)) 1 1;
.BlackBar {
width: 100%;

113
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/CrowdnessIndicatorRankings/index.vue

@ -1,20 +1,123 @@
<template>
<Card class='CrowdnessIndicatorRankings' title="拥挤度指标排名情况">
CrowdnessIndicatorRankings
<Card class='CrowdnessIndicatorRankings border' title="拥挤度指标排名情况">
<div class="map">
map
</div>
<div class="right border">
<div :class="['item', { active: active === item.key }]" v-for="item in operation" :key="item.key"
@click="handleClick(item)">
<Popover :disabled="item.key !== 'weather'">
<div v-if="item.key === 'weather'">
天气 能见度 风向西南 风力1
</div>
<div class="label" slot="reference"
:style="{ backgroundImage: `url(${require(`./images/${item.key}${active === item.key ? '-active' : ''}.svg`)})` }" />
</Popover>
</div>
</div>
</Card>
</template>
<script>
import Card from "./../../components/Card.vue"
import Card from "./../../components/Card.vue";
import Popover from "@screen/components/Popover/index.vue"
export default {
name: 'CrowdnessIndicatorRankings',
components: {
Card
Card,
Popover
},
data() {
return {
active: "weather",
operation: [
{
key: 'weather',
label: "天气"
},
{
key: 'camera',
label: "摄像机"
},
{
key: 'bar',
label: "柱状图"
},
{
key: 'level',
label: "天气"
},
{
key: 'car',
label: "天气"
},
{
key: 'pie',
label: "天气"
},
]
}
},
methods: {
handleClick(item) {
this.active = item.key
}
}
}
</script>
<style lang='scss' scoped>
.CrowdnessIndicatorRankings {}
.border {
border: 1px solid;
border-image: linear-gradient(360deg, rgba(55, 231, 255, .42), rgba(55, 231, 255, 0)) 1 1;
}
.CrowdnessIndicatorRankings {
::v-deep {
.content {
display: flex;
padding: 0;
}
}
.map {
flex: 1;
}
.right {
right: 0px;
height: 100%;
top: 0;
width: 34px;
background: linear-gradient(180deg, rgba(25, 40, 52, .6) 0%, rgba(28, 50, 60, .6) 100%);
border-right: 0;
border-bottom: 0;
display: flex;
flex-direction: column;
gap: 6px;
.item {
width: 100%;
height: 34px;
padding: 3px;
cursor: pointer;
div {
width: 100%;
height: 100%;
transition: all .15s linear;
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
}
.active {
background: linear-gradient(180deg, #005C79 0%, #009BCC 100%);
}
}
}
</style>

220
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/DisposalPlan/index.vue

@ -1,20 +1,234 @@
<template>
<Card class='DisposalPlan' title="处置预案">
DisposalPlan
<canvas ref="FlowCanvasRef" />
</Card>
</template>
<script>
import Card from "./../../components/Card.vue"
import Card from "./../../components/Card.vue";
import { CanvasFlow } from "./utils";
import { merge } from "lodash"
function getDefaultBlockOption() {
return {
width: 100,
height: 30,
radius: 9,
linearGradient: "linear-gradient(180deg, #005C79 0%, #009BCC 100%)",
text: {
font: "PingFang SC",
fontSize: 14,
color: "#FFFFFF"
},
}
}
function getDefaultLegendOption() {
return {
width: 9,
height: 9,
y: 0,
text: {
font: "PingFang SC",
fontSize: 9,
align: 'left',
color: "#FFFFFF"
},
}
}
export default {
name: 'DisposalPlan',
components: {
Card
},
data() {
return {
// list: []
}
},
mounted() {
this.canvasFlow = new CanvasFlow(this.$refs.FlowCanvasRef);
this.draw();
},
methods: {
drawBlock({ x, y, width, height, backgroundColor, linearGradient,
radius,
text: {
color, text, fontSize, fontWeight, fontFamily
} = {} }) {
if (linearGradient) this.canvasFlow.setLinearGradient(...this.canvasFlow.transformCssLinearGradient(x, y, width, height, linearGradient))
this.canvasFlow.drawRectangle({ x, y, width, height, backgroundColor, radius });
if (text) {
this.canvasFlow.fillText(text, { x, y, color, fontSize, fontWeight, fontFamily }, { width, height });
}
},
drawLegend({ x, y, width, height, backgroundColor, linearGradient,
radius,
text: {
text, ...textOptions
} = {} }) {
if (linearGradient) this.canvasFlow.setLinearGradient(...this.canvasFlow.transformCssLinearGradient(x, y, width, height, linearGradient))
this.canvasFlow.drawRectangle({ x, y, width, height, backgroundColor, radius });
if (text) {
this.canvasFlow.fillText(text, { ...textOptions, x: x + width + 3, y: y + height / 2, }, { height });
}
},
drawLine({ x, y, width, height, backgroundColor, linearGradient, }) {
},
draw() {
const { clientWidth } = this.$refs.FlowCanvasRef;
const defaultBlockOption = getDefaultBlockOption();
const halfWidth = defaultBlockOption.width / 2;
this.canvasFlow.clear();
const legends = [
{
type: 'drawLegend',
options: merge(getDefaultLegendOption(), {
x: 150,
linearGradient: "linear-gradient(180deg, #004960 0%, #004B62 100%)",
text: {
text: "未完成"
}
})
},
{
type: 'drawLegend',
options: merge(getDefaultLegendOption(), {
x: 210,
linearGradient: "linear-gradient(90deg, #006121 0%, #488000 100%)",
text: {
text: "进行中"
}
})
},
{
type: 'drawLegend',
options: merge(getDefaultLegendOption(), {
x: 270,
linearGradient: "linear-gradient(180deg, #005C79 0%, #009BCC 100%)",
text: {
text: "已完成"
}
})
}
]
const blockList = [
{
type: 'drawBlock',
key: "DisposalPlan",
options: merge(getDefaultBlockOption(), {
x: clientWidth / 2 - halfWidth,
y: 24,
text: {
text: "处置预案"
}
})
},
{
type: 'drawBlock',
key: "AnalyzeConfirm",
options: merge(getDefaultBlockOption(), {
x: clientWidth / 2 - halfWidth,
y: 75,
text: {
text: "分析确认"
}
})
},
{
type: 'drawBlock',
key: "InstructionsGiven",
options: merge(getDefaultBlockOption(), {
x: clientWidth / 7 - halfWidth,
y: 123,
linearGradient: "linear-gradient(90deg, #006121 0%, #488000 100%)",
text: {
text: "指令下达"
}
})
},
{
type: 'drawBlock',
key: "OnSiteConfirmation",
options: merge(getDefaultBlockOption(), {
x: clientWidth / 7 * 6 - halfWidth,
y: 123,
linearGradient: "linear-gradient(90deg, #006121 0%, #488000 100%)",
text: {
text: "现场确认"
}
})
},
{
type: 'drawBlock',
key: "OnSiteDisposal",
options: merge(getDefaultBlockOption(), {
x: clientWidth / 2 - halfWidth,
y: 170,
linearGradient: "linear-gradient(180deg, #004960 0%, #004B62 100%)",
text: {
text: "现场处置"
}
})
},
{
type: 'drawBlock',
key: "FollowUpProcessing",
options: merge(getDefaultBlockOption(), {
x: clientWidth / 2 - halfWidth,
y: 225,
linearGradient: "linear-gradient(180deg, #004960 0%, #004B62 100%)",
text: {
text: "后续处理"
}
})
},
];
const linePoints = [
{
x: clientWidth / 7 - halfWidth,
y: 1
}
];
[...blockList, ...legends].forEach(item => {
this[item.type]?.(item.options)
})
}
},
}
</script>
<style lang='scss' scoped>
.DisposalPlan {}
.DisposalPlan {
::v-deep {
.content {
display: flex;
flex-direction: column;
}
}
canvas {
flex: 1;
width: 100%;
height: 100%;
}
}
</style>

202
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/DisposalPlan/utils.js

@ -0,0 +1,202 @@
export function getQuadrant(angle) {
angle %= 360.0;
if (angle < 0) angle += 360.0;
var quadrant = Math.floor(angle / 90) + 1;
return quadrant;
}
export function calcPoint(x0, y0, width, height, angle) {
const parseAngle = parseFloat(angle);
angle = (Math.PI / 180) * parseFloat(parseAngle);
x0 += width / 2;
y0 += height / 2;
const hypotenuse = width / 2 > height / 2 ? width / 2 : height / 2;
// 对边
let oppositeEdge = Math.abs(hypotenuse * Math.sin(angle));
// 邻边
let adjacentEdge = Math.abs(hypotenuse * Math.cos(angle));
let point0 = [],
point1 = [];
switch (parseFloat(parseAngle) % 360.0) {
case 180:
oppositeEdge = adjacentEdge;
adjacentEdge = 0;
break;
case 90:
case 270:
adjacentEdge = oppositeEdge;
oppositeEdge = 0;
break;
}
switch (getQuadrant(parseAngle)) {
case 1:
point0 = [x0 - adjacentEdge, y0 + oppositeEdge];
point1 = [x0 + adjacentEdge, y0 - oppositeEdge];
break;
case 2:
point0 = [x0 - adjacentEdge, y0 - oppositeEdge];
point1 = [x0 + adjacentEdge, y0 + oppositeEdge];
break;
case 3:
point0 = [x0 + adjacentEdge, y0 - oppositeEdge];
point1 = [x0 - adjacentEdge, y0 + oppositeEdge];
break;
case 4:
point0 = [x0 + adjacentEdge, y0 + oppositeEdge];
point1 = [x0 - adjacentEdge, y0 - oppositeEdge];
break;
}
return angle > 0 ? [point0, point1] : [point1, point0];
}
export class CanvasFlow {
canvas = null;
context = null;
zoom = 3;
constructor(canvas) {
this.canvas = canvas;
this.context = canvas.getContext("2d");
this.canvas.width = canvas.clientWidth * this.zoom;
this.canvas.height = canvas.clientHeight * this.zoom;
}
drawRectangle({
x,
y,
width,
height,
borderWidth,
borderColor,
backgroundColor,
radius,
}) {
if (backgroundColor) this.context.fillStyle = backgroundColor;
x *= this.zoom;
y *= this.zoom;
width *= this.zoom;
height *= this.zoom;
if (radius) {
this.context.beginPath();
this.context.roundRect(x, y, width, height, radius);
this.context.fill();
} else {
this.context.fillRect(x, y, width, height);
}
if (typeof borderWidth === "number") {
borderWidth *= this.zoom;
this.context.lineWidth = borderWidth;
this.context.strokeStyle = borderColor;
this.context.stroke();
}
}
transformCssLinearGradient(x, y, width, height, linearGradient) {
const [_, deg, ...stopStrings] = linearGradient.match(/[^,()]+/g);
const stops = stopStrings.map((stop) => {
const [color, offset] = stop.trim().split(" ");
return {
color,
offset: parseFloat(offset) * 0.01,
};
});
const [point0, point1] = calcPoint(x, y, width, height, deg);
return [
{
x0: point0[0],
y0: point0[1],
x1: point1[0],
y1: point1[1],
},
stops,
];
}
setLinearGradient({ x0, y0, x1, y1 }, stops) {
x0 *= this.zoom;
x1 *= this.zoom;
y0 *= this.zoom;
y1 *= this.zoom;
const gradient = this.context.createLinearGradient(x0, y0, x1, y1);
stops.forEach(({ offset, color }) => {
gradient.addColorStop(offset, color);
});
this.context.fillStyle = gradient;
}
drawLine({ startX, endX, color }, vertices) {
startX *= this.zoom;
endX *= this.zoom;
ctx.beginPath();
ctx.moveTo(startX, endX);
vertices.forEach(({ x, y }) => {
ctx.lineTo(x * this.zoom, y * this.zoom);
});
this.context.strokeStyle = color;
ctx.stroke();
}
fillText(
text,
{
x,
y,
fontSize = 15,
color,
align = "center",
fontWeight = "normal",
fontFamily = "微软雅黑",
} = {},
{ width: rectWidth = 0, height: rectHeight = 0 } = {}
) {
this.context.font = `${fontWeight} ${fontSize * this.zoom}px ${fontFamily}`;
this.context.textBaseline = "middle";
const textWidth = this.context.measureText(text).width;
x *= this.zoom;
switch (align) {
case "center":
x += (rectWidth * this.zoom - textWidth) / 2;
y += rectHeight / 2;
break;
}
this.context.fillStyle = color;
this.context.fillText(text, x, y * this.zoom);
}
clear() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}

2
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/index.vue

@ -80,7 +80,7 @@ export default {
gap: 18px;
>div {
transition: all .3s linear;
transition: all .18s linear;
}
::v-deep {

42
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/dispatch/EventDetailDialog/index.vue

@ -2,7 +2,25 @@
<Dialog v-model="modelVisible" title="事件详情">
<div class="EventDetail">
<BlackBar class="left">
<img src="./images/test.png" />
<!-- <img src="./images/test.png" style="width: 100%;" /> -->
<div class="example">
<div class="title">
<h3>调度记录</h3>
<span>
2024年01月12日 00时00分00秒 2024年01月12日 23时59分59秒
</span>
</div>
<div class="body">
<p>2024-01-12 08:59,山东高速济南发展有限公司,集团账号:由出行转接上报了一起交通事故事件;</p>
<p>2024-01-12 09:08,山东高速济南发展有限公司,系统消息:自动分配路管人员陈清泉,救援车辆鲁AJ7K68参与事件处置</p>
<p>2024-01-12 09:08,山东高速济南发展有限公司,晋雪艳1;</p>
<p>2024-01-12 09:00,山东高速济南发展有限公司,三雪艳2;</p>
<p>2024-01-12 09:11,山东高速济南发展有限公司,晋雪艳2;</p>
<p>2024-01-12 09:11,山东高速济南发展有限公司,晋雪艳3;</p>
<p>2024-01-12 09:12.山东高速济南发展有限公司,晋雪艳4;</p>
<p>2024-01-12 09:12,山东高速济南发展有限公司,晋雪艳4;</p>
</div>
</div>
<!-- <div style="width: 900px;height: 900px; background-color: #0F191E;"></div> -->
</BlackBar>
<div class="right">
@ -52,6 +70,28 @@ export default {
flex: 1;
width: 600px;
height: 720px;
.example {
display: flex;
flex-direction: column;
gap: 9px;
>div {
display: flex;
flex-direction: column;
}
>.body {
gap: 6px;
font-size: 13px;
}
>.title {
align-items: center;
border-bottom: 1px solid white;
padding-bottom: 6px;
}
}
}
.right {

9
ruoyi-ui/vue.config.js

@ -40,12 +40,13 @@ module.exports = {
// target: `http://192.168.0.182:8080`,
// target: `http://192.168.0.194:8080`,
// target: `http://10.0.81.201:8080`,
target: `http://10.168.77.209:8080`,// 刘朋
target: `http://10.168.77.209:8080`, // 刘朋
target: `http://10.168.73.36:8080`, // 周乐
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
["^" + process.env.VUE_APP_BASE_API]: "",
},
},
},
disableHostCheck: true,

Loading…
Cancel
Save