Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client

This commit is contained in:
Yuan 2023-06-29 17:33:54 +08:00
commit 81dd9ed450
25 changed files with 827 additions and 45 deletions

View File

@ -74,3 +74,16 @@ export async function getPublishLineNet(): Promise<Item> {
const response = await api.get(`${PublishUriBase}/publish/lineNetwork/info`);
return response.data;
}
/**
*
* @param id 线ID
* @param type 线
*/
export async function getPublishMapInfoByLineId(
lineId: number,
type: string
): Promise<Item> {
const response = await api.get(`${PublishUriBase}/${type}/${lineId}`);
return response.data;
}

View File

@ -81,6 +81,9 @@
<axle-counting-property
v-else-if="drawStore.selectedGraphicType === AxleCounting.Type"
></axle-counting-property>
<separator-property
v-else-if="drawStore.selectedGraphicType === Separator.Type"
></separator-property>
</q-card-section>
</template>
</q-card>
@ -108,12 +111,13 @@ import TurnoutProperty from './properties/TurnoutProperty.vue';
import SectionProperty from './properties/SectionProperty.vue';
import RunLineProperty from './properties/RunLineProperty.vue';
import PathLineProperty from './properties/PathLineProperty.vue';
import SeparatorProperty from './properties/SeparatorProperty.vue';
import { Link } from 'src/graphics/link/Link';
import { Rect } from 'src/graphics/rect/Rect';
import { Platform } from 'src/graphics/platform/Platform';
import { Station } from 'src/graphics/station/Station';
import { StationLine } from 'src/graphics/stationLine/StationLine';
import { Train } from 'src/graphics/train/Train';
// import { Train } from 'src/graphics/train/Train';
import { useDrawStore } from 'src/stores/draw-store';
import { IscsFan } from 'src/graphics/iscs-fan/IscsFan';
import { Signal } from 'src/graphics/signal/Signal';
@ -123,6 +127,7 @@ import { Section } from 'src/graphics/section/Section';
import { TrainWindow } from 'src/graphics/trainWindow/TrainWindow';
import { PathLine } from 'src/graphics/pathLine/PathLine';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { Separator } from 'src/graphics/separator/Separator';
const drawStore = useDrawStore();
</script>

View File

@ -16,14 +16,23 @@
lazy-rules
autogrow
/>
<q-select
outlined
style="margin-top: 10px"
v-model="kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
label="公里标"
type="textarea"
style="margin-top: 10px"
v-model.number="kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
v-model="axleCountingModel.kilometerCode"
lazy-rules
autogrow
label="公里标(mm):"
/>
<q-list bordered separator class="rounded-borders">
<q-item>
@ -72,6 +81,13 @@ import { computed, onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const axleCountingModel = reactive(new AxleCountingData());
const kilometerSystem = reactive({ coordinateSystem: '', kilometer: 0 });
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
{ label: '停车场', value: 'PARKING_LOT' },
{ label: '正线', value: 'MAIN_LINE' },
];
drawStore.$subscribe;
watch(
@ -79,6 +95,11 @@ watch(
(val) => {
if (val && val.type == AxleCounting.Type) {
axleCountingModel.copyFrom(val.saveData() as AxleCountingData);
if (axleCountingModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
axleCountingModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = axleCountingModel.kilometerSystem.kilometer;
}
}
}
);
@ -87,11 +108,20 @@ onMounted(() => {
const axleCounting = drawStore.selectedGraphic as AxleCounting;
if (axleCounting) {
axleCountingModel.copyFrom(axleCounting.saveData());
if (axleCountingModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
axleCountingModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = axleCountingModel.kilometerSystem.kilometer;
}
}
});
function onUpdate() {
const axleCounting = drawStore.selectedGraphic as AxleCounting;
axleCountingModel.kilometerSystem = {
coordinateSystem: kilometerSystem.coordinateSystem,
kilometer: kilometerSystem.kilometer,
};
if (axleCounting) {
drawStore
.getDrawApp()

View File

@ -0,0 +1,63 @@
<template>
<q-form>
<q-input outlined readonly v-model="separatorModel.id" label="id" hint="" />
<q-select
v-if="showType"
outlined
style="margin-top: 10px"
v-model="separatorModel.separatorType"
:options="typeOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="分隔符方向"
></q-select>
</q-form>
</template>
<script setup lang="ts">
import { SeparatorData } from 'src/drawApp/graphics/SeparatorInteraction';
import { Separator } from 'src/graphics/separator/Separator';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const separatorModel = reactive(new SeparatorData());
const typeOptions = [
{ label: '左方向', value: 'endA' },
{ label: '右方向', value: 'endB' },
];
const showType = computed(() => {
const find = typeOptions.find((item) => {
return item.value == separatorModel.separatorType;
});
return !!find;
});
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Separator.Type) {
separatorModel.copyFrom(val.saveData() as SeparatorData);
}
}
);
onMounted(() => {
const Separator = drawStore.selectedGraphic as Separator;
if (Separator) {
separatorModel.copyFrom(Separator.saveData());
}
});
function onUpdate() {
const Separator = drawStore.selectedGraphic as Separator;
if (Separator) {
drawStore.getDrawApp().updateGraphicAndRecord(Separator, separatorModel);
}
}
</script>

View File

@ -10,14 +10,23 @@
lazy-rules
autogrow
/>
<q-select
outlined
style="margin-top: 10px"
v-model="kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
label="公里标"
type="textarea"
style="margin-top: 10px"
v-model.number="kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
v-model="stationModel.kilometerCode"
lazy-rules
autogrow
label="公里标(mm):"
/>
<q-select
outlined
@ -55,6 +64,13 @@ enum showSelectData {
true = '是',
false = '否',
}
const kilometerSystem = reactive({ coordinateSystem: '', kilometer: 0 });
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
{ label: '停车场', value: 'PARKING_LOT' },
{ label: '正线', value: 'MAIN_LINE' },
];
drawStore.$subscribe;
watch(
@ -68,6 +84,11 @@ watch(
concentrationStations.value = (showSelectData as never)[
stationModel.concentrationStations + ''
];
if (stationModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
stationModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = stationModel.kilometerSystem.kilometer;
}
}
}
);
@ -80,6 +101,11 @@ onMounted(() => {
concentrationStations.value = (showSelectData as never)[
stationModel.concentrationStations + ''
];
if (stationModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
stationModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = stationModel.kilometerSystem.kilometer;
}
}
});
@ -88,6 +114,10 @@ function onUpdate() {
stationModel.concentrationStations = JSON.parse(
(showSelect as never)[concentrationStations.value]
);
stationModel.kilometerSystem = {
coordinateSystem: kilometerSystem.coordinateSystem,
kilometer: kilometerSystem.kilometer,
};
const station = drawStore.selectedGraphic as Station;
if (station) {
drawStore.getDrawApp().updateGraphicAndRecord(station, stationModel);

View File

@ -5,6 +5,7 @@ import {
} from 'src/graphics/axleCounting/AxleCounting';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { KilometerSystem } from 'src/graphics/signal/Signal';
export class AxleCountingData
extends GraphicDataBase
@ -31,17 +32,17 @@ export class AxleCountingData
set code(v: string) {
this.data.code = v;
}
get kilometerCode(): string {
return this.data.kilometerCode;
get kilometerSystem(): KilometerSystem {
return this.data.kilometerSystem;
}
set kilometerCode(v: string) {
this.data.kilometerCode = v;
set kilometerSystem(v: KilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem(v);
}
get axleCountingRef(): graphicData.RelatedRef[] {
return this.data.axleCountingRef;
}
set axleCountingRef(points: graphicData.RelatedRef[]) {
this.data.axleCountingRef=points
this.data.axleCountingRef = points;
}
clone(): AxleCountingData {
return new AxleCountingData(this.data.cloneMessage());

View File

@ -21,6 +21,7 @@ import {
PolylineEditPlugin,
removeLineWayPoint,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
import { RunLineGraphicHitArea } from 'src/graphics/runLine/RunLineDrawAssistant';
export class RunLineData extends GraphicDataBase implements IRunLineData {
constructor(data?: graphicData.RunLine) {
@ -184,3 +185,30 @@ export class DrawRunLinePlugin extends GraphicInteractionPlugin<RunLine> {
RunLineEditMenu.open(e.global);
}
}
export class RunLineOperateInteraction extends GraphicInteractionPlugin<RunLine> {
static Name = 'runLine_operate_menu';
constructor(app: GraphicApp) {
super(RunLineOperateInteraction.Name, app);
app.registerMenu(EpEditMenu);
}
static init(app: GraphicApp) {
return new RunLineOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): RunLine[] | undefined {
return grahpics
.filter((g) => g.type === RunLine.Type)
.map((g) => g as RunLine);
}
bind(g: RunLine): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.lineBody.hitArea = new RunLineGraphicHitArea(g);
g.selectable = true;
}
unbind(g: RunLine): void {
g.selectable = false;
g.eventMode = 'none';
}
}

View File

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

View File

@ -15,6 +15,7 @@ import {
JlGraphic,
} from 'src/jl-graphic';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { KilometerSystem } from 'src/graphics/signal/Signal';
export class StationData extends GraphicDataBase implements IStationData {
constructor(data?: graphicData.Station) {
@ -38,11 +39,11 @@ export class StationData extends GraphicDataBase implements IStationData {
set code(v: string) {
this.data.code = v;
}
get kilometerCode(): string {
return this.data.kilometerCode;
get kilometerSystem(): KilometerSystem {
return this.data.kilometerSystem;
}
set kilometerCode(v: string) {
this.data.kilometerCode = v;
set kilometerSystem(v: KilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem(v);
}
get hasControl(): boolean {
return this.data.hasControl;
@ -164,12 +165,10 @@ export class StationOperateInteraction extends GraphicInteractionPlugin<Station>
powerUnlockConfig.handler = () => {
station.states.ipRtuStusInLocalCtrl = true;
station.doRepaint();
console.log(2222);
};
chainConfig.handler = () => {
station.states.ipRtuStusDown = true;
station.doRepaint();
console.log(2222);
};
removeChainConfig.handler = () => {
console.log(2222);

View File

@ -4,6 +4,14 @@ import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_status';
import { train } from 'src/protos/train';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import {
GraphicApp,
GraphicInteractionPlugin,
JlGraphic,
} from 'src/jl-graphic';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
export class TrainData extends GraphicDataBase implements ITrainData {
constructor(data?: graphicData.Train) {
@ -202,3 +210,87 @@ class StateTrain extends train.TrainInfo {
}
}
}
const negativeDirectionConfig: MenuItemOptions = {
name: '反方向运行',
};
const HoldTrainConfig: MenuItemOptions = {
name: '扣车',
};
const openDoorConfig: MenuItemOptions = {
name: '开门',
};
const editGroupConfig: MenuItemOptions = {
name: '修改车组号',
};
const TrainOperateMenu: ContextMenu = ContextMenu.init({
name: '列车操作菜单',
groups: [
{
items: [
negativeDirectionConfig,
HoldTrainConfig,
openDoorConfig,
editGroupConfig,
],
},
],
});
export class TrainOperateInteraction extends GraphicInteractionPlugin<Train> {
static Name = 'train_operate_menu';
constructor(app: GraphicApp) {
super(TrainOperateInteraction.Name, app);
app.registerMenu(TrainOperateMenu);
}
static init(app: GraphicApp) {
return new TrainOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): Train[] | undefined {
return grahpics.filter((g) => g.type === Train.Type).map((g) => g as Train);
}
bind(g: Train): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.selectable = true;
g.on('_rightclick', this.onContextMenu, this);
}
unbind(g: Train): void {
g.selectable = false;
g.eventMode = 'none';
g.off('_rightclick', this.onContextMenu, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const train = target.getGraphic() as Train;
this.app.updateSelected(train);
negativeDirectionConfig.handler = () => {
const mode = train.states.mode;
if (!train.states.mode.ipModeTrainDirUp) {
mode.ipModeTrainDirUp = true;
mode.ipModeTrainDirDown = false;
} else if (!train.states.mode.ipModeTrainDirDown) {
mode.ipModeTrainDirUp = false;
mode.ipModeTrainDirDown = true;
}
train.chagneDirection();
};
HoldTrainConfig.handler = () => {
train.states.mode.ipModeTrainHolded =
!train.states.mode.ipModeTrainHolded;
train.chagneState();
};
openDoorConfig.handler = () => {
train.states.mode.ipModeTrainDoorOpen =
!train.states.mode.ipModeTrainDoorOpen;
train.chagneState();
};
editGroupConfig.handler = () => {
train.states.trainId = '022';
train.doRepaint();
};
TrainOperateMenu.open(e.global);
}
}

View File

@ -79,6 +79,9 @@ import { PathLine, PathLineTemplate } from 'src/graphics/pathLine/PathLine';
import { PathLineDraw } from 'src/graphics/pathLine/PathLineDrawAssistant';
import { PathLineData } from './graphics/PathLineInteraction';
import { toStorageTransform } from './graphics/GraphicDataBase';
import { SeparatorDraw } from 'src/graphics/separator/SeparatorDrawAssistant';
import { Separator, SeparatorTemplate } from 'src/graphics/separator/Separator';
import { SeparatorData } from './graphics/SeparatorInteraction';
// export function fromStoragePoint(p: graphicData.Point): Point {
// return new Point(p.x, p.y);
@ -165,6 +168,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
| TrainDraw
| OneClickGenerateDraw
| AxleCountingDraw
| SeparatorDraw
)[] = [];
if (draftType === 'Line') {
drawAssistants = [
@ -189,6 +193,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
app,
new AxleCountingTemplate(new AxleCountingData())
),
new SeparatorDraw(app, new SeparatorTemplate(new SeparatorData())),
];
DrawSignalInteraction.init(app);
} else {
@ -305,6 +310,9 @@ export function saveDrawDatas(app: JlDrawApp) {
} else if (AxleCounting.Type === g.type) {
const axleCountingData = (g as AxleCounting).saveData();
storage.axleCountings.push((axleCountingData as AxleCountingData).data);
} else if (Separator.Type === g.type) {
const separatorData = (g as Separator).saveData();
storage.separators.push((separatorData as SeparatorData).data);
}
});
const base64 = fromUint8Array(storage.serialize());
@ -375,6 +383,9 @@ export async function loadDrawDatas(app: GraphicApp) {
storage.axleCountings.forEach((axleCounting) => {
datas.push(new AxleCountingData(axleCounting));
});
storage.separators.forEach((separator) => {
datas.push(new SeparatorData(separator));
});
app.loadGraphic(datas);
} else {
app.loadGraphic([]);

View File

@ -19,7 +19,7 @@ import { TurnoutData } from './graphics/TurnoutInteraction';
import { TurnoutTemplate } from 'src/graphics/turnout/Turnout';
import { SectionData } from './graphics/SectionInteraction';
import { SectionTemplate } from 'src/graphics/section/Section';
import { getPublishMapInfoById } from 'src/api/PublishApi';
import { getPublishMapInfoByLineId } from 'src/api/PublishApi';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useLineStore } from 'src/stores/line-store';
import { toUint8Array } from 'js-base64';
@ -65,11 +65,14 @@ export function initLineApp(dom: HTMLElement): GraphicApp {
export async function loadLineDatas(app: GraphicApp) {
const lineStore = useLineStore();
const id = lineStore.lineId;
if (!id) {
const lineId = lineStore.lineId;
if (!lineId) {
return;
}
const { proto: base64, name: lineName } = await getPublishMapInfoById(id);
const { proto: base64, name: lineName } = await getPublishMapInfoByLineId(
lineId,
'line'
);
lineStore.setLineName(lineName);
if (base64) {
const storage = graphicData.RtssGraphicStorage.deserialize(

View File

@ -2,11 +2,17 @@ import { GraphicApp, GraphicData } from 'src/jl-graphic';
import { getPublishLineNet } from 'src/api/PublishApi';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { RunLineTemplate } from 'src/graphics/runLine/RunLine';
import { RunLineData } from './graphics/RunLineInteraction';
import { RunLine, RunLineTemplate } from 'src/graphics/runLine/RunLine';
import {
RunLineData,
RunLineOperateInteraction,
} from './graphics/RunLineInteraction';
import { PathLineTemplate, PathLine } from 'src/graphics/pathLine/PathLine';
import { PathLineData } from './graphics/PathLineInteraction';
import { StationLineTemplate } from 'src/graphics/stationLine/StationLine';
import {
StationLineTemplate,
StationLine,
} from 'src/graphics/stationLine/StationLine';
import { StationLineData } from './graphics/StationLineInteraction';
import { ItrainLineTemplate } from 'src/graphics/trainLine/TrainLine';
import { TrainLineData } from './graphics/TrainLineInteraction';
@ -45,7 +51,11 @@ export function initLineNetApp(dom: HTMLElement): GraphicApp {
viewportDrag: true,
wheelZoom: true,
},
interactiveTypeOptions: {
interactiveGraphicTypeIncludes: [RunLine.Type, StationLine.Type],
},
});
RunLineOperateInteraction.init(lineNetApp);
return lineNetApp;
}

View File

@ -7,12 +7,13 @@ import {
VectorText,
} from 'src/jl-graphic';
import { IRelatedRefData, protoPort2Data } from '../CommonGraphics';
import { KilometerSystem } from '../signal/Signal';
export interface IAxleCountingData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get kilometerCode(): string; // 公里标
set kilometerCode(v: string);
get kilometerSystem(): KilometerSystem;
set kilometerSystem(v: KilometerSystem);
get axleCountingRef(): IRelatedRefData[]; //关联的设备
set axleCountingRef(ref: IRelatedRefData[]);
clone(): IAxleCountingData;

View File

@ -109,7 +109,7 @@ export class AxleCountingDraw extends GraphicDrawAssistant<
}
axleCounting.id = GraphicIdGenerator.next();
axleCounting.datas.axleCountingRef = [refData2, refData1];
axleCounting.code = `${graphic.code}-${port}+${refGraphic.code}-${refPort}`;
axleCounting.datas.code = `${graphic.datas.code}-${port}+${refGraphic.datas.code}-${refPort}`;
this.storeGraphic(axleCounting);
axleCounting.loadRelations();
}
@ -136,7 +136,7 @@ export class AxleCountingDraw extends GraphicDrawAssistant<
}
axleCounting.id = GraphicIdGenerator.next();
axleCounting.datas.axleCountingRef = [refData];
axleCounting.code = `${graphic.code}-${port}`;
axleCounting.datas.code = `${graphic.datas.code}-${port}`;
this.storeGraphic(axleCounting);
axleCounting.loadRelations();
}

View File

@ -0,0 +1,90 @@
import { Color, Graphics } from 'pixi.js';
import { GraphicData, JlGraphic, JlGraphicTemplate } from 'src/jl-graphic';
export interface ISeparatorData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get separatorType(): string; // 类型
set separatorType(v: string);
clone(): ISeparatorData;
copyFrom(data: ISeparatorData): void;
eq(other: ISeparatorData): boolean;
}
export enum separatorTypeEnum {
turnout = 'turnout', // 道岔分隔符
endA = 'endA', // A端尽头分隔符
endB = 'endB', // B端尽头分隔符
section = 'section', // 区段分隔符
}
export const SeparatorConsts = {
height: 15,
lineWidth: 2,
lineColor: '0x617799',
circleColor: '0xEF0200',
radius: 5,
};
export class Separator extends JlGraphic {
static Type = 'Separator';
rectGraphic: Graphics = new Graphics();
circleGraphic: Graphics = new Graphics();
constructor() {
super(Separator.Type);
this.addChild(this.rectGraphic);
this.addChild(this.circleGraphic);
}
get datas(): ISeparatorData {
return this.getDatas<ISeparatorData>();
}
doRepaint(): void {
const rectGraphic = this.rectGraphic;
rectGraphic.clear();
if (!this.datas.separatorType) {
this.datas.separatorType = separatorTypeEnum.endA;
}
const typeArr = ['section', 'turnout'];
if (typeArr.includes(this.datas.separatorType)) {
rectGraphic.lineStyle(
SeparatorConsts.lineWidth,
new Color(SeparatorConsts.lineColor)
);
rectGraphic.moveTo(0, -SeparatorConsts.height / 2);
rectGraphic.lineTo(0, SeparatorConsts.height / 2);
if (this.datas.separatorType == 'turnout') {
this.circleGraphic.lineStyle(1, SeparatorConsts.circleColor);
this.circleGraphic.drawCircle(0, 0, SeparatorConsts.radius);
}
}
const endTypeArr = ['endA', 'endB'];
if (endTypeArr.includes(this.datas.separatorType)) {
let d = SeparatorConsts.radius;
if (this.datas.separatorType == 'endB') {
d = -d;
}
rectGraphic.lineStyle(
SeparatorConsts.lineWidth,
new Color(SeparatorConsts.lineColor)
);
rectGraphic.moveTo(0, 0);
rectGraphic.lineTo(-d, 0);
rectGraphic.lineTo(-d, -d);
rectGraphic.lineTo(-d * 3, -d);
rectGraphic.moveTo(-d, 0);
rectGraphic.lineTo(-d, d);
rectGraphic.lineTo(-d * 3, d);
}
}
}
export class SeparatorTemplate extends JlGraphicTemplate<Separator> {
constructor(dataTemplate: ISeparatorData) {
super(Separator.Type, {
dataTemplate,
});
}
new(): Separator {
return new Separator();
}
}

View File

@ -0,0 +1,239 @@
import { FederatedPointerEvent, IHitArea, Point } from 'pixi.js';
import {
GraphicDrawAssistant,
GraphicIdGenerator,
GraphicInteractionPlugin,
GraphicRelationParam,
JlDrawApp,
JlGraphic,
linePoint,
} from 'src/jl-graphic';
import { Section } from '../section/Section';
import {
ISeparatorData,
Separator,
SeparatorConsts,
SeparatorTemplate,
separatorTypeEnum,
} from './Separator';
import { SeparatorData } from 'src/drawApp/graphics/SeparatorInteraction';
import { Turnout } from '../turnout/Turnout';
export class SeparatorDraw extends GraphicDrawAssistant<
SeparatorTemplate,
ISeparatorData
> {
SeparatorGraph: Separator;
constructor(app: JlDrawApp, template: SeparatorTemplate) {
super(app, template, 'sym_o_square', '不展示');
this.SeparatorGraph = this.graphicTemplate.new();
this.container.addChild(this.SeparatorGraph);
SeparatorInteraction.init(app);
}
bind(): void {
super.bind();
this.SeparatorGraph.loadData(this.graphicTemplate.datas);
this.SeparatorGraph.doRepaint();
}
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: ISeparatorData): boolean {
data.transform = this.container.saveTransform();
return true;
}
oneGenerates() {
const SeparatorAll = this.app.queryStore.queryByType<Separator>(
Separator.Type
);
this.app.deleteGraphics(...SeparatorAll);
const rMap = new Map();
const sections = this.app.queryStore.queryByType<Section>(Section.Type);
const turnouts = this.app.queryStore.queryByType<Turnout>(Turnout.Type);
function setKey(gr: GraphicRelationParam): string {
let key = '';
key = `${gr.g.id}_${gr.param}`;
return key;
}
sections.forEach((section) => {
const allR = section.relationManage.getRelationsOfGraphic(section);
const port: string[] = [];
allR.forEach((relation, index) => {
const r = relation.getRelationParam(section);
port.push(r.param);
const other = relation.getOtherRelationParam(section);
if (!rMap.has(setKey(r))) {
rMap.set(setKey(r), { ...r });
}
if (!rMap.has(setKey(other))) {
rMap.set(setKey(other), { ...other, repetition: true });
}
if (index == allR.length - 1) {
if (!port.includes('A')) {
rMap.set(`${section.id}_A`, {
g: section,
param: 'A',
separatorType: separatorTypeEnum.endA,
});
}
if (!port.includes('B')) {
rMap.set(`${section.id}_B`, {
g: section,
param: 'B',
separatorType: separatorTypeEnum.endB,
});
}
}
});
});
turnouts.forEach((turnout) => {
const allR = turnout.relationManage.getRelationsOfGraphic(turnout);
const port: string[] = [];
allR.forEach((relation, index) => {
const r = relation.getRelationParam(turnout);
port.push(r.param);
const other = relation.getOtherRelationParam(turnout);
if (!rMap.has(setKey(r))) {
let t = separatorTypeEnum.section;
if (r.param == 'C' && other.param == 'C') {
t = separatorTypeEnum.turnout;
}
rMap.set(setKey(r), {
...r,
separatorType: t,
});
}
if (!rMap.has(setKey(other))) {
let t = separatorTypeEnum.section;
if (r.param == 'C' && other.param == 'C') {
t = separatorTypeEnum.turnout;
}
rMap.set(setKey(other), {
...other,
separatorType: t,
repetition: true,
});
}
if (index == allR.length - 1) {
if (!port.includes('A')) {
rMap.set(`${turnout.id}_A`, {
g: turnout,
param: 'A',
separatorType: separatorTypeEnum.endB,
});
}
if (!port.includes('B')) {
rMap.set(`${turnout.id}_B`, {
g: turnout,
param: 'B',
separatorType: separatorTypeEnum.endA,
});
}
}
});
});
rMap.forEach((item) => {
if (!item.repetition) {
const sType = item.separatorType || separatorTypeEnum.section;
const separator = new Separator();
const data = new SeparatorData();
data.separatorType = sType;
separator.loadData(data);
let p;
if (item.g.type == Section.Type) {
p = item.g.getStartPoint();
if (item.param == 'B') {
p = item.g.getEndPoint();
}
} else if (item.g.type == Turnout.Type) {
const ps = item.g.getPortPoints();
let l = 2;
if (item.param == 'A') {
l = 0;
} else if (item.param == 'B') {
l = 1;
}
p = ps[l][0];
}
const tps = item.g.localToCanvasPoint(p);
separator.position.set(tps.x, tps.y);
separator.id = GraphicIdGenerator.next();
this.storeGraphic(separator);
}
});
}
}
//碰撞检测
export class SeparatorGraphicHitArea implements IHitArea {
separator: Separator;
constructor(separator: Separator) {
this.separator = separator;
}
contains(x: number, y: number): boolean {
let contains = false;
const p = new Point(x, y);
const typeArr = ['section', 'turnout'];
const endTypeArr = ['endA', 'endB'];
let d = SeparatorConsts.radius;
if (typeArr.includes(this.separator.datas.separatorType)) {
const tolerance = SeparatorConsts.lineWidth;
const p1 = new Point(0, -SeparatorConsts.height / 2);
const p2 = new Point(0, SeparatorConsts.height / 2);
contains = contains || linePoint(p1, p2, p, tolerance);
return contains;
} else if (endTypeArr.includes(this.separator.datas.separatorType)) {
if (this.separator.datas.separatorType == 'endB') {
d = -d;
}
const tolerance = SeparatorConsts.lineWidth;
const p1 = new Point(0, 0);
const p2 = new Point(-d, 0);
const p3 = new Point(-d, -d);
const p4 = new Point(-d * 3, -d);
const p5 = new Point(-d, d);
const p6 = new Point(-d * 3, d);
contains = contains || linePoint(p1, p2, p, tolerance);
contains = contains || linePoint(p2, p3, p, tolerance);
contains = contains || linePoint(p3, p4, p, tolerance);
contains = contains || linePoint(p2, p5, p, tolerance);
contains = contains || linePoint(p5, p6, p, tolerance);
}
return contains;
}
}
export class SeparatorInteraction extends GraphicInteractionPlugin<Separator> {
static Name = 'Separator_transform';
constructor(app: JlDrawApp) {
super(SeparatorInteraction.Name, app);
}
static init(app: JlDrawApp) {
return new SeparatorInteraction(app);
}
filter(...grahpics: JlGraphic[]): Separator[] | undefined {
return grahpics
.filter((g) => g.type === Separator.Type)
.map((g) => g as Separator);
}
bind(g: Separator): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
g.rectGraphic.hitArea = new SeparatorGraphicHitArea(g);
}
unbind(g: Separator): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
}
}

View File

@ -6,12 +6,13 @@ import {
JlGraphicTemplate,
VectorText,
} from 'src/jl-graphic';
import { KilometerSystem } from '../signal/Signal';
export interface IStationData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get kilometerCode(): string; // 公里标
set kilometerCode(v: string);
get kilometerSystem(): KilometerSystem;
set kilometerSystem(v: KilometerSystem);
get hasControl(): boolean; /// 是否有控制
set hasControl(v: boolean);
get concentrationStations(): boolean; ////是否集中站
@ -174,16 +175,18 @@ export class Station extends JlGraphic {
codeGraph.style.fill = stationConsts.codeColor;
codeGraph.setVectorFontSize(stationConsts.codeFontSize);
codeGraph.anchor.set(0.5);
const kilometerCode = this.datas?.kilometerCode || 12345.67;
if (Math.floor(Number(kilometerCode)).toString().length > 3) {
const kiloBit = Math.floor(Number(kilometerCode) / 1000).toString();
const kilometerCode = this.datas.kilometerSystem?.kilometer || 12345678;
if (Math.floor(kilometerCode * 1000).toString().length > 3) {
const kiloBit = Math.floor(Number(kilometerCode) / 1000000).toString();
kilometerGraph.text =
'K' +
kiloBit +
'+' +
kilometerCode.toString().substring(kiloBit.length);
(
Number(kilometerCode.toString().substring(kiloBit.length)) / 1000
).toFixed(3);
} else {
kilometerGraph.text = kilometerCode;
kilometerGraph.text = (kilometerCode * 1000).toFixed(3);
}
kilometerGraph.style.fill = stationConsts.kilometerCodeColor;
kilometerGraph.setVectorFontSize(stationConsts.kilometerCodeFontSize);

View File

@ -178,6 +178,8 @@ import { errorNotify, successNotify } from 'src/utils/CommonNotify';
import { saveAsDraft } from 'src/api/DraftApi';
import { ApiError } from 'src/boot/axios';
import { OneClickGenerate } from 'src/graphics/trainWindow/oneClickDrawAssistant';
import { Separator } from 'src/graphics/separator/Separator';
import { SeparatorDraw } from 'src/graphics/separator/SeparatorDrawAssistant';
const route = useRoute();
const router = useRouter();
@ -303,6 +305,10 @@ function buildRelations() {
}
function oneClickGeneration() {
const separatorDraw = drawStore
.getDrawApp()
.getDrawAssistant(Separator.Type) as SeparatorDraw;
separatorDraw.oneGenerates();
drawStore.getDrawApp().interactionPlugin(OneClickGenerate.Type).resume();
}

View File

@ -70,14 +70,12 @@ onMounted(() => {
const lineApp = lineStore.initLineApp(dom);
loadLineDatas(lineApp);
} else if (mapType.value === 'LineNetwork') {
lineNetStore.setLineNetId(+route.params.id as number);
const lineApp = lineNetStore.initLineNetApp(dom);
loadLineNetDatas(lineApp);
}
onResize();
} else {
lineStore.setLineId(null);
lineNetStore.setLineNetId(null);
}
});
</script>

View File

@ -0,0 +1,69 @@
<template>
<q-layout view="hHh LpR fFf">
<q-header reveal class="bg-primary text-white">
<q-toolbar>
<q-toolbar-title> {{ mapName }} </q-toolbar-title>
<q-btn color="info" label="返回" @click="backConfirm" />
</q-toolbar>
<q-resize-observer @resize="onHeaderResize" />
</q-header>
<q-page-container>
<div id="line-app-container"></div>
</q-page-container>
</q-layout>
</template>
<script setup lang="ts">
import { onMounted, ref, computed } from 'vue';
import { useLineStore } from 'src/stores/line-store';
import { useLineNetStore } from 'src/stores/line-net-store';
import { useRoute, useRouter } from 'vue-router';
import { loadLineDatas, getLineApp } from 'src/drawApp/lineApp';
const canvasWidth = ref(0);
const canvasHeight = ref(0);
const headerHeight = ref(0);
const route = useRoute();
const router = useRouter();
const lineStore = useLineStore();
const lineNetStore = useLineNetStore();
const mapName = computed(() => lineStore.lineName || lineNetStore.lineNetName);
function onResize() {
const clientWidth = document.body.clientWidth;
const clientHeight = document.body.clientHeight;
canvasWidth.value = clientWidth;
canvasHeight.value = clientHeight - headerHeight.value;
const dom = document.getElementById('line-app-container');
if (dom) {
dom.style.width = canvasWidth.value + 'px';
dom.style.height = canvasHeight.value + 'px';
}
const lineApp = getLineApp();
if (lineApp) {
lineApp.onDomResize(canvasWidth.value, canvasHeight.value);
}
}
function onHeaderResize(size: { height: number; width: number }) {
headerHeight.value = size.height;
onResize();
}
function backConfirm() {
router.replace('/monitor');
}
onMounted(() => {
const dom = document.getElementById('line-app-container');
if (dom) {
lineStore.setLineId(+route.params.lineId as number);
const lineApp = lineStore.initLineApp(dom);
loadLineDatas(lineApp);
onResize();
} else {
lineStore.setLineId(null);
}
});
</script>

View File

@ -9,6 +9,9 @@
import { onMounted, watch } from 'vue';
import { useLineNetStore } from 'src/stores/line-net-store';
import { loadLineNetDatas, getLineNetApp } from 'src/drawApp/lineNetApp';
import { RunLine } from 'src/graphics/runLine/RunLine';
import { getLineList } from 'src/api/LineInfoApi';
import { useRouter } from 'vue-router';
const props = withDefaults(
defineProps<{
@ -17,6 +20,17 @@ const props = withDefaults(
}>(),
{ sizeHeight: 500, sizeWidth: 500 }
);
const router = useRouter();
const lineNetStore = useLineNetStore();
interface LineInfo {
get name(): string;
set name(v: string);
get lineId(): number;
set lineId(v: number);
}
let lineList: LineInfo[] = [];
watch(
() => props.sizeHeight,
@ -30,8 +44,19 @@ watch(
onResize();
}
);
const lineNetStore = useLineNetStore();
watch(
() => lineNetStore.selectedGraphic,
(val) => {
if (val && lineNetStore.selectedGraphicType == RunLine.Type) {
const line = lineList.find(
(line) => line.name === (val as RunLine)?.datas.code
);
if (line) {
router.replace(`/line/monitor/${line.lineId}`);
}
}
}
);
function onResize() {
const dom = document.getElementById('line-app-container');
@ -47,6 +72,16 @@ function onResize() {
onMounted(() => {
const dom = document.getElementById('line-app-container');
lineList = [];
getLineList()
.then((res) => {
res.forEach((item) => {
lineList.push({ lineId: item.lineId, name: item.name });
});
})
.catch((err) => {
console.error('获取线路列表失败:' + err.message);
});
if (dom) {
const lineApp = lineNetStore.initLineNetApp(dom);
loadLineNetDatas(lineApp);

View File

@ -31,7 +31,7 @@
color="primary"
:disable="operateDisabled"
label="预览"
:to="`/linemap/${props.row.id}/${props.row.type}`"
:to="`/linemap/${props.row.lineId}/${props.row.type}`"
/>
<q-btn
color="red"

View File

@ -67,6 +67,11 @@ const routes: RouteRecordRaw[] = [
name: 'linemap',
component: () => import('layouts/LineLayout.vue'),
},
{
path: '/line/monitor/:lineId',
name: 'linemonitor',
component: () => import('pages/LineMonitorPage.vue'),
},
{
path: '/monitor',
name: 'monitor',

View File

@ -19,6 +19,14 @@ export const useLineNetStore = defineStore('lineNet', {
}
}
},
selectedGraphic: (state) => {
if (state.selectedGraphics) {
if (state.selectedGraphics.length === 1) {
return state.selectedGraphics[0];
}
}
return null;
},
},
actions: {
getLineNetApp(): GraphicApp {