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", "test": "echo \"No test specified\" && exit 0",
"dev": "quasar dev", "dev": "quasar dev",
"build": "quasar build", "build": "quasar build",
"build:test": "set NODE_ENV=test&&quasar build",
"build:publish": "set NODE_ENV=publish&&quasar build",
"protoc": "node scripts/proto.cjs", "protoc": "node scripts/proto.cjs",
"sync": "node scripts/sync.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 // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
build: { build: {
env: {
// test:测试服务器publish正式服务器其他本地
ENV_MODE: process.env.NODE_ENV,
},
target: { target: {
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'], browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
node: 'node16', node: 'node16',

View File

@ -60,6 +60,7 @@ export async function setSignalState(data: {
simulationId: string; simulationId: string;
mapId: number; mapId: number;
id: string; id: string;
operation: number;
aspect: number; aspect: number;
}) { }) {
return await api.post(`${UriBase}/signal/operation`, data); 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); 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.Type
" "
></phaseFailureProtector-property> ></phaseFailureProtector-property>
<signalFaultAlarm-property
v-if="
relayCabinetStore.selectedGraphicType === SignalFaultAlarm.Type
"
></signalFaultAlarm-property>
</q-card-section> </q-card-section>
</template> </template>
</q-card> </q-card>
@ -41,6 +46,8 @@ import RelayProperty from './properties/RelayProperty.vue';
import { Relay } from 'src/graphics/relay/Relay'; import { Relay } from 'src/graphics/relay/Relay';
import PhaseFailureProtectorProperty from './properties/PhaseFailureProtectorProperty.vue'; import PhaseFailureProtectorProperty from './properties/PhaseFailureProtectorProperty.vue';
import { PhaseFailureProtector } from 'src/graphics/phaseFailureProtector/PhaseFailureProtector'; 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'; import { useRelayCabinetStore } from 'src/stores/relayCabinet-store';
const relayCabinetStore = useRelayCabinetStore(); const relayCabinetStore = useRelayCabinetStore();

View File

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

View File

@ -133,6 +133,10 @@ const optionsType = [
{ label: '信号机', value: graphicData.RelatedRef.DeviceType.signal }, { label: '信号机', value: graphicData.RelatedRef.DeviceType.signal },
{ label: '车站', value: graphicData.RelatedRef.DeviceType.station }, { label: '车站', value: graphicData.RelatedRef.DeviceType.station },
{ label: '屏蔽门', value: graphicData.RelatedRef.DeviceType.ScreenDoor }, { label: '屏蔽门', value: graphicData.RelatedRef.DeviceType.ScreenDoor },
{
label: '信号机故障报警仪',
value: graphicData.RelatedRef.DeviceType.SignalFaultAlarm,
},
]; ];
let selectGraphic: JlGraphic[] = []; 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" @blur="onUpdate"
label="索引" 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-list bordered separator class="rounded-borders">
<q-item no-wrap class="q-gutter-y-sm column"> <q-item no-wrap class="q-gutter-y-sm column">
<div>公里标配置</div> <div>公里标配置</div>
@ -48,7 +58,7 @@
<q-select <q-select
outlined outlined
class="q-mt-sm" class="q-mt-sm"
:model-value="refDevData.deviceType" v-model="refDevData.deviceType"
:options="DeviceTypeOptions" :options="DeviceTypeOptions"
readonly readonly
map-options map-options
@ -58,7 +68,7 @@
<q-input <q-input
outlined outlined
class="q-mt-sm" class="q-mt-sm"
:model-value="refDevData.code" v-model="refDevData.code"
:readonly="true" :readonly="true"
label="关联设备:" label="关联设备:"
></q-input> ></q-input>
@ -128,6 +138,14 @@ const DeviceTypeOptions = [
{ label: '区段', value: graphicData.RelatedRef.DeviceType.Section }, { label: '区段', value: graphicData.RelatedRef.DeviceType.Section },
{ label: '道岔', value: graphicData.RelatedRef.DeviceType.Turnout }, { 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 = [ const DevicePortOptions = [
{ label: 'A端', value: graphicData.RelatedRef.DevicePort.A }, { label: 'A端', value: graphicData.RelatedRef.DevicePort.A },
{ label: 'B端', value: graphicData.RelatedRef.DevicePort.B }, { 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 readonly v-model="stationModel.id" label="id" />
<q-input <q-input
outlined outlined
label="车站" label="车站名"
type="textarea" type="textarea"
@blur="onUpdate" @blur="onUpdate"
v-model="stationModel.code" v-model="stationModel.code"
lazy-rules lazy-rules
autogrow autogrow
/> />
<q-input
outlined
label="车站名"
type="textarea"
@blur="onUpdate"
v-model="stationModel.stationName"
lazy-rules
autogrow
/>
<q-input <q-input
outlined outlined
v-model.number="stationModel.index" v-model.number="stationModel.index"

View File

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

View File

@ -3,39 +3,55 @@
seamless seamless
title="列车属性曲线图" title="列车属性曲线图"
@show="onDialogShow" @show="onDialogShow"
:height="510" :height="546"
:width="710" :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 <div
id="train-echarts" id="train-echarts"
class="overflow-hidden" class="q-pa-sm overflow-hidden"
style="height: 100%; width: 100%" style="height: 510px; width: 710px"
></div> ></div>
</div> </div>
</DraggableDialog> </DraggableDialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { watch } from 'vue'; import { ref, watch } from 'vue';
import { useLineStore } from 'src/stores/line-store'; import { useLineStore } from 'src/stores/line-store';
import DraggableDialog from 'src/components/common/DraggableDialog.vue'; import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import 'default-passive-events'; import 'default-passive-events';
import { date } from 'quasar'; import { date } from 'quasar';
import { getMapKilometerRange } from 'src/api/Simulation';
const lineStore = useLineStore(); const lineStore = useLineStore();
const tab = ref('time');
let speedList: [Date, number][] = []; let speedList: [Date, number][] = [];
let accelerationList: [Date, number][] = []; let accelerationList: [Date, number][] = [];
let tractionForceList: [Date, number][] = []; let tractionForceList: [Date, number][] = [];
let brakeForceList: [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<{ const props = defineProps<{
trainId: string; trainId: string;
}>(); }>();
function onDialogShow() { function onDialogShow() {
getKilometerRange();
if (props.trainId) { if (props.trainId) {
getDataList(); getDataList();
initEcharts(); initEcharts();
@ -47,6 +63,11 @@ function getDataList() {
accelerationList = []; accelerationList = [];
tractionForceList = []; tractionForceList = [];
brakeForceList = []; brakeForceList = [];
kmList = [];
km_speedList = [];
km_accelerationList = [];
km_tractionForceList = [];
km_brakeForceList = [];
lineStore.trainStateMap.forEach((list, key) => { lineStore.trainStateMap.forEach((list, key) => {
const find = list.find((ii) => { const find = list.find((ii) => {
return ii.id == props.trainId; return ii.id == props.trainId;
@ -56,11 +77,30 @@ function getDataList() {
accelerationList.push([key, find.dynamicState.acceleration]); accelerationList.push([key, find.dynamicState.acceleration]);
tractionForceList.push([key, find.vobcState.tractionForce / 100]); tractionForceList.push([key, find.vobcState.tractionForce / 100]);
brakeForceList.push([key, find.vobcState.brakeForce / 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: '速度', name: '速度',
type: 'line', type: 'line',
@ -72,6 +112,7 @@ let series = [
name: '加速度', name: '加速度',
type: 'line', type: 'line',
showSymbol: false, showSymbol: false,
yAxisIndex: 1,
data: accelerationList, data: accelerationList,
unit: 'm/s', unit: 'm/s',
}, },
@ -90,6 +131,54 @@ let series = [
unit: 'kn', 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; let myChart: echarts.EChartsType;
function initEcharts() { function initEcharts() {
@ -99,7 +188,8 @@ function initEcharts() {
renderer: 'canvas', renderer: 'canvas',
useDirtyRect: false, useDirtyRect: false,
}); });
const option = { let option: echarts.EChartsOption = {
animation: false,
title: { title: {
text: '', text: '',
}, },
@ -139,6 +229,7 @@ function initEcharts() {
`; `;
// eslint-disable-next-line // eslint-disable-next-line
params.forEach((item: any, index: number) => { params.forEach((item: any, index: number) => {
let val = item.value[1].toFixed(2);
result += result +=
"<div style='height: 28px;line-height:28px'>" + "<div style='height: 28px;line-height:28px'>" +
'<span style="display:inline-block;margin-right:5px;border-radius:20px;width:10px;height:10px;background-color:' + '<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 + item.seriesName +
' : ' + ' : ' +
'<span style="float:right;margin-left:20px;font-size:14px;color:#666;font-weight:bold">' + '<span style="float:right;margin-left:20px;font-size:14px;color:#666;font-weight:bold">' +
item.value[1].toFixed(2) + val +
' ' + ' ' +
series[index].unit + series[index].unit +
'</span>' + '</span>' +
@ -169,13 +260,119 @@ function initEcharts() {
show: false, show: false,
}, },
}, },
yAxis: { yAxis: [
type: 'value', {
boundaryGap: [0, '100%'], type: 'value',
}, // max: 100,
boundaryGap: [0, 0.1],
},
{
type: 'value',
scale: true,
name: '加速度 m/s',
boundaryGap: [0, 0.4],
},
],
series: series, 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); myChart.setOption(option);
} }
@ -183,7 +380,7 @@ watch(
() => lineStore.socketStates, () => lineStore.socketStates,
() => { () => {
getDataList(); getDataList();
myChart?.setOption({ let op: echarts.EChartsOption = {
series: [ series: [
{ {
data: speedList, data: speedList,
@ -198,8 +395,47 @@ watch(
data: brakeForceList, 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> </script>
<style scoped></style> <style scoped></style>

View File

@ -1,7 +1,22 @@
<template> <template>
<q-card flat bordered> <q-card flat bordered>
<q-card-section> <q-card-section class="flex justify-between">
<div class="text-h6">信号机状态</div> <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-card-section>
<q-separator inset /> <q-separator inset />
<q-form> <q-form>
@ -37,15 +52,99 @@
import { useLineStore } from 'src/stores/line-store'; import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted } from 'vue'; import { ref, watch, onMounted } from 'vue';
import { Signal } from 'src/graphics/signal/Signal'; 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 lineStore = useLineStore();
const signalState = ref({ id: '', index: 0, code: '' }); 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( watch(
() => lineStore.selectedGraphics, () => lineStore.selectedGraphics,
(val) => { (val) => {
if (val?.length == 1 && val[0].type == Signal.Type) { if (val?.length == 1 && val[0].type == Signal.Type) {
setSignalState(val[0] as Signal); initSignalState(val[0] as Signal);
} else { } else {
signalState.value = { signalState.value = {
id: '', id: '',
@ -55,7 +154,7 @@ watch(
} }
} }
); );
function setSignalState(signal: Signal) { function initSignalState(signal: Signal) {
signalState.value = { signalState.value = {
id: signal.datas.id, id: signal.datas.id,
index: signal.datas.index, index: signal.datas.index,
@ -68,13 +167,29 @@ function submitState() {
} }
function onReset() { function onReset() {
if (lineStore.selectedGraphics) { 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(() => { onMounted(() => {
if (lineStore.selectedGraphics) { if (lineStore.selectedGraphics) {
setSignalState(lineStore.selectedGraphics[0] as Signal); initSignalState(lineStore.selectedGraphics[0] as Signal);
} }
}); });
</script> </script>

View File

@ -1,4 +1,9 @@
function getHost(): string { 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.7:9091';
// return '192.168.3.47:9091'; // return '192.168.3.47:9091';
// return '192.168.3.37:9091'; // return '192.168.3.37:9091';
@ -6,18 +11,28 @@ function getHost(): string {
// return '192.168.3.5:9091'; // return '192.168.3.5:9091';
// return '192.168.3.37:9091'; //卫志宏 // return '192.168.3.37:9091'; //卫志宏
return '192.168.3.233:9091'; return '192.168.3.233:9091';
// return 'test.joylink.club/bjrtss-server';
} }
export function getHttpBase() { export function getHttpBase() {
return `http://${getHost()}`; let protocol = 'http';
// return `https://${getHost()}`; if (['test', 'publish'].includes(process.env.ENV_MODE as string)) {
protocol = 'https';
}
return `${protocol}://${getHost()}`;
} }
export function getWebsocketUrl() { export function getWebsocketUrl() {
const host = '192.168.3.233'; let protocol = 'ws';
const port = 8000; let host = '192.168.3.233';
// return `ws://${host}/ws-bj`; let port = '8000';
return `ws://${host}:${port}/connection/websocket`; if (process.env.ENV_MODE == 'test') {
// return `wss://${getHost()}/ws-bj`; 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, ScreenDoor,
ScreenDoorTemplate, ScreenDoorTemplate,
} from 'src/graphics/screenDoor/ScreenDoor'; } from 'src/graphics/screenDoor/ScreenDoor';
import { ScreenDoorData } from './graphics/ScreenDoorInteraction'; import {
ScreenDoorData,
ScreenDoorState,
} from './graphics/ScreenDoorInteraction';
import { ScreenDoorDraw } from 'src/graphics/screenDoor/ScreenDoorDrawAssistant'; import { ScreenDoorDraw } from 'src/graphics/screenDoor/ScreenDoorDrawAssistant';
import { Station, StationTemplate } from 'src/graphics/station/Station'; import { Station, StationTemplate } from 'src/graphics/station/Station';
import { StationDraw } from 'src/graphics/station/StationDrawAssistant'; import { StationDraw } from 'src/graphics/station/StationDrawAssistant';
@ -168,7 +171,10 @@ export function initCommonDrawApp(app: IDrawApp) {
app, app,
new PlatformTemplate(new PlatformData(), new PlatformState()) new PlatformTemplate(new PlatformData(), new PlatformState())
); );
new ScreenDoorDraw(app, new ScreenDoorTemplate(new ScreenDoorData())); new ScreenDoorDraw(
app,
new ScreenDoorTemplate(new ScreenDoorData(), new ScreenDoorState())
);
new StationDraw( new StationDraw(
app, app,
new StationTemplate(new StationData(), new StationState()) 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 { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { graphicData } from 'src/protos/stationLayoutGraphics'; import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useLineStore } from 'src/stores/line-store';
import { GraphicDataBase } from './GraphicDataBase'; import { GraphicDataBase } from './GraphicDataBase';
import { usePslStore } from 'src/stores/psl-store';
export class GatedBoxData extends GraphicDataBase implements IGatedBox { export class GatedBoxData extends GraphicDataBase implements IGatedBox {
constructor(data?: graphicData.GatedBox) { constructor(data?: graphicData.GatedBox) {
@ -141,8 +141,12 @@ export class GatedBoxOperateInteraction extends GraphicInteractionPlugin<GatedBo
g.eventMode = 'none'; g.eventMode = 'none';
g.off('_leftclick', this.onLeftClick, this); g.off('_leftclick', this.onLeftClick, this);
} }
onLeftClick() { onLeftClick(e: FederatedMouseEvent) {
// useLineStore().stateProCountIncrease(); const target = e.target as DisplayObject;
useLineStore().increaseGatedBoxCount(); 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 * as pb_1 from 'google-protobuf';
import { IPslButtonData, PslButton } from 'src/graphics/pslButton/pslButton'; import {
IPslButtonData,
IPslButtonState,
PslButton,
} from 'src/graphics/pslButton/pslButton';
import { import {
GraphicInteractionPlugin, GraphicInteractionPlugin,
IGraphicScene, IGraphicScene,
JlGraphic, JlGraphic,
} from 'src/jl-graphic'; } from 'src/jl-graphic';
import { pslGraphicData } from 'src/protos/pslGraphics'; 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 { export class PslButtonData extends GraphicDataBase implements IPslButtonData {
constructor(data?: pslGraphicData.PslButton) { constructor(data?: pslGraphicData.PslButton) {
@ -53,6 +63,42 @@ export class PslButtonData extends GraphicDataBase implements IPslButtonData {
return pb_1.Message.equals(this.data, other.data); 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> { export class PslButtonOperateInteraction extends GraphicInteractionPlugin<PslButton> {
static Name = 'psl_button_operate_menu'; static Name = 'psl_button_operate_menu';
constructor(app: IGraphicScene) { constructor(app: IGraphicScene) {
@ -70,16 +116,72 @@ export class PslButtonOperateInteraction extends GraphicInteractionPlugin<PslBut
g.eventMode = 'static'; g.eventMode = 'static';
g.cursor = 'pointer'; g.cursor = 'pointer';
g.selectable = true; 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 { unbind(g: PslButton): void {
g.selectable = false; g.selectable = false;
g.eventMode = 'none'; 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() { onMouseOut(e: FederatedMouseEvent) {
// useLineStore().stateProCountIncrease(); const target = e.target as DisplayObject;
// useLineStore().increaseGatedBoxCount(); 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 * as pb_1 from 'google-protobuf';
import { import {
IScreenDoorData, IScreenDoorData,
IScreenDoorState,
ScreenDoor, ScreenDoor,
} from 'src/graphics/screenDoor/ScreenDoor'; } from 'src/graphics/screenDoor/ScreenDoor';
import { graphicData } from 'src/protos/stationLayoutGraphics'; 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 { export class ScreenDoorData extends GraphicDataBase implements IScreenDoorData {
constructor(data?: graphicData.ScreenDoor) { constructor(data?: graphicData.ScreenDoor) {
@ -59,3 +61,36 @@ export class ScreenDoorData extends GraphicDataBase implements IScreenDoorData {
return pb_1.Message.equals(this.data, other.data); 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 { SignalGraphicHitArea } from 'src/graphics/signal/SignalDrawAssistant';
import { setSignalState } from 'src/api/Simulation'; import { setSignalState } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify'; import { errorNotify } from 'src/utils/CommonNotify';
import { request } from 'src/protos/request';
export class SignalData extends GraphicDataBase implements ISignalData { export class SignalData extends GraphicDataBase implements ISignalData {
constructor(data?: graphicData.Signal) { constructor(data?: graphicData.Signal) {
@ -75,6 +76,12 @@ export class SignalData extends GraphicDataBase implements ISignalData {
set centralizedStations(v: string[]) { set centralizedStations(v: string[]) {
this.data.centralizedStations = v; 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 { clone(): SignalData {
return new SignalData(this.data.cloneMessage()); return new SignalData(this.data.cloneMessage());
} }
@ -237,6 +244,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId, mapId,
id: signal.datas.id, id: signal.datas.id,
aspect: state.Signal.Aspect.OFF, aspect: state.Signal.Aspect.OFF,
operation: request.Signal.Operation.Display,
}).catch((err) => { }).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title }); errorNotify('操作失败', { message: err.origin.response.data.title });
}); });
@ -247,6 +255,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId, mapId,
id: signal.datas.id, id: signal.datas.id,
aspect: state.Signal.Aspect.H, aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.Display,
}).catch((err) => { }).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title }); errorNotify('操作失败', { message: err.origin.response.data.title });
}); });
@ -257,6 +266,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId, mapId,
id: signal.datas.id, id: signal.datas.id,
aspect: state.Signal.Aspect.L, aspect: state.Signal.Aspect.L,
operation: request.Signal.Operation.Display,
}).catch((err) => { }).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title }); errorNotify('操作失败', { message: err.origin.response.data.title });
}); });
@ -267,6 +277,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId, mapId,
id: signal.datas.id, id: signal.datas.id,
aspect: state.Signal.Aspect.U, aspect: state.Signal.Aspect.U,
operation: request.Signal.Operation.Display,
}).catch((err) => { }).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title }); errorNotify('操作失败', { message: err.origin.response.data.title });
}); });
@ -277,6 +288,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
mapId, mapId,
id: signal.datas.id, id: signal.datas.id,
aspect: state.Signal.Aspect.HU, aspect: state.Signal.Aspect.HU,
operation: request.Signal.Operation.Display,
}).catch((err) => { }).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title }); errorNotify('操作失败', { message: err.origin.response.data.title });
}); });

View File

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

View File

@ -21,7 +21,10 @@ import {
PlatformState, PlatformState,
} from './graphics/PlatformInteraction'; } from './graphics/PlatformInteraction';
import { PlatformTemplate, Platform } from 'src/graphics/platform/Platform'; import { PlatformTemplate, Platform } from 'src/graphics/platform/Platform';
import { ScreenDoorData } from './graphics/ScreenDoorInteraction'; import {
ScreenDoorData,
ScreenDoorState,
} from './graphics/ScreenDoorInteraction';
import { import {
ScreenDoor, ScreenDoor,
ScreenDoorTemplate, ScreenDoorTemplate,
@ -179,6 +182,9 @@ export const layerList = [
export function initLineScene(lineApp: IGraphicApp, sceneName: string) { export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
const options: GraphicAppOptions = { const options: GraphicAppOptions = {
dataLoader: loadLineDatas, dataLoader: loadLineDatas,
};
const lineScene = lineApp.initScene(sceneName, options);
lineScene.setOptions({
mouseToolOptions: { mouseToolOptions: {
boxSelect: false, boxSelect: false,
viewportDrag: true, viewportDrag: true,
@ -194,8 +200,7 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
Section.Type, Section.Type,
Transponder.Type, Transponder.Type,
], ],
}; });
const lineScene = lineApp.initScene(sceneName, options);
const categoryType = useLineStore().categoryType; const categoryType = useLineStore().categoryType;
if (!categoryType) { if (!categoryType) {
throw new Error('未获取到厂商信息'); throw new Error('未获取到厂商信息');
@ -209,7 +214,7 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
getTypeConsts(Signal.Type) getTypeConsts(Signal.Type)
), ),
new PlatformTemplate(new PlatformData(), new PlatformState()), new PlatformTemplate(new PlatformData(), new PlatformState()),
new ScreenDoorTemplate(new ScreenDoorData()), new ScreenDoorTemplate(new ScreenDoorData(), new ScreenDoorState()),
new StationTemplate(new StationData(), new StationState()), new StationTemplate(new StationData(), new StationState()),
new TurnoutTemplate(new TurnoutData(), new TurnoutStates()), new TurnoutTemplate(new TurnoutData(), new TurnoutStates()),
new SectionTemplate(new SectionData()), new SectionTemplate(new SectionData()),
@ -284,6 +289,11 @@ function handleSubscribe(lineScene: IGraphicScene) {
// states.push(new SectionState(item)); // states.push(new SectionState(item));
} }
}); });
storage.allStatus.psdState.forEach((item) => {
if (item.id) {
states.push(new ScreenDoorState(item));
}
});
storage.allStatus.switchState.forEach((item) => { storage.allStatus.switchState.forEach((item) => {
// 道岔 // 道岔
if (item.id) { 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 { PslKey, PslKeyTemplate } from 'src/graphics/pslKey/pslKey';
import { PslKeyData } from './graphics/PslKeyInteraction'; import { PslKeyData } from './graphics/PslKeyInteraction';
import { PslButton, PslButtonTemplate } from 'src/graphics/pslButton/pslButton'; 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 { PslLight, PslLightTemplate } from 'src/graphics/pslLight/pslLight';
import { PslLightData } from './graphics/PslLightInteraction'; import { PslLightData } from './graphics/PslLightInteraction';
import { import {
@ -75,7 +75,10 @@ export function initPslDrawApp(): IDrawApp {
const app = drawApp; const app = drawApp;
//根据草稿图类型加载绘图工具 //根据草稿图类型加载绘图工具
new PslKeyDraw(app, new PslKeyTemplate(new PslKeyData())); 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 PslLightDraw(app, new PslLightTemplate(new PslLightData()));
new TextContentDraw(app, new TextContentTemplate(new PslTextData())); new TextContentDraw(app, new TextContentTemplate(new PslTextData()));

View File

@ -5,7 +5,7 @@ import {
IGraphicScene, IGraphicScene,
IGraphicStorage, IGraphicStorage,
} from 'src/jl-graphic'; } from 'src/jl-graphic';
import { getPublishMapInfoByLineId } from 'src/api/PublishApi'; import { getPublishMapInfoByName } from 'src/api/PublishApi';
import { usePslStore } from 'src/stores/psl-store'; import { usePslStore } from 'src/stores/psl-store';
import { toUint8Array } from 'js-base64'; import { toUint8Array } from 'js-base64';
import { PslKeyTemplate } from 'src/graphics/pslKey/pslKey'; import { PslKeyTemplate } from 'src/graphics/pslKey/pslKey';
@ -14,6 +14,7 @@ import { PslButtonTemplate } from 'src/graphics/pslButton/pslButton';
import { import {
PslButtonData, PslButtonData,
PslButtonOperateInteraction, PslButtonOperateInteraction,
PslButtonState,
} from './graphics/PslButtonInteraction'; } from './graphics/PslButtonInteraction';
import { PslLightTemplate } from 'src/graphics/pslLight/pslLight'; import { PslLightTemplate } from 'src/graphics/pslLight/pslLight';
import { PslLightData } from './graphics/PslLightInteraction'; import { PslLightData } from './graphics/PslLightInteraction';
@ -21,6 +22,7 @@ import { pslGraphicData } from 'src/protos/pslGraphics';
import { PslTextData } from './graphics/TextContentInteraction'; import { PslTextData } from './graphics/TextContentInteraction';
import { TextContentTemplate } from 'src/graphics/textContent/TextContent'; import { TextContentTemplate } from 'src/graphics/textContent/TextContent';
import { useLineStore } from 'src/stores/line-store'; import { useLineStore } from 'src/stores/line-store';
import { state } from 'src/protos/device_state';
export function initPslScene(lineApp: IGraphicApp, sceneName: string) { export function initPslScene(lineApp: IGraphicApp, sceneName: string) {
// psl // psl
@ -28,13 +30,13 @@ export function initPslScene(lineApp: IGraphicApp, sceneName: string) {
dataLoader: loadPslDatas, dataLoader: loadPslDatas,
mouseToolOptions: { mouseToolOptions: {
boxSelect: false, boxSelect: false,
viewportDrag: true, viewportDrag: false,
wheelZoom: true, wheelZoom: false,
}, },
}); });
const graphicTemplate = [ const graphicTemplate = [
new PslKeyTemplate(new PslKeyData()), new PslKeyTemplate(new PslKeyData()),
new PslButtonTemplate(new PslButtonData()), new PslButtonTemplate(new PslButtonData(), new PslButtonState()),
new PslLightTemplate(new PslLightData()), new PslLightTemplate(new PslLightData()),
new TextContentTemplate(new PslTextData()), new TextContentTemplate(new PslTextData()),
]; ];
@ -43,28 +45,37 @@ export function initPslScene(lineApp: IGraphicApp, sceneName: string) {
pslScene.on('postdataloaded', () => { pslScene.on('postdataloaded', () => {
handleSubscribe(pslScene); handleSubscribe(pslScene);
}); });
pslScene.setOptions({ // pslScene.setOptions({
mouseToolOptions: { // mouseToolOptions: {
boxSelect: false, // boxSelect: false,
viewportDrag: false, // viewportDrag: false,
wheelZoom: false, // wheelZoom: false,
}, // },
}); // });
return lineApp; return pslScene;
} }
function handleSubscribe(pslScene: IGraphicScene) { function handleSubscribe(pslScene: IGraphicScene) {
const lineStore = useLineStore(); const lineStore = useLineStore();
const pslStore = usePslStore();
const simulationId = lineStore.simulationId; const simulationId = lineStore.simulationId;
const mapId = lineStore.mapId; const mapId = lineStore.mapId;
const pslId = lineStore.pslId; const pslId = pslStore.gatedBoxId;
const app = pslScene; const app = pslScene;
app.subscribe({ app.subscribe({
destination: `simulation-psl-${simulationId}_${mapId}_${pslId}-status`, destination: `simulation-psl-${simulationId}_${mapId}_${pslId}-status`,
messageConverter: (message: Uint8Array) => { messageConverter: (message: Uint8Array) => {
// console.log('收到消息', message); // console.log('收到消息', message);
const states: GraphicState[] = []; 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; return states;
}, },
}); });
@ -72,12 +83,10 @@ function handleSubscribe(pslScene: IGraphicScene) {
async function loadPslDatas(): Promise<IGraphicStorage> { async function loadPslDatas(): Promise<IGraphicStorage> {
const pslStore = usePslStore(); const pslStore = usePslStore();
const mapId = pslStore.mapId; const { proto: base64 } = await getPublishMapInfoByName({
const simulationId = pslStore.simulationId; name: pslStore.pslMapCode,
if (!mapId || !simulationId) { detail: true,
throw new Error('获取数据异常未获取到地图ID或仿真ID'); });
}
const { proto: base64 } = await getPublishMapInfoByLineId(mapId + '');
if (base64) { if (base64) {
const storage = pslGraphicData.PslGraphicStorage.deserialize( const storage = pslGraphicData.PslGraphicStorage.deserialize(
toUint8Array(base64) 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'; } from 'src/graphics/phaseFailureProtector/PhaseFailureProtector';
import { PhaseFailureProtectorData } from './relayCabinetGraphics/PhaseFailureProtectorInteraction'; import { PhaseFailureProtectorData } from './relayCabinetGraphics/PhaseFailureProtectorInteraction';
import { PhaseFailureProtectorDraw } from 'src/graphics/phaseFailureProtector/PhaseFailureProtectorDrawAssistant'; 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 = { const UndoOptions: MenuItemOptions = {
name: '撤销', name: '撤销',
@ -80,6 +86,10 @@ export function initDrawApp(): IDrawApp {
app, app,
new PhaseFailureProtectorTemplate(new PhaseFailureProtectorData()) new PhaseFailureProtectorTemplate(new PhaseFailureProtectorData())
); );
new SignalFaultAlarmDraw(
app,
new SignalFaultAlarmTemplate(new SignalFaultAlarmData())
);
// 画布右键菜单 // 画布右键菜单
app.registerMenu(DefaultCanvasMenu); app.registerMenu(DefaultCanvasMenu);
@ -205,6 +215,12 @@ export function saveDrawDatas(app: IDrawApp) {
(phaseFailureProtectorData as PhaseFailureProtectorData).data (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.deviceRelateRelayList = refRelaysList;
storage.combinationtypeList = combinationTypeList; storage.combinationtypeList = combinationTypeList;
@ -236,6 +252,9 @@ export async function loadDrawDatas(): Promise<IGraphicStorage> {
storage.phaseFailureProtectors.forEach((phaseFailureProtector) => { storage.phaseFailureProtectors.forEach((phaseFailureProtector) => {
datas.push(new PhaseFailureProtectorData(phaseFailureProtector)); datas.push(new PhaseFailureProtectorData(phaseFailureProtector));
}); });
storage.signalFaultAlarms.forEach((signalFaultAlarm) => {
datas.push(new SignalFaultAlarmData(signalFaultAlarm));
});
refRelaysList = storage.deviceRelateRelayList; refRelaysList = storage.deviceRelateRelayList;
combinationTypeList = storage.combinationtypeList; combinationTypeList = storage.combinationtypeList;
UniqueIdPrefix = storage.UniqueIdPrefix; UniqueIdPrefix = storage.UniqueIdPrefix;

View File

@ -59,8 +59,18 @@ export class GatedBox extends JlGraphic {
codeGraph.text = this.datas.code; codeGraph.text = this.datas.code;
codeGraph.style.fill = gatedBoxConsts.codeColor; codeGraph.style.fill = gatedBoxConsts.codeColor;
codeGraph.setVectorFontSize(gatedBoxConsts.codeFontSize); codeGraph.setVectorFontSize(gatedBoxConsts.codeFontSize);
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); codeGraph.anchor.set(0.5);
codeGraph.position.set(20, 0);
this.textGraph.style.fill = gatedBoxConsts.codeColor; this.textGraph.style.fill = gatedBoxConsts.codeColor;
this.textGraph.setVectorFontSize(gatedBoxConsts.codeFontSize); this.textGraph.setVectorFontSize(gatedBoxConsts.codeFontSize);
this.textGraph.anchor.set(0.5); this.textGraph.anchor.set(0.5);

View File

@ -59,76 +59,6 @@ export class rectGraphic extends Container {
this.rectGraphic.clear(); 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 { export class Platform extends JlGraphic {
static Type = 'Platform'; static Type = 'Platform';
rectGraphic: rectGraphic = new rectGraphic(); rectGraphic: rectGraphic = new rectGraphic();

View File

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

View File

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

View File

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

View File

@ -18,6 +18,7 @@ import {
import { SignalCode } from './SignalCode'; import { SignalCode } from './SignalCode';
import { Section, SectionPort, SectionType } from '../section/Section'; import { Section, SectionPort, SectionType } from '../section/Section';
import { Turnout, TurnoutPort } from '../turnout/Turnout'; import { Turnout, TurnoutPort } from '../turnout/Turnout';
import { graphicData } from 'src/protos/stationLayoutGraphics';
export enum Direction { export enum Direction {
LEFT = 0, LEFT = 0,
@ -46,6 +47,8 @@ export interface ISignalData extends GraphicData {
set refDev(v: IRelatedRefData); set refDev(v: IRelatedRefData);
get centralizedStations(): string[]; get centralizedStations(): string[];
set centralizedStations(v: string[]); set centralizedStations(v: string[]);
get mt(): graphicData.Signal.Model;
set mt(v: graphicData.Signal.Model);
clone(): ISignalData; clone(): ISignalData;
copyFrom(data: ISignalData): void; copyFrom(data: ISignalData): void;
eq(other: ISignalData): boolean; 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.text = this.datas.code;
codeGraph.style.fill = spksSwitchConsts.codeColor; codeGraph.style.fill = spksSwitchConsts.codeColor;
codeGraph.setVectorFontSize(spksSwitchConsts.codeFontSize); codeGraph.setVectorFontSize(spksSwitchConsts.codeFontSize);
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); codeGraph.anchor.set(0.5);
codeGraph.position.set(20, 0);
this.textGraph.style.fill = spksSwitchConsts.codeColor; this.textGraph.style.fill = spksSwitchConsts.codeColor;
this.textGraph.setVectorFontSize(spksSwitchConsts.codeFontSize); this.textGraph.setVectorFontSize(spksSwitchConsts.codeFontSize);
this.textGraph.anchor.set(0.5); this.textGraph.anchor.set(0.5);

View File

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

View File

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

View File

@ -37,11 +37,18 @@
<q-page-container> <q-page-container>
<div id="line-app-container" class="overflow-hidden"></div> <div id="line-app-container" class="overflow-hidden"></div>
</q-page-container> </q-page-container>
<q-dialog v-model="pslDialog" @before-hide="pslHide"> <draggable-dialog
<q-page-container> v-model="pslStore.isPslDialogOpen"
<div id="psl-app-container" class="overflow-hidden"></div> :width="pslCanvasWidth"
</q-page-container> :height="pslCanvasHeight"
</q-dialog> @hide="pslHide"
>
<div
id="psl-app-container"
class="overflow-hidden"
style="width: 500px; height: 600px"
></div>
</draggable-dialog>
<DraggableDialog <DraggableDialog
:title="`${ibpStore.stationCode}IBP`" :title="`${ibpStore.stationCode}IBP`"
v-model="ibpStore.isIbpDialogOpen" v-model="ibpStore.isIbpDialogOpen"
@ -84,8 +91,6 @@ import { ISceneName, getSceneName } from 'src/drawApp/lineApp';
import { useTestManageStore } from 'src/stores/testManage-store'; import { useTestManageStore } from 'src/stores/testManage-store';
import { CategoryType } from 'src/components/CategoryType'; import { CategoryType } from 'src/components/CategoryType';
import TrainInfoEcharts from 'src/components/line-app/infos/TrainInfoEcharts.vue'; 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'; import { useIbpStore } from 'src/stores/ibp-store';
const $q = useQuasar(); const $q = useQuasar();
@ -96,8 +101,8 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
const lineStore = useLineStore(); const lineStore = useLineStore();
const ibpStore = useIbpStore(); const ibpStore = useIbpStore();
const pslStore = usePslStore();
const testManageStore = useTestManageStore(); const testManageStore = useTestManageStore();
const pslDialog = ref(false);
const simulationId = (route.query.simulationId as string) || ''; const simulationId = (route.query.simulationId as string) || '';
const projectId = (route.query.projectId as string) || ''; const projectId = (route.query.projectId as string) || '';
const defaultMapId = (route.query.defaultMapId as string) || ''; const defaultMapId = (route.query.defaultMapId as string) || '';
@ -170,6 +175,11 @@ onMounted(async () => {
} }
lineStore.addAllScene(projectInfo.mapInfoLinks || []); lineStore.addAllScene(projectInfo.mapInfoLinks || []);
} }
lineStore.setSceneName(sceneName);
scene = lineApp.getScene(sceneName);
scene.bindDom(dom);
scene.reload();
onResize();
} catch (e) { } catch (e) {
const error = e as ApiError; const error = e as ApiError;
$q.notify({ $q.notify({
@ -177,19 +187,11 @@ onMounted(async () => {
message: error.title, message: error.title,
}); });
} }
lineStore.setSceneName(sceneName);
scene = lineApp.getScene(sceneName);
scene.bindDom(dom);
scene.reload();
onResize();
} else { } else {
lineStore.setMapId(null); lineStore.setMapId(null);
lineStore.setSimulationId(null); lineStore.setSimulationId(null);
} }
drawerRight.value = false; drawerRight.value = false;
// setTimeout(() => {
// pslShow();
// }, 5000);
}); });
onUnmounted(() => { onUnmounted(() => {
if (dialogInstance.value && lineStore.showLayerDialog) { if (dialogInstance.value && lineStore.showLayerDialog) {
@ -216,16 +218,34 @@ watch(
} }
); );
const pslCanvasWidth = ref(500);
const pslCanvasHeight = ref(600);
watch( watch(
() => lineStore.gatedBoxCount, () => pslStore.isPslDialogOpen,
() => { (val: boolean) => {
if (lineStore.selectedGraphics) { if (val === true) {
const gatedBox = lineStore.selectedGraphics[0] as GatedBox; nextTick(async () => {
pslShow(gatedBox); 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(); const dialogInstance = ref();
watch( 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() { function ibpHide() {
ibpStore.destory(); ibpStore.destory();
} }

View File

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

View File

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

View File

@ -1,102 +1,32 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { import { initPslScene } from 'src/drawApp/pslScene';
IJlCanvas, import { getLineApp } from 'src/drawApp/lineApp';
JlGraphic, import { GraphicApp } from 'src/jl-graphic/app/JlGraphicApp';
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';
export const usePslStore = defineStore('psl', { export const usePslStore = defineStore('psl', {
state: () => ({ state: () => ({
selectedGraphics: null as JlGraphic[] | null, pslMapCode: '',
lineId: null as number | null, gatedBoxId: '',
lineName: null as string | null, isPslDialogOpen: false,
simulationId: null as string | null,
socketStates: null as GraphicState[] | null,
stateProCount: 0,
showLayer: [] as string[], // 显示的图层(草稿和发布图公用)
showLayerDialog: false, // 显示图层控制弹窗(草稿和发布图公用)
mapId: null as number | null,
sceneName: '', // 场景名称
}), }),
getters: {
selectedGraphicType: (state) => {
if (state.selectedGraphics) {
if (state.selectedGraphics.length === 1) {
return state.selectedGraphics[0].type;
}
}
},
},
actions: { actions: {
getLineApp(): IGraphicApp { getPslScene() {
const app = getLineApp(); const lineApp = getLineApp() as GraphicApp;
if (app == null) { if (!lineApp) return;
throw new Error('未初始化app'); if (lineApp.scenes.get('psl')) {
return lineApp.getScene('psl');
} }
return app; return initPslScene(lineApp, 'psl');
}, },
getJlCanvas(): IJlCanvas { setPslParam(gatedBoxId: string, pslMapCode: string) {
return this.getLineApp().canvas; this.gatedBoxId = gatedBoxId;
this.pslMapCode = pslMapCode;
this.isPslDialogOpen = true;
}, },
initLineApp() { clearPslParam() {
const app = initLineApp(); this.gatedBoxId = '';
app.on('graphicselected', () => { this.pslMapCode = '';
this.selectedGraphics = markRaw( this.isPslDialogOpen = false;
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;
}, },
}, },
}); });