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

This commit is contained in:
Yuan 2023-06-19 17:18:38 +08:00
commit 98f768cc9f
24 changed files with 654 additions and 322 deletions

@ -1 +1 @@
Subproject commit ff5ed78027861c0af12c5bcfb8c073e362d282b0
Subproject commit 533ebdc9a89ac1e2a6e5d9f3fbdc98c9f7d416c8

View File

@ -59,3 +59,11 @@ export async function pageQuery(
export function deletePublish(id: number) {
return api.delete(`${PublishUriBase}/${id}`);
}
/**
*
* @param id id
*/
export async function getPublishMapInfoById(id: number): Promise<Item> {
const response = await api.get(`${PublishUriBase}/${id}`);
return response.data;
}

View File

@ -16,57 +16,37 @@
lazy-rules
autogrow
/>
<div>
<q-input
outlined
label="生成车次窗数量"
v-model.number="generateParams.count"
type="number"
:rules="[(val) => val > 0 || '生成数量需要大于0']"
/>
<q-input
outlined
label="车次窗间隔"
v-model.number="generateParams.interval"
type="number"
hint=""
/>
<q-list bordered class="rounded-borders">
<q-item-label header>生成方向</q-item-label>
<q-item>
<q-item-section no-wrap>
<div class="q-gutter-sm">
<q-radio v-model="generateParams.pd" :val="0" label="左侧" />
<q-radio v-model="generateParams.pd" :val="1" label="右侧" />
</div>
</q-item-section>
</q-item>
</q-list>
<q-card-actions align="right">
<q-btn color="primary" label="生成" @click="onCreateTw" />
<q-btn label="取消" @click="redset" />
</q-card-actions>
</div>
<q-list bordered separator class="rounded-borders">
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
<q-item-label> 关联的区段 </q-item-label>
<div class="q-gutter-sm row">
<q-chip
v-for="item in relatedProcessPositions"
:key="item.id"
square
color="primary"
text-color="white"
>
{{ item.id }}
</q-chip>
</div>
</q-item-section>
</q-item>
</q-list>
</q-form>
</template>
<script setup lang="ts">
import { TrainWindowData } from 'src/drawApp/graphics/TrainWindowInteraction';
import { Section } from 'src/graphics/section/Section';
import { TrainWindow } from 'src/graphics/trainWindow/TrainWindow';
import {
GenerateParams,
TrainWindowDraw,
} from 'src/graphics/trainWindow/TrainWindowDrawAssistant';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
import { computed, onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const trainWindowModel = reactive(new TrainWindowData());
const generateParams = reactive({
count: 1,
interval: 5,
pd: 1,
});
drawStore.$subscribe;
watch(
@ -94,24 +74,13 @@ function onUpdate() {
}
}
function onCreateTw() {
if (generateParams.count <= 0) {
return;
const relatedProcessPositions = computed((): Section[] => {
if (
drawStore.selectedGraphic &&
drawStore.selectedGraphic.type === 'TrainWindow'
) {
return (drawStore.selectedGraphic as TrainWindow).getRelatedSections();
}
let params: GenerateParams = new GenerateParams(
generateParams.count,
generateParams.interval,
generateParams.pd > 0 ? true : false
);
const trainWindowDraw = drawStore
.getDrawApp()
.getDrawAssistant(TrainWindow.Type) as TrainWindowDraw;
trainWindowDraw.generates(drawStore.selectedGraphic as TrainWindow, params);
}
function redset() {
generateParams.count = 1;
generateParams.interval = 5;
generateParams.pd = 1;
}
return [];
});
</script>

View File

@ -2,7 +2,20 @@ import * as pb_1 from 'google-protobuf';
import { IRunLineData, RunLine } from 'src/graphics/runLine/RunLine';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { IPointData } from 'pixi.js';
import {
GraphicInteractionPlugin,
GraphicApp,
JlGraphic,
} from 'src/jl-graphic';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { FederatedMouseEvent, DisplayObject, IPointData } from 'pixi.js';
import {
addWayPoint,
addWaypointConfig,
clearWayPoint,
clearWaypointsConfig,
getWaypointRangeIndex,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
export class RunLineData extends GraphicDataBase implements IRunLineData {
constructor(data?: graphicData.RunLine) {
@ -67,3 +80,52 @@ export class RunLineData extends GraphicDataBase implements IRunLineData {
return pb_1.Message.equals(this.data, other.data);
}
}
const RunLineEditMenu: ContextMenu = ContextMenu.init({
name: '运行线编辑菜单',
groups: [
{
items: [addWaypointConfig, clearWaypointsConfig],
},
],
});
export class DrawRunLinePlugin extends GraphicInteractionPlugin<RunLine> {
static Name = 'runline_draw_right_menu';
constructor(app: GraphicApp) {
super(DrawRunLinePlugin.Name, app);
app.registerMenu(RunLineEditMenu);
}
static init(app: GraphicApp) {
return new DrawRunLinePlugin(app);
}
filter(...grahpics: JlGraphic[]): RunLine[] | undefined {
return grahpics
.filter((g) => g.type === RunLine.Type)
.map((g) => g as RunLine);
}
bind(g: RunLine): void {
g.on('_rightclick', this.onContextMenu, this);
}
unbind(g: RunLine): void {
g.off('_rightclick', this.onContextMenu, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const runLine = target.getGraphic() as RunLine;
this.app.updateSelected(runLine);
addWaypointConfig.handler = () => {
const linePoints = runLine.linePoints;
const p = runLine.screenToLocalPoint(e.global);
const { start, end } = getWaypointRangeIndex(linePoints, false, p);
addWayPoint(runLine, false, start, end, p);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(runLine, false);
};
RunLineEditMenu.open(e.global);
}
}

View File

@ -2,6 +2,14 @@ import * as pb_1 from 'google-protobuf';
import { ISignalData, Signal } from 'src/graphics/signal/Signal';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import {
GraphicInteractionPlugin,
GraphicApp,
JlGraphic,
} from 'src/jl-graphic';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { FederatedMouseEvent, DisplayObject } from 'pixi.js';
export class SignalData extends GraphicDataBase implements ISignalData {
constructor(data?: graphicData.Signal) {
@ -40,3 +48,98 @@ export class SignalData extends GraphicDataBase implements ISignalData {
return pb_1.Message.equals(this.data, other.data);
}
}
const mirrorFlipConfig: MenuItemOptions = {
name: '镜像翻转',
};
const SignalEditMenu: ContextMenu = ContextMenu.init({
name: '信号机编辑菜单',
groups: [
{
items: [mirrorFlipConfig],
},
],
});
const signalCloseConfig: MenuItemOptions = {
name: '信号机关闭',
};
const signalOpenConfig: MenuItemOptions = {
name: '信号机开放',
};
const SignalOperateMenu: ContextMenu = ContextMenu.init({
name: '信号机操作菜单',
groups: [
{
items: [signalCloseConfig, signalOpenConfig],
},
],
});
export class DrawSignalInteraction extends GraphicInteractionPlugin<Signal> {
static Name = 'signal_draw_right_menu';
constructor(app: GraphicApp) {
super(DrawSignalInteraction.Name, app);
app.registerMenu(SignalEditMenu);
}
static init(app: GraphicApp) {
return new DrawSignalInteraction(app);
}
filter(...grahpics: JlGraphic[]): Signal[] | undefined {
return grahpics
.filter((g) => g.type === Signal.Type)
.map((g) => g as Signal);
}
bind(g: Signal): void {
g.on('_rightclick', this.onContextMenu, this);
}
unbind(g: Signal): void {
g.off('_rightclick', this.onContextMenu, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const signal = target.getGraphic() as Signal;
this.app.updateSelected(signal);
mirrorFlipConfig.handler = () => {
signal.mirror = !signal.mirror;
};
SignalEditMenu.open(e.global);
}
}
export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
static Name = 'signal_operate_menu';
constructor(app: GraphicApp) {
super(SignalOperateInteraction.Name, app);
app.registerMenu(SignalOperateMenu);
}
static init(app: GraphicApp) {
return new SignalOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): Signal[] | undefined {
return grahpics
.filter((g) => g.type === Signal.Type)
.map((g) => g as Signal);
}
bind(g: Signal): void {
g.on('_rightclick', this.onContextMenu, this);
}
unbind(g: Signal): void {
g.off('_rightclick', this.onContextMenu, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const signal = target.getGraphic() as Signal;
this.app.updateSelected(signal);
signalCloseConfig.handler = () => {
console.log('关灯');
};
signalOpenConfig.handler = () => {
console.log('开灯');
};
SignalOperateMenu.open(e.global);
}
}

View File

@ -31,6 +31,12 @@ export class TrainWindowData
set code(v: string) {
this.data.code = v;
}
get sectionId(): string {
return this.data.sectionId;
}
set sectionId(v: string) {
this.data.sectionId = v;
}
clone(): TrainWindowData {
return new TrainWindowData(this.data.cloneMessage());
}

View File

@ -20,7 +20,10 @@ import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { IscsFanData } from './graphics/IscsFanInteraction';
import { LinkData } from './graphics/LinkInteraction';
import { TrainData } from './graphics/TrainInteraction';
import { SignalData } from './graphics/SignalInteraction';
import {
SignalData,
DrawSignalInteraction,
} from './graphics/SignalInteraction';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { Rect } from 'src/graphics/rect/Rect';
import { RectDraw } from 'src/graphics/rect/RectDrawAssistant';
@ -48,14 +51,14 @@ import { TurnoutDraw } from 'src/graphics/turnout/TurnoutDrawAssistant';
import { TurnoutData } from './graphics/TurnoutInteraction';
import { RunLine } from 'src/graphics/runLine/RunLine';
import { RunLineDraw } from 'src/graphics/runLine/RunLineDrawAssistant';
import { RunLineData } from './graphics/RunLineInteraction';
import { RunLineData, DrawRunLinePlugin } from './graphics/RunLineInteraction';
import { saveDraft, getDraft } from 'src/api/DraftApi';
import { useDrawStore } from 'src/stores/draw-store';
import { successNotify, errorNotify } from '../utils/CommonNotify';
import { Section } from 'src/graphics/section/Section';
import { SectionDraw } from 'src/graphics/section/SectionDrawAssistant';
import { SectionData } from './graphics/SectionInteraction';
import { PathLine } from 'src/graphics/pathLine/PathLine';
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';
@ -169,6 +172,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
return new TrainWindowData();
}),
];
DrawSignalInteraction.init(app);
} else {
drawAssistants = [
new StationLineDraw(app, () => {
@ -187,6 +191,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
return new PathLineData();
}),
];
DrawRunLinePlugin.init(app);
}
app.setOptions({ drawAssistants: drawAssistants });

View File

@ -1,7 +1,10 @@
import { GraphicApp, GraphicData } from 'src/jl-graphic';
import { TrainData } from './graphics/TrainInteraction';
import { TrainTemplate } from 'src/graphics/train/Train';
import { SignalData } from './graphics/SignalInteraction';
import {
SignalData,
SignalOperateInteraction,
} from './graphics/SignalInteraction';
import { SignalTemplate } from 'src/graphics/signal/Signal';
import { PlatformData } from './graphics/PlatformInteraction';
import { PlatformTemplate } from 'src/graphics/platform/Platform';
@ -11,7 +14,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 { getDraft } from 'src/api/DraftApi';
import { getPublishMapInfoById } from 'src/api/PublishApi';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useLineStore } from 'src/stores/line-store';
import { toUint8Array } from 'js-base64';
@ -41,17 +44,18 @@ export function initLineApp(dom: HTMLElement): GraphicApp {
new SectionTemplate(),
];
lineApp.registerGraphicTemplates(...graphicTemplate);
SignalOperateInteraction.init(lineApp);
return lineApp;
}
export async function loadLineDatas(app: GraphicApp) {
const lineStore = useLineStore();
const id = lineStore.lineId;
console.log(id, '***********');
if (!id) {
return;
}
const { proto: base64 } = await getDraft(id);
const { proto: base64, name: lineName } = await getPublishMapInfoById(id);
lineStore.setLineName(lineName);
if (base64) {
const storage = graphicData.RtssGraphicStorage.deserialize(
toUint8Array(base64)
@ -78,7 +82,14 @@ export async function loadLineDatas(app: GraphicApp) {
storage.section.forEach((section) => {
datas.push(new SectionData(section));
});
app.loadGraphic(datas);
await app.loadGraphic(datas);
app.setOptions({
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
wheelZoom: true,
},
});
} else {
app.loadGraphic([]);
}

88
src/drawApp/lineNetApp.ts Normal file
View File

@ -0,0 +1,88 @@
import { GraphicApp, GraphicData } from 'src/jl-graphic';
import { getPublishMapInfoById } from 'src/api/PublishApi';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { RunLineTemplate } from 'src/graphics/runLine/RunLine';
import { RunLineData } from './graphics/RunLineInteraction';
import { PathLineTemplate, PathLine } from 'src/graphics/pathLine/PathLine';
import { PathLineData } from './graphics/PathLineInteraction';
import { StationLineTemplate } from 'src/graphics/stationLine/StationLine';
import { StationLineData } from './graphics/StationLineInteraction';
import { ItrainLineTemplate } from 'src/graphics/trainLine/TrainLine';
import { TrainLineData } from './graphics/TrainLineInteraction';
import { useLineNetStore } from 'src/stores/line-net-store';
import { toUint8Array } from 'js-base64';
let lineNetApp: GraphicApp | null = null;
export function getLineNetApp(): GraphicApp | null {
return lineNetApp;
}
export function destroyLineNetApp(): void {
if (lineNetApp) {
lineNetApp.destroy();
lineNetApp = null;
}
}
export function initLineNetApp(dom: HTMLElement): GraphicApp {
lineNetApp = new GraphicApp(dom);
const graphicTemplate = [
new RunLineTemplate(),
new PathLineTemplate(),
new StationLineTemplate(),
new ItrainLineTemplate(),
];
lineNetApp.registerGraphicTemplates(...graphicTemplate);
return lineNetApp;
}
export async function loadLineNetDatas(app: GraphicApp) {
const lineNetStore = useLineNetStore();
const id = lineNetStore.lineNetId;
if (!id) {
return;
}
const { proto: base64, name: lineNetName } = await getPublishMapInfoById(id);
lineNetStore.setLineNetName(lineNetName);
if (base64) {
const storage = graphicData.RtssGraphicStorage.deserialize(
toUint8Array(base64)
);
console.log('加载数据', storage);
app.updateCanvas(storage.canvas);
const datas: GraphicData[] = [];
storage.runLines.forEach((runLines) => {
const g = new RunLineData(runLines);
datas.push(g);
});
storage.pathLines.forEach((pathLine) => {
const g = new PathLineData(pathLine);
datas.push(g);
});
storage.stationLines.forEach((stationLine) => {
const g = new StationLineData(stationLine);
datas.push(g);
});
storage.trainLines.forEach((trainLine) => {
const g = new TrainLineData(trainLine);
datas.push(g);
});
await app.loadGraphic(datas);
app.setOptions({
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
wheelZoom: true,
},
});
const pathLineList = app.queryStore.queryByType(PathLine.Type);
pathLineList.forEach((pathLine) => {
pathLine.visible = false;
});
} else {
app.loadGraphic([]);
}
}

View File

@ -1,34 +1,6 @@
import {
GraphicDrawAssistant,
JlDrawApp,
JlGraphic,
GraphicInteractionPlugin,
linePoint,
GraphicApp,
} from 'src/jl-graphic';
import {
IPathLineData,
PathLine,
PathLineTemplate,
pathLineConsts,
} from './PathLine';
import {
PolylineEditPlugin,
addWayPoint,
addWaypointConfig,
clearWayPoint,
clearWaypointsConfig,
getWaypointRangeIndex,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
import {
FederatedPointerEvent,
Point,
Graphics,
LINE_JOIN,
IHitArea,
DisplayObject,
FederatedMouseEvent,
} from 'pixi.js';
import { GraphicDrawAssistant, JlDrawApp } from 'src/jl-graphic';
import { IPathLineData, PathLineTemplate } from './PathLine';
import { Point, Graphics, LINE_JOIN } from 'pixi.js';
export interface IPathLineDrawOptions {
newData: () => IPathLineData;
@ -50,7 +22,7 @@ export class PathLineDraw extends GraphicDrawAssistant<
'不展示'
);
this.container.addChild(this.graphic);
PathLinePointsEditPlugin.init(app);
// PathLinePointsEditPlugin.init(app);
}
clearCache(): void {
this.points = [];
@ -94,84 +66,66 @@ export class PathLineDraw extends GraphicDrawAssistant<
}
}
export class PathLineGraphicHitArea implements IHitArea {
pathLine: PathLine;
constructor(pathLine: PathLine) {
this.pathLine = pathLine;
}
contains(x: number, y: number): boolean {
const p = new Point(x, y);
for (let i = 1; i < this.pathLine.datas.points.length; i++) {
const p1 = this.pathLine.datas.points[i - 1];
const p2 = this.pathLine.datas.points[i];
if (linePoint(p1, p2, p, pathLineConsts.pathLineWidth)) {
return true;
}
}
return false;
}
}
// export class PathLineGraphicHitArea implements IHitArea {
// pathLine: PathLine;
// constructor(pathLine: PathLine) {
// this.pathLine = pathLine;
// }
// contains(x: number, y: number): boolean {
// const p = new Point(x, y);
// for (let i = 1; i < this.pathLine.datas.points.length; i++) {
// const p1 = this.pathLine.datas.points[i - 1];
// const p2 = this.pathLine.datas.points[i];
// if (linePoint(p1, p2, p, pathLineConsts.pathLineWidth)) {
// return true;
// }
// }
// return false;
// }
// }
export class PathLinePointsEditPlugin extends GraphicInteractionPlugin<PathLine> {
static Name = 'LinkPointsDrag';
constructor(app: GraphicApp) {
super(PathLinePointsEditPlugin.Name, app);
}
static init(app: GraphicApp): PathLinePointsEditPlugin {
return new PathLinePointsEditPlugin(app);
}
filter(...grahpics: JlGraphic[]): PathLine[] | undefined {
return grahpics.filter((g) => g.type == PathLine.Type) as PathLine[];
}
bind(g: PathLine): void {
g.pathLine.eventMode = 'static';
g.pathLine.cursor = 'pointer';
g.pathLine.hitArea = new PathLineGraphicHitArea(g);
g.on('_rightclick', this.onContextMenu, this);
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnselected, this);
}
unbind(g: PathLine): void {
g.off('_rightclick', this.onContextMenu, this);
g.off('selected', this.onSelected, this);
g.off('unselected', this.onUnselected, this);
}
// export class PathLinePointsEditPlugin extends GraphicInteractionPlugin<PathLine> {
// static Name = 'LinkPointsDrag';
// constructor(app: GraphicApp) {
// super(PathLinePointsEditPlugin.Name, app);
// }
// static init(app: GraphicApp): PathLinePointsEditPlugin {
// return new PathLinePointsEditPlugin(app);
// }
// filter(...grahpics: JlGraphic[]): PathLine[] | undefined {
// return grahpics.filter((g) => g.type == PathLine.Type) as PathLine[];
// }
// bind(g: PathLine): void {
// g.pathLine.eventMode = 'static';
// g.pathLine.cursor = 'pointer';
// g.pathLine.hitArea = new PathLineGraphicHitArea(g);
// g.on('selected', this.onSelected, this);
// g.on('unselected', this.onUnselected, this);
// }
// unbind(g: PathLine): void {
// g.off('selected', this.onSelected, this);
// g.off('unselected', this.onUnselected, this);
// }
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const runLine = target.getGraphic() as PathLine;
this.app.updateSelected(runLine);
addWaypointConfig.handler = () => {
const linePoints = runLine.linePoints;
const p = runLine.screenToLocalPoint(e.global);
const { start, end } = getWaypointRangeIndex(linePoints, false, p);
addWayPoint(runLine, false, start, end, p);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(runLine, false);
};
}
onSelected(g: DisplayObject): void {
const runLine = g as PathLine;
let lep;
lep = runLine.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (!lep) {
lep = new PolylineEditPlugin(runLine);
runLine.addAssistantAppend(lep);
}
lep.showAll();
}
onUnselected(g: DisplayObject): void {
const runLine = g as PathLine;
const lep = runLine.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (lep) {
lep.hideAll();
}
}
}
// onSelected(g: DisplayObject): void {
// const runLine = g as PathLine;
// let lep;
// lep = runLine.getAssistantAppend<PolylineEditPlugin>(
// PolylineEditPlugin.Name
// );
// if (!lep) {
// lep = new PolylineEditPlugin(runLine);
// runLine.addAssistantAppend(lep);
// }
// lep.showAll();
// }
// onUnselected(g: DisplayObject): void {
// const runLine = g as PathLine;
// const lep = runLine.getAssistantAppend<PolylineEditPlugin>(
// PolylineEditPlugin.Name
// );
// if (lep) {
// lep.hideAll();
// }
// }
// }

View File

@ -1,5 +1,7 @@
import { FederatedPointerEvent, Point } from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
GraphicDrawAssistant,
GraphicInteractionPlugin,
JlDrawApp,
@ -67,6 +69,22 @@ export class PlatformDraw extends GraphicDrawAssistant<
}
}
function buildAbsorbablePositions(platform: Platform): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const platforms = platform.queryStore.queryByType<Platform>(Platform.Type);
const { width, height } = platform.getGraphicApp().canvas;
platforms.forEach((other) => {
if (other.id == platform.id) {
return;
}
const ps = other.datas.transform.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 platformInteraction extends GraphicInteractionPlugin<Platform> {
static Name = 'platform_transform';
constructor(app: JlDrawApp) {
@ -85,10 +103,18 @@ export class platformInteraction extends GraphicInteractionPlugin<Platform> {
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
g.on('selected', this.onSelected, this);
}
unbind(g: Platform): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
g.off('selected', this.onSelected, this);
}
onSelected(): void {
const platform = this.app.selectedGraphics[0] as Platform;
this.app.setOptions({
absorbablePositions: buildAbsorbablePositions(platform),
});
}
}

View File

@ -17,11 +17,6 @@ import {
} from './RunLine';
import {
PolylineEditPlugin,
addWayPoint,
addWaypointConfig,
clearWayPoint,
clearWaypointsConfig,
getWaypointRangeIndex,
ILineGraphic,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
import {
@ -31,9 +26,7 @@ import {
LINE_JOIN,
IHitArea,
DisplayObject,
FederatedMouseEvent,
} from 'pixi.js';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { AbsorbableLine } from 'src/jl-graphic/graphic/AbsorbablePosition';
export interface IRunLineDrawOptions {
@ -173,20 +166,10 @@ function onEditPointCreate(
});
}
const RunLineEditMenu: ContextMenu = ContextMenu.init({
name: '运行线编辑菜单',
groups: [
{
items: [addWaypointConfig, clearWaypointsConfig],
},
],
});
export class RunLinePointsEditPlugin extends GraphicInteractionPlugin<RunLine> {
static Name = 'LinkPointsDrag';
constructor(app: GraphicApp) {
super(RunLinePointsEditPlugin.Name, app);
app.registerMenu(RunLineEditMenu);
}
static init(app: GraphicApp): RunLinePointsEditPlugin {
return new RunLinePointsEditPlugin(app);
@ -211,7 +194,6 @@ export class RunLinePointsEditPlugin extends GraphicInteractionPlugin<RunLine> {
g.rightRunLineName.eventMode = 'static';
g.rightRunLineName.cursor = 'pointer';
g.lineBody.hitArea = new RunLineGraphicHitArea(g);
g.on('_rightclick', this.onContextMenu, this);
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnselected, this);
}
@ -228,28 +210,10 @@ export class RunLinePointsEditPlugin extends GraphicInteractionPlugin<RunLine> {
g.rightRunLineName.transformSave = false;
g.rightRunLineName.eventMode = 'none';
g.off('_rightclick', this.onContextMenu, this);
g.off('selected', this.onSelected, this);
g.off('unselected', this.onUnselected, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const runLine = target.getGraphic() as RunLine;
this.app.updateSelected(runLine);
addWaypointConfig.handler = () => {
const linePoints = runLine.linePoints;
const p = runLine.screenToLocalPoint(e.global);
const { start, end } = getWaypointRangeIndex(linePoints, false, p);
addWayPoint(runLine, false, start, end, p);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(runLine, false);
};
RunLineEditMenu.open(e.global);
}
onSelected(g: DisplayObject): void {
const runLine = g as RunLine;
let lep;

View File

@ -73,7 +73,6 @@ export class Signal extends JlGraphic {
if (mirror) {
hmp = calculateMirrorPoint(new Point(0, 0), hmp);
}
console.log(hmp, 'hmp');
this.humanControl.drawRegularPolygon(
hmp.x,
hmp.y,
@ -92,7 +91,6 @@ export class Signal extends JlGraphic {
if (mirror) {
lmp = calculateMirrorPoint(new Point(0, 0), lmp);
}
console.log(lmp, 'hmp');
drawArrow(
this.fleetMode,
lmp.x,

View File

@ -1,9 +1,4 @@
import {
DisplayObject,
FederatedMouseEvent,
FederatedPointerEvent,
Point,
} from 'pixi.js';
import { DisplayObject, FederatedPointerEvent, Point } from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
@ -13,8 +8,7 @@ import {
JlDrawApp,
JlGraphic,
} from 'src/jl-graphic';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ISignalData, Signal, SignalTemplate } from './Signal';
export interface ISignalDrawOptions {
@ -48,9 +42,6 @@ export class SignalDraw extends GraphicDrawAssistant<
return this._signal;
}
clearCache(): void {
//this.codeGraph.clear();
}
onRightClick(): void {
this.createAndStore(true);
}
@ -94,23 +85,11 @@ function buildAbsorbablePositions(signal: Signal): AbsorbablePosition[] {
return aps;
}
// MenuItemOptions
const mirrorFlipConfig: MenuItemOptions = {
name: '镜像翻转',
};
const SignalEditMenu: ContextMenu = ContextMenu.init({
name: '信号机编辑菜单',
groups: [
{
items: [mirrorFlipConfig],
},
],
});
export class signalInteraction extends GraphicInteractionPlugin<Signal> {
static Name = 'signal_transform';
constructor(app: JlDrawApp) {
super(signalInteraction.Name, app);
app.registerMenu(SignalEditMenu);
}
static init(app: JlDrawApp) {
return new signalInteraction(app);
@ -126,7 +105,6 @@ export class signalInteraction extends GraphicInteractionPlugin<Signal> {
g.scalable = true;
g.rotatable = true;
g.on('transformstart', this.transformstart, this);
g.on('_rightclick', this.onContextMenu, this);
g.codeGraph.draggable = true;
g.codeGraph.selectable = true;
g.codeGraph.rotatable = true;
@ -139,7 +117,6 @@ export class signalInteraction extends GraphicInteractionPlugin<Signal> {
g.scalable = false;
g.rotatable = false;
g.off('transformstart', this.transformstart, this);
g.off('_rightclick', this.onContextMenu, this);
g.codeGraph.draggable = false;
g.codeGraph.selectable = false;
g.codeGraph.rotatable = false;
@ -153,14 +130,4 @@ export class signalInteraction extends GraphicInteractionPlugin<Signal> {
absorbablePositions: buildAbsorbablePositions(signal),
});
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const signal = target.getGraphic() as Signal;
this.app.updateSelected(signal);
mirrorFlipConfig.handler = () => {
signal.mirror = !signal.mirror;
// signal.doRepaint();
};
SignalEditMenu.open(e.global);
}
}

View File

@ -1,5 +1,7 @@
import { FederatedPointerEvent, Point } from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
GraphicDrawAssistant,
GraphicInteractionPlugin,
JlDrawApp,
@ -54,6 +56,21 @@ export class StationDraw extends GraphicDrawAssistant<
}
}
function buildAbsorbablePositions(station: Station): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const stations = station.queryStore.queryByType<Station>(Station.Type);
const { width } = station.getGraphicApp().canvas;
stations.forEach((other) => {
if (other.id == station.id) {
return;
}
const ps = other.datas.transform.position;
const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y });
aps.push(xs);
});
return aps;
}
export class stationInteraction extends GraphicInteractionPlugin<Station> {
static Name = 'station_transform';
constructor(app: JlDrawApp) {
@ -82,6 +99,7 @@ export class stationInteraction extends GraphicInteractionPlugin<Station> {
g.kilometerGraph.draggable = true;
g.kilometerGraph.selectable = true;
g.kilometerGraph.transformSave = true;
g.on('selected', this.onSelected, this);
}
unbind(g: Station): void {
g.eventMode = 'none';
@ -95,5 +113,12 @@ export class stationInteraction extends GraphicInteractionPlugin<Station> {
g.kilometerGraph.draggable = false;
g.kilometerGraph.selectable = false;
g.kilometerGraph.transformSave = false;
g.off('selected', this.onSelected, this);
}
onSelected(): void {
const station = this.app.selectedGraphics[0] as Station;
this.app.setOptions({
absorbablePositions: buildAbsorbablePositions(station),
});
}
}

View File

@ -1,14 +1,18 @@
import { Color, Graphics, Rectangle } from 'pixi.js';
import {
GraphicData,
GraphicRelationParam,
JlGraphic,
JlGraphicTemplate,
getRectangleCenter,
} from 'src/jl-graphic';
import { Section } from '../section/Section';
export interface ITrainWindowData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get sectionId(): string; // 编号
set sectionId(v: string);
clone(): ITrainWindowData;
copyFrom(data: ITrainWindowData): void;
eq(other: ITrainWindowData): boolean;
@ -19,6 +23,7 @@ export const TrainWindowConsts = {
height: 15,
lineWidth: 2,
lineColor: '0x0fe81f',
offsetSection: 60,
};
export class TrainWindow extends JlGraphic {
@ -52,6 +57,23 @@ export class TrainWindow extends JlGraphic {
);
rectGraphic.pivot = getRectangleCenter(rectP);
}
loadRealtions(): void {
const sectionId = this.datas.sectionId;
if (sectionId) {
const section = this.queryStore.queryById<Section>(sectionId);
if (section) {
this.relationManage.addRelation(
this,
new GraphicRelationParam(section, section.datas.id)
);
}
}
}
getRelatedSections(): Section[] {
return this.queryRelationByType('Section').map((rl) =>
rl.getOtherGraphic<Section>(this)
);
}
}
export class TrainWindowTemplate extends JlGraphicTemplate<TrainWindow> {

View File

@ -16,6 +16,7 @@ import {
TrainWindowTemplate,
TrainWindowConsts,
} from './TrainWindow';
import { Section } from '../section/Section';
export interface ITrainWindowDrawOptions {
newData: () => ITrainWindowData;
@ -38,13 +39,7 @@ export class TrainWindowDraw extends GraphicDrawAssistant<
> {
trainWindowGraph: TrainWindow;
constructor(app: JlDrawApp, createData: () => ITrainWindowData) {
super(
app,
new TrainWindowTemplate(),
createData,
'sym_o_square',
'车次窗TrainWindow'
);
super(app, new TrainWindowTemplate(), createData, 'sym_o_square', '不展示');
this.trainWindowGraph = this.graphicTemplate.new();
this.container.addChild(this.trainWindowGraph);
TrainWindowInteraction.init(app);
@ -99,6 +94,29 @@ export class TrainWindowDraw extends GraphicDrawAssistant<
}
this.storeGraphic(...trainWindows);
}
oneGenerates() {
const sections = this.app.queryStore.queryByType<Section>(Section.Type);
const trainWindowAll = this.app.queryStore.queryByType<TrainWindow>(
TrainWindow.Type
);
this.app.deleteGraphics(...trainWindowAll);
sections.forEach((section) => {
const points = section.datas.points;
for (let i = 0; i < points.length - 1; i++) {
const x = (points[i].x + points[i + 1].x) / 2;
const trainWindow = new TrainWindow();
trainWindow.loadData(this.createGraphicData());
trainWindow.position.set(
x,
points[i].y - TrainWindowConsts.offsetSection
);
trainWindow.id = GraphicIdGenerator.next();
trainWindow.datas.sectionId = section.id;
this.storeGraphic(trainWindow);
trainWindow.loadRealtions();
}
});
}
}
//碰撞检测
@ -150,7 +168,6 @@ function buildAbsorbablePositions(
export class TrainWindowInteraction extends GraphicInteractionPlugin<TrainWindow> {
static Name = 'TrainWindow_transform';
static trainWindow: TrainWindow;
constructor(app: JlDrawApp) {
super(TrainWindowInteraction.Name, app);
}
@ -163,7 +180,6 @@ export class TrainWindowInteraction extends GraphicInteractionPlugin<TrainWindow
.map((g) => g as TrainWindow);
}
bind(g: TrainWindow): void {
TrainWindowInteraction.trainWindow = g;
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
@ -175,12 +191,12 @@ export class TrainWindowInteraction extends GraphicInteractionPlugin<TrainWindow
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
g.off('selected', this.onSelected, this);
}
onSelected(): void {
const trainWindow = this.app.selectedGraphics[0] as TrainWindow;
this.app.setOptions({
absorbablePositions: buildAbsorbablePositions(
TrainWindowInteraction.trainWindow
),
absorbablePositions: buildAbsorbablePositions(trainWindow),
});
}
}

View File

@ -9,8 +9,19 @@ import type { GraphicApp } from '../app/JlGraphicApp';
import { GraphicState } from '../core/JlGraphic';
export interface StompCliOption {
wsUrl: string; // websocket url
token: string; // 认证token
/**
* websocket url地址
*/
wsUrl: string;
/**
* token
*/
token?: string;
/**
*
* @returns
*/
onAuthenticationFailed?: () => void;
reconnectDelay?: number; // 重连延时默认3秒
heartbeatIncoming?: number; // 服务端过来的心跳间隔默认30秒
heartbeatOutgoing?: number; // 到服务端的心跳间隔默认30秒
@ -32,7 +43,7 @@ export class StompCli {
private static connected = false;
static new(options: StompCliOption) {
if (StompCli.enabled) {
// 以及启用
// 已经启用
return;
// throw new Error('websocket 已连接若确实需要重新连接请先断开StompCli.close再重新StompCli.new')
}
@ -41,12 +52,8 @@ export class StompCli {
StompCli.client = new StompClient({
brokerURL: StompCli.options.wsUrl,
connectHeaders: {
Authorization: StompCli.options.token,
// Authorization: ''
Authorization: StompCli.options.token ? StompCli.options.token : '',
},
// debug: (str) => {
// console.log(str)
// }
reconnectDelay: StompCli.options.reconnectDelay,
heartbeatIncoming: StompCli.options.heartbeatIncoming,
heartbeatOutgoing: StompCli.options.heartbeatOutgoing,
@ -61,19 +68,21 @@ export class StompCli {
};
StompCli.client.onStompError = (frame: Frame) => {
console.error(
'Stomp收到error消息,可能是认证失败(暂时没有判断具体错误类型,后需添加判断),关闭Stomp客户端',
frame
);
StompCli.close();
const errMsg = frame.headers['message'];
if (errMsg === '401') {
console.warn('认证失败,断开WebSocket连接');
StompCli.close();
if (StompCli.options.onAuthenticationFailed) {
StompCli.options.onAuthenticationFailed();
}
} else {
console.error('收到Stomp错误消息', frame);
}
};
StompCli.client.onDisconnect = (frame: Frame) => {
console.log('Stomp 断开连接', frame);
StompCli.connected = false;
// StompCli.appMsgBroker.forEach(broker => {
// broker.close();
// });
};
StompCli.client.onWebSocketClose = (evt: CloseEvent) => {
console.log('websocket 关闭', evt);
@ -82,9 +91,6 @@ export class StompCli {
// websocket错误处理
StompCli.client.onWebSocketError = (err: Event) => {
console.log('websocket错误', err);
// StompCli.appMsgBroker.forEach(broker => {
// broker.unsbuscribeAll();
// });
};
StompCli.client.activate();
@ -140,19 +146,10 @@ export class StompCli {
// 状态订阅消息转换器
export type MessageConverter = (message: Uint8Array) => GraphicState[];
// 图形app状态订阅
export class AppStateSubscription {
export interface AppStateSubscription {
destination: string;
messageConverter: MessageConverter;
subscription?: StompSubscription; // 订阅成功对象,用于取消订阅
constructor(
destination: string,
messageConverter: MessageConverter,
subscription?: StompSubscription
) {
this.destination = destination;
this.messageConverter = messageConverter;
this.subscription = subscription;
}
}
/**

View File

@ -15,6 +15,9 @@
<q-item clickable v-close-popup @click="buildRelations">
<q-item-section>一键关联</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="oneClickGeneration">
<q-item-section>一键生成</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
@ -174,6 +177,8 @@ import { useRoute, useRouter } from 'vue-router';
import { errorNotify, successNotify } from 'src/utils/CommonNotify';
import { saveAsDraft } from 'src/api/DraftApi';
import { ApiError } from 'src/boot/axios';
import { TrainWindowDraw } from 'src/graphics/trainWindow/TrainWindowDrawAssistant';
import { TrainWindow } from 'src/graphics/trainWindow/TrainWindow';
const route = useRoute();
const router = useRouter();
@ -298,6 +303,13 @@ function buildRelations() {
console.log(app);
}
function oneClickGeneration() {
const trainWindowDraw = drawStore
.getDrawApp()
.getDrawAssistant(TrainWindow.Type) as TrainWindowDraw;
trainWindowDraw.oneGenerates();
}
function backConfirm() {
router.go(-1);
}

View File

@ -1,6 +1,12 @@
<template>
<q-layout view="hHh LpR fFf">
<q-header reveal class="bg-primary text-white"></q-header>
<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>
@ -8,51 +14,70 @@
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { onMounted, ref, computed } from 'vue';
import { useLineStore } from 'src/stores/line-store';
import { useRoute } from 'vue-router';
import { useLineNetStore } from 'src/stores/line-net-store';
import { useRoute, useRouter } from 'vue-router';
import { loadLineDatas, getLineApp } from 'src/drawApp/lineApp';
const lineStore = useLineStore();
import { loadLineNetDatas, getLineNetApp } from 'src/drawApp/lineNetApp';
const canvasWidth = ref(0);
const canvasHeight = ref(0);
const headerHeight = ref(0);
const leftWidth = ref(0);
const rightWidth = ref(0);
const leftDrawerOpen = ref(false);
const rightDrawerOpen = ref(false);
const route = useRoute();
const router = useRouter();
const mapType = ref(route.params.type as string);
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 -
(leftDrawerOpen.value ? leftWidth.value : 0) -
(rightDrawerOpen.value ? rightWidth.value : 0);
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();
let lineApp;
if (mapType.value === 'Line') {
lineApp = getLineApp();
} else if (mapType.value === 'LineNetwork') {
lineApp = getLineNetApp();
}
if (lineApp) {
lineApp.onDomResize(canvasWidth.value, canvasHeight.value);
}
}
function onHeaderResize(size: { height: number; width: number }) {
headerHeight.value = size.height;
onResize();
}
function backConfirm() {
router.go(-1);
}
onMounted(() => {
const dom = document.getElementById('line-app-container');
if (dom) {
const route = useRoute();
lineStore.setLineId(+route.params.id as number);
const lineApp = lineStore.initLineApp(dom);
console.log('1111111111');
loadLineDatas(lineApp);
if (mapType.value === 'Line') {
lineStore.setLineId(+route.params.id as number);
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

@ -1,6 +1,5 @@
<template>
<div class="q-pa-md">
<!-- <q-btn @click="goMap">测试</q-btn> -->
<q-table
ref="tableRef"
title="发布图"
@ -28,6 +27,12 @@
<template v-slot:body-cell-operations="props">
<q-td :props="props">
<div class="q-gutter-sm row justify-center">
<q-btn
color="primary"
:disable="operateDisabled"
label="预览"
:to="`/linemap/${props.row.id}/${props.row.type}`"
/>
<q-btn
color="red"
:disable="operateDisabled"
@ -61,6 +66,19 @@ const tableHeight = computed(() => {
return props.sizeHeight - 32;
});
const typeOptions = [
{ label: '线路', value: 'Line' },
{ label: '线网', value: 'LineNetwork' },
];
const typeOptionsMap = computed(() => {
const obj: { [k: string]: string } = {};
typeOptions.forEach((item: { value: string; label: string }) => {
obj[item.value] = item.label;
});
return obj;
});
onMounted(() => {
tableRef.value.requestServerInteraction();
});
@ -76,7 +94,9 @@ const columnDefs: QTableColumn[] = [
{
name: 'type',
label: '类型',
field: 'type',
field: (row) => {
return typeOptionsMap.value[row.type];
},
align: 'center',
},
{
@ -137,10 +157,6 @@ async function onRequest(props: any) {
}
}
function goMap() {
router.push('/linemap/7');
}
async function deleteData(row: any) {
operateDisabled.value = true;
$q.dialog({

View File

@ -62,7 +62,7 @@ const routes: RouteRecordRaw[] = [
component: () => import('layouts/DrawLayout.vue'),
},
{
path: '/linemap/:id',
path: '/linemap/:id/:type',
name: 'linemap',
component: () => import('layouts/LineLayout.vue'),
},

View File

@ -0,0 +1,54 @@
import { defineStore } from 'pinia';
import { JlCanvas, JlGraphic, GraphicApp } from 'src/jl-graphic';
import {
initLineNetApp,
getLineNetApp,
destroyLineNetApp,
} from 'src/drawApp/lineNetApp';
export const useLineNetStore = defineStore('lineNet', {
state: () => ({
selectedGraphics: null as JlGraphic[] | null,
lineNetId: null as number | null,
lineNetName: null as string | null,
}),
getters: {
selectedGraphicType: (state) => {
if (state.selectedGraphics) {
if (state.selectedGraphics.length === 1) {
return state.selectedGraphics[0].type;
}
}
},
},
actions: {
getLineNetApp(): GraphicApp {
const app = getLineNetApp();
if (app == null) {
throw new Error('未初始化app');
}
return app;
},
getJlCanvas(): JlCanvas {
return this.getLineNetApp().canvas;
},
initLineNetApp(dom: HTMLElement) {
const app = initLineNetApp(dom);
app.on('graphicselectedchange', () => {
this.selectedGraphics = app.selectedGraphics;
});
this.selectedGraphics = [];
return app;
},
destroy() {
this.selectedGraphics = null;
destroyLineNetApp();
},
setLineNetId(id: number | null) {
this.lineNetId = id;
},
setLineNetName(name: string | null) {
this.lineNetName = name;
},
},
});

View File

@ -6,6 +6,7 @@ export const useLineStore = defineStore('line', {
state: () => ({
selectedGraphics: null as JlGraphic[] | null,
lineId: null as number | null,
lineName: null as string | null,
}),
getters: {
selectedGraphicType: (state) => {
@ -42,5 +43,8 @@ export const useLineStore = defineStore('line', {
setLineId(id: number | null) {
this.lineId = id;
},
setLineName(name: string | null) {
this.lineName = name;
},
},
});