区段状态

This commit is contained in:
Yuan 2023-07-27 15:05:43 +08:00
parent 15dce2e5b2
commit 7a4d2fe9a0
10 changed files with 383 additions and 19 deletions

View File

@ -45,3 +45,12 @@ export async function setSwitchStatus(lineId: string, state: State) {
console.error(err); console.error(err);
} }
} }
export async function setTrackStatus(lineId: string, state: State) {
try {
delete state._state;
delete state._graphicType;
return await api.post(`/mock/track/status/${lineId}`, state);
} catch (err) {
console.error(err);
}
}

View File

@ -1,11 +1,155 @@
import { import {
ILogicSectionData, ILogicSectionData,
ILogicSectionState,
LimitType,
LogicSection, LogicSection,
} from 'src/graphics/logicSection/LogicSection'; } from 'src/graphics/logicSection/LogicSection';
import * as pb_1 from 'google-protobuf'; import * as pb_1 from 'google-protobuf';
import { GraphicDataBase } from './GraphicDataBase'; import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { graphicData } from 'src/protos/stationLayoutGraphics'; import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IPointData } from 'pixi.js'; import { DisplayObject, FederatedMouseEvent, IPointData } from 'pixi.js';
import { state } from 'src/protos/device_status';
import {
GraphicApp,
GraphicInteractionPlugin,
JlGraphic,
} from 'src/jl-graphic';
import { LogicSectionGraphicHitArea } from 'src/graphics/logicSection/LogicSectionDrawAssistant';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { useLineStore } from 'src/stores/line-store';
import { setTrackStatus } from 'src/api/TurnoutApi';
let menuItemHandler: (propName: keyof ILogicSectionState) => void;
const ciOccupied: MenuItemOptions = {
name: '连锁报告区段占用 - ciOccupied',
handler: () => menuItemHandler('ciOccupied'),
};
const cbtcOccupied: MenuItemOptions = {
name: 'CBTC报告区段占用 - cbtcOccupied',
handler: () => menuItemHandler('cbtcOccupied'),
};
const locked: MenuItemOptions = {
name: '锁闭 - locked',
handler: () => menuItemHandler('locked'),
};
const failLocked: MenuItemOptions = {
name: '故障锁闭 - failLocked',
handler: () => menuItemHandler('failLocked'),
};
const cut: MenuItemOptions = {
name: '轨道切除 - cut',
handler: () => menuItemHandler('cut'),
};
const atcInvalid: MenuItemOptions = {
name: '轨道区段被ATC报告失效 - atcInvalid',
handler: () => menuItemHandler('atcInvalid'),
};
const overlap: MenuItemOptions = {
name: 'overlap - overlap',
handler: () => menuItemHandler('overlap'),
};
const blocked: MenuItemOptions = {
name: '轨道区段封锁 - blocked',
handler: () => menuItemHandler('blocked'),
};
const LogicSectionMenu = ContextMenu.init({
name: 'LogicSection菜单',
groups: [
{
items: [
ciOccupied,
cbtcOccupied,
locked,
failLocked,
cut,
atcInvalid,
overlap,
blocked,
],
},
],
});
export class LogicSectionOperationPlugin extends GraphicInteractionPlugin<LogicSection> {
static Name = 'logic_section_menu';
constructor(app: GraphicApp) {
super(LogicSectionOperationPlugin.Name, app);
app.registerMenu(LogicSectionMenu);
}
filter(...grahpics: JlGraphic[]): LogicSection[] | undefined {
return grahpics.filter((g): g is LogicSection => g instanceof LogicSection);
}
static init(app: GraphicApp) {
return new LogicSectionOperationPlugin(app);
}
bind(g: LogicSection): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.lineGraphic.hitArea = new LogicSectionGraphicHitArea(g);
g.on('rightclick', this.onContextMenu, this);
}
unbind(g: LogicSection): void {
g.off('rightclick', this.onContextMenu);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const section = target.getGraphic() as LogicSection;
this.app.updateSelected(section);
const state = {
id: section.datas.code,
ciOccupied: section.states.cbtcOccupied,
cbtcOccupied: section.states.cbtcOccupied,
locked: section.states.locked,
failLocked: section.states.failLocked,
expectLock: false,
expectUnlock: false,
inRoute: false,
cut: section.states.cut,
atcInvalid: section.states.atcInvalid,
overlap: section.states.overlap,
blocked: section.states.blocked,
limitType: section.states.limitType,
speedLimit: section.states.speedLimit,
};
(Object.keys(state) as unknown as (keyof ILogicSectionState)[]).forEach(
(key: keyof ILogicSectionState) => {
const item = LogicSectionMenu.groups[0].items.find((item) =>
item.config.name.includes(key)
);
if (!item) return;
if (
section.states[key] === true &&
!item?.config?.name?.endsWith('✔️')
) {
if (item?.config?.name) item.config.name += '✔️';
}
if (
section.states[key] !== true &&
item?.config?.name?.endsWith('✔️')
) {
item.config.name = item?.config?.name.slice(
0,
item.config.name.length - 2
);
}
}
);
menuItemHandler = (propName) => {
const lineId = useLineStore().lineId?.toString();
if (!lineId) return;
console.log({ ...section.states });
setTrackStatus(lineId, {
...state,
[propName]: !section.states[propName],
});
};
LogicSectionMenu.open(e.global);
}
}
export class LogicSectionData export class LogicSectionData
extends GraphicDataBase extends GraphicDataBase
@ -49,3 +193,115 @@ export class LogicSectionData
return pb_1.Message.equals(this.data, other.data); return pb_1.Message.equals(this.data, other.data);
} }
} }
export class LogicSectionState
extends GraphicStateBase
implements ILogicSectionState
{
constructor(proto?: state.Track) {
let states;
if (proto) {
states = proto;
} else {
states = new state.Track();
}
super(states, LogicSection.Type);
}
get code(): string {
return this.states.id;
}
get states(): state.Track {
return this.getState<state.Track>();
}
public get id(): string {
return this.states.id;
}
public set id(id: string) {
this.states.id = id;
}
public get ciOccupied(): boolean {
return this.states.ciOccupied;
}
public set ciOccupied(value: boolean) {
this.states.ciOccupied = value;
}
// CBTC报告区段占用
public get cbtcOccupied(): boolean {
return this.states.cbtcOccupied;
}
public set cbtcOccupied(value: boolean) {
this.states.cbtcOccupied = value;
}
//锁闭
public get locked(): boolean {
return this.states.locked;
}
public set locked(value: boolean) {
this.states.locked = value;
}
//故障锁闭
public get failLocked(): boolean {
return this.states.failLocked;
}
public set failLocked(value: boolean) {
this.states.failLocked = value;
}
//轨道切除
public get cut(): boolean {
return this.states.cut;
}
public set cut(value: boolean) {
this.states.cut = value;
}
//轨道区段被ATC报告失效
public get atcInvalid(): boolean {
return this.states.atcInvalid;
}
public set atcInvalid(value: boolean) {
this.states.atcInvalid = value;
}
// OVERLAP
public get overlap(): boolean {
return this.states.overlap;
}
public set overlap(value: boolean) {
this.states.overlap = value;
}
//轨道区段封锁
public get blocked(): boolean {
return this.states.blocked;
}
public set blocked(value: boolean) {
this.states.blocked = value;
}
//限速
public get speedLimit(): number {
return this.states.speedLimit;
}
public set speedLimit(value: number) {
this.states.speedLimit = value;
}
//限速类型
public get limitType(): LimitType {
return this.states.limitType;
}
public set limitType(value: LimitType) {
this.states.limitType = value;
}
clone(): LogicSectionState {
return new LogicSectionState(this.states.cloneMessage());
}
copyFrom(data: LogicSectionState): void {
pb_1.Message.copyInto(data.states, this.states);
}
eq(data: LogicSectionState): boolean {
return pb_1.Message.equals(this.states, data.states);
}
}

View File

@ -23,7 +23,7 @@ import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { setSwitchStatus } from 'src/api/TurnoutApi'; import { setSwitchStatus } from 'src/api/TurnoutApi';
import { useLineStore } from 'src/stores/line-store'; import { useLineStore } from 'src/stores/line-store';
let menuItemHandler: (propName: string) => void; let menuItemHandler: (propName: keyof ITurnoutState) => void;
const ipSingleSwitchStusCiOccupied: MenuItemOptions = { const ipSingleSwitchStusCiOccupied: MenuItemOptions = {
name: '连锁报告道岔占用-ipSingleSwitchStusCiOccupied', name: '连锁报告道岔占用-ipSingleSwitchStusCiOccupied',
@ -217,10 +217,9 @@ export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
} }
} }
); );
menuItemHandler = (propName: string) => { menuItemHandler = (propName) => {
const lineId = useLineStore().lineId?.toString(); const lineId = useLineStore().lineId?.toString();
if (!lineId) return; if (!lineId) return;
console.log({ ...turnout.states });
setSwitchStatus(lineId, { setSwitchStatus(lineId, {
...state, ...state,
id: turnout.datas.code, id: turnout.datas.code,

View File

@ -84,7 +84,10 @@ import {
LogicSection, LogicSection,
LogicSectionTemplate, LogicSectionTemplate,
} from 'src/graphics/logicSection/LogicSection'; } from 'src/graphics/logicSection/LogicSection';
import { LogicSectionData } from './graphics/LogicSectionInteraction'; import {
LogicSectionData,
LogicSectionState,
} from './graphics/LogicSectionInteraction';
import { FederatedMouseEvent } from 'pixi.js'; import { FederatedMouseEvent } from 'pixi.js';
// export function fromStoragePoint(p: graphicData.Point): Point { // export function fromStoragePoint(p: graphicData.Point): Point {
@ -254,7 +257,10 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
new SectionDraw(app, new SectionTemplate(new SectionData())), new SectionDraw(app, new SectionTemplate(new SectionData())),
new LogicSectionDraw( new LogicSectionDraw(
app, app,
new LogicSectionTemplate(new LogicSectionData()) new LogicSectionTemplate(
new LogicSectionData(),
new LogicSectionState()
)
), ),
new TurnoutDraw( new TurnoutDraw(
app, app,

View File

@ -67,7 +67,11 @@ import {
LogicSection, LogicSection,
LogicSectionTemplate, LogicSectionTemplate,
} from 'src/graphics/logicSection/LogicSection'; } from 'src/graphics/logicSection/LogicSection';
import { LogicSectionData } from './graphics/LogicSectionInteraction'; import {
LogicSectionData,
LogicSectionOperationPlugin,
LogicSectionState,
} from './graphics/LogicSectionInteraction';
import { alert } from 'src/protos/alertInfo'; import { alert } from 'src/protos/alertInfo';
import { useLineNetStore } from 'src/stores/line-net-store'; import { useLineNetStore } from 'src/stores/line-net-store';
import { QNotifyUpdateOptions, Notify } from 'quasar'; import { QNotifyUpdateOptions, Notify } from 'quasar';
@ -105,7 +109,7 @@ export function initLineApp(dom: HTMLElement): GraphicApp {
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()),
new LogicSectionTemplate(new LogicSectionData()), new LogicSectionTemplate(new LogicSectionData(), new LogicSectionState()),
new SeparatorTemplate(new SeparatorData()), new SeparatorTemplate(new SeparatorData()),
new AxleCountingTemplate(new AxleCountingData()), new AxleCountingTemplate(new AxleCountingData()),
new TrainWindowTemplate(new TrainWindowData()), new TrainWindowTemplate(new TrainWindowData()),
@ -133,6 +137,7 @@ export function initLineApp(dom: HTMLElement): GraphicApp {
StationOperateInteraction.init(lineApp); StationOperateInteraction.init(lineApp);
TrainOperateInteraction.init(lineApp); TrainOperateInteraction.init(lineApp);
TurnoutOperationPlugin.init(lineApp); TurnoutOperationPlugin.init(lineApp);
LogicSectionOperationPlugin.init(lineApp);
return lineApp; return lineApp;
} }
@ -246,6 +251,9 @@ export async function loadLineDatas(app: GraphicApp) {
storage.switch.forEach((item) => { storage.switch.forEach((item) => {
states.push(new TurnoutStates(item)); states.push(new TurnoutStates(item));
}); });
storage.track.forEach((item) => {
states.push(new LogicSectionState(item));
});
return states; return states;
}, },
}); });

View File

@ -1,6 +1,8 @@
import { Graphics, IPointData } from 'pixi.js'; import { Graphics, IPointData } from 'pixi.js';
import { import {
GraphicAnimation,
GraphicData, GraphicData,
GraphicState,
JlGraphic, JlGraphic,
JlGraphicTemplate, JlGraphicTemplate,
VectorText, VectorText,
@ -17,11 +19,37 @@ export interface ILogicSectionData extends GraphicData {
copyFrom(data: ILogicSectionData): void; copyFrom(data: ILogicSectionData): void;
eq(other: ILogicSectionData): boolean; eq(other: ILogicSectionData): boolean;
} }
export enum LimitType {
Unknown = 0,
//为1时CBTC限速
Cbtc = 1,
//为2时联锁限速
Interlock = 2,
//为4时同时限速。
CbtcInterlock = 4,
}
export interface ILogicSectionState extends GraphicState {
id: string; //设备唯一识别码,一般为设备名称
ciOccupied: boolean; //连锁报告区段占用
cbtcOccupied: boolean; // CBTC报告区段占用
locked: boolean; //锁闭
failLocked: boolean; //故障锁闭
// expectLock: boolean; //进路办理中,期望锁闭
// expectUnlock: boolean; //进路取消中, 期望解除锁闭
// inRoute: boolean; //是否在进路中锁闭, 控制是否需要显示锁闭
cut: boolean; //轨道切除
atcInvalid: boolean; //轨道区段被ATC报告失效
overlap: boolean; // OVERLAP
blocked: boolean; //轨道区段封锁
speedLimit: number; //限速
limitType: LimitType; //限速类型
}
export class LogicSection extends JlGraphic implements ILineGraphic { export class LogicSection extends JlGraphic implements ILineGraphic {
static Type = 'LogicSection'; static Type = 'LogicSection';
lineGraphic: Graphics; lineGraphic: Graphics;
labelGraphic: VectorText; labelGraphic: VectorText;
dt = 0;
constructor() { constructor() {
super(LogicSection.Type); super(LogicSection.Type);
@ -37,9 +65,20 @@ export class LogicSection extends JlGraphic implements ILineGraphic {
this.addChild(this.labelGraphic); this.addChild(this.labelGraphic);
} }
get code(): string {
return this.datas.code;
}
set code(code: string) {
this.datas.code = code;
}
get datas(): ILogicSectionData { get datas(): ILogicSectionData {
return this.getDatas<ILogicSectionData>(); return this.getDatas<ILogicSectionData>();
} }
get states(): ILogicSectionState {
return this.getStates<ILogicSectionState>();
}
get linePoints(): IPointData[] { get linePoints(): IPointData[] {
return this.datas.points; return this.datas.points;
} }
@ -54,11 +93,27 @@ export class LogicSection extends JlGraphic implements ILineGraphic {
throw new Error('Link坐标数据异常'); throw new Error('Link坐标数据异常');
} }
this.lineGraphic.clear(); let lineColor = SectionConsts.idleColor;
this.lineGraphic.lineStyle(
SectionConsts.lineWidth, if (this.states.ciOccupied) {
SectionConsts.lineColor lineColor = SectionConsts.ciOccupiedColor;
); } else if (this.states.cbtcOccupied) {
lineColor = SectionConsts.cbtcOccupiedColor;
} else if (this.states.locked) {
lineColor = SectionConsts.lockedColor;
} else if (this.states.failLocked) {
lineColor = SectionConsts.failLockedColor;
} else if (this.states.blocked) {
lineColor = SectionConsts.blockedColor;
}
if (this.states.cut) {
this.bindFlashAnimation(this.lineGraphic);
this.animation('flash')?.resume();
} else {
this.lineGraphic.visible = true;
this.removeAnimation('flash');
}
this.lineGraphic.clear().lineStyle(SectionConsts.lineWidth, lineColor);
this.datas.points.forEach((p, i) => { this.datas.points.forEach((p, i) => {
if (i !== 0) { if (i !== 0) {
@ -81,13 +136,35 @@ export class LogicSection extends JlGraphic implements ILineGraphic {
); );
} }
} }
bindFlashAnimation(g: Graphics) {
const flashAnimation = GraphicAnimation.init({
name: 'flash',
run: (dt: number) => {
this.dt += dt;
if (this.dt > 60) {
this.dt = 0;
g.visible = true;
} else if (this.dt > 30) {
g.visible = false;
}
},
});
this.addAnimation(flashAnimation);
return flashAnimation;
}
} }
export class LogicSectionTemplate extends JlGraphicTemplate<LogicSection> { export class LogicSectionTemplate extends JlGraphicTemplate<LogicSection> {
constructor(dataTemplate: ILogicSectionData) { constructor(
super(LogicSection.Type, { dataTemplate }); dataTemplate: ILogicSectionData,
stateTemplate: ILogicSectionState
) {
super(LogicSection.Type, { dataTemplate, stateTemplate });
} }
new() { new() {
return new LogicSection(); const g = new LogicSection();
g.loadData(this.datas);
g.loadState(this.states);
return g;
} }
} }

View File

@ -41,7 +41,7 @@ export class LogicSectionDraw extends GraphicDrawAssistant<
} }
} }
class LogicSectionGraphicHitArea implements IHitArea { export class LogicSectionGraphicHitArea implements IHitArea {
section: LogicSection; section: LogicSection;
constructor(section: LogicSection) { constructor(section: LogicSection) {
this.section = section; this.section = section;

View File

@ -53,6 +53,12 @@ export interface ISectionData extends GraphicData {
export const SectionConsts = { export const SectionConsts = {
lineColor: '#5578b6', lineColor: '#5578b6',
idleColor: '#888', //空闲
ciOccupiedColor: '#f00', //非通信车占用
cbtcOccupiedColor: '#f49', //通信车占用
lockedColor: '#fff', //锁闭
failLockedColor: '#954', //故障锁闭
blockedColor: '#606', //封锁
lineWidth: 5, lineWidth: 5,
}; };

View File

@ -43,6 +43,7 @@ export interface ITurnoutData extends GraphicData {
export const TurnoutConsts = { export const TurnoutConsts = {
lineColor: '#5578b6', lineColor: '#5578b6',
idleColor: '#888', //空闲
jammedLineColor: '#f00', //挤岔 jammedLineColor: '#f00', //挤岔
ciOccupiedColor: '#f00', //非通信车占用 ciOccupiedColor: '#f00', //非通信车占用
cbtcOccupiedColor: '#f49', //通信车占用 cbtcOccupiedColor: '#f49', //通信车占用
@ -295,6 +296,8 @@ export class Turnout extends JlGraphic {
this.lineColor = TurnoutConsts.lockedColor; this.lineColor = TurnoutConsts.lockedColor;
} else if (this.states.ipSingleSwitchStusFailLocked) { } else if (this.states.ipSingleSwitchStusFailLocked) {
this.lineColor = TurnoutConsts.failLockedColor; this.lineColor = TurnoutConsts.failLockedColor;
} else {
this.lineColor = TurnoutConsts.idleColor;
} }
this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint()); this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint());

@ -1 +1 @@
Subproject commit ec5889fd030d15bc93efdaf8f73d62039bde31a9 Subproject commit 605c24f4e3de26b317bce2b644efa83d69c63475