diff --git a/src/components/draw-app/properties/CombinationTypeConfig.vue b/src/components/draw-app/properties/CombinationTypeConfig.vue index c4b224c..4bacc6c 100644 --- a/src/components/draw-app/properties/CombinationTypeConfig.vue +++ b/src/components/draw-app/properties/CombinationTypeConfig.vue @@ -20,10 +20,8 @@ 关联的继电器
(); + } + clone(): RelayState { + return new RelayState(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); + } +} diff --git a/src/drawApp/relayCabinetLayoutApp.ts b/src/drawApp/relayCabinetLayoutApp.ts index f4b1f86..071f348 100644 --- a/src/drawApp/relayCabinetLayoutApp.ts +++ b/src/drawApp/relayCabinetLayoutApp.ts @@ -25,7 +25,7 @@ import { import { RelayCabinetData } from './relayCabinetGraphics/RelayCabinetInteraction'; import { RelayCabinetDraw } from 'src/graphics/relayCabinet/RelayCabinetDrawAssistant'; import { Relay, RelayTemplate } from 'src/graphics/relay/Relay'; -import { RelayData } from './relayCabinetGraphics/RelayInteraction'; +import { RelayData, RelayState } from './relayCabinetGraphics/RelayInteraction'; import { RelayDraw } from 'src/graphics/relay/RelayDrawAssistant'; import { PhaseFailureProtector, @@ -75,7 +75,7 @@ export function initDrawApp(): IDrawApp { }); const app = drawApp; new RelayCabinetDraw(app, new RelayCabinetTemplate(new RelayCabinetData())); - new RelayDraw(app, new RelayTemplate(new RelayData())); + new RelayDraw(app, new RelayTemplate(new RelayData(), new RelayState())); new PhaseFailureProtectorDraw( app, new PhaseFailureProtectorTemplate(new PhaseFailureProtectorData()) diff --git a/src/drawApp/relayScene.ts b/src/drawApp/relayScene.ts index 6f784d1..e39c114 100644 --- a/src/drawApp/relayScene.ts +++ b/src/drawApp/relayScene.ts @@ -1,13 +1,25 @@ -import { GraphicData, IGraphicApp, IGraphicStorage } from 'src/jl-graphic'; +import { + ClientEngine, + GraphicData, + GraphicQueryStore, + GraphicState, + IGraphicApp, + IGraphicScene, + IGraphicStorage, +} from 'src/jl-graphic'; import { getPublishMapInfoByLineId } from 'src/api/PublishApi'; import { useLineStore } from 'src/stores/line-store'; import { toUint8Array } from 'js-base64'; import { relayCabinetGraphicData } from 'src/protos/relayCabinetLayoutGraphics'; import { RelayCabinetData } from './relayCabinetGraphics/RelayCabinetInteraction'; -import { RelayData } from './relayCabinetGraphics/RelayInteraction'; +import { RelayData, RelayState } from './relayCabinetGraphics/RelayInteraction'; import { RelayCabinetTemplate } from 'src/graphics/relayCabinet/RelayCabinet'; import { RelayTemplate } from 'src/graphics/relay/Relay'; import { SceneToPictureType } from './lineApp'; +import { getWebsocketUrl } from 'src/configs/UrlManage'; +import { getOnlyToken } from 'src/configs/TokenManage'; +import { state } from 'src/protos/device_state'; +import { Notify, QNotifyUpdateOptions } from 'quasar'; export function initRelayScene(lineApp: IGraphicApp) { // 继电器 @@ -21,10 +33,68 @@ export function initRelayScene(lineApp: IGraphicApp) { }); const relayGraphicTemplate = [ new RelayCabinetTemplate(new RelayCabinetData()), - new RelayTemplate(new RelayData()), + new RelayTemplate(new RelayData(), new RelayState()), ]; relayScene.registerGraphicTemplates(...relayGraphicTemplate); - return lineApp; + relayScene.on('postdataloaded', () => { + handleSubscribe(relayScene, lineApp); + }); +} + +function handleSubscribe(relayScene: IGraphicScene, lineApp: IGraphicApp) { + const lineStore = useLineStore(); + const simulationId = lineStore.simulationId; + const mapId = lineStore.mapId; + const app = relayScene; + + lineApp?.enableWsMassaging({ + engine: ClientEngine.Centrifugo, + wsUrl: `${getWebsocketUrl()}`, + token: getOnlyToken() as string, + }); + app.subscribe({ + destination: `simulation-${simulationId}_${mapId}-devices-status`, + messageConverter: (message: Uint8Array) => { + const states: GraphicState[] = []; + const storage = state.PushedDevicesStatus.deserialize(message); + if (storage.all) { + storage.allStatus.replyState.forEach((relayState) => { + if (relayState.id) { + states.push(new RelayState(relayState)); + } + }); + } else { + storage.varStatus.updatedReply.forEach((relayState) => { + if (relayState.id) { + states.push(new RelayState(relayState)); + } + }); + } + if (states && states.length > 0) { + lineStore.setSocketStates(states); + } + return states; + }, + graphicQueryer: (state: GraphicState, store: GraphicQueryStore) => { + return store.queryById(state.code); + }, + }); + + let msgNotify: null | ((props?: QNotifyUpdateOptions | undefined) => void) = + null; + app.on('websocket-connect-state-change', (connected) => { + if (!connected && !msgNotify) { + msgNotify = Notify.create({ + type: 'negative', + timeout: 0, + position: 'top-right', + message: '通信链接已断开!', + }); + } else if (msgNotify && connected) { + msgNotify(); + msgNotify = null; + } + }); } async function loadRelayDatas(): Promise { diff --git a/src/graphics/relay/Relay.ts b/src/graphics/relay/Relay.ts index 4242529..43d62da 100644 --- a/src/graphics/relay/Relay.ts +++ b/src/graphics/relay/Relay.ts @@ -1,6 +1,7 @@ import { Color, Graphics } from 'pixi.js'; import { GraphicData, + GraphicState, JlGraphic, JlGraphicTemplate, VectorText, @@ -16,10 +17,16 @@ export interface IRelayData extends GraphicData { eq(other: IRelayData): boolean; } +export interface IRelayState extends GraphicState { + get xh(): boolean; //继电器吸合 + set xh(v: boolean); +} + export const relayConsts = { radius: 8, lineWidth: 3, - lineColor: '0xff0000', + closeColor: '0x00FF00', + openColor: '0xff0000', }; export class Relay extends JlGraphic { static Type = 'Relay'; @@ -39,6 +46,11 @@ export class Relay extends JlGraphic { get datas(): IRelayData { return this.getDatas(); } + + get states(): IRelayState { + return this.getStates(); + } + doRepaint(): void { this.labelGraphic.text = this.datas.code; const labelPosition = this.datas.childTransforms?.find( @@ -51,10 +63,16 @@ export class Relay extends JlGraphic { } this.refDevice.position.set(0, -20); const relayGraphic = this.relayGraphic; + let relayColor = relayConsts.openColor; + if (this.states?.xh) { + relayColor = relayConsts.closeColor; + } else { + relayColor = relayConsts.openColor; + } relayGraphic .clear() - .lineStyle(relayConsts.lineWidth, new Color(relayConsts.lineColor)); - relayGraphic.beginFill(relayConsts.lineColor); + .lineStyle(relayConsts.lineWidth, new Color(relayColor)); + relayGraphic.beginFill(relayColor); relayGraphic.drawCircle(0, 0, relayConsts.radius); relayGraphic.endFill; } @@ -68,14 +86,16 @@ export class Relay extends JlGraphic { } export class RelayTemplate extends JlGraphicTemplate { - constructor(dataTemplate: IRelayData) { + constructor(dataTemplate: IRelayData, stateTemplate?: IRelayState) { super(Relay.Type, { dataTemplate, + stateTemplate, }); } new(): Relay { const relay = new Relay(); relay.loadData(this.datas); + relay.loadState(this.states); return relay; } } diff --git a/src/protos/device_state.ts b/src/protos/device_state.ts index 4a3e641..ca12c58 100644 --- a/src/protos/device_state.ts +++ b/src/protos/device_state.ts @@ -2166,9 +2166,10 @@ export namespace state { removedTrainId?: string[]; updatedSwitch?: SwitchState[]; updatedSection?: SectionState[]; + updatedReply?: ReplyState[]; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1, 2, 3, 4], this.#one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1, 2, 3, 4, 5], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("updatedTrain" in data && data.updatedTrain != undefined) { this.updatedTrain = data.updatedTrain; @@ -2182,6 +2183,9 @@ export namespace state { if ("updatedSection" in data && data.updatedSection != undefined) { this.updatedSection = data.updatedSection; } + if ("updatedReply" in data && data.updatedReply != undefined) { + this.updatedReply = data.updatedReply; + } } } get updatedTrain() { @@ -2208,11 +2212,18 @@ export namespace state { set updatedSection(value: SectionState[]) { pb_1.Message.setRepeatedWrapperField(this, 4, value); } + get updatedReply() { + return pb_1.Message.getRepeatedWrapperField(this, ReplyState, 5) as ReplyState[]; + } + set updatedReply(value: ReplyState[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } static fromObject(data: { updatedTrain?: ReturnType[]; removedTrainId?: string[]; updatedSwitch?: ReturnType[]; updatedSection?: ReturnType[]; + updatedReply?: ReturnType[]; }): VariationStatus { const message = new VariationStatus({}); if (data.updatedTrain != null) { @@ -2227,6 +2238,9 @@ export namespace state { if (data.updatedSection != null) { message.updatedSection = data.updatedSection.map(item => SectionState.fromObject(item)); } + if (data.updatedReply != null) { + message.updatedReply = data.updatedReply.map(item => ReplyState.fromObject(item)); + } return message; } toObject() { @@ -2235,6 +2249,7 @@ export namespace state { removedTrainId?: string[]; updatedSwitch?: ReturnType[]; updatedSection?: ReturnType[]; + updatedReply?: ReturnType[]; } = {}; if (this.updatedTrain != null) { data.updatedTrain = this.updatedTrain.map((item: TrainState) => item.toObject()); @@ -2248,6 +2263,9 @@ export namespace state { if (this.updatedSection != null) { data.updatedSection = this.updatedSection.map((item: SectionState) => item.toObject()); } + if (this.updatedReply != null) { + data.updatedReply = this.updatedReply.map((item: ReplyState) => item.toObject()); + } return data; } serialize(): Uint8Array; @@ -2262,6 +2280,8 @@ export namespace state { writer.writeRepeatedMessage(3, this.updatedSwitch, (item: SwitchState) => item.serialize(writer)); if (this.updatedSection.length) writer.writeRepeatedMessage(4, this.updatedSection, (item: SectionState) => item.serialize(writer)); + if (this.updatedReply.length) + writer.writeRepeatedMessage(5, this.updatedReply, (item: ReplyState) => item.serialize(writer)); if (!w) return writer.getResultBuffer(); } @@ -2283,6 +2303,9 @@ export namespace state { case 4: reader.readMessage(message.updatedSection, () => pb_1.Message.addToRepeatedWrapperField(message, 4, SectionState.deserialize(reader), SectionState)); break; + case 5: + reader.readMessage(message.updatedReply, () => pb_1.Message.addToRepeatedWrapperField(message, 5, ReplyState.deserialize(reader), ReplyState)); + break; default: reader.skipField(); } }