diff --git a/src/api/PublishApi.ts b/src/api/PublishApi.ts index 42ce8ef..db1f1c3 100644 --- a/src/api/PublishApi.ts +++ b/src/api/PublishApi.ts @@ -74,3 +74,16 @@ export async function getPublishLineNet(): Promise { 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 { + const response = await api.get(`${PublishUriBase}/${type}/${lineId}`); + return response.data; +} diff --git a/src/drawApp/graphics/RunLineInteraction.ts b/src/drawApp/graphics/RunLineInteraction.ts index 2961acc..71fbb46 100644 --- a/src/drawApp/graphics/RunLineInteraction.ts +++ b/src/drawApp/graphics/RunLineInteraction.ts @@ -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 { RunLineEditMenu.open(e.global); } } + +export class RunLineOperateInteraction extends GraphicInteractionPlugin { + 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'; + } +} diff --git a/src/drawApp/lineApp.ts b/src/drawApp/lineApp.ts index afad7d5..8909938 100644 --- a/src/drawApp/lineApp.ts +++ b/src/drawApp/lineApp.ts @@ -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( diff --git a/src/drawApp/lineNetApp.ts b/src/drawApp/lineNetApp.ts index 9f829bb..47b1cc8 100644 --- a/src/drawApp/lineNetApp.ts +++ b/src/drawApp/lineNetApp.ts @@ -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; } diff --git a/src/graphics/axleCounting/AxleCountingDrawAssistant.ts b/src/graphics/axleCounting/AxleCountingDrawAssistant.ts index 241c463..9071f8e 100644 --- a/src/graphics/axleCounting/AxleCountingDrawAssistant.ts +++ b/src/graphics/axleCounting/AxleCountingDrawAssistant.ts @@ -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(); } diff --git a/src/graphics/turnout/Turnout.ts b/src/graphics/turnout/Turnout.ts index df906e7..3db11c3 100644 --- a/src/graphics/turnout/Turnout.ts +++ b/src/graphics/turnout/Turnout.ts @@ -6,6 +6,7 @@ import { JlGraphic, JlGraphicTemplate, VectorText, + angleOfIncludedAngle, distance2, } from 'src/jl-graphic'; import { Section, SectionPort } from '../section/Section'; @@ -208,9 +209,11 @@ export class Turnout extends JlGraphic { }); /** 道岔和道岔 */ - this.queryStore.queryByType(Turnout.Type).forEach((turnout) => { - if (turnout.id === this.id) return; - this.getPortPoints().forEach((thisPort, i) => { + this.getPortPoints().forEach((thisPort, i) => { + let params: GraphicRelationParam[] = [], + deflection = 180; + this.queryStore.queryByType(Turnout.Type).forEach((turnout) => { + if (turnout.id === this.id) return; turnout.getPortPoints().forEach((otherPort, j) => { if ( distance2( @@ -218,19 +221,34 @@ export class Turnout extends JlGraphic { turnout.localToCanvasPoint(otherPort[otherPort.length - 1]) ) <= epsilon ) { - this.relationManage.addRelation( - new GraphicRelationParam( - this, - [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i] - ), - new GraphicRelationParam( - turnout, - [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][j] - ) + const angle = angleOfIncludedAngle( + this.localToCanvasPoint(thisPort[thisPort.length - 1]) /* 交点 */, + thisPort[thisPort.length - 2] + ? this.localToCanvasPoint(thisPort[thisPort.length - 2]) + : this.position, + otherPort[otherPort.length - 2] + ? turnout.localToCanvasPoint(otherPort[otherPort.length - 2]) + : turnout.position ); + if (180 - Math.abs(angle) <= deflection) { + deflection = 180 - Math.abs(angle); + params = [ + new GraphicRelationParam( + this, + [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i] + ), + new GraphicRelationParam( + turnout, + [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][j] + ), + ]; + } } }); }); + if (params.length === 2) { + this.relationManage.addRelation(params[0], params[1]); + } }); } diff --git a/src/layouts/LineLayout.vue b/src/layouts/LineLayout.vue index 46ae264..404f66b 100644 --- a/src/layouts/LineLayout.vue +++ b/src/layouts/LineLayout.vue @@ -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); } }); diff --git a/src/pages/LineMonitorPage.vue b/src/pages/LineMonitorPage.vue new file mode 100644 index 0000000..abd5510 --- /dev/null +++ b/src/pages/LineMonitorPage.vue @@ -0,0 +1,69 @@ + + + diff --git a/src/pages/MonitorPage.vue b/src/pages/MonitorPage.vue index 0489beb..38ec6b1 100644 --- a/src/pages/MonitorPage.vue +++ b/src/pages/MonitorPage.vue @@ -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); diff --git a/src/pages/PublishManage.vue b/src/pages/PublishManage.vue index 394e6eb..4faa6d5 100644 --- a/src/pages/PublishManage.vue +++ b/src/pages/PublishManage.vue @@ -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}`" /> []; children?: ReturnType[]; + convertKilometer?: number[]; }): Section { const message = new Section({}); if (data.id != null) { @@ -82,12 +93,15 @@ export namespace state { if (data.type != null) { message.type = data.type; } - if (data.kilometerCode != null) { - message.kilometerCode = data.kilometerCode; + if (data.kilometerSystem != null) { + message.kilometerSystem = data.kilometerSystem.map(item => dependency_1.graphicData.KilometerSystem.fromObject(item)); } if (data.children != null) { message.children = data.children.map(item => Section.fromObject(item)); } + if (data.convertKilometer != null) { + message.convertKilometer = data.convertKilometer; + } return message; } toObject() { @@ -95,8 +109,9 @@ export namespace state { id?: string; code?: string; type?: dependency_1.graphicData.Section.SectionType; - kilometerCode?: string[]; + kilometerSystem?: ReturnType[]; children?: ReturnType[]; + convertKilometer?: number[]; } = {}; if (this.id != null) { data.id = this.id; @@ -107,12 +122,15 @@ export namespace state { if (this.type != null) { data.type = this.type; } - if (this.kilometerCode != null) { - data.kilometerCode = this.kilometerCode; + if (this.kilometerSystem != null) { + data.kilometerSystem = this.kilometerSystem.map((item: dependency_1.graphicData.KilometerSystem) => item.toObject()); } if (this.children != null) { data.children = this.children.map((item: Section) => item.toObject()); } + if (this.convertKilometer != null) { + data.convertKilometer = this.convertKilometer; + } return data; } serialize(): Uint8Array; @@ -125,10 +143,12 @@ export namespace state { writer.writeString(2, this.code); if (this.type != dependency_1.graphicData.Section.SectionType.Physical) writer.writeEnum(3, this.type); - if (this.kilometerCode.length) - writer.writeRepeatedString(4, this.kilometerCode); + if (this.kilometerSystem.length) + writer.writeRepeatedMessage(4, this.kilometerSystem, (item: dependency_1.graphicData.KilometerSystem) => item.serialize(writer)); if (this.children.length) writer.writeRepeatedMessage(5, this.children, (item: Section) => item.serialize(writer)); + if (this.convertKilometer.length) + writer.writePackedInt64(6, this.convertKilometer); if (!w) return writer.getResultBuffer(); } @@ -148,11 +168,14 @@ export namespace state { message.type = reader.readEnum(); break; case 4: - pb_1.Message.addToRepeatedField(message, 4, reader.readString()); + reader.readMessage(message.kilometerSystem, () => pb_1.Message.addToRepeatedWrapperField(message, 4, dependency_1.graphicData.KilometerSystem.deserialize(reader), dependency_1.graphicData.KilometerSystem)); break; case 5: reader.readMessage(message.children, () => pb_1.Message.addToRepeatedWrapperField(message, 5, Section.deserialize(reader), Section)); break; + case 6: + message.convertKilometer = reader.readPackedInt64(); + break; default: reader.skipField(); } } @@ -170,12 +193,11 @@ export namespace state { constructor(data?: any[] | { id?: string; code?: string; - paSection?: Section; - pbSection?: Section; - pcSection?: Section; + kilometerSystem?: dependency_1.graphicData.KilometerSystem[]; + convertKilometer?: number[]; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [3, 4], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("id" in data && data.id != undefined) { this.id = data.id; @@ -183,14 +205,11 @@ export namespace state { if ("code" in data && data.code != undefined) { this.code = data.code; } - if ("paSection" in data && data.paSection != undefined) { - this.paSection = data.paSection; + if ("kilometerSystem" in data && data.kilometerSystem != undefined) { + this.kilometerSystem = data.kilometerSystem; } - if ("pbSection" in data && data.pbSection != undefined) { - this.pbSection = data.pbSection; - } - if ("pcSection" in data && data.pcSection != undefined) { - this.pcSection = data.pcSection; + if ("convertKilometer" in data && data.convertKilometer != undefined) { + this.convertKilometer = data.convertKilometer; } } } @@ -206,39 +225,23 @@ export namespace state { set code(value: string) { pb_1.Message.setField(this, 2, value); } - get paSection() { - return pb_1.Message.getWrapperField(this, Section, 3) as Section; + get kilometerSystem() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.graphicData.KilometerSystem, 3) as dependency_1.graphicData.KilometerSystem[]; } - set paSection(value: Section) { - pb_1.Message.setWrapperField(this, 3, value); + set kilometerSystem(value: dependency_1.graphicData.KilometerSystem[]) { + pb_1.Message.setRepeatedWrapperField(this, 3, value); } - get has_paSection() { - return pb_1.Message.getField(this, 3) != null; + get convertKilometer() { + return pb_1.Message.getFieldWithDefault(this, 4, []) as number[]; } - get pbSection() { - return pb_1.Message.getWrapperField(this, Section, 4) as Section; - } - set pbSection(value: Section) { - pb_1.Message.setWrapperField(this, 4, value); - } - get has_pbSection() { - return pb_1.Message.getField(this, 4) != null; - } - get pcSection() { - return pb_1.Message.getWrapperField(this, Section, 5) as Section; - } - set pcSection(value: Section) { - pb_1.Message.setWrapperField(this, 5, value); - } - get has_pcSection() { - return pb_1.Message.getField(this, 5) != null; + set convertKilometer(value: number[]) { + pb_1.Message.setField(this, 4, value); } static fromObject(data: { id?: string; code?: string; - paSection?: ReturnType; - pbSection?: ReturnType; - pcSection?: ReturnType; + kilometerSystem?: ReturnType[]; + convertKilometer?: number[]; }): Switch { const message = new Switch({}); if (data.id != null) { @@ -247,14 +250,11 @@ export namespace state { if (data.code != null) { message.code = data.code; } - if (data.paSection != null) { - message.paSection = Section.fromObject(data.paSection); + if (data.kilometerSystem != null) { + message.kilometerSystem = data.kilometerSystem.map(item => dependency_1.graphicData.KilometerSystem.fromObject(item)); } - if (data.pbSection != null) { - message.pbSection = Section.fromObject(data.pbSection); - } - if (data.pcSection != null) { - message.pcSection = Section.fromObject(data.pcSection); + if (data.convertKilometer != null) { + message.convertKilometer = data.convertKilometer; } return message; } @@ -262,9 +262,8 @@ export namespace state { const data: { id?: string; code?: string; - paSection?: ReturnType; - pbSection?: ReturnType; - pcSection?: ReturnType; + kilometerSystem?: ReturnType[]; + convertKilometer?: number[]; } = {}; if (this.id != null) { data.id = this.id; @@ -272,14 +271,11 @@ export namespace state { if (this.code != null) { data.code = this.code; } - if (this.paSection != null) { - data.paSection = this.paSection.toObject(); + if (this.kilometerSystem != null) { + data.kilometerSystem = this.kilometerSystem.map((item: dependency_1.graphicData.KilometerSystem) => item.toObject()); } - if (this.pbSection != null) { - data.pbSection = this.pbSection.toObject(); - } - if (this.pcSection != null) { - data.pcSection = this.pcSection.toObject(); + if (this.convertKilometer != null) { + data.convertKilometer = this.convertKilometer; } return data; } @@ -291,12 +287,10 @@ export namespace state { writer.writeString(1, this.id); if (this.code.length) writer.writeString(2, this.code); - if (this.has_paSection) - writer.writeMessage(3, this.paSection, () => this.paSection.serialize(writer)); - if (this.has_pbSection) - writer.writeMessage(4, this.pbSection, () => this.pbSection.serialize(writer)); - if (this.has_pcSection) - writer.writeMessage(5, this.pcSection, () => this.pcSection.serialize(writer)); + if (this.kilometerSystem.length) + writer.writeRepeatedMessage(3, this.kilometerSystem, (item: dependency_1.graphicData.KilometerSystem) => item.serialize(writer)); + if (this.convertKilometer.length) + writer.writePackedInt64(4, this.convertKilometer); if (!w) return writer.getResultBuffer(); } @@ -313,13 +307,10 @@ export namespace state { message.code = reader.readString(); break; case 3: - reader.readMessage(message.paSection, () => message.paSection = Section.deserialize(reader)); + reader.readMessage(message.kilometerSystem, () => pb_1.Message.addToRepeatedWrapperField(message, 3, dependency_1.graphicData.KilometerSystem.deserialize(reader), dependency_1.graphicData.KilometerSystem)); break; case 4: - reader.readMessage(message.pbSection, () => message.pbSection = Section.deserialize(reader)); - break; - case 5: - reader.readMessage(message.pcSection, () => message.pcSection = Section.deserialize(reader)); + message.convertKilometer = reader.readPackedInt64(); break; default: reader.skipField(); } diff --git a/src/protos/ws_message.ts b/src/protos/ws_message.ts index 99d400c..e23b80d 100644 --- a/src/protos/ws_message.ts +++ b/src/protos/ws_message.ts @@ -469,7 +469,7 @@ export namespace state { groupId?: string; destinationId?: number; show?: boolean; - kilometerCode?: string; + kilometerCode?: number; dir?: number; }) { super(); @@ -529,9 +529,9 @@ export namespace state { pb_1.Message.setField(this, 5, value); } get kilometerCode() { - return pb_1.Message.getFieldWithDefault(this, 6, "") as string; + return pb_1.Message.getFieldWithDefault(this, 6, 0) as number; } - set kilometerCode(value: string) { + set kilometerCode(value: number) { pb_1.Message.setField(this, 6, value); } get dir() { @@ -546,7 +546,7 @@ export namespace state { groupId?: string; destinationId?: number; show?: boolean; - kilometerCode?: string; + kilometerCode?: number; dir?: number; }): WsLineNetTrainOffsetMessage { const message = new WsLineNetTrainOffsetMessage({}); @@ -580,7 +580,7 @@ export namespace state { groupId?: string; destinationId?: number; show?: boolean; - kilometerCode?: string; + kilometerCode?: number; dir?: number; } = {}; if (this.lineId != null) { @@ -620,8 +620,8 @@ export namespace state { writer.writeInt32(4, this.destinationId); if (this.show != false) writer.writeBool(5, this.show); - if (this.kilometerCode.length) - writer.writeString(6, this.kilometerCode); + if (this.kilometerCode != 0) + writer.writeInt64(6, this.kilometerCode); if (this.dir != 0) writer.writeInt32(7, this.dir); if (!w) @@ -649,7 +649,7 @@ export namespace state { message.show = reader.readBool(); break; case 6: - message.kilometerCode = reader.readString(); + message.kilometerCode = reader.readInt64(); break; case 7: message.dir = reader.readInt32(); diff --git a/src/router/routes.ts b/src/router/routes.ts index 88f7f02..b553b77 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -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', diff --git a/src/stores/line-net-store.ts b/src/stores/line-net-store.ts index 9a14e5c..c8fdad6 100644 --- a/src/stores/line-net-store.ts +++ b/src/stores/line-net-store.ts @@ -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 { diff --git a/xian-ncc-da-message b/xian-ncc-da-message index 0e4f2bd..c92fd31 160000 --- a/xian-ncc-da-message +++ b/xian-ncc-da-message @@ -1 +1 @@ -Subproject commit 0e4f2bd6fbb5eae436685260e622ec7796ae479a +Subproject commit c92fd31a301d06b5bfe5426d3da65203c82e84fb