Merge branch 'master' of git.code.tencent.com:beijing-rtss-test/bj-rtss-client

This commit is contained in:
Yuan 2023-10-23 16:47:28 +08:00
commit b41a25b95c
40 changed files with 1143 additions and 346 deletions

View File

@ -11,6 +11,8 @@
"test": "echo \"No test specified\" && exit 0",
"dev": "quasar dev",
"build": "quasar build",
"build:test": "set NODE_ENV=test&&quasar build",
"build:publish": "set NODE_ENV=publish&&quasar build",
"protoc": "node scripts/proto.cjs",
"sync": "node scripts/sync.cjs"
},

View File

@ -52,6 +52,10 @@ module.exports = configure(function (/* ctx */) {
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
build: {
env: {
// test:测试服务器publish正式服务器其他本地
ENV_MODE: process.env.NODE_ENV,
},
target: {
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
node: 'node16',

View File

@ -60,6 +60,7 @@ export async function setSignalState(data: {
simulationId: string;
mapId: number;
id: string;
operation: number;
aspect: number;
}) {
return await api.post(`${UriBase}/signal/operation`, data);
@ -158,3 +159,34 @@ export async function setRelayState(data: {
}) {
return await api.post(`${UriBase}/relay/operation`, data);
}
interface KilometerRange {
Coordinate: string;
MinCoordinate: number;
MaxCoordinate: number;
}
/**
*
* @param
* @returns
*/
export async function getMapKilometerRange(
id: string
): Promise<KilometerRange> {
const response = await api.get(`${UriBase}/${id}/getMapKilometerRange`);
return response.data;
}
/**
* PSL操作
*/
export async function pslOperate(data: {
simulationId: string;
mapId: number;
gateBoxId: string;
buttonCode: string;
down: boolean;
}) {
return await api.post(`${UriBase}/psl/operation`, data);
}

View File

@ -27,6 +27,11 @@
PhaseFailureProtector.Type
"
></phaseFailureProtector-property>
<signalFaultAlarm-property
v-if="
relayCabinetStore.selectedGraphicType === SignalFaultAlarm.Type
"
></signalFaultAlarm-property>
</q-card-section>
</template>
</q-card>
@ -41,6 +46,8 @@ import RelayProperty from './properties/RelayProperty.vue';
import { Relay } from 'src/graphics/relay/Relay';
import PhaseFailureProtectorProperty from './properties/PhaseFailureProtectorProperty.vue';
import { PhaseFailureProtector } from 'src/graphics/phaseFailureProtector/PhaseFailureProtector';
import SignalFaultAlarmProperty from './properties/SignalFaultAlarmProperty.vue';
import { SignalFaultAlarm } from 'src/graphics/signalFaultAlarm/SignalFaultAlarm';
import { useRelayCabinetStore } from 'src/stores/relayCabinet-store';
const relayCabinetStore = useRelayCabinetStore();

View File

@ -63,6 +63,7 @@ const deviceTypeMap = {
5: '信号机',
6: '车站',
7: '屏蔽门',
8: '信号机故障报警仪',
};
const columns: QTable['columns'] = [
{

View File

@ -133,6 +133,10 @@ const optionsType = [
{ label: '信号机', value: graphicData.RelatedRef.DeviceType.signal },
{ label: '车站', value: graphicData.RelatedRef.DeviceType.station },
{ label: '屏蔽门', value: graphicData.RelatedRef.DeviceType.ScreenDoor },
{
label: '信号机故障报警仪',
value: graphicData.RelatedRef.DeviceType.SignalFaultAlarm,
},
];
let selectGraphic: JlGraphic[] = [];

View File

@ -0,0 +1,25 @@
<template>
<q-form class="q-gutter-md">
<q-input outlined readonly v-model="signalFaultAlarmModel.id" label="id" />
<q-input
outlined
v-model="signalFaultAlarmModel.code"
:emit-value="true"
@update:model-value="onUpdate"
label="编号"
lazy-rules
/>
</q-form>
</template>
<script setup lang="ts">
import { SignalFaultAlarmData } from 'src/drawApp/relayCabinetGraphics/SignalFaultAlarmInteraction';
import { useRelayCabinetStore } from 'src/stores/relayCabinet-store';
import { useFormData } from 'src/components/relayCabinetAppFormUtils';
const relayCabinetStore = useRelayCabinetStore();
const { data: signalFaultAlarmModel, onUpdate } = useFormData(
new SignalFaultAlarmData(),
relayCabinetStore.getDrawApp()
);
</script>

View File

@ -15,6 +15,16 @@
@blur="onUpdate"
label="索引"
/>
<q-select
outlined
class="q-mt-sm"
v-model="signalModel.mt"
:options="SignalTypeOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="信号机类型:"
></q-select>
<q-list bordered separator class="rounded-borders">
<q-item no-wrap class="q-gutter-y-sm column">
<div>公里标配置</div>
@ -48,7 +58,7 @@
<q-select
outlined
class="q-mt-sm"
:model-value="refDevData.deviceType"
v-model="refDevData.deviceType"
:options="DeviceTypeOptions"
readonly
map-options
@ -58,7 +68,7 @@
<q-input
outlined
class="q-mt-sm"
:model-value="refDevData.code"
v-model="refDevData.code"
:readonly="true"
label="关联设备:"
></q-input>
@ -128,6 +138,14 @@ const DeviceTypeOptions = [
{ label: '区段', value: graphicData.RelatedRef.DeviceType.Section },
{ label: '道岔', value: graphicData.RelatedRef.DeviceType.Turnout },
];
const SignalTypeOptions = [
{ label: '红绿黄', value: graphicData.Signal.Model.HLU },
{ label: '红绿', value: graphicData.Signal.Model.HL },
{ label: '红绿黄,封黄灯', value: graphicData.Signal.Model.HLU_FU },
{ label: '红绿黄,封绿灯', value: graphicData.Signal.Model.HLU_FL },
{ label: '蓝白', value: graphicData.Signal.Model.AB },
{ label: '红白黄', value: graphicData.Signal.Model.HBU },
];
const DevicePortOptions = [
{ label: 'A端', value: graphicData.RelatedRef.DevicePort.A },
{ label: 'B端', value: graphicData.RelatedRef.DevicePort.B },

View File

@ -3,13 +3,22 @@
<q-input outlined readonly v-model="stationModel.id" label="id" />
<q-input
outlined
label="车站"
label="车站名"
type="textarea"
@blur="onUpdate"
v-model="stationModel.code"
lazy-rules
autogrow
/>
<q-input
outlined
label="车站名"
type="textarea"
@blur="onUpdate"
v-model="stationModel.stationName"
lazy-rules
autogrow
/>
<q-input
outlined
v-model.number="stationModel.index"

View File

@ -54,29 +54,39 @@ function addCentralizedStation() {
if (device.type === Section.Type) {
const data = new SectionData();
data.copyFrom(device.saveData());
if (!data.centralizedStations.includes(stationName.value)) {
data.centralizedStations.push(stationName.value);
device.updateData(data);
}
} else if (device.type === Signal.Type) {
const data = new SignalData();
data.copyFrom(device.saveData());
if (!data.centralizedStations.includes(stationName.value)) {
data.centralizedStations.push(stationName.value);
device.updateData(data);
}
} else if (device.type === Turnout.Type) {
const data = new TurnoutData();
data.copyFrom(device.saveData());
if (!data.centralizedStations.includes(stationName.value)) {
data.centralizedStations.push(stationName.value);
device.updateData(data);
}
} else if (device.type === AxleCounting.Type) {
const data = new AxleCountingData();
data.copyFrom(device.saveData());
if (!data.centralizedStations.includes(stationName.value)) {
data.centralizedStations.push(stationName.value);
device.updateData(data);
}
} else if (device.type === Transponder.Type) {
const data = new TransponderData();
data.copyFrom(device.saveData());
if (!data.centralizedStations.includes(stationName.value)) {
data.centralizedStations.push(stationName.value);
device.updateData(data);
}
}
});
stationName.value = '';
});

View File

@ -3,39 +3,55 @@
seamless
title="列车属性曲线图"
@show="onDialogShow"
:height="510"
:height="546"
:width="710"
>
<div style="height: 510px; width: 710px">
<div class="overflow-hidden">
<q-tabs v-model="tab" dense align="left" @update:model-value="changeTab">
<q-tab name="time" label="时间" />
<q-tab name="km" label="公里标" />
</q-tabs>
<q-separator />
<div
id="train-echarts"
class="overflow-hidden"
style="height: 100%; width: 100%"
class="q-pa-sm overflow-hidden"
style="height: 510px; width: 710px"
></div>
</div>
</DraggableDialog>
</template>
<script setup lang="ts">
import { watch } from 'vue';
import { ref, watch } from 'vue';
import { useLineStore } from 'src/stores/line-store';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import * as echarts from 'echarts';
import 'default-passive-events';
import { date } from 'quasar';
import { getMapKilometerRange } from 'src/api/Simulation';
const lineStore = useLineStore();
const tab = ref('time');
let speedList: [Date, number][] = [];
let accelerationList: [Date, number][] = [];
let tractionForceList: [Date, number][] = [];
let brakeForceList: [Date, number][] = [];
let kmList: number[] = [];
let km_speedList: [number, number][] = [];
let km_accelerationList: [number, number][] = [];
let km_tractionForceList: [number, number][] = [];
let km_brakeForceList: [number, number][] = [];
let maxKm: number;
let minKm: number;
const props = defineProps<{
trainId: string;
}>();
function onDialogShow() {
getKilometerRange();
if (props.trainId) {
getDataList();
initEcharts();
@ -47,6 +63,11 @@ function getDataList() {
accelerationList = [];
tractionForceList = [];
brakeForceList = [];
kmList = [];
km_speedList = [];
km_accelerationList = [];
km_tractionForceList = [];
km_brakeForceList = [];
lineStore.trainStateMap.forEach((list, key) => {
const find = list.find((ii) => {
return ii.id == props.trainId;
@ -56,11 +77,30 @@ function getDataList() {
accelerationList.push([key, find.dynamicState.acceleration]);
tractionForceList.push([key, find.vobcState.tractionForce / 100]);
brakeForceList.push([key, find.vobcState.brakeForce / 100]);
if (!kmList.includes(find.trainKilometer)) {
kmList.push(find.trainKilometer);
km_speedList.push([find.trainKilometer, find.dynamicState.speed / 100]);
km_accelerationList.push([
find.trainKilometer,
find.dynamicState.acceleration,
]);
km_tractionForceList.push([
find.trainKilometer,
find.vobcState.tractionForce / 100,
]);
km_brakeForceList.push([
find.trainKilometer,
find.vobcState.brakeForce / 100,
]);
}
}
});
}
let series = [
type SeriesObj = echarts.SeriesOption & {
unit?: string;
};
let series: SeriesObj[] = [
{
name: '速度',
type: 'line',
@ -72,6 +112,7 @@ let series = [
name: '加速度',
type: 'line',
showSymbol: false,
yAxisIndex: 1,
data: accelerationList,
unit: 'm/s',
},
@ -90,6 +131,54 @@ let series = [
unit: 'kn',
},
];
let km_series: SeriesObj[] = [
{
name: '速度',
type: 'line',
showSymbol: false,
data: km_speedList,
unit: 'km/h',
},
{
name: '加速度',
type: 'line',
showSymbol: false,
yAxisIndex: 1,
data: km_accelerationList,
unit: 'm/s',
},
{
name: '牵引力',
type: 'line',
showSymbol: false,
data: km_tractionForceList,
unit: 'kn',
},
{
name: '制动力',
type: 'line',
showSymbol: false,
data: brakeForceList,
unit: 'kn',
},
];
function trainKilometerFormat(v: number) {
const f = v.toFixed();
const r = f.split('').reverse();
const x = r.slice(0, 3).reverse();
const m = r.slice(3, 6).reverse();
const k = r.slice(6).reverse();
let n = '';
if (k.length) {
n = `k${k.join('')}+${m.join('')}.${x.join('')}`;
} else if (m.length) {
n = `${m.join('')}.${x.join('')}`;
} else if (x.length) {
n = `0.${x.join('')}`;
}
return n;
}
let myChart: echarts.EChartsType;
function initEcharts() {
@ -99,7 +188,8 @@ function initEcharts() {
renderer: 'canvas',
useDirtyRect: false,
});
const option = {
let option: echarts.EChartsOption = {
animation: false,
title: {
text: '',
},
@ -139,6 +229,7 @@ function initEcharts() {
`;
// eslint-disable-next-line
params.forEach((item: any, index: number) => {
let val = item.value[1].toFixed(2);
result +=
"<div style='height: 28px;line-height:28px'>" +
'<span style="display:inline-block;margin-right:5px;border-radius:20px;width:10px;height:10px;background-color:' +
@ -147,7 +238,7 @@ function initEcharts() {
item.seriesName +
' : ' +
'<span style="float:right;margin-left:20px;font-size:14px;color:#666;font-weight:bold">' +
item.value[1].toFixed(2) +
val +
' ' +
series[index].unit +
'</span>' +
@ -169,13 +260,119 @@ function initEcharts() {
show: false,
},
},
yAxis: {
yAxis: [
{
type: 'value',
boundaryGap: [0, '100%'],
// max: 100,
boundaryGap: [0, 0.1],
},
{
type: 'value',
scale: true,
name: '加速度 m/s',
boundaryGap: [0, 0.4],
},
],
series: series,
};
if (tab.value == 'km') {
option = {
animation: false,
title: {
text: '',
},
tooltip: {
trigger: 'axis',
// eslint-disable-next-line
formatter: function (params: any) {
const title = trainKilometerFormat(params[0].value[0]);
let result = `<div
style="height:100%;
min-height:${30 + 28 * params.length}px;
width: 200px;
background: rgba(255, 255, 255, 0.27);
"
>
<div
style="width: 100%;
height: 30px;
padding-left:10px;
font-size: 14px;
line-height: 30px;
"
>
${title}
</div>
<div
style="
height: 100%;
padding-left:10px;
width: 100%;
border-radius: 3px;
"
>
`;
// eslint-disable-next-line
params.forEach((item: any, index: number) => {
let val = item.value[1].toFixed(2);
result +=
"<div style='height: 28px;line-height:28px'>" +
'<span style="display:inline-block;margin-right:5px;border-radius:20px;width:10px;height:10px;background-color:' +
item.color +
'"></span>' +
item.seriesName +
' : ' +
'<span style="float:right;margin-left:20px;font-size:14px;color:#666;font-weight:bold">' +
val +
' ' +
km_series[index].unit +
'</span>' +
'<div style="clear:both"></div>' +
'</div>';
});
result += '</div>';
return result;
},
},
legend: {
data: ['速度', '加速度', '牵引力', '制动力'],
},
xAxis: {
type: 'value',
min: minKm,
max: maxKm,
splitLine: {
show: false,
},
},
yAxis: [
{
type: 'value',
// max: 100,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
boundaryGap: [0, 0.1],
},
{
type: 'value',
scale: true,
name: '加速度 m/s',
axisLine: {
show: false,
},
axisTick: {
show: false,
},
boundaryGap: [0, 0.4],
},
],
series: km_series,
};
}
myChart.setOption(option);
}
@ -183,7 +380,7 @@ watch(
() => lineStore.socketStates,
() => {
getDataList();
myChart?.setOption({
let op: echarts.EChartsOption = {
series: [
{
data: speedList,
@ -198,8 +395,47 @@ watch(
data: brakeForceList,
},
],
});
};
if (tab.value == 'km') {
op = {
series: [
{
data: km_speedList,
},
{
data: km_accelerationList,
},
{
data: km_tractionForceList,
},
{
data: km_brakeForceList,
},
],
};
}
myChart?.setOption(op);
}
);
function changeTab() {
myChart.dispose();
initEcharts();
}
function getKilometerRange() {
if (lineStore.simulationId) {
getMapKilometerRange(lineStore.simulationId)
.then((res) => {
console.log(res);
const d = (res.MaxCoordinate - res.MinCoordinate) * 0.05;
maxKm = res.MaxCoordinate + d;
minKm = res.MinCoordinate - d;
})
.catch((err) => {
console.log(err);
});
}
}
</script>
<style scoped></style>

View File

@ -1,7 +1,22 @@
<template>
<q-card flat bordered>
<q-card-section>
<q-card-section class="flex justify-between">
<div class="text-h6">信号机状态</div>
<q-btn-dropdown color="primary" label="操作">
<q-list>
<q-item
v-for="(item, index) in options"
:key="index"
clickable
v-close-popup
@click="doSignalOperation(item)"
>
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</q-card-section>
<q-separator inset />
<q-form>
@ -37,15 +52,99 @@
import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted } from 'vue';
import { Signal } from 'src/graphics/signal/Signal';
import { request } from 'src/protos/request';
import { state } from 'src/protos/device_state';
import { setSignalState } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
const lineStore = useLineStore();
const signalState = ref({ id: '', index: 0, code: '' });
const options = [
{
label: '开红灯',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.Display,
},
},
{
label: '开绿灯',
value: {
aspect: state.Signal.Aspect.L,
operation: request.Signal.Operation.Display,
},
},
{
label: '开黄灯',
value: {
aspect: state.Signal.Aspect.U,
operation: request.Signal.Operation.Display,
},
},
{
label: '开引导',
value: {
aspect: state.Signal.Aspect.HU,
operation: request.Signal.Operation.Display,
},
},
{
label: '关灯',
value: {
aspect: state.Signal.Aspect.OFF,
operation: request.Signal.Operation.Display,
},
},
{
label: '设置红灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightHFaultDs,
},
},
{
label: '设置绿灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightLFaultDs,
},
},
{
label: '设置黄灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightUFaultDs,
},
},
{
label: '取消红灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightHCancelDs,
},
},
{
label: '取消绿灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightLCancelDs,
},
},
{
label: '取消黄灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightUCancelDs,
},
},
];
watch(
() => lineStore.selectedGraphics,
(val) => {
if (val?.length == 1 && val[0].type == Signal.Type) {
setSignalState(val[0] as Signal);
initSignalState(val[0] as Signal);
} else {
signalState.value = {
id: '',
@ -55,7 +154,7 @@ watch(
}
}
);
function setSignalState(signal: Signal) {
function initSignalState(signal: Signal) {
signalState.value = {
id: signal.datas.id,
index: signal.datas.index,
@ -68,13 +167,29 @@ function submitState() {
}
function onReset() {
if (lineStore.selectedGraphics) {
setSignalState(lineStore.selectedGraphics[0] as Signal);
initSignalState(lineStore.selectedGraphics[0] as Signal);
}
}
function doSignalOperation(item: {
label: string;
value: { aspect: state.Signal.Aspect; operation: request.Signal.Operation };
}) {
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
setSignalState({
simulationId,
mapId,
id: signalState.value.id,
aspect: item.value.aspect,
operation: item.value.operation,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
}
onMounted(() => {
if (lineStore.selectedGraphics) {
setSignalState(lineStore.selectedGraphics[0] as Signal);
initSignalState(lineStore.selectedGraphics[0] as Signal);
}
});
</script>

View File

@ -1,4 +1,9 @@
function getHost(): string {
if (process.env.ENV_MODE == 'test') {
return 'test.joylink.club/bjrtss-server';
} else if (process.env.ENV_MODE == 'publish') {
return 'joylink.club/bjrtss-server';
}
// return '192.168.3.7:9091';
// return '192.168.3.47:9091';
// return '192.168.3.37:9091';
@ -6,18 +11,28 @@ function getHost(): string {
// return '192.168.3.5:9091';
// return '192.168.3.37:9091'; //卫志宏
return '192.168.3.233:9091';
// return 'test.joylink.club/bjrtss-server';
}
export function getHttpBase() {
return `http://${getHost()}`;
// return `https://${getHost()}`;
let protocol = 'http';
if (['test', 'publish'].includes(process.env.ENV_MODE as string)) {
protocol = 'https';
}
return `${protocol}://${getHost()}`;
}
export function getWebsocketUrl() {
const host = '192.168.3.233';
const port = 8000;
// return `ws://${host}/ws-bj`;
return `ws://${host}:${port}/connection/websocket`;
// return `wss://${getHost()}/ws-bj`;
let protocol = 'ws';
let host = '192.168.3.233';
let port = '8000';
if (process.env.ENV_MODE == 'test') {
protocol = 'wss';
host = 'test.joylink.club/bjrtss-server';
port = '';
} else if (process.env.ENV_MODE == 'publish') {
protocol = 'wss';
host = 'joylink.club/bjrtss-server';
port = '';
}
return `${protocol}://${host}:${port}/connection/websocket`;
}

View File

@ -17,7 +17,10 @@ import {
ScreenDoor,
ScreenDoorTemplate,
} from 'src/graphics/screenDoor/ScreenDoor';
import { ScreenDoorData } from './graphics/ScreenDoorInteraction';
import {
ScreenDoorData,
ScreenDoorState,
} from './graphics/ScreenDoorInteraction';
import { ScreenDoorDraw } from 'src/graphics/screenDoor/ScreenDoorDrawAssistant';
import { Station, StationTemplate } from 'src/graphics/station/Station';
import { StationDraw } from 'src/graphics/station/StationDrawAssistant';
@ -168,7 +171,10 @@ export function initCommonDrawApp(app: IDrawApp) {
app,
new PlatformTemplate(new PlatformData(), new PlatformState())
);
new ScreenDoorDraw(app, new ScreenDoorTemplate(new ScreenDoorData()));
new ScreenDoorDraw(
app,
new ScreenDoorTemplate(new ScreenDoorData(), new ScreenDoorState())
);
new StationDraw(
app,
new StationTemplate(new StationData(), new StationState())

View File

@ -11,8 +11,8 @@ import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useLineStore } from 'src/stores/line-store';
import { GraphicDataBase } from './GraphicDataBase';
import { usePslStore } from 'src/stores/psl-store';
export class GatedBoxData extends GraphicDataBase implements IGatedBox {
constructor(data?: graphicData.GatedBox) {
@ -141,8 +141,12 @@ export class GatedBoxOperateInteraction extends GraphicInteractionPlugin<GatedBo
g.eventMode = 'none';
g.off('_leftclick', this.onLeftClick, this);
}
onLeftClick() {
// useLineStore().stateProCountIncrease();
useLineStore().increaseGatedBoxCount();
onLeftClick(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const gatedBox = target.getGraphic() as GatedBox;
usePslStore().setPslParam(
gatedBox.datas.id,
gatedBox.datas.refGatedBoxMapCode
);
}
}

View File

@ -1,12 +1,22 @@
import * as pb_1 from 'google-protobuf';
import { IPslButtonData, PslButton } from 'src/graphics/pslButton/pslButton';
import {
IPslButtonData,
IPslButtonState,
PslButton,
} from 'src/graphics/pslButton/pslButton';
import {
GraphicInteractionPlugin,
IGraphicScene,
JlGraphic,
} from 'src/jl-graphic';
import { pslGraphicData } from 'src/protos/pslGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { pslOperate } from 'src/api/Simulation';
import { useLineStore } from 'src/stores/line-store';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { errorNotify } from 'src/utils/CommonNotify';
import { usePslStore } from 'src/stores/psl-store';
import { state } from 'src/protos/device_state';
export class PslButtonData extends GraphicDataBase implements IPslButtonData {
constructor(data?: pslGraphicData.PslButton) {
@ -53,6 +63,42 @@ export class PslButtonData extends GraphicDataBase implements IPslButtonData {
return pb_1.Message.equals(this.data, other.data);
}
}
export class PslButtonState
extends GraphicStateBase
implements IPslButtonState
{
constructor(proto?: state.ButtonState) {
let states;
if (proto) {
states = proto;
} else {
states = new state.ButtonState();
}
super(states, PslButton.Type);
}
get code(): string {
return this.states.id;
}
get down(): boolean {
return this.states.down;
}
set down(v: boolean) {
this.states.down = v;
}
get states(): state.ButtonState {
return this.getState<state.ButtonState>();
}
clone(): PslButtonState {
return new PslButtonState(this.states.cloneMessage());
}
copyFrom(data: GraphicStateBase): void {
pb_1.Message.copyInto(data._state, this._state);
}
eq(data: GraphicStateBase): boolean {
return pb_1.Message.equals(this._state, data._state);
}
}
export class PslButtonOperateInteraction extends GraphicInteractionPlugin<PslButton> {
static Name = 'psl_button_operate_menu';
constructor(app: IGraphicScene) {
@ -70,16 +116,72 @@ export class PslButtonOperateInteraction extends GraphicInteractionPlugin<PslBut
g.eventMode = 'static';
g.cursor = 'pointer';
g.selectable = true;
g.on('_leftclick', this.onLeftClick, this);
g.on('mousedown', this.onMouseDown, this);
g.on('mouseup', this.onMouseUp, this);
g.on('mouseout', this.onMouseOut, this);
}
unbind(g: PslButton): void {
g.selectable = false;
g.eventMode = 'none';
g.off('_leftclick', this.onLeftClick, this);
g.off('mousedown', this.onMouseDown, this);
g.on('mouseup', this.onMouseUp, this);
g.on('mouseout', this.onMouseOut, this);
}
onLeftClick() {
// useLineStore().stateProCountIncrease();
// useLineStore().increaseGatedBoxCount();
onMouseOut(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const pslButton = target.getGraphic() as PslButton;
if (pslButton.states.down && pslButton.datas.isSelfReset) {
pslButton.states.down = false;
pslButton.doRepaint();
}
}
onMouseDown(e: FederatedMouseEvent) {
const simulationId = useLineStore().simulationId;
const mapId = useLineStore().mapId;
const gateBoxId = usePslStore().gatedBoxId;
const target = e.target as DisplayObject;
const pslButton = target.getGraphic() as PslButton;
if (!simulationId || !mapId) {
return;
}
pslOperate({
simulationId,
mapId,
buttonCode: pslButton.datas.code,
gateBoxId: gateBoxId,
down: !pslButton.states.down,
})
.then(() => {
pslButton.states.down = !pslButton.states.down;
pslButton.doRepaint();
})
.catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
}
onMouseUp(e: FederatedMouseEvent) {
const simulationId = useLineStore().simulationId;
const mapId = useLineStore().mapId;
const gateBoxId = usePslStore().gatedBoxId;
const target = e.target as DisplayObject;
const pslButton = target.getGraphic() as PslButton;
if (!simulationId || !mapId || !pslButton.datas.isSelfReset) {
return;
}
pslOperate({
simulationId,
mapId,
buttonCode: pslButton.datas.code,
gateBoxId: gateBoxId,
down: false,
})
.then(() => {
pslButton.states.down = false;
pslButton.doRepaint();
})
.catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
}
}

View File

@ -1,10 +1,12 @@
import * as pb_1 from 'google-protobuf';
import {
IScreenDoorData,
IScreenDoorState,
ScreenDoor,
} from 'src/graphics/screenDoor/ScreenDoor';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_state';
export class ScreenDoorData extends GraphicDataBase implements IScreenDoorData {
constructor(data?: graphicData.ScreenDoor) {
@ -59,3 +61,36 @@ export class ScreenDoorData extends GraphicDataBase implements IScreenDoorData {
return pb_1.Message.equals(this.data, other.data);
}
}
export class ScreenDoorState
extends GraphicStateBase
implements IScreenDoorState
{
constructor(proto?: state.PsdState) {
let states;
if (proto) {
states = proto;
} else {
states = new state.PsdState();
}
super(states, ScreenDoor.Type);
}
get code(): string {
return this.states.id;
}
get openDoorCodes() {
return this.states.openDoorCodes;
}
get states(): state.PsdState {
return this.getState<state.PsdState>();
}
clone(): ScreenDoorState {
return new ScreenDoorState(this.states.cloneMessage());
}
copyFrom(data: GraphicStateBase): void {
pb_1.Message.copyInto(data._state, this._state);
}
eq(data: GraphicStateBase): boolean {
return pb_1.Message.equals(this._state, data._state);
}
}

View File

@ -20,6 +20,7 @@ import { useLineStore } from 'src/stores/line-store';
import { SignalGraphicHitArea } from 'src/graphics/signal/SignalDrawAssistant';
import { setSignalState } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
import { request } from 'src/protos/request';
export class SignalData extends GraphicDataBase implements ISignalData {
constructor(data?: graphicData.Signal) {
@ -75,6 +76,12 @@ export class SignalData extends GraphicDataBase implements ISignalData {
set centralizedStations(v: string[]) {
this.data.centralizedStations = v;
}
get mt(): graphicData.Signal.Model {
return this.data.mt;
}
set mt(v: graphicData.Signal.Model) {
this.data.mt = v;
}
clone(): SignalData {
return new SignalData(this.data.cloneMessage());
}
@ -237,6 +244,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.OFF,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
@ -247,6 +255,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
@ -257,6 +266,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.L,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
@ -267,6 +277,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.U,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
@ -277,6 +288,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.HU,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});

View File

@ -41,6 +41,12 @@ export class StationData extends GraphicDataBase implements IStationData {
set code(v: string) {
this.data.code = v;
}
get stationName(): string {
return this.data.stationName;
}
set stationName(v: string) {
this.data.stationName = v;
}
get kilometerSystem(): KilometerSystem {
if (!this.data.kilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem();

View File

@ -21,7 +21,10 @@ import {
PlatformState,
} from './graphics/PlatformInteraction';
import { PlatformTemplate, Platform } from 'src/graphics/platform/Platform';
import { ScreenDoorData } from './graphics/ScreenDoorInteraction';
import {
ScreenDoorData,
ScreenDoorState,
} from './graphics/ScreenDoorInteraction';
import {
ScreenDoor,
ScreenDoorTemplate,
@ -179,6 +182,9 @@ export const layerList = [
export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
const options: GraphicAppOptions = {
dataLoader: loadLineDatas,
};
const lineScene = lineApp.initScene(sceneName, options);
lineScene.setOptions({
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
@ -194,8 +200,7 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
Section.Type,
Transponder.Type,
],
};
const lineScene = lineApp.initScene(sceneName, options);
});
const categoryType = useLineStore().categoryType;
if (!categoryType) {
throw new Error('未获取到厂商信息');
@ -209,7 +214,7 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
getTypeConsts(Signal.Type)
),
new PlatformTemplate(new PlatformData(), new PlatformState()),
new ScreenDoorTemplate(new ScreenDoorData()),
new ScreenDoorTemplate(new ScreenDoorData(), new ScreenDoorState()),
new StationTemplate(new StationData(), new StationState()),
new TurnoutTemplate(new TurnoutData(), new TurnoutStates()),
new SectionTemplate(new SectionData()),
@ -284,6 +289,11 @@ function handleSubscribe(lineScene: IGraphicScene) {
// states.push(new SectionState(item));
}
});
storage.allStatus.psdState.forEach((item) => {
if (item.id) {
states.push(new ScreenDoorState(item));
}
});
storage.allStatus.switchState.forEach((item) => {
// 道岔
if (item.id) {

View File

@ -23,7 +23,7 @@ import { PslLightDraw } from 'src/graphics/pslLight/pslLightDrawAssistant';
import { PslKey, PslKeyTemplate } from 'src/graphics/pslKey/pslKey';
import { PslKeyData } from './graphics/PslKeyInteraction';
import { PslButton, PslButtonTemplate } from 'src/graphics/pslButton/pslButton';
import { PslButtonData } from './graphics/PslButtonInteraction';
import { PslButtonData, PslButtonState } from './graphics/PslButtonInteraction';
import { PslLight, PslLightTemplate } from 'src/graphics/pslLight/pslLight';
import { PslLightData } from './graphics/PslLightInteraction';
import {
@ -75,7 +75,10 @@ export function initPslDrawApp(): IDrawApp {
const app = drawApp;
//根据草稿图类型加载绘图工具
new PslKeyDraw(app, new PslKeyTemplate(new PslKeyData()));
new PslButtonDraw(app, new PslButtonTemplate(new PslButtonData()));
new PslButtonDraw(
app,
new PslButtonTemplate(new PslButtonData(), new PslButtonState())
);
new PslLightDraw(app, new PslLightTemplate(new PslLightData()));
new TextContentDraw(app, new TextContentTemplate(new PslTextData()));

View File

@ -5,7 +5,7 @@ import {
IGraphicScene,
IGraphicStorage,
} from 'src/jl-graphic';
import { getPublishMapInfoByLineId } from 'src/api/PublishApi';
import { getPublishMapInfoByName } from 'src/api/PublishApi';
import { usePslStore } from 'src/stores/psl-store';
import { toUint8Array } from 'js-base64';
import { PslKeyTemplate } from 'src/graphics/pslKey/pslKey';
@ -14,6 +14,7 @@ import { PslButtonTemplate } from 'src/graphics/pslButton/pslButton';
import {
PslButtonData,
PslButtonOperateInteraction,
PslButtonState,
} from './graphics/PslButtonInteraction';
import { PslLightTemplate } from 'src/graphics/pslLight/pslLight';
import { PslLightData } from './graphics/PslLightInteraction';
@ -21,6 +22,7 @@ import { pslGraphicData } from 'src/protos/pslGraphics';
import { PslTextData } from './graphics/TextContentInteraction';
import { TextContentTemplate } from 'src/graphics/textContent/TextContent';
import { useLineStore } from 'src/stores/line-store';
import { state } from 'src/protos/device_state';
export function initPslScene(lineApp: IGraphicApp, sceneName: string) {
// psl
@ -28,13 +30,13 @@ export function initPslScene(lineApp: IGraphicApp, sceneName: string) {
dataLoader: loadPslDatas,
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
wheelZoom: true,
viewportDrag: false,
wheelZoom: false,
},
});
const graphicTemplate = [
new PslKeyTemplate(new PslKeyData()),
new PslButtonTemplate(new PslButtonData()),
new PslButtonTemplate(new PslButtonData(), new PslButtonState()),
new PslLightTemplate(new PslLightData()),
new TextContentTemplate(new PslTextData()),
];
@ -43,28 +45,37 @@ export function initPslScene(lineApp: IGraphicApp, sceneName: string) {
pslScene.on('postdataloaded', () => {
handleSubscribe(pslScene);
});
pslScene.setOptions({
mouseToolOptions: {
boxSelect: false,
viewportDrag: false,
wheelZoom: false,
},
});
return lineApp;
// pslScene.setOptions({
// mouseToolOptions: {
// boxSelect: false,
// viewportDrag: false,
// wheelZoom: false,
// },
// });
return pslScene;
}
function handleSubscribe(pslScene: IGraphicScene) {
const lineStore = useLineStore();
const pslStore = usePslStore();
const simulationId = lineStore.simulationId;
const mapId = lineStore.mapId;
const pslId = lineStore.pslId;
const pslId = pslStore.gatedBoxId;
const app = pslScene;
app.subscribe({
destination: `simulation-psl-${simulationId}_${mapId}_${pslId}-status`,
messageConverter: (message: Uint8Array) => {
// console.log('收到消息', message);
const states: GraphicState[] = [];
// const storage = state.PushedDevicesStatus.deserialize(message);
const storage = state.PushedDevicesStatus.deserialize(message);
if (storage.all) {
// storage.allStatus.buttonState.forEach((item) => {
// if (item.id) {
// states.push(new PslButtonState(item));
// }
// });
}
// console.log(states, 'states');
return states;
},
});
@ -72,12 +83,10 @@ function handleSubscribe(pslScene: IGraphicScene) {
async function loadPslDatas(): Promise<IGraphicStorage> {
const pslStore = usePslStore();
const mapId = pslStore.mapId;
const simulationId = pslStore.simulationId;
if (!mapId || !simulationId) {
throw new Error('获取数据异常未获取到地图ID或仿真ID');
}
const { proto: base64 } = await getPublishMapInfoByLineId(mapId + '');
const { proto: base64 } = await getPublishMapInfoByName({
name: pslStore.pslMapCode,
detail: true,
});
if (base64) {
const storage = pslGraphicData.PslGraphicStorage.deserialize(
toUint8Array(base64)

View File

@ -0,0 +1,46 @@
import * as pb_1 from 'google-protobuf';
import {
ISignalFaultAlarmData,
SignalFaultAlarm,
} from 'src/graphics/signalFaultAlarm/SignalFaultAlarm';
import { relayCabinetGraphicData } from 'src/protos/relayCabinetLayoutGraphics';
import { GraphicDataBase } from '../graphics/GraphicDataBase';
export class SignalFaultAlarmData
extends GraphicDataBase
implements ISignalFaultAlarmData
{
constructor(data?: relayCabinetGraphicData.SignalFaultAlarm) {
let signalFaultAlarm;
if (!data) {
signalFaultAlarm = new relayCabinetGraphicData.SignalFaultAlarm(
{
common: GraphicDataBase.defaultCommonInfo(SignalFaultAlarm.Type),
}
);
} else {
signalFaultAlarm = data;
}
super(signalFaultAlarm);
}
public get data(): relayCabinetGraphicData.SignalFaultAlarm {
return this.getData<relayCabinetGraphicData.SignalFaultAlarm>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
clone(): SignalFaultAlarmData {
return new SignalFaultAlarmData(this.data.cloneMessage());
}
copyFrom(data: SignalFaultAlarmData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: SignalFaultAlarmData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -33,6 +33,12 @@ import {
} from 'src/graphics/phaseFailureProtector/PhaseFailureProtector';
import { PhaseFailureProtectorData } from './relayCabinetGraphics/PhaseFailureProtectorInteraction';
import { PhaseFailureProtectorDraw } from 'src/graphics/phaseFailureProtector/PhaseFailureProtectorDrawAssistant';
import {
SignalFaultAlarm,
SignalFaultAlarmTemplate,
} from 'src/graphics/signalFaultAlarm/SignalFaultAlarm';
import { SignalFaultAlarmData } from './relayCabinetGraphics/SignalFaultAlarmInteraction';
import { SignalFaultAlarmDraw } from 'src/graphics/signalFaultAlarm/SignalFaultAlarmDrawAssistant';
const UndoOptions: MenuItemOptions = {
name: '撤销',
@ -80,6 +86,10 @@ export function initDrawApp(): IDrawApp {
app,
new PhaseFailureProtectorTemplate(new PhaseFailureProtectorData())
);
new SignalFaultAlarmDraw(
app,
new SignalFaultAlarmTemplate(new SignalFaultAlarmData())
);
// 画布右键菜单
app.registerMenu(DefaultCanvasMenu);
@ -205,6 +215,12 @@ export function saveDrawDatas(app: IDrawApp) {
(phaseFailureProtectorData as PhaseFailureProtectorData).data
);
}
if (SignalFaultAlarm.Type === g.type) {
const signalFaultAlarmData = (g as SignalFaultAlarm).saveData();
storage.signalFaultAlarms.push(
(signalFaultAlarmData as SignalFaultAlarmData).data
);
}
});
storage.deviceRelateRelayList = refRelaysList;
storage.combinationtypeList = combinationTypeList;
@ -236,6 +252,9 @@ export async function loadDrawDatas(): Promise<IGraphicStorage> {
storage.phaseFailureProtectors.forEach((phaseFailureProtector) => {
datas.push(new PhaseFailureProtectorData(phaseFailureProtector));
});
storage.signalFaultAlarms.forEach((signalFaultAlarm) => {
datas.push(new SignalFaultAlarmData(signalFaultAlarm));
});
refRelaysList = storage.deviceRelateRelayList;
combinationTypeList = storage.combinationtypeList;
UniqueIdPrefix = storage.UniqueIdPrefix;

View File

@ -59,8 +59,18 @@ export class GatedBox extends JlGraphic {
codeGraph.text = this.datas.code;
codeGraph.style.fill = gatedBoxConsts.codeColor;
codeGraph.setVectorFontSize(gatedBoxConsts.codeFontSize);
codeGraph.anchor.set(0.5);
const codeTransform = this.datas?.childTransforms?.find(
(item) => item.name === 'gated_box_code'
);
if (codeTransform) {
const position = codeTransform?.transform.position;
const rotation = codeTransform?.transform?.rotation;
codeGraph.position.set(position?.x, position?.y);
codeGraph.rotation = rotation || 0;
} else {
codeGraph.position.set(20, 0);
}
codeGraph.anchor.set(0.5);
this.textGraph.style.fill = gatedBoxConsts.codeColor;
this.textGraph.setVectorFontSize(gatedBoxConsts.codeFontSize);
this.textGraph.anchor.set(0.5);

View File

@ -59,76 +59,6 @@ export class rectGraphic extends Container {
this.rectGraphic.clear();
}
}
//子元素--站台旁菱形图标
/* class emergClose extends JlGraphic {
static Type = 'emergClose';
lozenge: Graphics;
deltaTime = 0;
fillColor = PlatformColorEnum.lozengeRed;
constructor() {
super(emergClose.Type);
this.lozenge = new Graphics();
this.addChild(this.lozenge);
}
draw(): void {
const lozenge = this.lozenge;
lozenge.clear();
lozenge.lineStyle(1, new Color(this.fillColor));
lozenge.beginFill(PlatformColorEnum.lozengeRed, 1);
lozenge.drawRect(
0,
0,
platformConsts.height / 4,
platformConsts.height / 4
);
lozenge.endFill();
const rect = new Rectangle(
0,
0,
platformConsts.height / 4,
platformConsts.height / 4
);
lozenge.pivot = getRectangleCenter(rect);
lozenge.rotation = Math.PI / 4;
lozenge.visible = false;
}
doRepaint() {
// this.draw()
}
clear(): void {
this.lozenge.clear();
}
createFlashAnmiation(name: string): GraphicAnimation {
const flashAnmiation = GraphicAnimation.init({
name: name,
run: (dt: number) => {
this.deltaTime += dt;
if (this.deltaTime > 60) {
this.deltaTime = 0;
this.lozenge.visible = false;
} else if (this.deltaTime > 30) {
this.lozenge.visible = true;
}
},
});
return flashAnmiation;
}
changeState(id: string, stateData: IPlatformState): void {
let redFlash = this.animation(`${id}emergClose_red_flash`);
if (stateData.emergstop) {
if (!redFlash) {
redFlash = this.createFlashAnmiation(`${id}emergClose_red_flash`);
this.addAnimation(redFlash);
}
redFlash.resume();
} else {
if (redFlash) {
redFlash.pause();
}
}
}
} */
export class Platform extends JlGraphic {
static Type = 'Platform';
rectGraphic: rectGraphic = new rectGraphic();

View File

@ -27,8 +27,10 @@ export interface IPslButtonData extends GraphicData {
}
export interface IPslButtonState extends GraphicState {
get state(): number;
set state(v: number);
get code(): string;
set code(v: string);
get down(): boolean;
set down(v: boolean);
}
export class PslButton extends JlGraphic {
@ -48,27 +50,38 @@ export class PslButton extends JlGraphic {
get datas(): IPslButtonData {
return this.getDatas<IPslButtonData>();
}
get states(): IPslButtonState {
return this.getStates<IPslButtonState>();
}
doRepaint(): void {
this._pslButton.rotation = 0;
if (this.datas.buttonColor === pslGraphicData.PslElementColor.green) {
if (this.states.down) {
this._pslButton.texture = this.pslButtonTextures.greenBtnPress;
} else {
this._pslButton.texture = this.pslButtonTextures.greenBtn;
}
} else {
if (this.states.down) {
this._pslButton.texture = this.pslButtonTextures.redBtnPress;
} else {
this._pslButton.texture = this.pslButtonTextures.redBtn;
}
}
}
}
export class PslButtonTemplate extends JlGraphicTemplate<PslButton> {
pslButtonTextures?: PslButtonTextures;
constructor(dataTemplate: IPslButtonData) {
super(PslButton.Type, { dataTemplate });
constructor(dataTemplate: IPslButtonData, stateTemplate: IPslButtonState) {
super(PslButton.Type, { dataTemplate, stateTemplate });
this.loadAssets();
}
new(): PslButton {
if (this.pslButtonTextures) {
const g = new PslButton(this.pslButtonTextures);
g.loadData(this.datas);
// g.loadState(this.states);
g.loadState(this.states);
return g;
}
throw new Error('资源未加载/加载失败');

View File

@ -56,12 +56,9 @@ export class Relay extends JlGraphic {
this.labelGraphic.position.set(0, 20);
this.refDevice.position.set(0, -20);
const relayGraphic = this.relayGraphic;
let relayColor;
if (this.states?.xh) {
relayColor = relayConsts.closeColor;
} else {
relayColor = relayConsts.openColor;
}
const relayColor = this.states.xh
? relayConsts.closeColor
: relayConsts.openColor;
relayGraphic
.clear()
.lineStyle(relayConsts.lineWidth, new Color(relayColor))

View File

@ -1,6 +1,7 @@
import { Color, Container, Graphics } from 'pixi.js';
import {
GraphicData,
GraphicState,
JlGraphic,
JlGraphicTemplate,
VectorText,
@ -23,11 +24,15 @@ export interface IScreenDoorData extends GraphicData {
eq(other: IScreenDoorData): boolean;
}
export interface IScreenDoorState extends GraphicState {
get openDoorCodes(): number[]; //打开的屏蔽门的编号
}
const screenDoorConsts = {
lineWidth: 3,
smallDoorWidth: 10,
doorGreen: '0x00FF00', //屏蔽门的颜色
doorRed: '0xff0000',
doorClose: '0x00FF00', //屏蔽门的颜色
doorOpen: '0xff0000',
};
class smallDoorGraphic extends Container {
@ -42,22 +47,19 @@ class smallDoorGraphic extends Container {
this.addChild(this.smallDoorGraphic);
this.addChild(this.labelGraphic);
}
draw(data: IScreenDoorData, i: number): void {
draw(data: IScreenDoorData, i: number, open: boolean): void {
const start =
(-screenDoorConsts.smallDoorWidth * data.sonDoorAmount) / 2 +
screenDoorConsts.smallDoorWidth * i;
const smallDoorGraphic = this.smallDoorGraphic;
const lineColor = screenDoorConsts.doorGreen;
const direction = 'up';
const lineColor = open
? screenDoorConsts.doorOpen
: screenDoorConsts.doorClose;
smallDoorGraphic
.lineStyle(screenDoorConsts.lineWidth, new Color(lineColor))
.moveTo(start, 0)
.lineTo(start + screenDoorConsts.smallDoorWidth - 3, 0);
if (direction == 'up') {
this.labelGraphic.text = i + 1;
} else {
this.labelGraphic.text = data.sonDoorAmount - i;
}
this.labelGraphic.style.fill = 'red';
if (i % 2 == 0) {
this.labelGraphic.position.set(start + 4, 7);
@ -79,6 +81,10 @@ export class ScreenDoor extends JlGraphic {
return this.getDatas<IScreenDoorData>();
}
get states(): IScreenDoorState {
return this.getStates<IScreenDoorState>();
}
doRepaint(): void {
const doorGraphic = this.doorGraphic;
doorGraphic.children.forEach((g) => {
@ -88,7 +94,7 @@ export class ScreenDoor extends JlGraphic {
this.datas.sonDoorAmount = this.datas?.sonDoorAmount || 30;
for (let i = 0; i < this.datas.sonDoorAmount; i++) {
const smallDoor = new smallDoorGraphic();
smallDoor.draw(this.datas, i);
smallDoor.draw(this.datas, i, this.states.openDoorCodes.includes(i + 1));
doorGraphic.addChild(smallDoor);
}
}
@ -130,14 +136,16 @@ export class ScreenDoor extends JlGraphic {
}
export class ScreenDoorTemplate extends JlGraphicTemplate<ScreenDoor> {
constructor(dataTemplate: IScreenDoorData) {
constructor(dataTemplate: IScreenDoorData, stateTemplate?: IScreenDoorState) {
super(ScreenDoor.Type, {
dataTemplate,
stateTemplate,
});
}
new(): ScreenDoor {
const screenDoor = new ScreenDoor();
screenDoor.loadData(this.datas);
screenDoor.loadState(this.states);
return screenDoor;
}
}

View File

@ -18,6 +18,7 @@ import {
import { SignalCode } from './SignalCode';
import { Section, SectionPort, SectionType } from '../section/Section';
import { Turnout, TurnoutPort } from '../turnout/Turnout';
import { graphicData } from 'src/protos/stationLayoutGraphics';
export enum Direction {
LEFT = 0,
@ -46,6 +47,8 @@ export interface ISignalData extends GraphicData {
set refDev(v: IRelatedRefData);
get centralizedStations(): string[];
set centralizedStations(v: string[]);
get mt(): graphicData.Signal.Model;
set mt(v: graphicData.Signal.Model);
clone(): ISignalData;
copyFrom(data: ISignalData): void;
eq(other: ISignalData): boolean;

View File

@ -0,0 +1,80 @@
import { Assets, Sprite, Texture } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
} from 'src/jl-graphic';
import signalFaultAlarmSprites from './signalFaultAlarmSprites.png';
export interface ISignalFaultAlarmData extends GraphicData {
get code(): string; // 编号
set code(v: string);
clone(): ISignalFaultAlarmData;
copyFrom(data: ISignalFaultAlarmData): void;
eq(other: ISignalFaultAlarmData): boolean;
}
export const signalFaultAlarmConsts = {
scaleX: 0.2,
scaleY: 0.2,
};
export class SignalFaultAlarm extends JlGraphic {
static Type = 'SignalFaultAlarm';
signalFaultAlarm: Sprite;
signalFaultAlarmTextures: Texture;
labelGraphic = new VectorText();
constructor(signalFaultAlarmTextures: Texture) {
super(SignalFaultAlarm.Type);
this.signalFaultAlarmTextures = signalFaultAlarmTextures;
this.signalFaultAlarm = new Sprite();
this.signalFaultAlarm.texture = this.signalFaultAlarmTextures;
this.signalFaultAlarm.anchor.set(0.5, 0.5);
this.signalFaultAlarm.scale.set(
signalFaultAlarmConsts.scaleX,
signalFaultAlarmConsts.scaleY
);
this.addChild(this.signalFaultAlarm);
this.setTextGraphic(this.labelGraphic, 'label');
this.addChild(this.labelGraphic);
}
get datas(): ISignalFaultAlarmData {
return this.getDatas<ISignalFaultAlarmData>();
}
doRepaint(): void {
this.labelGraphic.text = this.datas.code;
this.labelGraphic.position.set(0, 25);
}
setTextGraphic(g: VectorText, name: string) {
g.setVectorFontSize(10);
g.anchor.set(0.5);
g.style.fill = '#0f0';
g.transformSave = true;
g.name = name;
}
}
export class SignalFaultAlarmTemplate extends JlGraphicTemplate<SignalFaultAlarm> {
signalFaultAlarmTextures?: Texture;
constructor(dataTemplate: ISignalFaultAlarmData) {
super(SignalFaultAlarm.Type, {
dataTemplate,
});
}
new(): SignalFaultAlarm {
if (this.signalFaultAlarmTextures) {
const signalFaultAlarm = new SignalFaultAlarm(
this.signalFaultAlarmTextures
);
signalFaultAlarm.loadData(this.datas);
return signalFaultAlarm;
}
throw new Error('资源未加载/加载失败');
}
async loadAssets(): Promise<Texture> {
this.signalFaultAlarmTextures = await Assets.load(signalFaultAlarmSprites);
return this.signalFaultAlarmTextures as Texture;
}
}

View File

@ -0,0 +1,104 @@
import { FederatedPointerEvent, Point } from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
GraphicDrawAssistant,
GraphicInteractionPlugin,
IDrawApp,
JlGraphic,
} from 'src/jl-graphic';
import {
ISignalFaultAlarmData,
SignalFaultAlarm,
SignalFaultAlarmTemplate,
} from './SignalFaultAlarm';
import { Relay } from '../relay/Relay';
export interface ISignalFaultAlarmDrawOptions {
newData: () => ISignalFaultAlarmData;
}
export class SignalFaultAlarmDraw extends GraphicDrawAssistant<
SignalFaultAlarmTemplate,
ISignalFaultAlarmData
> {
signalFaultAlarmGraphic: SignalFaultAlarm | null = null;
constructor(app: IDrawApp, template: SignalFaultAlarmTemplate) {
super(app, template, 'notifications_active', '信号机故障报警仪');
signalFaultAlarmInteraction.init(app);
}
bind(): void {
super.bind();
if (!this.signalFaultAlarmGraphic) {
this.signalFaultAlarmGraphic = this.graphicTemplate.new();
this.container.addChild(this.signalFaultAlarmGraphic);
}
}
onLeftDown(e: FederatedPointerEvent): void {
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
this.createAndStore(true);
}
redraw(p: Point): void {
this.container.position.copyFrom(p);
}
prepareData(data: ISignalFaultAlarmData): boolean {
data.transform = this.container.saveTransform();
return true;
}
}
/**
*
* @param polygon
* @returns
*/
function buildAbsorbablePositions(
signalFaultAlarmCabinet: SignalFaultAlarm
): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const relays = signalFaultAlarmCabinet.queryStore.queryByType<Relay>(
Relay.Type
);
const { width, height } = signalFaultAlarmCabinet.getGraphicApp().canvas;
relays.forEach((relay) => {
const ps = relay.position;
const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y });
const ys = new AbsorbableLine({ x: ps.x, y: 0 }, { x: ps.x, y: height });
aps.push(xs, ys);
});
return aps;
}
export class signalFaultAlarmInteraction extends GraphicInteractionPlugin<SignalFaultAlarm> {
static Name = 'signalFaultAlarm_transform';
constructor(app: IDrawApp) {
super(signalFaultAlarmInteraction.Name, app);
}
static init(app: IDrawApp) {
return new signalFaultAlarmInteraction(app);
}
filter(...grahpics: JlGraphic[]): SignalFaultAlarm[] | undefined {
return grahpics
.filter((g) => g.type === SignalFaultAlarm.Type)
.map((g) => g as SignalFaultAlarm);
}
bind(g: SignalFaultAlarm): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.on('transformstart', this.move, this);
}
unbind(g: SignalFaultAlarm): void {
g.eventMode = 'none';
g.off('transformstart', this.move, this);
}
move(): void {
const signalFaultAlarm = this.app.selectedGraphics[0] as SignalFaultAlarm;
this.app.setOptions({
absorbablePositions: buildAbsorbablePositions(signalFaultAlarm),
});
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -59,8 +59,18 @@ export class SpksSwitch extends JlGraphic {
codeGraph.text = this.datas.code;
codeGraph.style.fill = spksSwitchConsts.codeColor;
codeGraph.setVectorFontSize(spksSwitchConsts.codeFontSize);
codeGraph.anchor.set(0.5);
const codeTransform = this.datas?.childTransforms?.find(
(item) => item.name === 'spks_switch_code'
);
if (codeTransform) {
const position = codeTransform?.transform.position;
const rotation = codeTransform?.transform?.rotation;
codeGraph.position.set(position?.x, position?.y);
codeGraph.rotation = rotation || 0;
} else {
codeGraph.position.set(20, 0);
}
codeGraph.anchor.set(0.5);
this.textGraph.style.fill = spksSwitchConsts.codeColor;
this.textGraph.setVectorFontSize(spksSwitchConsts.codeFontSize);
this.textGraph.anchor.set(0.5);

View File

@ -8,8 +8,10 @@ import {
import { KilometerSystem } from '../signal/Signal';
export interface IStationData extends GraphicData {
get code(): string; // 编号
get code(): string; // 车站站名
set code(v: string);
get stationName(): string; // 车站名
set stationName(v: string);
get kilometerSystem(): KilometerSystem;
set kilometerSystem(v: KilometerSystem);
get concentrationStations(): boolean; //是否集中站
@ -36,7 +38,7 @@ const stationConsts = {
};
export class Station extends JlGraphic {
static Type = 'station';
codeGraph: VectorText = new VectorText(''); //车站
codeGraph: VectorText = new VectorText(''); //车站
kilometerGraph: VectorText = new VectorText(''); //公里标
constructor() {
super(Station.Type);

View File

@ -36,12 +36,6 @@
</template>
</q-btn-toggle>
</q-toolbar-title>
<q-btn
color="orange"
label="公里标转换"
style="margin-right: 10px"
@click="openkilometerConvertList"
/>
<q-btn square color="purple" style="margin-right: 10px" icon="search">
<q-popup-edit
ref="popupEdit"
@ -76,6 +70,11 @@
<q-item-label>关联设备列表</q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="openkilometerConvertList">
<q-item-section>
<q-item-label>公里标转换</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn color="info" label="返回" @click="backConfirm" />
@ -152,6 +151,14 @@
v-model="UniqueIdPrefix.lineId"
:rules="[(val) => val.trim() != '' || '集中站名称不能为空']"
/>
<q-input
outlined
label="地图的公里标主坐标系"
v-model="UniqueIdPrefix.mainCoordinateSystem"
:rules="[
(val) => val.trim() != '' || '地图的公里标主坐标系不能为空',
]"
/>
</q-card-section>
<q-card-actions align="right">

View File

@ -37,11 +37,18 @@
<q-page-container>
<div id="line-app-container" class="overflow-hidden"></div>
</q-page-container>
<q-dialog v-model="pslDialog" @before-hide="pslHide">
<q-page-container>
<div id="psl-app-container" class="overflow-hidden"></div>
</q-page-container>
</q-dialog>
<draggable-dialog
v-model="pslStore.isPslDialogOpen"
:width="pslCanvasWidth"
:height="pslCanvasHeight"
@hide="pslHide"
>
<div
id="psl-app-container"
class="overflow-hidden"
style="width: 500px; height: 600px"
></div>
</draggable-dialog>
<DraggableDialog
:title="`${ibpStore.stationCode}IBP`"
v-model="ibpStore.isIbpDialogOpen"
@ -84,8 +91,6 @@ import { ISceneName, getSceneName } from 'src/drawApp/lineApp';
import { useTestManageStore } from 'src/stores/testManage-store';
import { CategoryType } from 'src/components/CategoryType';
import TrainInfoEcharts from 'src/components/line-app/infos/TrainInfoEcharts.vue';
import { GatedBox } from 'src/graphics/gatedBox/GatedBox';
import { getPublishMapInfoByName } from 'src/api/PublishApi';
import { useIbpStore } from 'src/stores/ibp-store';
const $q = useQuasar();
@ -96,8 +101,8 @@ const route = useRoute();
const router = useRouter();
const lineStore = useLineStore();
const ibpStore = useIbpStore();
const pslStore = usePslStore();
const testManageStore = useTestManageStore();
const pslDialog = ref(false);
const simulationId = (route.query.simulationId as string) || '';
const projectId = (route.query.projectId as string) || '';
const defaultMapId = (route.query.defaultMapId as string) || '';
@ -170,6 +175,11 @@ onMounted(async () => {
}
lineStore.addAllScene(projectInfo.mapInfoLinks || []);
}
lineStore.setSceneName(sceneName);
scene = lineApp.getScene(sceneName);
scene.bindDom(dom);
scene.reload();
onResize();
} catch (e) {
const error = e as ApiError;
$q.notify({
@ -177,19 +187,11 @@ onMounted(async () => {
message: error.title,
});
}
lineStore.setSceneName(sceneName);
scene = lineApp.getScene(sceneName);
scene.bindDom(dom);
scene.reload();
onResize();
} else {
lineStore.setMapId(null);
lineStore.setSimulationId(null);
}
drawerRight.value = false;
// setTimeout(() => {
// pslShow();
// }, 5000);
});
onUnmounted(() => {
if (dialogInstance.value && lineStore.showLayerDialog) {
@ -216,16 +218,34 @@ watch(
}
);
const pslCanvasWidth = ref(500);
const pslCanvasHeight = ref(600);
watch(
() => lineStore.gatedBoxCount,
() => {
if (lineStore.selectedGraphics) {
const gatedBox = lineStore.selectedGraphics[0] as GatedBox;
pslShow(gatedBox);
() => pslStore.isPslDialogOpen,
(val: boolean) => {
if (val === true) {
nextTick(async () => {
const container = document.getElementById('psl-app-container');
if (!container) return;
const pslScene = pslStore.getPslScene();
pslScene?.bindDom(container);
await pslScene?.reload();
if (pslScene) {
pslCanvasWidth.value = pslScene.canvas.width;
pslCanvasHeight.value = pslScene.canvas.height;
container.style.width = pslCanvasWidth.value + 'px';
container.style.height = pslCanvasHeight.value + 'px';
}
});
}
}
);
function pslHide() {
pslStore.clearPslParam();
lineApp.getScene('psl').unbindDom();
}
const dialogInstance = ref();
watch(
@ -302,46 +322,6 @@ function switchScene(val: MapInfo) {
}
}
function pslShow(gatedBox: GatedBox) {
pslDialog.value = true;
const pslApp = usePslStore().initLineApp();
if (gatedBox.datas.refGatedBoxMapCode) {
const params = {
name: gatedBox.datas.refGatedBoxMapCode,
detail: false,
};
lineStore.setPslId(gatedBox.datas.id);
getPublishMapInfoByName(params).then(async (mapInfo) => {
const dom = document.getElementById('psl-app-container');
if (dom) {
usePslStore().addAllScene([mapInfo]);
usePslStore().setMapId(mapInfo.id);
usePslStore().setSimulationId(simulationId);
sceneName = getSceneNameFn(mapInfo);
usePslStore().setSceneName(sceneName);
scene = pslApp.getScene(sceneName);
scene.bindDom(dom);
await scene.reload();
dom.style.width = scene.canvas.width + 'px';
dom.style.height = scene.canvas.height + 'px';
}
});
} else {
$q.notify({
type: 'negative',
message: '未获取到关联门控箱地图数据',
});
}
}
function pslHide() {
const pslApp = usePslStore().initLineApp();
lineStore.setPslId('');
pslApp.unbindDom();
pslApp.destroy();
pslDialog.value = false;
}
function ibpHide() {
ibpStore.destory();
}

View File

@ -198,6 +198,7 @@ import { DialogChainObject, useQuasar } from 'quasar';
import { Relay } from 'src/graphics/relay/Relay';
import { RelayCabinet } from 'src/graphics/relayCabinet/RelayCabinet';
import { PhaseFailureProtector } from 'src/graphics/phaseFailureProtector/PhaseFailureProtector';
import { SignalFaultAlarm } from 'src/graphics/signalFaultAlarm/SignalFaultAlarm';
import { relayCabinetGraphicData } from 'src/protos/relayCabinetLayoutGraphics';
const $q = useQuasar();
@ -291,6 +292,7 @@ onMounted(() => {
RelayCabinet.Type,
Relay.Type,
PhaseFailureProtector.Type,
SignalFaultAlarm.Type,
];
drawAssistantsTypes.forEach((type) => {
const drawAssistant = getDrawApp()?.getDrawAssistant(type);

View File

@ -33,8 +33,6 @@ export const useLineStore = defineStore('line', {
categoryType: null as CategoryType | null,
echartsTrainId: '',
trainStateMap: new Map() as Map<Date, TrainState[]>,
gatedBoxCount: 0,
pslId: '',
}),
getters: {
selectedGraphicType: (state) => {
@ -64,7 +62,6 @@ export const useLineStore = defineStore('line', {
);
});
this.selectedGraphics = [];
this.gatedBoxCount = 0;
return app;
},
addAllScene(list: MapInfo[]) {
@ -135,11 +132,5 @@ export const useLineStore = defineStore('line', {
setCategoryType(type: CategoryType | null) {
this.categoryType = type;
},
increaseGatedBoxCount() {
this.gatedBoxCount++;
},
setPslId(id: string) {
this.pslId = id;
},
},
});

View File

@ -1,102 +1,32 @@
import { defineStore } from 'pinia';
import {
IJlCanvas,
JlGraphic,
IGraphicApp,
GraphicState,
} from 'src/jl-graphic';
import {
initLineApp,
getLineApp,
destroyLineApp,
addSceneList,
ISceneName,
} from 'src/drawApp/lineApp';
import { markRaw } from 'vue';
import { MapInfo } from 'src/api/ProjectLinkApi';
import { initPslScene } from 'src/drawApp/pslScene';
import { getLineApp } from 'src/drawApp/lineApp';
import { GraphicApp } from 'src/jl-graphic/app/JlGraphicApp';
export const usePslStore = defineStore('psl', {
state: () => ({
selectedGraphics: null as JlGraphic[] | null,
lineId: null as number | null,
lineName: null as string | null,
simulationId: null as string | null,
socketStates: null as GraphicState[] | null,
stateProCount: 0,
showLayer: [] as string[], // 显示的图层(草稿和发布图公用)
showLayerDialog: false, // 显示图层控制弹窗(草稿和发布图公用)
mapId: null as number | null,
sceneName: '', // 场景名称
pslMapCode: '',
gatedBoxId: '',
isPslDialogOpen: false,
}),
getters: {
selectedGraphicType: (state) => {
if (state.selectedGraphics) {
if (state.selectedGraphics.length === 1) {
return state.selectedGraphics[0].type;
}
}
},
},
actions: {
getLineApp(): IGraphicApp {
const app = getLineApp();
if (app == null) {
throw new Error('未初始化app');
getPslScene() {
const lineApp = getLineApp() as GraphicApp;
if (!lineApp) return;
if (lineApp.scenes.get('psl')) {
return lineApp.getScene('psl');
}
return app;
return initPslScene(lineApp, 'psl');
},
getJlCanvas(): IJlCanvas {
return this.getLineApp().canvas;
setPslParam(gatedBoxId: string, pslMapCode: string) {
this.gatedBoxId = gatedBoxId;
this.pslMapCode = pslMapCode;
this.isPslDialogOpen = true;
},
initLineApp() {
const app = initLineApp();
app.on('graphicselected', () => {
this.selectedGraphics = markRaw(
app.getScene(this.sceneName).selectedGraphics
);
});
this.selectedGraphics = [];
return app;
},
addAllScene(list: MapInfo[]) {
const arr: ISceneName[] = list.map((item) => {
return { type: item.type, id: item.id };
});
addSceneList(arr);
},
appCurrentScene() {
return this.getLineApp().getScene(this.sceneName);
},
destroy() {
this.selectedGraphics = null;
destroyLineApp();
},
setLineId(id: number | null) {
this.lineId = id;
},
setLineName(name: string | null) {
this.lineName = name;
},
setSimulationId(id: string | null) {
this.simulationId = id;
},
setSocketStates(v: GraphicState[] | null) {
this.socketStates = v;
},
stateProCountIncrease() {
this.stateProCount++;
},
setShowLayer(v: string[]) {
this.showLayer = v;
},
setShowLayerDialog(v: boolean) {
this.showLayerDialog = v;
},
setMapId(id: number | null) {
this.mapId = id;
},
setSceneName(sceneName: string) {
this.sceneName = sceneName;
clearPslParam() {
this.gatedBoxId = '';
this.pslMapCode = '';
this.isPslDialogOpen = false;
},
},
});