This commit is contained in:
Yuan 2023-08-04 17:31:17 +08:00
commit f882c8dfb1
25 changed files with 1357 additions and 284 deletions

View File

@ -0,0 +1,79 @@
import { api } from 'src/boot/axios';
import { PageDto, PageQueryDto } from './ApiCommon';
const UriBase = '/api/v1/category';
export interface createParams {
name: string;
id?: number;
config?: string;
}
export interface CategoryItem extends createParams {
id: number;
created_at: string;
update_at: string;
}
export class PagingQueryParams extends PageQueryDto {
name?: string;
}
/**
*
* @param params
* @returns
*/
export async function pageQuery(
params: PagingQueryParams
): Promise<PageDto<CategoryItem>> {
const response = await api.get(`${UriBase}/paging`, {
params: params,
});
return response.data;
}
/**
*
* @param params
* @returns
*/
export function createCategory(data: createParams) {
return api.post(`${UriBase}`, data);
}
/**
*
* @param id id
*/
export function deleteCategory(id: number) {
return api.delete(`${UriBase}/${id}`);
}
/**
*
* @param id 稿id
*/
export function saveCategoryData(id: number, data: createParams) {
return api.put(`${UriBase}/${id}`, data);
}
/**
*
* @param params
* @returns
*/
export async function getCategoryInfo(id: number): Promise<CategoryItem> {
const response = await api.get(`${UriBase}/${id}`);
return response.data;
}
/**
*
* @param params
* @returns
*/
export async function getCategoryList(): Promise<Array<CategoryItem>> {
const response = await api.get(`${UriBase}/list`);
return response.data;
}

View File

@ -3,14 +3,15 @@ import { PageDto, PageQueryDto } from './ApiCommon';
const DraftUriBase = '/api/v1/drafting';
interface Item {
export interface DraftItem {
id: number;
name: string;
proto: string;
type: string;
createdAt: string;
updateAt: string;
created_at: string;
update_at: string;
creatorId?: number;
category?: number;
}
export class PagingQueryParams extends PageQueryDto {
@ -24,7 +25,7 @@ export class PagingQueryParams extends PageQueryDto {
*/
export async function pageQuery(
params: PagingQueryParams
): Promise<PageDto<Item>> {
): Promise<PageDto<DraftItem>> {
const response = await api.get(`${DraftUriBase}/paging`, {
params: params,
});
@ -36,7 +37,7 @@ export async function pageQuery(
* @param params
* @returns
*/
export function createDraft(draftData: { name: string; type: string }) {
export function createDraft(draftData: { name: string; category: number }) {
return api.post(`${DraftUriBase}`, draftData);
}
@ -53,7 +54,7 @@ export function deleteDraft(id: number) {
* @param params
* @returns
*/
export async function getDraft(id: number): Promise<Item> {
export async function getDraft(id: number): Promise<DraftItem> {
const response = await api.get(`${DraftUriBase}/${id}`);
return response.data;
}
@ -80,7 +81,7 @@ export function saveDraft(
export async function saveAsDraft(
id: number,
data: { name: string; proto: string }
): Promise<Item> {
): Promise<DraftItem> {
const response = await api.post(`${DraftUriBase}/${id}/saveAs`, data);
return response.data;
}

View File

@ -3,13 +3,13 @@ import { PageDto, PageQueryDto } from './ApiCommon';
const PublishUriBase = '/api/v1/publishedGi';
interface Item {
export interface PublishItem {
id: number;
name: string;
proto: string;
createdAt: string;
updateAt: string;
creatorId?: number;
note: string;
publishAt: string;
userID: number;
}
export class PagingQueryParams extends PageQueryDto {
@ -18,11 +18,12 @@ export class PagingQueryParams extends PageQueryDto {
/**
* 稿
* @param id 稿id
* @param draftId 稿id
* @param note
*/
export function publishDraft(data: {
name: string;
lineId?: number;
note: string;
draftId: number;
}) {
return api.post(`${PublishUriBase}/publish`, data);
@ -33,7 +34,7 @@ export function publishDraft(data: {
* @param params
* @returns
*/
export async function getDraft(): Promise<Item> {
export async function getDraft(): Promise<PublishItem> {
const response = await api.get(`${PublishUriBase}/list`);
return response.data;
}
@ -45,7 +46,7 @@ export async function getDraft(): Promise<Item> {
*/
export async function pageQuery(
params: PagingQueryParams
): Promise<PageDto<Item>> {
): Promise<PageDto<PublishItem>> {
const response = await api.get(`${PublishUriBase}/paging`, {
params: params,
});
@ -54,7 +55,7 @@ export async function pageQuery(
/**
*
* @param id 稿id
* @param id id
*/
export function deletePublish(id: number) {
return api.delete(`${PublishUriBase}/${id}`);
@ -63,14 +64,14 @@ export function deletePublish(id: number) {
*
* @param id id
*/
export async function getPublishMapInfoById(id: number): Promise<Item> {
export async function getPublishMapInfoById(id: number): Promise<PublishItem> {
const response = await api.get(`${PublishUriBase}/${id}`);
return response.data;
}
/**
* 线
*/
export async function getPublishLineNet(): Promise<Item> {
export async function getPublishLineNet(): Promise<PublishItem> {
const response = await api.get(`${PublishUriBase}/publish/lineNetwork/info`);
return response.data;
}
@ -79,7 +80,22 @@ export async function getPublishLineNet(): Promise<Item> {
*
* @param id 线ID
*/
export async function getPublishMapInfoByLineId(lineId: string): Promise<Item> {
export async function getPublishMapInfoByLineId(
lineId: string
): Promise<PublishItem> {
const response = await api.get(`${PublishUriBase}/${lineId}`);
return response.data;
}
/**
* 稿
* @param id id
*/
export function saveToDraft(
id: number,
data: {
name: string;
}
) {
return api.post(`${PublishUriBase}/saveAsDrafting/${id}`, data);
}

View File

@ -69,11 +69,11 @@ const list = reactive([
label: '发布管理',
icon: 'app_registration',
},
// {
// path: '/dataManage/lineInfo',
// label: '线',
// icon: 'app_registration',
// },
{
path: '/dataManage/categoryInfo',
label: '厂家信息管理',
icon: 'app_registration',
},
],
},
]);

View File

@ -99,6 +99,9 @@
<KiloMarkerProperty
v-else-if="drawStore.selectedGraphicType === SlopeKiloMarker.Type"
/>
<slope-property
v-else-if="drawStore.selectedGraphicType === Slope.Type"
></slope-property>
</q-card-section>
</template>
</q-card>
@ -148,6 +151,8 @@ import EsbButtonProperty from './properties/EsbButtonProperty.vue';
import { EsbButton } from 'src/graphics/esbButton/EsbButton';
import KiloMarkerProperty from './properties/KiloMarkerProperty.vue';
import { SlopeKiloMarker } from 'src/graphics/slopeKiloMarker/SlopeKiloMarker';
import { Slope } from 'src/graphics/slope/Slope';
import SlopeProperty from './properties/SlopeProperty.vue';
const drawStore = useDrawStore();
</script>

View File

@ -1,6 +1,6 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<q-dialog v-model="lineStore.showLayerDialog">
<q-dialog v-model="show" @hide="onDialogCancel">
<q-card class="q-pa-md">
<q-card-section> <div class="text-h6">显示控制</div> </q-card-section>
<q-card-section>
@ -16,7 +16,7 @@
<div class="row">
<q-checkbox
class="col-4"
v-for="(item, index) in layerList"
v-for="(item, index) in props.layerList"
:key="index"
v-model="list"
:label="item.label"
@ -34,17 +34,29 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
import { layerList } from 'src/drawApp/lineApp';
import { useLineStore } from 'src/stores/line-store';
interface ItemData {
label: string;
value: string;
}
const lineStore = useLineStore();
const list = ref<string[]>([]);
const allList = ref(false);
const show = ref(false);
const props = defineProps<{
showDialog: boolean;
layerList: ItemData[];
showLayer: string[];
}>();
function allListFn() {
const arr: string[] = [];
if (allList.value) {
layerList.forEach((item) => {
props.layerList.forEach((item) => {
arr.push(item.value);
});
list.value = arr;
@ -54,34 +66,29 @@ function allListFn() {
}
watch(
() => lineStore.showLayerDialog,
() => props.showDialog,
(val) => {
show.value = val;
if (val) {
list.value = lineStore.showLayer;
allList.value = layerList.length == lineStore.showLayer.length;
list.value = props.showLayer;
allList.value = props.layerList.length == props.showLayer.length;
}
}
);
const emits = defineEmits(['setShowLayer', 'onDialogClose']);
watch(
() => list.value,
(val) => {
lineStore.setShowLayer(val);
allList.value = layerList.length == val.length;
const lineApp = lineStore.getLineApp();
const alllGraphic = lineApp.queryStore.getAllGraphics();
alllGraphic.forEach((g) => {
if (val.includes(g.type)) {
g.visible = true;
} else {
g.visible = false;
}
});
allList.value = props.layerList.length == val.length;
emits('setShowLayer', val);
}
);
function onDialogCancel() {
lineStore.setShowLayerDialog(false);
emits('onDialogClose');
}
</script>
<style scoped></style>

View File

@ -32,37 +32,125 @@
@blur="onUpdate"
label="公里标(mm):"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="refDevData.deviceType"
:options="DeviceTypeOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联设备类型:"
></q-select>
<q-select
outlined
v-if="refDevData.deviceType === graphicData.RelatedRef.DeviceType.Section"
style="margin-top: 10px"
v-model="refDevData.id"
:options="sectionList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联设备:"
></q-select>
<q-select
outlined
v-if="refDevData.deviceType === graphicData.RelatedRef.DeviceType.Turnout"
style="margin-top: 10px"
v-model="refDevData.id"
:options="turnoutList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联设备:"
></q-select>
<q-select
outlined
v-if="refDevData.deviceType === graphicData.RelatedRef.DeviceType.Turnout"
style="margin-top: 10px"
v-model="refDevData.devicePort"
:options="DevicePortOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联设备端口:"
></q-select>
</q-form>
</template>
<script setup lang="ts">
import { SignalData } from 'src/drawApp/graphics/SignalInteraction';
import { Section } from 'src/graphics/section/Section';
import { Signal } from 'src/graphics/signal/Signal';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const signalModel = reactive(new SignalData());
const kilometerSystem = reactive({ coordinateSystem: '', kilometer: 0 });
const sectionList: { label: string; value: string }[] = reactive([]);
const turnoutList: { label: string; value: string }[] = reactive([]);
const refDevData = reactive({
id: '',
deviceType: graphicData.RelatedRef.DeviceType.Section,
devicePort: graphicData.RelatedRef.DevicePort.A,
});
const DeviceTypeOptions = [
{ label: '区段', value: graphicData.RelatedRef.DeviceType.Section },
{ label: '道岔', value: graphicData.RelatedRef.DeviceType.Turnout },
];
const DevicePortOptions = [
{ label: 'A端', value: graphicData.RelatedRef.DevicePort.A },
{ label: 'B端', value: graphicData.RelatedRef.DevicePort.B },
{ label: 'C端', value: graphicData.RelatedRef.DevicePort.C },
];
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
{ label: '停车场', value: 'PARKING_LOT' },
{ label: '正线', value: 'MAIN_LINE' },
{ label: '换线', value: 'TRANSFER' },
];
function initRefData(signal: Signal) {
signalModel.copyFrom(signal.saveData());
if (signalModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
signalModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = signalModel.kilometerSystem.kilometer;
}
if (signalModel.refDev) {
refDevData.id = signalModel.refDev.id;
refDevData.devicePort = signalModel.refDev.devicePort;
refDevData.deviceType = signalModel.refDev.deviceType;
}
}
function initDeviceList() {
const sections = drawStore
.getDrawApp()
.queryStore.queryByType<Section>(Section.Type);
sections.forEach((sec) => {
sectionList.push({
label: `${sec.datas.code}[${sec.datas.index}]`,
value: sec.datas.id,
});
});
const trunouts = drawStore
.getDrawApp()
.queryStore.queryByType<Turnout>(Turnout.Type);
trunouts.forEach((tur) => {
turnoutList.push({
label: `${tur.datas.code}[${tur.datas.index}]`,
value: tur.datas.id,
});
});
}
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Signal.Type) {
signalModel.copyFrom(val.saveData() as SignalData);
if (signalModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
signalModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = signalModel.kilometerSystem.kilometer;
}
initRefData(val as Signal);
}
}
);
@ -70,12 +158,8 @@ watch(
onMounted(() => {
const signal = drawStore.selectedGraphic as Signal;
if (signal) {
signalModel.copyFrom(signal.saveData());
if (signalModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
signalModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = signalModel.kilometerSystem.kilometer;
}
initDeviceList();
initRefData(signal);
}
});
@ -85,6 +169,16 @@ function onUpdate() {
coordinateSystem: kilometerSystem.coordinateSystem,
kilometer: kilometerSystem.kilometer,
};
if (refDevData.id) {
signalModel.refDev = new graphicData.RelatedRef({
id: refDevData.id,
deviceType: refDevData.deviceType,
devicePort:
refDevData.deviceType === graphicData.RelatedRef.DeviceType.Section
? graphicData.RelatedRef.DevicePort.A
: refDevData.devicePort,
});
}
if (signal) {
drawStore.getDrawApp().updateGraphicAndRecord(signal, signalModel);
}

View File

@ -0,0 +1,112 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="slopeModel.id" label="id" hint="" />
<q-input
outlined
readonly
label="坡度长度"
type="textarea"
@blur="onUpdate"
v-model="slopeModel.slopeLong"
lazy-rules
autogrow
/>
<q-input
outlined
label="坡度值"
type="textarea"
@blur="onUpdate"
v-model="slopeModel.slopeNumber"
lazy-rules
autogrow
/>
<q-select
outlined
@blur="onUpdate"
v-model="direction"
:options="optionsDirection"
label="坡度方向"
/>
<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 axleCountingRelations"
:key="item"
square
color="primary"
text-color="white"
>
{{ item }}
</q-chip>
</div>
</q-item-section>
</q-item>
</q-list>
</q-form>
</template>
<script setup lang="ts">
import { SlopeData } from 'src/drawApp/graphics/SlopeInteraction';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { Slope } from 'src/graphics/slope/Slope';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, onMounted, reactive, ref, watch } from 'vue';
const drawStore = useDrawStore();
const slopeModel = reactive(new SlopeData());
const direction = ref('');
const optionsDirection = ['上坡', '下坡', '无坡度'];
enum showSelect {
上坡 = 'up',
下坡 = 'down',
无坡度 = 'none',
}
enum showSelectData {
up = '上坡',
down = '下坡',
none = '无坡度',
}
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Slope.Type) {
slopeModel.copyFrom(val.saveData() as SlopeData);
direction.value = (showSelectData as never)[slopeModel.slopeDirection];
}
}
);
onMounted(() => {
const slope = drawStore.selectedGraphic as Slope;
if (slope) {
slopeModel.copyFrom(slope.saveData());
direction.value = (showSelectData as never)[slopeModel.slopeDirection];
}
});
function onUpdate() {
slopeModel.slopeDirection = (showSelect as never)[direction.value];
const slope = drawStore.selectedGraphic as Slope;
if (slope) {
drawStore.getDrawApp().updateGraphicAndRecord(slope, slopeModel);
}
}
const axleCountingRelations = computed(() => {
const slope = drawStore.selectedGraphic as Slope;
const sectionRelations =
slope?.relationManage.getRelationsOfGraphicAndOtherType(
slope,
AxleCounting.Type
);
const ref = sectionRelations.map(
(relation) => `${relation.getOtherGraphic<AxleCounting>(slope).datas.code}`
);
return Array.from(new Set(ref));
});
</script>

View File

@ -42,25 +42,42 @@
@blur="onUpdate"
label="公里标(mm):"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="refDevData.id"
:options="sectionList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联设备"
></q-select>
</q-form>
</template>
<script setup lang="ts">
import { StopPositionData } from 'src/drawApp/graphics/StopPositionInteraction';
import { Section } from 'src/graphics/section/Section';
import { StopPosition, CoachNum } from 'src/graphics/stopPosition/StopPosition';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const stopPositionModel = reactive(new StopPositionData());
const kilometerSystem = reactive({ coordinateSystem: '', kilometer: 0 });
const refDevData = reactive({
id: '',
deviceType: graphicData.RelatedRef.DeviceType.Section,
devicePort: graphicData.RelatedRef.DevicePort.A,
});
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
{ label: '停车场', value: 'PARKING_LOT' },
{ label: '正线', value: 'MAIN_LINE' },
{ label: '换线', value: 'TRANSFER' },
];
const sectionList: { label: string; value: string }[] = reactive([]);
const optionsCoachNum = [
{
label: 4,
@ -73,12 +90,7 @@ watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == StopPosition.Type) {
stopPositionModel.copyFrom(val.saveData() as StopPositionData);
if (stopPositionModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
stopPositionModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = stopPositionModel.kilometerSystem.kilometer;
}
initRefData(val as StopPosition);
}
}
);
@ -86,21 +98,44 @@ watch(
onMounted(() => {
const stopPosition = drawStore.selectedGraphic as StopPosition;
if (stopPosition) {
stopPositionModel.copyFrom(stopPosition.saveData());
if (stopPositionModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
stopPositionModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = stopPositionModel.kilometerSystem.kilometer;
}
const sections = drawStore
.getDrawApp()
.queryStore.queryByType<Section>(Section.Type);
sections.forEach((sec) => {
sectionList.push({
label: `${sec.datas.code}[${sec.datas.index}]`,
value: sec.datas.id,
});
});
initRefData(stopPosition);
}
});
function initRefData(stopPosition: StopPosition) {
stopPositionModel.copyFrom(stopPosition.saveData());
if (stopPositionModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
stopPositionModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = stopPositionModel.kilometerSystem.kilometer;
}
if (stopPositionModel.refDev) {
refDevData.id = stopPositionModel.refDev.id;
}
}
function onUpdate() {
const stopPosition = drawStore.selectedGraphic as StopPosition;
stopPositionModel.kilometerSystem = {
coordinateSystem: kilometerSystem.coordinateSystem,
kilometer: kilometerSystem.kilometer,
};
if (refDevData.id) {
stopPositionModel.refDev = new graphicData.RelatedRef({
id: refDevData.id,
deviceType: refDevData.deviceType,
devicePort: refDevData.devicePort,
});
}
if (stopPosition) {
drawStore
.getDrawApp()

View File

@ -57,6 +57,12 @@ export class SignalData extends GraphicDataBase implements ISignalData {
set index(v: number) {
this.data.index = v;
}
get refDev(): graphicData.RelatedRef {
return this.data.refDev;
}
set refDev(v: graphicData.RelatedRef) {
this.data.refDev = v;
}
clone(): SignalData {
return new SignalData(this.data.cloneMessage());
}

View File

@ -0,0 +1,70 @@
import * as pb_1 from 'google-protobuf';
import { GraphicDataBase } from './GraphicDataBase';
import { ISlopeData, Slope } from 'src/graphics/slope/Slope';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IPointData } from 'pixi.js';
export class SlopeData extends GraphicDataBase implements ISlopeData {
constructor(data?: graphicData.Slope) {
let slope;
if (!data) {
slope = new graphicData.Slope({
common: GraphicDataBase.defaultCommonInfo(Slope.Type),
});
} else {
slope = data;
}
super(slope);
}
public get data(): graphicData.Slope {
return this.getData<graphicData.Slope>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get points(): IPointData[] {
return this.data.points;
}
set points(points: IPointData[]) {
this.data.points = points.map(
(p) => new graphicData.Point({ x: p.x, y: p.y })
);
}
get slopeNumber(): string {
return this.data.slopeNumber;
}
set slopeNumber(v: string) {
this.data.slopeNumber = v;
}
get slopeDirection(): string {
return this.data.slopeDirection;
}
set slopeDirection(v: string) {
this.data.slopeDirection = v;
}
get slopeLong(): number {
return this.data.slopeLong;
}
set slopeLong(v: number) {
this.data.slopeLong = v;
}
get refDeviceId(): string[] {
return this.data.refDeviceId;
}
set refDeviceId(v: string[]) {
this.data.refDeviceId = v;
}
clone(): SlopeData {
return new SlopeData(this.data.cloneMessage());
}
copyFrom(data: SlopeData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: SlopeData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -62,6 +62,12 @@ export class StopPositionData extends GraphicDataBase implements IStopPosition {
set kilometerSystem(v: KilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem(v);
}
get refDev(): graphicData.RelatedRef {
return this.data.refDev;
}
set refDev(v: graphicData.RelatedRef) {
this.data.refDev = v;
}
clone(): StopPositionData {
return new StopPositionData(this.data.cloneMessage());
}

View File

@ -117,6 +117,10 @@ import {
SlopeKiloMarkerTemplate,
} from 'src/graphics/slopeKiloMarker/SlopeKiloMarker';
import { SlopeKiloMarkerData } from './graphics/SlopeKiloMarkerInteraction';
import { SlopeDraw } from 'src/graphics/slope/SlopeAssistant';
import { SlopeData } from './graphics/SlopeInteraction';
import { Slope, SlopeTemplate } from 'src/graphics/slope/Slope';
import { useLineStore } from 'src/stores/line-store';
// export function fromStoragePoint(p: graphicData.Point): Point {
// return new Point(p.x, p.y);
@ -157,49 +161,8 @@ const RedoOptions: MenuItemOptions = {
const SelectAllOptions: MenuItemOptions = {
name: '全选',
};
const AllOptions: MenuItemOptions = {
name: '全部图层',
};
const physicalSection: MenuItemOptions = {
name: '图层-物理区段',
};
const linkOptions: MenuItemOptions = {
name: '图层-Link',
};
const axleCountingSectionOptions: MenuItemOptions = {
name: '图层-计轴区段',
};
const LogicSectionOptions: MenuItemOptions = {
name: '图层-逻辑区段',
};
// [
// {
// name: '图层菜单',
// items: [
// AllOptions,
// linkOptions,
// axleCountingSectionOptions,
// LogicSectionOptions,
// ],
// },
// ]
const layerOptions: MenuItemOptions = {
name: '图层',
subMenu: {
name: '图层菜单',
groups: [
{
name: '图层菜单',
items: [
AllOptions,
physicalSection,
linkOptions,
axleCountingSectionOptions,
LogicSectionOptions,
],
},
],
},
name: '显示控制',
};
export const DefaultCanvasMenu = new ContextMenu({
@ -230,6 +193,43 @@ export function destroyDrawApp(): void {
}
}
const showType = [
// 默认显示的图层
Section.Type,
AxleCounting.Type,
Platform.Type,
Station.Type,
Turnout.Type,
Signal.Type,
Separator.Type,
StopPosition.Type,
SpksSwitch.Type,
GatedBox.Type,
EsbButton.Type,
Transponder.Type,
TrainWindow.Type,
Slope.Type,
];
export const drawLayerList = [
// 图层列表
{ label: '区段', value: Section.Type },
{ label: 'link', value: SectionLink.Type },
{ label: '计轴', value: AxleCounting.Type },
{ label: '站台', value: Platform.Type },
{ label: '车站', value: Station.Type },
{ label: '道岔', value: Turnout.Type },
{ label: '信号机', value: Signal.Type },
{ label: '分隔符', value: Separator.Type },
{ label: '停车位置标', value: StopPosition.Type },
{ label: 'Spks开关', value: SpksSwitch.Type },
{ label: '门控箱', value: GatedBox.Type },
{ label: '紧急关闭按钮', value: EsbButton.Type },
{ label: '应答器', value: Transponder.Type },
{ label: '车次窗', value: TrainWindow.Type },
{ label: '计轴区段', value: AxleCountingSection.Type },
{ label: '逻辑区段', value: LogicSection.Type },
];
export function initDrawApp(dom: HTMLElement): JlDrawApp {
drawApp = new JlDrawApp(dom);
const app = drawApp;
@ -255,6 +255,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
| EsbButtonDraw
| TransponderDraw
| SlopeKiloMarkerDrawAssistant
| SlopeDraw
)[] = [];
if (draftType === 'Line') {
drawAssistants = [
@ -304,6 +305,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
app,
new SlopeKiloMarkerTemplate(new SlopeKiloMarkerData())
),
new SlopeDraw(app, new SlopeTemplate(new SlopeData())),
];
DrawSignalInteraction.init(app);
DrawStopPositionInteraction.init(app);
@ -330,23 +332,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
if (app._drawing) return;
UndoOptions.disabled = !app.opRecord.hasUndo;
RedoOptions.disabled = !app.opRecord.hasRedo;
const axleCountingSections =
app.queryStore.queryByType<AxleCountingSection>(AxleCountingSection.Type);
const logicSections = app.queryStore.queryByType<LogicSection>(
LogicSection.Type
);
const sections = app.queryStore.queryByType<Section>(Section.Type);
const sectionLinks = app.queryStore.queryByType<SectionLink>(
SectionLink.Type
);
const turnouts = app.queryStore.queryByType<Turnout>(Turnout.Type);
const disvisibleGraphics = [
...sections,
...turnouts,
...sectionLinks,
...axleCountingSections,
...logicSections,
];
UndoOptions.handler = () => {
app.opRecord.undo();
};
@ -356,45 +342,9 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
SelectAllOptions.handler = () => {
app.selectAllGraphics();
};
AllOptions.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = true;
});
};
physicalSection.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = false;
});
sections.forEach((axleCountingSection) => {
axleCountingSection.visible = true;
});
turnouts.forEach((axleCountingSection) => {
axleCountingSection.visible = true;
});
};
linkOptions.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = false;
});
sectionLinks.forEach((axleCountingSection) => {
axleCountingSection.visible = true;
});
};
axleCountingSectionOptions.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = false;
});
axleCountingSections.forEach((axleCountingSection) => {
axleCountingSection.visible = true;
});
};
LogicSectionOptions.handler = () => {
disvisibleGraphics.forEach((g) => {
g.visible = false;
});
logicSections.forEach((logicSection) => {
logicSection.visible = true;
});
const lineStore = useLineStore();
layerOptions.handler = () => {
lineStore.setShowLayerDialog(true);
};
DefaultCanvasMenu.open(e.global);
});
@ -521,6 +471,9 @@ export function saveDrawDatas(app: JlDrawApp) {
storage.slopeKiloMarker.push(
(slopeKiloMarkerData as SlopeKiloMarkerData).data
);
} else if (Slope.Type === g.type) {
const slopeData = (g as Slope).saveData();
storage.slopes.push((slopeData as SlopeData).data);
}
});
const base64 = fromUint8Array(storage.serialize());
@ -607,27 +560,21 @@ export async function loadDrawDatas(app: GraphicApp) {
storage.slopeKiloMarker.forEach((slopeKiloMarker) => {
datas.push(new SlopeKiloMarkerData(slopeKiloMarker));
});
storage.slopes.forEach((slope) => {
datas.push(new SlopeData(slope));
});
await app.loadGraphic(datas);
} else {
app.loadGraphic([]);
}
//隐藏计轴区段--Link
const axleCountingSections = app.queryStore.queryByType<AxleCountingSection>(
AxleCountingSection.Type
);
axleCountingSections.forEach((axleCountingSection) => {
axleCountingSection.visible = false;
});
const sectionLinks = app.queryStore.queryByType<SectionLink>(
SectionLink.Type
);
sectionLinks.forEach((sectionLink) => {
sectionLink.visible = false;
});
const logicSections = app.queryStore.queryByType<LogicSection>(
LogicSection.Type
);
logicSections.forEach((logicSection) => {
logicSection.visible = false;
const lineStore = useLineStore();
const alllGraphic = app.queryStore.getAllGraphics();
alllGraphic.forEach((g) => {
if (showType.includes(g.type)) {
g.visible = true;
} else {
g.visible = false;
}
});
lineStore.setShowLayer(showType);
}

View File

@ -116,6 +116,8 @@ const DefaultCanvasMenu = new ContextMenu({
],
});
const showType = [
// 默认显示的图层
Section.Type,
Platform.Type,
Station.Type,
Turnout.Type,
@ -128,9 +130,9 @@ const showType = [
EsbButton.Type,
Transponder.Type,
];
const physicShowType = [...showType, Section.Type];
export const layerList = [
// 图层列表
{ label: '区段', value: Section.Type },
{ label: 'link', value: SectionLink.Type },
{ label: '计轴', value: AxleCounting.Type },
@ -280,7 +282,7 @@ export async function loadLineDatas(app: GraphicApp) {
const alllGraphic = (lineApp as GraphicApp).queryStore.getAllGraphics();
alllGraphic.forEach((g) => {
if (physicShowType.includes(g.type)) {
if (showType.includes(g.type)) {
g.visible = true;
} else {
g.visible = false;
@ -290,7 +292,7 @@ export async function loadLineDatas(app: GraphicApp) {
(g as Transponder).labelGraphic.visible = false;
}
});
lineStore.setShowLayer(physicShowType);
lineStore.setShowLayer(showType);
app.enableWsMassaging({
engine: ClientEngine.Centrifugo,
wsUrl: `${getWebsocketUrl()}`,

View File

@ -7,7 +7,7 @@ import {
} from 'src/jl-graphic';
import { calculateMirrorPoint } from 'src/jl-graphic';
import { LampMainBody } from './LampMainBody';
import { drawArrow } from '../CommonGraphics';
import { drawArrow, IRelatedRefData } from '../CommonGraphics';
import { SignalCode } from './SignalCode';
export interface KilometerSystem {
@ -16,7 +16,6 @@ export interface KilometerSystem {
get kilometer(): number;
set kilometer(v: number);
}
export interface ISignalData extends GraphicData {
get code(): string; // 编号
set code(v: string);
@ -26,6 +25,8 @@ export interface ISignalData extends GraphicData {
set kilometerSystem(v: KilometerSystem);
get index(): number;
set index(v: number);
get refDev(): IRelatedRefData;
set refDev(v: IRelatedRefData);
clone(): ISignalData;
copyFrom(data: ISignalData): void;
eq(other: ISignalData): boolean;

152
src/graphics/slope/Slope.ts Normal file
View File

@ -0,0 +1,152 @@
import { Graphics, IPointData } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
calculateLineMidpoint,
} from 'src/jl-graphic';
export interface ITurnoutPosRefData {
get id(): string; //道岔的ID
set id(v: string);
get position(): number; //道岔的正反为0是正位1是反位
set position(v: number);
}
export interface ISlopeData extends GraphicData {
get code(): string; // 名称
set code(v: string);
get points(): IPointData[]; // 线坐标点
set points(points: IPointData[]);
get slopeNumber(): string; // 坡度的值
set slopeNumber(v: string);
get slopeDirection(): string; //坡度方向 有三种,无坡度--上坡--下坡
set slopeDirection(v: string);
get slopeLong(): number; //该坡度的长度--两端公里标的差值
set slopeLong(v: number);
get refDeviceId(): string[]; // 坡度关联的设备id
set refDeviceId(v: string[]);
clone(): ISlopeData;
copyFrom(data: ISlopeData): void;
eq(other: ISlopeData): boolean;
}
export const SlopeConsts = {
lineColor: '0xffffff',
lineWidth: 2,
height: 40,
};
export class Slope extends JlGraphic {
static Type = 'Slope';
lineGraphic: Graphics;
slopeNumber: VectorText;
slopeLong: VectorText;
constructor() {
super(Slope.Type);
this.lineGraphic = new Graphics();
this.slopeNumber = new VectorText();
this.slopeNumber.name = 'slopeNumber';
this.slopeLong = new VectorText();
this.slopeLong.name = 'slopeLong';
const vectorTexts = [this.slopeNumber, this.slopeLong];
vectorTexts.forEach((vectorText) => {
vectorText.setVectorFontSize(14);
vectorText.anchor.set(0.5);
vectorText.style.fill = '0xffffff';
vectorText.transformSave = true;
});
this.transformSave = true;
this.addChild(this.lineGraphic);
this.addChild(this.slopeNumber);
this.addChild(this.slopeLong);
}
get datas(): ISlopeData {
return this.getDatas<ISlopeData>();
}
doRepaint(): void {
if (this.datas.points.length < 2) {
throw new Error('Slope坐标数据异常');
}
this.lineGraphic.clear();
this.lineGraphic.lineStyle(SlopeConsts.lineWidth, SlopeConsts.lineColor);
let distanceY = 0;
switch (this.datas.slopeDirection) {
case 'up':
distanceY = -SlopeConsts.height / 2;
break;
case 'down':
distanceY = SlopeConsts.height / 2;
break;
}
this.datas.points.forEach((p, i) => {
if (i !== 0) {
this.lineGraphic.lineTo(p.x, p.y + distanceY);
} else {
this.lineGraphic.moveTo(p.x, p.y - distanceY);
}
});
//坡度值
this.slopeNumber.text = this.datas.slopeNumber;
const slopeNumberPosition = this.datas.childTransforms?.find(
(t) => t.name === this.slopeNumber.name
)?.transform.position;
if (slopeNumberPosition) {
this.slopeNumber.position.set(
slopeNumberPosition.x,
slopeNumberPosition.y
);
} else {
const centerPos = calculateLineMidpoint(
this.datas.points[0],
this.datas.points[this.datas.points.length - 1]
);
this.slopeNumber.position.set(centerPos.x, centerPos.y - 15);
}
//坡度长度
this.slopeLong.text = this.datas.slopeLong;
const slopeLongPosition = this.datas.childTransforms?.find(
(t) => t.name === this.slopeLong.name
)?.transform.position;
if (slopeLongPosition) {
this.slopeLong.position.set(slopeLongPosition.x, slopeLongPosition.y);
} else {
const centerPos = calculateLineMidpoint(
this.datas.points[0],
this.datas.points[this.datas.points.length - 1]
);
this.slopeLong.position.set(centerPos.x, centerPos.y + 15);
}
}
get linePoints(): IPointData[] {
return this.datas.points;
}
set linePoints(points: IPointData[]) {
const old = this.datas.clone();
old.points = points;
this.updateData(old);
}
loadRelations() {
if (this.datas.refDeviceId.length) {
this.datas.refDeviceId.forEach((id) => {
const section = this.queryStore.queryById(id);
this.relationManage.addRelation(this, section);
});
}
}
}
export class SlopeTemplate extends JlGraphicTemplate<Slope> {
constructor(dataTemplate: ISlopeData) {
super(Slope.Type, {
dataTemplate,
});
}
new(): Slope {
const slope = new Slope();
slope.loadData(this.datas);
return slope;
}
}

View File

@ -0,0 +1,134 @@
import { FederatedPointerEvent, IHitArea, Point } from 'pixi.js';
import {
GraphicDrawAssistant,
GraphicIdGenerator,
GraphicInteractionPlugin,
JlDrawApp,
JlGraphic,
linePoint,
} from 'src/jl-graphic';
import { ISlopeData, Slope, SlopeTemplate, SlopeConsts } from './Slope';
import { AxleCounting } from '../axleCounting/AxleCounting';
export interface ISlopeDrawOptions {
newData: () => ISlopeData;
}
export class SlopeDraw extends GraphicDrawAssistant<SlopeTemplate, ISlopeData> {
codeGraph: Slope;
constructor(app: JlDrawApp, template: SlopeTemplate) {
super(app, template, 'sym_o_circle', '不展示');
this.codeGraph = this.graphicTemplate.new();
this.container.addChild(this.codeGraph);
SlopeInteraction.init(app);
}
bind(): void {
super.bind();
this.codeGraph.loadData(this.graphicTemplate.datas);
this.codeGraph.doRepaint();
}
clearCache(): void {
//this.codeGraph.destroy();
}
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: ISlopeData): boolean {
data.transform = this.container.saveTransform();
return true;
}
draw(graphics: AxleCounting[], map: Map<string, number>) {
if (
map.has(`${graphics[0].id}+${graphics[1].id}`) ||
map.has(`${graphics[1].id}+${graphics[0].id}`)
)
return;
map.set(`${graphics[0].id}+${graphics[1].id}`, 1);
const slope = new Slope();
slope.loadData(this.graphicTemplate.datas);
slope.datas.points = [graphics[0].position, graphics[1].position];
slope.id = GraphicIdGenerator.next();
slope.datas.refDeviceId = [graphics[0].id, graphics[1].id];
this.storeGraphic(slope);
slope.loadRelations();
}
oneGenerates() {
const map = new Map();
const slopes = this.app.queryStore.queryByType<Slope>(Slope.Type);
const axleCountings = this.app.queryStore.queryByType<AxleCounting>(
AxleCounting.Type
);
axleCountings.sort((a, b) => a.position.x - b.position.x);
const axleCountingsPos = axleCountings.map((g) => g.position.x);
//检验坡度有效性--是否有增加和删除
slopes.forEach((slope) => {
const pS = slope.datas.points[0].x;
const mapS = axleCountingsPos.findIndex((x) => x == pS);
const pE = slope.datas.points[1].x;
const mapE = axleCountingsPos.findIndex((x) => x == pE);
if (mapS !== -1 && mapE !== -1 && mapE - mapS == 1) {
map.set(
`${slope.datas.refDeviceId[0]}+${slope.datas.refDeviceId[1]}`,
1
);
} else {
this.app.deleteGraphics(slope);
}
});
for (let i = 0; i < axleCountings.length - 1; i++) {
this.draw([axleCountings[i], axleCountings[i + 1]], map);
}
}
}
class SlopeGraphicHitArea implements IHitArea {
slope: Slope;
constructor(slope: Slope) {
this.slope = slope;
}
contains(x: number, y: number): boolean {
for (let i = 1; i < this.slope.datas.points.length; i++) {
const p1 = this.slope.datas.points[i - 1];
const p2 = this.slope.datas.points[i];
if (linePoint(p1, p2, { x, y }, SlopeConsts.lineWidth)) {
return true;
}
}
return false;
}
}
export class SlopeInteraction extends GraphicInteractionPlugin<Slope> {
static Name = 'Slope_transform';
constructor(app: JlDrawApp) {
super(SlopeInteraction.Name, app);
}
static init(app: JlDrawApp) {
return new SlopeInteraction(app);
}
filter(...grahpics: JlGraphic[]): Slope[] | undefined {
return grahpics.filter((g) => g.type === Slope.Type).map((g) => g as Slope);
}
bind(g: Slope): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.transformSave = true;
g.lineGraphic.eventMode = 'static';
g.lineGraphic.cursor = 'pointer';
g.lineGraphic.hitArea = new SlopeGraphicHitArea(g);
}
unbind(g: Slope): void {
g.eventMode = 'none';
g.lineGraphic.eventMode = 'none';
g.lineGraphic.draggable = false;
g.lineGraphic.selectable = false;
g.lineGraphic.transformSave = false;
}
}

View File

@ -5,6 +5,7 @@ import {
JlGraphicTemplate,
VectorText,
} from 'src/jl-graphic';
import { IRelatedRefData } from '../CommonGraphics';
export enum CoachNum {
Four = 0,
@ -17,7 +18,6 @@ export interface KilometerSystem {
get kilometer(): number;
set kilometer(v: number);
}
export interface IStopPosition extends GraphicData {
get code(): string;
set code(v: string);
@ -29,6 +29,8 @@ export interface IStopPosition extends GraphicData {
set index(v: number);
get kilometerSystem(): KilometerSystem;
set kilometerSystem(v: KilometerSystem);
get refDev(): IRelatedRefData;
set refDev(v: IRelatedRefData);
clone(): IStopPosition;
copyFrom(data: IStopPosition): void;
eq(other: IStopPosition): boolean;

View File

@ -43,6 +43,9 @@
<q-item clickable v-close-popup @click="oneClickLogicSection">
<q-item-section>一键生成逻辑区段</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="oneClickSlope">
<q-item-section>一键生成坡度</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
@ -206,6 +209,13 @@
</q-card-actions>
</q-card>
</q-dialog>
<LayerControlDialog
:showLayer="lineStore.showLayer"
:layerList="drawLayerList"
:showDialog="lineStore.showLayerDialog"
@setShowLayer="setShowLayer"
@onDialogClose="onDialogClose"
></LayerControlDialog>
</q-layout>
</template>
@ -236,7 +246,12 @@ import { SectionDraw } from 'src/graphics/section/SectionDrawAssistant';
import { Section } from 'src/graphics/section/Section';
import { LogicSection } from 'src/graphics/logicSection/LogicSection';
import { LogicSectionDraw } from 'src/graphics/logicSection/LogicSectionDrawAssistant';
import { Slope } from 'src/graphics/slope/Slope';
import { SlopeDraw } from 'src/graphics/slope/SlopeAssistant';
import { useQuasar } from 'quasar';
import LayerControlDialog from 'src/components/draw-app/dialogs/LayerControlDialog.vue';
import { drawLayerList } from 'src/drawApp/index';
import { useLineStore } from 'src/stores/line-store';
const $q = useQuasar();
const route = useRoute();
@ -244,6 +259,7 @@ const router = useRouter();
const searchId = ref('');
const drawStore = useDrawStore();
const lineStore = useLineStore();
watch(
() => drawStore.drawMode,
@ -419,6 +435,13 @@ function oneClickLogicSection() {
.getDrawAssistant(LogicSection.Type) as LogicSectionDraw;
logicSectionDraw.oneGenerates();
}
function oneClickSlope() {
//
const slopeDraw = drawStore
.getDrawApp()
.getDrawAssistant(Slope.Type) as SlopeDraw;
slopeDraw.oneGenerates();
}
function oneClickLink() {
drawStore.oneClickType = 'SectionLink';
const draw = drawStore
@ -462,4 +485,20 @@ async function saveAs(name: string) {
onUnmounted(() => {
drawStore.destroy();
});
function setShowLayer(val: string[]) {
lineStore.setShowLayer(val);
const drawApp = drawStore.getDrawApp();
const alllGraphic = drawApp.queryStore.getAllGraphics();
alllGraphic.forEach((g) => {
if (val.includes(g.type)) {
g.visible = true;
} else {
g.visible = false;
}
});
}
function onDialogClose() {
lineStore.setShowLayerDialog(false);
}
</script>

View File

@ -21,7 +21,13 @@
<q-page-container>
<div id="line-app-container"></div>
</q-page-container>
<LayerControlDialog></LayerControlDialog>
<LayerControlDialog
:showLayer="lineStore.showLayer"
:layerList="layerList"
:showDialog="lineStore.showLayerDialog"
@setShowLayer="setShowLayer"
@onDialogClose="onDialogClose"
></LayerControlDialog>
</q-layout>
</template>
@ -35,6 +41,7 @@ import StateProperties from 'src/components/line-app/StateProperties.vue';
// import { Train } from 'src/graphics/train/Train';
// import { Turnout } from 'src/graphics/turnout/Turnout';
import LayerControlDialog from 'src/components/draw-app/dialogs/LayerControlDialog.vue';
import { layerList } from 'src/drawApp/lineApp';
const canvasWidth = ref(0);
const canvasHeight = ref(0);
@ -103,4 +110,20 @@ watch(
}
}
);
function setShowLayer(val: string[]) {
lineStore.setShowLayer(val);
const lineApp = lineStore.getLineApp();
const alllGraphic = lineApp.queryStore.getAllGraphics();
alllGraphic.forEach((g) => {
if (val.includes(g.type)) {
g.visible = true;
} else {
g.visible = false;
}
});
}
function onDialogClose() {
lineStore.setShowLayerDialog(false);
}
</script>

View File

@ -0,0 +1,271 @@
<template>
<div class="q-pa-md">
<q-table
ref="tableRef"
title="厂家信息"
:style="{ height: tableHeight + 'px' }"
:rows="rows"
:columns="columnDefs"
row-key="id"
v-model:pagination="pagination"
:rows-per-page-options="[10, 20, 50, 100]"
:loading="loading"
:filter="filter"
binary-state-sort
@request="onRequest"
>
<template v-slot:top-right>
<q-input
dense
debounce="1000"
v-model="filter.name"
label="名称"
></q-input>
<q-btn flat round color="primary" icon="search" />
<q-btn color="primary" label="新建" @click="createFormShow = true" />
</template>
<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="编辑"
@click="editData(props.row)"
/>
<q-btn
color="red"
:disable="operateDisabled"
label="删除"
@click="deleteData(props.row)"
/>
</div>
</q-td>
</template>
</q-table>
<q-dialog
v-model="createFormShow"
persistent
transition-show="scale"
transition-hide="scale"
>
<q-card style="width: 300px">
<q-card-section>
<q-form
ref="myForm"
@submit="onCreate"
@reset="onReset"
class="q-gutter-md"
>
<div class="text-h6">
{{ editInfo.id ? '编辑厂家信息' : '新建厂家信息' }}
</div>
<q-input
outlined
label="名称"
v-model="editInfo.categoryName"
lazy-rules
:rules="[(val) => val.length > 0 || '请输入名称!']"
/>
<q-input outlined label="配置" v-model="editInfo.config" />
<q-card-actions align="right">
<q-btn
color="primary"
:label="editInfo.id ? '修改' : '创建'"
type="submit"
/>
<q-btn label="取消" type="reset" v-close-popup />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</q-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue';
import { useQuasar, type QTableColumn, QForm } from 'quasar';
import {
pageQuery,
createCategory,
deleteCategory,
saveCategoryData,
createParams,
CategoryItem,
getCategoryInfo,
} from '../api/CategoryInfoApi';
import { ApiError } from 'src/boot/axios';
const $q = useQuasar();
const props = withDefaults(
defineProps<{
sizeHeight: number;
}>(),
{ sizeHeight: 500 }
);
const tableHeight = computed(() => {
return props.sizeHeight - 32;
});
onMounted(() => {
tableRef.value.requestServerInteraction();
});
const columnDefs: QTableColumn[] = [
{
name: 'name',
label: '名称',
field: 'name',
required: true,
align: 'center',
},
{
name: 'created_at',
label: '创建时间',
field: 'created_at',
align: 'center',
},
{
name: 'update_at',
label: '更新时间',
field: 'update_at',
align: 'center',
},
{ name: 'operations', label: '操作', field: 'operations', align: 'center' },
];
const operateDisabled = ref(false);
const tableRef = ref();
const rows = reactive([]);
const filter = reactive({
name: '',
});
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
async function onRequest(props: any) {
const { page, rowsPerPage, sortBy, descending } = props.pagination;
const filter = props.filter;
loading.value = true;
try {
let response = await pageQuery({
current: page,
size: rowsPerPage,
name: filter.name,
});
const pageData = response;
pagination.value.rowsNumber = pageData.total;
pagination.value.page = page;
pagination.value.rowsPerPage = rowsPerPage;
pagination.value.sortBy = sortBy;
pagination.value.descending = descending;
rows.splice(0, rows.length, ...(pageData.records as []));
} catch (err) {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
} finally {
loading.value = false;
}
}
const createFormShow = ref(false);
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
operateDisabled.value = true;
try {
const params: createParams = {
name: editInfo.categoryName,
config: JSON.stringify(editInfo.config),
};
if (editInfo.id) {
await saveCategoryData(+editInfo.id, params);
} else {
await createCategory(params);
}
onReset();
createFormShow.value = false;
tableRef.value.requestServerInteraction(); //
} catch (err) {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
} finally {
operateDisabled.value = false;
}
}
});
}
function onReset() {
editInfo.id = '';
editInfo.categoryName = '';
editInfo.config = '';
myForm.value?.resetValidation();
}
async function deleteData(row: CategoryItem) {
operateDisabled.value = true;
$q.dialog({
title: '确认',
message: `确认删除厂家 "${row.name}" 吗?`,
cancel: true,
})
.onOk(async () => {
try {
await deleteCategory(row.id);
tableRef.value.requestServerInteraction(); //
} catch (err) {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
}
})
.onDismiss(() => {
operateDisabled.value = false;
});
}
const editInfo = reactive({
id: '',
categoryName: '',
config: '',
});
function editData(row: CategoryItem) {
getCategoryInfo(row.id)
.then((res: CategoryItem) => {
editInfo.id = res.id + '';
editInfo.categoryName = res.name;
editInfo.config = res.config ? JSON.parse(res.config) : '';
createFormShow.value = true;
})
.catch((err) => {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
});
}
</script>

View File

@ -58,30 +58,32 @@
transition-hide="scale"
>
<q-card style="width: 300px">
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-card-section>
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<div class="text-h6">新建草稿图</div>
<q-input
outlined
label="名称"
label="名称 * "
v-model="draftName"
lazy-rules
:rules="[(val) => val.length > 0 || '请输入名称!']"
/>
<q-select
v-model="createType"
:options="typeOptions"
v-model="categoryId"
:options="categoryOptions"
emit-value
map-options
label="类型 * "
label="厂家 * "
lazy-rules
:rules="[(val) => val.length > 0 || '请选择厂家!']"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn color="primary" label="创建" type="submit" />
<q-btn label="取消" v-close-popup />
</q-card-actions>
</q-form>
<q-card-actions align="right">
<q-btn color="primary" label="创建" type="submit" />
<q-btn label="取消" v-close-popup />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</q-dialog>
@ -93,11 +95,8 @@
>
<q-card style="width: 300px">
<q-card-section>
<div class="text-h6">草稿发布</div>
</q-card-section>
<q-form ref="pubForm" @submit="publishGraphics" class="q-gutter-md">
<q-card-section>
<q-form ref="pubForm" @submit="publishGraphics" class="q-gutter-md">
<div class="text-h6">草稿发布</div>
<q-input
outlined
disable
@ -111,23 +110,20 @@
lazy-rules
:rules="[(val) => val.length > 0 || '请输入名称!']"
/>
<!-- <q-select
v-if="publishForm.type == 'Line'"
v-model="publishForm.lineId"
:options="lineOptions"
emit-value
map-options
label="线路 * "
<q-input
outlined
label="备注 * "
v-model="publishForm.note"
lazy-rules
:rules="[(val) => val || '请选择线路!']"
/> -->
</q-card-section>
:rules="[(val) => val.length > 0 || '请输入备注!']"
/>
<q-card-actions align="right">
<q-btn color="primary" label="发布" type="submit" />
<q-btn label="取消" v-close-popup />
</q-card-actions>
</q-form>
<q-card-actions align="right">
<q-btn color="primary" label="发布" type="submit" />
<q-btn label="取消" v-close-popup />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</q-dialog>
</div>
@ -136,10 +132,20 @@
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue';
import { useQuasar, type QTableColumn, QForm } from 'quasar';
import { pageQuery, createDraft, deleteDraft } from '../api/DraftApi';
import {
pageQuery,
createDraft,
deleteDraft,
DraftItem,
} from '../api/DraftApi';
import { publishDraft } from '../api/PublishApi';
// import { getLineList } from '../api/LineInfoApi';
import { ApiError } from 'src/boot/axios';
import { CategoryItem, getCategoryList } from 'src/api/CategoryInfoApi';
interface OptionsItem {
label: string;
value: string;
}
const $q = useQuasar();
@ -154,41 +160,9 @@ const tableHeight = computed(() => {
return props.sizeHeight - 32;
});
const typeOptions = [
{ label: '线路', value: 'Line' },
// { label: '线', value: 'LineNetwork' },
];
const createType = ref('Line');
// let lineOptions: Array<{ label: string; value: number }> = [];
// function getAllLineList() {
// lineOptions = [];
// getLineList()
// .then((res) => {
// res.forEach((item) => {
// const obj = {
// label: item.name,
// value: item.lineId,
// };
// lineOptions.push(obj);
// });
// })
// .catch((err) => {
// console.log(err, '---err--');
// });
// }
// 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();
// getAllLineList();
getCategoryListFn();
});
const columnDefs: QTableColumn[] = [
@ -200,14 +174,14 @@ const columnDefs: QTableColumn[] = [
align: 'center',
},
// { name: 'creator', label: '', field: 'creator', align: 'center' },
// {
// name: 'type',
// label: '',
// field: (row) => {
// return typeOptionsMap.value[row.type];
// },
// align: 'center',
// },
{
name: 'category',
label: '厂家',
field: (row) => {
return categoryName(row.category);
},
align: 'center',
},
{
name: 'created_at',
label: '创建时间',
@ -277,7 +251,7 @@ function onCreate() {
try {
await createDraft({
name: draftName.value,
type: createType.value,
category: +categoryId.value,
});
createFormShow.value = false;
tableRef.value.requestServerInteraction(); //
@ -299,25 +273,23 @@ const publishForm = reactive({
id: '',
draftName: '',
pubName: '',
// lineId: '',
type: 'Line',
note: '',
});
function prePublish(row: any) {
function prePublish(row: DraftItem) {
publishFormShow.value = true;
publishForm.id = row.id;
publishForm.id = row.id + '';
publishForm.draftName = row.name;
publishForm.pubName = row.name;
// publishForm.lineId = '';
publishForm.type = row.type || 'Line';
}
async function publishGraphics() {
pubForm.value?.validate().then(async (res) => {
if (res) {
try {
const params: { draftId: number; name: string; lineId?: number } = {
const params: { draftId: number; name: string; note: string } = {
draftId: +publishForm.id,
name: publishForm.pubName,
note: publishForm.note,
};
await publishDraft(params);
publishFormShow.value = false;
@ -336,7 +308,7 @@ async function publishGraphics() {
});
}
async function deleteData(row: any) {
async function deleteData(row: DraftItem) {
operateDisabled.value = true;
$q.dialog({
title: '确认',
@ -359,4 +331,28 @@ async function deleteData(row: any) {
operateDisabled.value = false;
});
}
const categoryOptions: OptionsItem[] = [];
const categoryId = ref('');
function categoryName(val?: number) {
let n = '';
if (val) {
const find = categoryOptions.find((item) => {
return item.value == val + '';
});
n = find ? find.label : '';
}
return n;
}
function getCategoryListFn() {
getCategoryList()
.then((res: CategoryItem[]) => {
res.forEach((item) => {
categoryOptions.push({ label: item.name, value: item.id + '' });
});
})
.catch((err) => {
console.log(err, '获取厂家列表失败!');
});
}
</script>

View File

@ -32,6 +32,11 @@
label="创建仿真"
@click="create(props.row)"
/>
<q-btn
color="primary"
label="另存到草稿"
@click="showSaveToDraftFn(props.row)"
/>
<q-btn
color="red"
:disable="operateDisabled"
@ -42,13 +47,50 @@
</q-td>
</template>
</q-table>
<q-dialog
v-model="showDialog"
persistent
transition-show="scale"
transition-hide="scale"
>
<q-card style="width: 300px">
<q-card-section>
<q-form ref="pubForm" @submit="saveToDraftFn" class="q-gutter-md">
<div class="text-h6">另存到草稿</div>
<q-input
outlined
disable
label="发布图名称"
v-model="toDraftForm.name"
/>
<q-input
outlined
label="草稿名称"
v-model="toDraftForm.draftName"
lazy-rules
:rules="[(val) => val.length > 0 || '请输入草稿名称!']"
/>
<q-card-actions align="right">
<q-btn color="primary" label="确定" type="submit" />
<q-btn label="取消" v-close-popup />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</q-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue';
import { useQuasar, type QTableColumn } from 'quasar';
import { pageQuery, deletePublish } from '../api/PublishApi';
import {
pageQuery,
deletePublish,
saveToDraft,
PublishItem,
} from '../api/PublishApi';
import { useRouter } from 'vue-router';
import { createSimulation } from 'src/api/Simulation';
import { ApiError } from 'src/boot/axios';
@ -79,6 +121,13 @@ const columnDefs: QTableColumn[] = [
required: true,
align: 'center',
},
{
name: 'note',
label: '备注',
field: 'note',
required: true,
align: 'center',
},
{
name: 'publishAt',
label: '发布时间',
@ -133,7 +182,7 @@ async function onRequest(props: any) {
}
}
async function create(row: any) {
async function create(row: PublishItem) {
createSimulation({ mapId: row.id })
.then((res) => {
const query = {
@ -152,7 +201,7 @@ async function create(row: any) {
});
}
async function deleteData(row: any) {
async function deleteData(row: PublishItem) {
operateDisabled.value = true;
$q.dialog({
title: '确认',
@ -175,4 +224,30 @@ async function deleteData(row: any) {
operateDisabled.value = false;
});
}
const showDialog = ref(false);
const toDraftForm = reactive({
id: '',
name: '',
draftName: '',
});
function showSaveToDraftFn(row: PublishItem) {
toDraftForm.id = row.id + '';
toDraftForm.name = row.name;
showDialog.value = true;
}
function saveToDraftFn() {
saveToDraft(+toDraftForm.id, { name: toDraftForm.draftName })
.then((res) => {
console.log(res, 'res');
showDialog.value = false;
})
.catch((err) => {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
});
}
</script>

View File

@ -35,9 +35,9 @@ const routes: RouteRecordRaw[] = [
component: () => import('pages/PublishManage.vue'),
},
{
path: 'lineInfo',
name: 'lineInfo',
component: () => import('pages/LineInfoManage.vue'),
path: 'categoryInfo',
name: 'categoryInfo',
component: () => import('pages/CategoryManage.vue'),
},
],
},

View File

@ -10,8 +10,8 @@ export const useLineStore = defineStore('line', {
simulationId: null as string | null,
socketStates: null as GraphicState[] | null,
stateProCount: 0,
showLayer: [] as string[], // 显示的图层
showLayerDialog: false, // 显示图层控制弹窗
showLayer: [] as string[], // 显示的图层(草稿和发布图公用)
showLayerDialog: false, // 显示图层控制弹窗(草稿和发布图公用)
}),
getters: {
selectedGraphicType: (state) => {