diff --git a/src/components/draw-app/DrawRelayCabinetProperties.vue b/src/components/draw-app/DrawRelayCabinetProperties.vue index 678f791..8316497 100644 --- a/src/components/draw-app/DrawRelayCabinetProperties.vue +++ b/src/components/draw-app/DrawRelayCabinetProperties.vue @@ -27,6 +27,11 @@ PhaseFailureProtector.Type " > + @@ -41,6 +46,8 @@ import RelayProperty from './properties/RelayProperty.vue'; import { Relay } from 'src/graphics/relay/Relay'; import PhaseFailureProtectorProperty from './properties/PhaseFailureProtectorProperty.vue'; import { PhaseFailureProtector } from 'src/graphics/phaseFailureProtector/PhaseFailureProtector'; +import SignalFaultAlarmProperty from './properties/SignalFaultAlarmProperty.vue'; +import { SignalFaultAlarm } from 'src/graphics/signalFaultAlarm/SignalFaultAlarm'; import { useRelayCabinetStore } from 'src/stores/relayCabinet-store'; const relayCabinetStore = useRelayCabinetStore(); diff --git a/src/components/draw-app/dialogs/DeviceRelateRelayList.vue b/src/components/draw-app/dialogs/DeviceRelateRelayList.vue index f5ccdc2..c6d787b 100644 --- a/src/components/draw-app/dialogs/DeviceRelateRelayList.vue +++ b/src/components/draw-app/dialogs/DeviceRelateRelayList.vue @@ -63,6 +63,7 @@ const deviceTypeMap = { 5: '信号机', 6: '车站', 7: '屏蔽门', + 8: '信号机故障报警仪', }; const columns: QTable['columns'] = [ { diff --git a/src/components/draw-app/properties/RelateRelayConfig.vue b/src/components/draw-app/properties/RelateRelayConfig.vue index a1ac778..d43992b 100644 --- a/src/components/draw-app/properties/RelateRelayConfig.vue +++ b/src/components/draw-app/properties/RelateRelayConfig.vue @@ -133,6 +133,10 @@ const optionsType = [ { label: '信号机', value: graphicData.RelatedRef.DeviceType.signal }, { label: '车站', value: graphicData.RelatedRef.DeviceType.station }, { label: '屏蔽门', value: graphicData.RelatedRef.DeviceType.ScreenDoor }, + { + label: '信号机故障报警仪', + value: graphicData.RelatedRef.DeviceType.SignalFaultAlarm, + }, ]; let selectGraphic: JlGraphic[] = []; diff --git a/src/components/draw-app/properties/SignalFaultAlarmProperty.vue b/src/components/draw-app/properties/SignalFaultAlarmProperty.vue new file mode 100644 index 0000000..c152078 --- /dev/null +++ b/src/components/draw-app/properties/SignalFaultAlarmProperty.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/drawApp/relayCabinetGraphics/SignalFaultAlarmInteraction.ts b/src/drawApp/relayCabinetGraphics/SignalFaultAlarmInteraction.ts new file mode 100644 index 0000000..2878442 --- /dev/null +++ b/src/drawApp/relayCabinetGraphics/SignalFaultAlarmInteraction.ts @@ -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(); + } + + 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); + } +} diff --git a/src/drawApp/relayCabinetLayoutApp.ts b/src/drawApp/relayCabinetLayoutApp.ts index d423185..4a9bd00 100644 --- a/src/drawApp/relayCabinetLayoutApp.ts +++ b/src/drawApp/relayCabinetLayoutApp.ts @@ -33,6 +33,12 @@ import { } from 'src/graphics/phaseFailureProtector/PhaseFailureProtector'; import { PhaseFailureProtectorData } from './relayCabinetGraphics/PhaseFailureProtectorInteraction'; import { PhaseFailureProtectorDraw } from 'src/graphics/phaseFailureProtector/PhaseFailureProtectorDrawAssistant'; +import { + SignalFaultAlarm, + SignalFaultAlarmTemplate, +} from 'src/graphics/signalFaultAlarm/SignalFaultAlarm'; +import { SignalFaultAlarmData } from './relayCabinetGraphics/SignalFaultAlarmInteraction'; +import { SignalFaultAlarmDraw } from 'src/graphics/signalFaultAlarm/SignalFaultAlarmDrawAssistant'; const UndoOptions: MenuItemOptions = { name: '撤销', @@ -80,6 +86,10 @@ export function initDrawApp(): IDrawApp { app, new PhaseFailureProtectorTemplate(new PhaseFailureProtectorData()) ); + new SignalFaultAlarmDraw( + app, + new SignalFaultAlarmTemplate(new SignalFaultAlarmData()) + ); // 画布右键菜单 app.registerMenu(DefaultCanvasMenu); @@ -205,6 +215,12 @@ export function saveDrawDatas(app: IDrawApp) { (phaseFailureProtectorData as PhaseFailureProtectorData).data ); } + if (SignalFaultAlarm.Type === g.type) { + const signalFaultAlarmData = (g as SignalFaultAlarm).saveData(); + storage.signalFaultAlarms.push( + (signalFaultAlarmData as SignalFaultAlarmData).data + ); + } }); storage.deviceRelateRelayList = refRelaysList; storage.combinationtypeList = combinationTypeList; @@ -236,6 +252,9 @@ export async function loadDrawDatas(): Promise { storage.phaseFailureProtectors.forEach((phaseFailureProtector) => { datas.push(new PhaseFailureProtectorData(phaseFailureProtector)); }); + storage.signalFaultAlarms.forEach((signalFaultAlarm) => { + datas.push(new SignalFaultAlarmData(signalFaultAlarm)); + }); refRelaysList = storage.deviceRelateRelayList; combinationTypeList = storage.combinationtypeList; UniqueIdPrefix = storage.UniqueIdPrefix; diff --git a/src/graphics/signalFaultAlarm/SignalFaultAlarm.ts b/src/graphics/signalFaultAlarm/SignalFaultAlarm.ts new file mode 100644 index 0000000..239c8d7 --- /dev/null +++ b/src/graphics/signalFaultAlarm/SignalFaultAlarm.ts @@ -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(); + } + 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 { + 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 { + this.signalFaultAlarmTextures = await Assets.load(signalFaultAlarmSprites); + return this.signalFaultAlarmTextures as Texture; + } +} diff --git a/src/graphics/signalFaultAlarm/SignalFaultAlarmDrawAssistant.ts b/src/graphics/signalFaultAlarm/SignalFaultAlarmDrawAssistant.ts new file mode 100644 index 0000000..9bcd783 --- /dev/null +++ b/src/graphics/signalFaultAlarm/SignalFaultAlarmDrawAssistant.ts @@ -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.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 { + 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), + }); + } +} diff --git a/src/graphics/signalFaultAlarm/signalFaultAlarmSprites.png b/src/graphics/signalFaultAlarm/signalFaultAlarmSprites.png new file mode 100644 index 0000000..dd8830e Binary files /dev/null and b/src/graphics/signalFaultAlarm/signalFaultAlarmSprites.png differ diff --git a/src/layouts/RelayCabinetLayout.vue b/src/layouts/RelayCabinetLayout.vue index fb0da20..507b222 100644 --- a/src/layouts/RelayCabinetLayout.vue +++ b/src/layouts/RelayCabinetLayout.vue @@ -198,6 +198,7 @@ import { DialogChainObject, useQuasar } from 'quasar'; import { Relay } from 'src/graphics/relay/Relay'; import { RelayCabinet } from 'src/graphics/relayCabinet/RelayCabinet'; import { PhaseFailureProtector } from 'src/graphics/phaseFailureProtector/PhaseFailureProtector'; +import { SignalFaultAlarm } from 'src/graphics/signalFaultAlarm/SignalFaultAlarm'; import { relayCabinetGraphicData } from 'src/protos/relayCabinetLayoutGraphics'; const $q = useQuasar(); @@ -291,6 +292,7 @@ onMounted(() => { RelayCabinet.Type, Relay.Type, PhaseFailureProtector.Type, + SignalFaultAlarm.Type, ]; drawAssistantsTypes.forEach((type) => { const drawAssistant = getDrawApp()?.getDrawAssistant(type); diff --git a/src/protos/relayCabinetLayoutGraphics.ts b/src/protos/relayCabinetLayoutGraphics.ts index b7b845f..5cd96d9 100644 --- a/src/protos/relayCabinetLayoutGraphics.ts +++ b/src/protos/relayCabinetLayoutGraphics.ts @@ -16,9 +16,10 @@ export namespace relayCabinetGraphicData { UniqueIdPrefix?: UniqueIdType; phaseFailureProtectors?: PhaseFailureProtector[]; combinationtypeList?: Combinationtype[]; + signalFaultAlarms?: SignalFaultAlarm[]; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [2, 3, 4, 7, 8], this.#one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [2, 3, 4, 7, 8, 9], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("canvas" in data && data.canvas != undefined) { this.canvas = data.canvas; @@ -41,6 +42,9 @@ export namespace relayCabinetGraphicData { if ("combinationtypeList" in data && data.combinationtypeList != undefined) { this.combinationtypeList = data.combinationtypeList; } + if ("signalFaultAlarms" in data && data.signalFaultAlarms != undefined) { + this.signalFaultAlarms = data.signalFaultAlarms; + } } } get canvas() { @@ -91,6 +95,12 @@ export namespace relayCabinetGraphicData { set combinationtypeList(value: Combinationtype[]) { pb_1.Message.setRepeatedWrapperField(this, 8, value); } + get signalFaultAlarms() { + return pb_1.Message.getRepeatedWrapperField(this, SignalFaultAlarm, 9) as SignalFaultAlarm[]; + } + set signalFaultAlarms(value: SignalFaultAlarm[]) { + pb_1.Message.setRepeatedWrapperField(this, 9, value); + } static fromObject(data: { canvas?: ReturnType; relayCabinets?: ReturnType[]; @@ -99,6 +109,7 @@ export namespace relayCabinetGraphicData { UniqueIdPrefix?: ReturnType; phaseFailureProtectors?: ReturnType[]; combinationtypeList?: ReturnType[]; + signalFaultAlarms?: ReturnType[]; }): RelayCabinetGraphicStorage { const message = new RelayCabinetGraphicStorage({}); if (data.canvas != null) { @@ -122,6 +133,9 @@ export namespace relayCabinetGraphicData { if (data.combinationtypeList != null) { message.combinationtypeList = data.combinationtypeList.map(item => Combinationtype.fromObject(item)); } + if (data.signalFaultAlarms != null) { + message.signalFaultAlarms = data.signalFaultAlarms.map(item => SignalFaultAlarm.fromObject(item)); + } return message; } toObject() { @@ -133,6 +147,7 @@ export namespace relayCabinetGraphicData { UniqueIdPrefix?: ReturnType; phaseFailureProtectors?: ReturnType[]; combinationtypeList?: ReturnType[]; + signalFaultAlarms?: ReturnType[]; } = {}; if (this.canvas != null) { data.canvas = this.canvas.toObject(); @@ -155,6 +170,9 @@ export namespace relayCabinetGraphicData { if (this.combinationtypeList != null) { data.combinationtypeList = this.combinationtypeList.map((item: Combinationtype) => item.toObject()); } + if (this.signalFaultAlarms != null) { + data.signalFaultAlarms = this.signalFaultAlarms.map((item: SignalFaultAlarm) => item.toObject()); + } return data; } serialize(): Uint8Array; @@ -175,6 +193,8 @@ export namespace relayCabinetGraphicData { writer.writeRepeatedMessage(7, this.phaseFailureProtectors, (item: PhaseFailureProtector) => item.serialize(writer)); if (this.combinationtypeList.length) writer.writeRepeatedMessage(8, this.combinationtypeList, (item: Combinationtype) => item.serialize(writer)); + if (this.signalFaultAlarms.length) + writer.writeRepeatedMessage(9, this.signalFaultAlarms, (item: SignalFaultAlarm) => item.serialize(writer)); if (!w) return writer.getResultBuffer(); } @@ -205,6 +225,9 @@ export namespace relayCabinetGraphicData { case 8: reader.readMessage(message.combinationtypeList, () => pb_1.Message.addToRepeatedWrapperField(message, 8, Combinationtype.deserialize(reader), Combinationtype)); break; + case 9: + reader.readMessage(message.signalFaultAlarms, () => pb_1.Message.addToRepeatedWrapperField(message, 9, SignalFaultAlarm.deserialize(reader), SignalFaultAlarm)); + break; default: reader.skipField(); } } @@ -532,6 +555,99 @@ export namespace relayCabinetGraphicData { return PhaseFailureProtector.deserialize(bytes); } } + export class SignalFaultAlarm extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: dependency_1.graphicData.CommonInfo; + code?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, dependency_1.graphicData.CommonInfo, 1) as dependency_1.graphicData.CommonInfo; + } + set common(value: dependency_1.graphicData.CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + }): SignalFaultAlarm { + const message = new SignalFaultAlarm({}); + if (data.common != null) { + message.common = dependency_1.graphicData.CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): SignalFaultAlarm { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new SignalFaultAlarm(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = dependency_1.graphicData.CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): SignalFaultAlarm { + return SignalFaultAlarm.deserialize(bytes); + } + } export class DeviceRelateRelay extends pb_1.Message { #one_of_decls: number[][] = []; constructor(data?: any[] | { diff --git a/src/protos/stationLayoutGraphics.ts b/src/protos/stationLayoutGraphics.ts index c701c22..5c081bf 100644 --- a/src/protos/stationLayoutGraphics.ts +++ b/src/protos/stationLayoutGraphics.ts @@ -3515,7 +3515,8 @@ export namespace graphicData { SectionLink = 4, signal = 5, station = 6, - ScreenDoor = 7 + ScreenDoor = 7, + SignalFaultAlarm = 8 } export enum DevicePort { A = 0,