Merge branch 'master' of git.code.tencent.com:beijing-rtss-test/bj-rtss-client

This commit is contained in:
Yuan 2023-10-12 16:22:00 +08:00
commit 56d857a7b1
35 changed files with 1767 additions and 733 deletions

View File

@ -7,18 +7,9 @@
</q-card-section>
<q-separator inset></q-separator>
<q-card-section>
<!-- <template v-if="drawStore.drawGraphicType === Rect.Type">
<rect-template></rect-template>
</template> -->
<template v-if="drawStore.drawGraphicType === Platform.Type">
<platform-template></platform-template>
</template>
<template v-if="drawStore.drawGraphicType === Section.Type">
<section-template></section-template>
</template>
<template v-if="drawStore.drawGraphicType === Station.Type">
<station-template></station-template>
</template>
<!-- <template v-if="drawStore.drawGraphicType === Train.Type">
<train-template></train-template>
</template> -->
@ -48,6 +39,9 @@
<platform-property
v-if="drawStore.selectedGraphicType === Platform.Type"
></platform-property>
<screenDoor-property
v-if="drawStore.selectedGraphicType === ScreenDoor.Type"
></screenDoor-property>
<station-property
v-if="drawStore.selectedGraphicType === Station.Type"
></station-property>
@ -132,14 +126,15 @@
</template>
<script setup lang="ts">
// import RectTemplate from './templates/RectTemplate.vue';
import PlatformTemplate from './templates/PlatformTemplate.vue';
import StationTemplate from './templates/StationTemplate.vue';
// import TrainTemplate from './templates/TrainTemplate.vue';
import SectionTemplate from './templates/SectionTemplate.vue';
import CanvasProperty from './properties/CanvasProperty.vue';
import PlatformProperty from './properties/PlatformProperty.vue';
import { Platform } from 'src/graphics/platform/Platform';
import ScreenDoorProperty from './properties/ScreenDoorProperty.vue';
import { ScreenDoor } from 'src/graphics/screenDoor/ScreenDoor';
import StationProperty from './properties/StationProperty.vue';
import { Station } from 'src/graphics/station/Station';
// import TrainTemplate from './templates/TrainTemplate.vue';
import SectionTemplate from './templates/SectionTemplate.vue';
// import TrainProperty from './properties/TrainProperty.vue';
import TrainWindowProperty from './properties/TrainWindowProperty.vue';
import AxleCountingProperty from './properties/AxleCountingProperty.vue';
@ -151,8 +146,6 @@ import SectionProperty from './properties/SectionProperty.vue';
import SeparatorProperty from './properties/SeparatorProperty.vue';
import TransponderProperty from './properties/TransponderProperty.vue';
import SectionLinkProperty from './properties/SectionLinkProperty.vue';
import { Platform } from 'src/graphics/platform/Platform';
import { Station } from 'src/graphics/station/Station';
// import { Train } from 'src/graphics/train/Train';
import { useDrawStore } from 'src/stores/draw-store';
import { Signal } from 'src/graphics/signal/Signal';

View File

@ -61,6 +61,8 @@ const tableRef = ref<QTable>();
const deviceTypeMap = {
1: '道岔',
5: '信号机',
6: '车站',
7: '屏蔽门',
};
const columns: QTable['columns'] = [
{

View File

@ -0,0 +1,151 @@
<template>
<draggable-dialog
seamless
@show="onDialogShow"
title="门控箱关联的设备"
:width="600"
:height="0"
>
<template v-slot:footer>
<q-table
ref="tableRef"
row-key="id"
v-model:pagination="pagination"
:loading="loading"
:rows="rows"
:columns="columns"
@request="onRequest"
:rows-per-page-options="[5, 10, 20, 50]"
>
<template v-slot:body-cell="props">
<q-td :props="props" class="custom-column">
{{ props.value }}
</q-td>
</template>
<template v-slot:body-cell-operations="props">
<q-td :props="props">
<div class="q-gutter-sm row justify-center">
<q-btn color="primary" label="编辑" @click="onEdit(props.row)" />
<q-btn color="red" label="删除" @click="deleteData(props.row)" />
</div>
</q-td>
</template>
</q-table>
</template>
<template v-slot:titleButton>
<q-btn
color="primary"
label="新建"
style="margin-right: 10px"
@click="creatData"
/>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { QTable, useQuasar } from 'quasar';
import { errorNotify, successNotify } from 'src/utils/CommonNotify';
import {
deleteGatedRelateDevice,
loadGatedRelateDeviceList,
RelateDevicelistItem,
} from 'src/drawApp/pslApp';
import { usePslDrawStore } from 'src/stores/psl-draw-store';
const pslDrawStore = usePslDrawStore();
const $q = useQuasar();
const tableRef = ref<QTable>();
const deviceTypeMap = {
6: '车站',
};
const columns: QTable['columns'] = [
{
name: 'deviceType',
label: '设备类型',
field: (row) => deviceTypeMap[row.deviceType as keyof typeof deviceTypeMap],
align: 'center',
},
{ name: 'code', label: '设备编号', field: 'code', align: 'center' },
{
name: 'combinationtypes',
label: '关联的组合类型',
field: (row: RelateDevicelistItem) => {
if (row.combinationtypes) {
const ref = row.combinationtypes.map(
(combinationtype) => combinationtype.code
);
return ref.join('\\');
}
},
align: 'center',
},
{ name: 'operations', label: '操作', field: 'operations', align: 'center' },
];
const rows = ref<RelateDevicelistItem[]>([]);
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
const onRequest: QTable['onRequest'] = async (props) => {
const { page, rowsPerPage } = props.pagination;
loading.value = true;
const refDatas = loadGatedRelateDeviceList();
pagination.value.rowsNumber = refDatas.length;
pagination.value.page = page;
pagination.value.rowsPerPage = rowsPerPage;
rows.value = refDatas.slice((page - 1) * rowsPerPage, page * rowsPerPage);
loading.value = false;
};
const onDialogShow = () => {
tableRef.value?.requestServerInteraction();
pslDrawStore.table = tableRef.value;
};
const props = defineProps<{
onEditClick: (row: RelateDevicelistItem) => void;
}>();
function onEdit(row: RelateDevicelistItem) {
pslDrawStore.showRelateDeviceConfig = true;
setTimeout(() => {
props.onEditClick(row);
}, 0);
}
function creatData() {
pslDrawStore.showRelateDeviceConfig = true;
}
function deleteData(row: RelateDevicelistItem) {
$q.dialog({ message: `确定删除 "${row.code}" 吗?`, cancel: true }).onOk(
async () => {
try {
deleteGatedRelateDevice(row);
successNotify('删除数据成功!');
} catch (err) {
errorNotify('删除失败:', err);
} finally {
tableRef.value?.requestServerInteraction();
}
}
);
}
</script>
<style scoped>
.custom-column {
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -0,0 +1,151 @@
<template>
<draggable-dialog
seamless
@show="onDialogShow"
title="车站关联的设备"
:width="600"
:height="0"
>
<template v-slot:footer>
<q-table
ref="tableRef"
row-key="id"
v-model:pagination="pagination"
:loading="loading"
:rows="rows"
:columns="columns"
@request="onRequest"
:rows-per-page-options="[5, 10, 20, 50]"
>
<template v-slot:body-cell="props">
<q-td :props="props" class="custom-column">
{{ props.value }}
</q-td>
</template>
<template v-slot:body-cell-operations="props">
<q-td :props="props">
<div class="q-gutter-sm row justify-center">
<q-btn color="primary" label="编辑" @click="onEdit(props.row)" />
<q-btn color="red" label="删除" @click="deleteData(props.row)" />
</div>
</q-td>
</template>
</q-table>
</template>
<template v-slot:titleButton>
<q-btn
color="primary"
label="新建"
style="margin-right: 10px"
@click="creatData"
/>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { QTable, useQuasar } from 'quasar';
import { errorNotify, successNotify } from 'src/utils/CommonNotify';
import {
deleteStationRelateDevice,
loadStationRelateDeviceList,
RelateDevicelistItem,
} from 'src/drawApp/thApp';
import { useDrawStore } from 'src/stores/draw-store';
const drawStore = useDrawStore();
const $q = useQuasar();
const tableRef = ref<QTable>();
const deviceTypeMap = {
6: '车站',
};
const columns: QTable['columns'] = [
{
name: 'deviceType',
label: '设备类型',
field: (row) => deviceTypeMap[row.deviceType as keyof typeof deviceTypeMap],
align: 'center',
},
{ name: 'code', label: '设备编号', field: 'code', align: 'center' },
{
name: 'combinationtypes',
label: '关联的组合类型',
field: (row: RelateDevicelistItem) => {
if (row.combinationtypes) {
const ref = row.combinationtypes.map(
(combinationtype) => combinationtype.code
);
return ref.join('\\');
}
},
align: 'center',
},
{ name: 'operations', label: '操作', field: 'operations', align: 'center' },
];
const rows = ref<RelateDevicelistItem[]>([]);
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
const onRequest: QTable['onRequest'] = async (props) => {
const { page, rowsPerPage } = props.pagination;
loading.value = true;
const refDatas = loadStationRelateDeviceList();
pagination.value.rowsNumber = refDatas.length;
pagination.value.page = page;
pagination.value.rowsPerPage = rowsPerPage;
rows.value = refDatas.slice((page - 1) * rowsPerPage, page * rowsPerPage);
loading.value = false;
};
const onDialogShow = () => {
tableRef.value?.requestServerInteraction();
drawStore.table = tableRef.value;
};
const props = defineProps<{
onEditClick: (row: RelateDevicelistItem) => void;
}>();
function onEdit(row: RelateDevicelistItem) {
drawStore.showRelateDeviceConfig = true;
setTimeout(() => {
props.onEditClick(row);
}, 0);
}
function creatData() {
drawStore.showRelateDeviceConfig = true;
}
function deleteData(row: RelateDevicelistItem) {
$q.dialog({ message: `确定删除 "${row.code}" 吗?`, cancel: true }).onOk(
async () => {
try {
deleteStationRelateDevice(row);
successNotify('删除数据成功!');
} catch (err) {
errorNotify('删除失败:', err);
} finally {
tableRef.value?.requestServerInteraction();
}
}
);
}
</script>
<style scoped>
.custom-column {
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -15,6 +15,16 @@
@blur="onUpdate"
label="名称"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="gatedBoxModel.refScreenDoor"
:options="gatedBoxList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联屏蔽门"
></q-select>
</q-form>
</template>
@ -22,9 +32,24 @@
import { GatedBoxData } from 'src/drawApp/graphics/GatedBoxInteraction';
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive } from 'vue';
import { GatedBox } from 'src/graphics/gatedBox/GatedBox';
const { data: gatedBoxModel, onUpdate } = useFormData(
new GatedBoxData(),
useDrawStore().getDrawApp()
);
const gatedBoxList: { label: string; value: string }[] = reactive([]);
onMounted(() => {
const gatedBoxs = useDrawStore()
.getDrawApp()
.queryStore.queryByType<GatedBox>(GatedBox.Type);
gatedBoxs.forEach((p) => {
gatedBoxList.push({
value: p.id,
label: `${p.datas.code}[${p.datas.index}]`,
});
});
});
</script>

View File

@ -7,14 +7,14 @@
label="id"
hint=""
/>
<q-input
<!-- <q-input
outlined
class="q-mt-sm"
v-model="textContentModel.code"
@blur="onUpdate"
label="IBP文字Code"
lazy-rules
/>
/> -->
<q-input
outlined
class="q-mt-sm"

View File

@ -1,6 +1,15 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="platformModel.id" label="id" hint="" />
<q-input outlined readonly v-model="platformModel.id" label="id" />
<q-input
outlined
label="站台编号"
type="textarea"
@blur="onUpdate"
v-model="platformModel.code"
lazy-rules
autogrow
/>
<q-input
outlined
v-model.number="platformModel.index"
@ -8,32 +17,6 @@
@blur="onUpdate"
label="索引"
/>
<q-select
outlined
@blur="onUpdate"
v-model="platformModel.hasdoor"
emit-value
map-options
:options="optionsDoor"
label="是否有屏蔽门"
/>
<q-select
outlined
@blur="onUpdate"
v-model="platformModel.direction"
emit-value
map-options
:options="optionsDirection"
label="方向"
/>
<q-input
v-if="platformModel.hasdoor"
outlined
v-model.number="platformModel.sonDoorAmount"
type="number"
@blur="onUpdate"
label="子屏蔽门的数量"
/>
<q-list bordered separator class="rounded-borders">
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
@ -45,6 +28,16 @@
</div>
</q-item-section>
</q-item>
<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 square color="primary" text-color="white">
{{ sectionRelation }}
</q-chip>
</div>
</q-item-section>
</q-item>
</q-list>
</q-form>
</template>
@ -56,20 +49,13 @@ import { useDrawStore } from 'src/stores/draw-store';
import { computed } from 'vue';
import { Station } from 'src/graphics/station/Station';
import { Platform } from 'src/graphics/platform/Platform';
import { Section } from 'src/graphics/section/Section';
const drawStore = useDrawStore();
const { data: platformModel, onUpdate } = useFormData(
new PlatformData(),
drawStore.getDrawApp()
);
const optionsDoor = [
{ label: '是', value: true },
{ label: '否', value: false },
];
const optionsDirection = [
{ label: '向上', value: 'up' },
{ label: '向下', value: 'down' },
];
const stationRelation = computed(() => {
const platform = drawStore.selectedGraphic as Platform;
@ -78,7 +64,18 @@ const stationRelation = computed(() => {
.map((relation) => relation.getOtherGraphic<Station>(platform).datas.code);
let refStation;
if (refStations) {
return (refStation = refStations[0]);
refStation = refStations[0];
}
return refStation;
});
const sectionRelation = computed(() => {
const platform = drawStore.selectedGraphic as Platform;
const refSections = platform?.relationManage
.getRelationsOfGraphicAndOtherType(platform, Section.Type)
.map((relation) => relation.getOtherGraphic<Section>(platform).datas.code);
let refStation;
if (refSections) {
refStation = refSections[0];
}
return refStation;
});

View File

@ -0,0 +1,326 @@
<template>
<div v-if="showRangeConfig">
<q-card class="q-gutter-sm q-pa-sm">
<q-card-section>
<div class="text-h6">{{ handleState }}</div>
</q-card-section>
<q-separator inset></q-separator>
<q-form ref="myForm" @submit="onSubmit" @reset="onReset">
<q-select
outlined
v-model="relateDeviceConfig.deviceType"
:options="optionsType"
label="设备类型"
:map-options="true"
:emit-value="true"
:rules="[(val) => val != '' || '设备类型不能为空']"
/>
<q-input
outlined
label="设备编号"
v-model="relateDeviceConfig.code"
:rules="[(val) => val.trim() != '' || '名称不能为空']"
/>
<q-list bordered separator class="rounded-borders">
<q-expansion-item
expand-separator
v-for="(
combinationtype, index
) in relateDeviceConfig.combinationtypes"
:key="index"
v-model="combinationtype.expanded"
:label="combinationtype.code"
@click="toggleItem(index)"
>
<q-card>
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
<q-input
outlined
v-model="combinationtype.code"
label="组合类型"
lazy-rules
/>
<div class="q-gutter-sm row">
<q-chip
v-for="item in combinationtype.refDevicesCode"
:key="item"
square
color="primary"
text-color="white"
removable
@remove="removeSelect(item)"
>
{{ item }}
</q-chip>
</div>
<div>
<q-btn
v-show="combinationtype.refDevicesCode.length > 0"
style="width: 130px"
label="清空框选的设备"
color="red"
class="q-mr-md"
@click="clearAllSelect(index)"
/>
<q-btn
label="删除组合类型"
color="secondary"
@click="deleteCombinationtype(index)"
/>
</div>
</q-item-section>
</q-item>
</q-card>
</q-expansion-item>
</q-list>
<q-btn
class="q-mt-md"
label="增加组合类型"
color="secondary"
@click="addCombinationtype"
/>
<div class="q-gutter-sm q-pa-md row justify-center">
<q-btn label="提交" type="submit" color="primary" class="q-mr-md" />
<q-btn label="重置" type="reset" color="primary" class="q-mr-md" />
<q-btn label="返回" color="primary" @click="goBack" />
</div>
</q-form>
</q-card>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import { QForm, useQuasar } from 'quasar';
import { JlGraphic } from 'src/jl-graphic';
import { usePslDrawStore } from 'src/stores/psl-draw-store';
import { PslKey } from 'src/graphics/pslKey/pslKey';
import { PslButton } from 'src/graphics/pslButton/pslButton';
import { PslLight } from 'src/graphics/pslLight/pslLight';
import { pslGraphicData } from 'src/protos/pslGraphics';
import {
creatGatedRelateDevice,
editGatedRelateDevice,
RelateDevicelistItem,
} from 'src/drawApp/pslApp';
import { graphicData } from 'src/protos/stationLayoutGraphics';
defineExpose({ editRelateDevices });
const pslDrawStore = usePslDrawStore();
const $q = useQuasar();
const showRangeConfig = ref(true);
const relateDeviceConfig = ref<{
deviceType: graphicData.RelatedRef.DeviceType | undefined;
code: string;
combinationtypes: {
code: string;
refDevices: string[];
refDevicesCode: string[];
expanded: boolean;
}[];
}>({
deviceType: undefined,
code: '',
combinationtypes: [
{ code: '组合类型', refDevices: [], refDevicesCode: [], expanded: false },
],
});
const handleState = ref('新建门控箱关联设备');
const optionsType = [
{ label: '车站', value: graphicData.RelatedRef.DeviceType.station },
];
let selectGraphic: JlGraphic[] = [];
watch(
() => pslDrawStore.selectedGraphics,
(val) => {
if (val && val.length > 0 && clickIndex !== null) {
const selectFilter = pslDrawStore.selectedGraphics?.filter(
(g) =>
g.type == PslKey.Type ||
g.type == PslButton.Type ||
g.type == PslLight.Type
) as JlGraphic[];
selectGraphic.push(...selectFilter);
selectGraphic = Array.from(new Set(selectGraphic));
pslDrawStore.getDrawApp().updateSelected(...selectGraphic);
relateDeviceConfig.value.combinationtypes[clickIndex].refDevicesCode =
selectGraphic.map((g) =>
(g as PslKey | PslButton | PslLight).datas.code == ''
? g.id
: (g as PslKey | PslButton | PslLight).datas.code
);
relateDeviceConfig.value.combinationtypes[clickIndex].refDevices =
selectGraphic.map((g) => g.id) as string[];
}
}
);
onMounted(() => {
onReset();
});
const myForm = ref<QForm | null>(null);
let editRow: RelateDevicelistItem;
let handle = ref('');
let handleError = ref('');
async function onSubmit() {
myForm.value?.validate().then(async (res) => {
if (res) {
try {
const combinationtypes: pslGraphicData.Combinationtype[] = [];
relateDeviceConfig.value.combinationtypes.forEach((combinationtype) => {
combinationtypes.push(
new pslGraphicData.Combinationtype({
code: combinationtype.code,
refDevices: combinationtype.refDevices,
})
);
});
const gatedRelateDevice = new pslGraphicData.GatedRelateDevice({
deviceType: relateDeviceConfig.value.deviceType,
code: relateDeviceConfig.value.code,
combinationtypes: combinationtypes,
});
if (handleState.value == '新建门控箱关联设备') {
handle.value = '创建成功';
handleError.value = '创建失败';
creatGatedRelateDevice(gatedRelateDevice);
} else {
handle.value = '更新成功';
handleError.value = '更新失败';
editGatedRelateDevice(editRow, gatedRelateDevice);
}
pslDrawStore.table?.requestServerInteraction();
$q.notify({
type: 'positive',
message: handle.value,
});
onReset();
showRangeConfig.value = false;
} catch (err) {
$q.notify({
type: 'negative',
message: handleError.value,
});
} finally {
setTimeout(() => {
showRangeConfig.value = true;
}, 0);
}
}
});
}
async function editRelateDevices(row: RelateDevicelistItem) {
try {
const drawApp = pslDrawStore.getDrawApp();
handleState.value = '编辑门控箱关联设备';
selectGraphic = [];
drawApp.updateSelected();
editRow = row;
relateDeviceConfig.value.deviceType = row.deviceType;
relateDeviceConfig.value.code = row.code;
row.combinationtypes.forEach((combinationtype) => {
const refCode: string[] = [];
combinationtype.refDevices.forEach((id) => {
const g = drawApp.queryStore.queryById(id);
refCode.push(g.code);
});
combinationtype.refDevicesCode = refCode;
combinationtype.expanded = false;
});
relateDeviceConfig.value.combinationtypes = [];
row.combinationtypes.forEach((combinationtype) => {
const { code, refDevices, refDevicesCode, expanded } = combinationtype;
relateDeviceConfig.value.combinationtypes.push({
code,
refDevices,
refDevicesCode: refDevicesCode as string[],
expanded: expanded as boolean,
});
});
} catch (err) {
$q.notify({
type: 'negative',
message: '没有需要编辑的详细信息',
});
}
}
let clickIndex: null | number = null;
function toggleItem(index: number) {
const drawApp = pslDrawStore.getDrawApp();
selectGraphic = [];
drawApp.updateSelected();
const combinationtypes = relateDeviceConfig.value.combinationtypes;
if (combinationtypes[index].expanded == true) {
clickIndex = index;
const select: JlGraphic[] = [];
combinationtypes[index].refDevices.forEach((id: string) => {
const g = drawApp.queryStore.queryById(id);
select.push(g);
});
drawApp.updateSelected(...select);
} else {
clickIndex = null;
}
}
function removeSelect(code: string) {
const clickTarget =
relateDeviceConfig.value.combinationtypes[clickIndex as number];
const removeIndex = clickTarget.refDevicesCode.findIndex(
(item) => item == code
);
selectGraphic.splice(removeIndex, 1);
clickTarget.refDevicesCode.splice(removeIndex, 1);
clickTarget.refDevices.splice(removeIndex, 1);
pslDrawStore.getDrawApp().updateSelected(...selectGraphic);
}
function clearAllSelect(index: number) {
relateDeviceConfig.value.combinationtypes[index].refDevices = [];
relateDeviceConfig.value.combinationtypes[index].refDevicesCode = [];
clearAllSelectAtCanvas();
}
function clearAllSelectAtCanvas() {
selectGraphic = [];
pslDrawStore.getDrawApp().updateSelected();
}
function addCombinationtype() {
relateDeviceConfig.value.combinationtypes.push({
code: '组合类型',
refDevices: [],
refDevicesCode: [],
expanded: false,
});
}
function deleteCombinationtype(index: number) {
relateDeviceConfig.value.combinationtypes.splice(index, 1);
clearAllSelectAtCanvas();
}
function onReset() {
clickIndex = null;
handleState.value = '新建门控箱关联设备';
relateDeviceConfig.value = {
deviceType: undefined,
code: '',
combinationtypes: [
{ code: '组合类型', refDevices: [], refDevicesCode: [], expanded: false },
],
};
clearAllSelectAtCanvas();
}
function goBack() {
onReset();
pslDrawStore.showRelateDeviceConfig = false;
}
</script>

View File

@ -131,6 +131,8 @@ const handleState = ref('新建设备关联继电器');
const optionsType = [
{ label: '道岔', value: graphicData.RelatedRef.DeviceType.Turnout },
{ label: '信号机', value: graphicData.RelatedRef.DeviceType.signal },
{ label: '车站', value: graphicData.RelatedRef.DeviceType.station },
{ label: '屏蔽门', value: graphicData.RelatedRef.DeviceType.ScreenDoor },
];
let selectGraphic: JlGraphic[] = [];

View File

@ -0,0 +1,128 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="screenDoorModel.id" label="id" />
<q-input
outlined
label="屏蔽门编号"
type="textarea"
@blur="onUpdate"
v-model="screenDoorModel.code"
lazy-rules
autogrow
/>
<q-input
outlined
v-model.number="screenDoorModel.sonDoorAmount"
type="number"
@blur="onUpdate"
label="子屏蔽门的数量"
/>
<q-list bordered separator class="rounded-borders">
<q-expansion-item
expand-separator
v-for="(screenDoorGroup, index) in screenDoorModel.screenDoorGroupList"
:key="screenDoorGroup"
:label="'列车编组数量为' + screenDoorGroup.trainGroupAmount"
>
<q-card>
<q-item no-wrap class="q-gutter-y-sm column">
<q-input
outlined
v-model.number="screenDoorGroup.trainGroupAmount"
type="number"
label="列车编组数量"
/>
<q-input
outlined
v-model.number="screenDoorGroup.startSmallDoor"
type="number"
label="起始的屏蔽门编号"
/>
<q-input
outlined
v-model.number="screenDoorGroup.endSmallDoor"
type="number"
label="结束的屏蔽门编号"
/>
<div>
<q-btn
label="确认修改"
color="secondary"
@click="onUpdate"
class="q-mr-md"
/>
<q-btn
label="删除列车编组"
color="secondary"
@click="deleteScreenDoorGroup(index)"
/>
</div>
</q-item>
</q-card>
</q-expansion-item>
</q-list>
<q-btn
class="q-mt-md"
label="增加列车编组"
color="secondary"
@click="addScreenDoorGroup"
/>
<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 square color="primary" text-color="white">
{{ platformRelation }}
</q-chip>
</div>
</q-item-section>
</q-item>
</q-list>
</q-form>
</template>
<script setup lang="ts">
import { ScreenDoorData } from 'src/drawApp/graphics/ScreenDoorInteraction';
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useDrawStore } from 'src/stores/draw-store';
import { computed } from 'vue';
import { ScreenDoor } from 'src/graphics/screenDoor/ScreenDoor';
import { Platform } from 'src/graphics/platform/Platform';
import { graphicData } from 'src/protos/stationLayoutGraphics';
const drawStore = useDrawStore();
const { data: screenDoorModel, onUpdate } = useFormData(
new ScreenDoorData(),
drawStore.getDrawApp()
);
const platformRelation = computed(() => {
const screenDoor = drawStore.selectedGraphic as ScreenDoor;
const refStations = screenDoor?.relationManage
.getRelationsOfGraphicAndOtherType(screenDoor, Platform.Type)
.map(
(relation) => relation.getOtherGraphic<Platform>(screenDoor).datas.code
);
let refStation;
if (refStations) {
refStation = refStations[0];
}
return refStation;
});
function addScreenDoorGroup() {
screenDoorModel.screenDoorGroupList = [
...screenDoorModel.screenDoorGroupList,
new graphicData.ScreenDoorGroup(),
];
}
function deleteScreenDoorGroup(index: number) {
const screenDoor = drawStore.selectedGraphic as ScreenDoor;
const data = screenDoor.datas.clone().screenDoorGroupList;
data.splice(index, 1);
screenDoor.datas.screenDoorGroupList = data;
screenDoorModel.screenDoorGroupList = data;
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="stationModel.id" label="id" hint="" />
<q-input outlined readonly v-model="stationModel.id" label="id" />
<q-input
outlined
label="车站名称"

View File

@ -0,0 +1,318 @@
<template>
<div v-if="showRangeConfig">
<q-card class="q-gutter-sm q-pa-sm">
<q-card-section>
<div class="text-h6">{{ handleState }}</div>
</q-card-section>
<q-separator inset></q-separator>
<q-form ref="myForm" @submit="onSubmit" @reset="onReset">
<q-select
outlined
v-model="relateDeviceConfig.deviceType"
:options="optionsType"
label="设备类型"
:map-options="true"
:emit-value="true"
:rules="[(val) => val != '' || '设备类型不能为空']"
/>
<q-input
outlined
label="设备编号"
v-model="relateDeviceConfig.code"
:rules="[(val) => val.trim() != '' || '名称不能为空']"
/>
<q-list bordered separator class="rounded-borders">
<q-expansion-item
expand-separator
v-for="(
combinationtype, index
) in relateDeviceConfig.combinationtypes"
:key="index"
v-model="combinationtype.expanded"
:label="combinationtype.code"
@click="toggleItem(index)"
>
<q-card>
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
<q-input
outlined
v-model="combinationtype.code"
label="组合类型"
lazy-rules
/>
<div class="q-gutter-sm row">
<q-chip
v-for="item in combinationtype.refDevicesCode"
:key="item"
square
color="primary"
text-color="white"
removable
@remove="removeSelect(item)"
>
{{ item }}
</q-chip>
</div>
<div>
<q-btn
v-show="combinationtype.refDevicesCode.length > 0"
style="width: 130px"
label="清空框选的设备"
color="red"
class="q-mr-md"
@click="clearAllSelect(index)"
/>
<q-btn
label="删除组合类型"
color="secondary"
@click="deleteCombinationtype(index)"
/>
</div>
</q-item-section>
</q-item>
</q-card>
</q-expansion-item>
</q-list>
<q-btn
class="q-mt-md"
label="增加组合类型"
color="secondary"
@click="addCombinationtype"
/>
<div class="q-gutter-sm q-pa-md row justify-center">
<q-btn label="提交" type="submit" color="primary" class="q-mr-md" />
<q-btn label="重置" type="reset" color="primary" class="q-mr-md" />
<q-btn label="返回" color="primary" @click="goBack" />
</div>
</q-form>
</q-card>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import { QForm, useQuasar } from 'quasar';
import { JlGraphic } from 'src/jl-graphic';
import { useDrawStore } from 'src/stores/draw-store';
import { EsbButton } from 'src/graphics/esbButton/EsbButton';
import {
creatStationRelateDevice,
editStationRelateDevice,
RelateDevicelistItem,
} from 'src/drawApp/thApp';
import { graphicData } from 'src/protos/stationLayoutGraphics';
defineExpose({ editRelateDevices });
const drawStore = useDrawStore();
const $q = useQuasar();
const showRangeConfig = ref(true);
const relateDeviceConfig = ref<{
deviceType: graphicData.RelatedRef.DeviceType | undefined;
code: string;
combinationtypes: {
code: string;
refDevices: string[];
refDevicesCode: string[];
expanded: boolean;
}[];
}>({
deviceType: undefined,
code: '',
combinationtypes: [
{ code: '组合类型', refDevices: [], refDevicesCode: [], expanded: false },
],
});
const handleState = ref('新建车站关联设备');
const optionsType = [
{ label: '车站', value: graphicData.RelatedRef.DeviceType.station },
];
let selectGraphic: JlGraphic[] = [];
watch(
() => drawStore.selectedGraphics,
(val) => {
if (val && val.length > 0 && clickIndex !== null) {
const selectFilter = drawStore.selectedGraphics?.filter(
(g) => g.type == EsbButton.Type
) as JlGraphic[];
selectGraphic.push(...selectFilter);
selectGraphic = Array.from(new Set(selectGraphic));
drawStore.getDrawApp().updateSelected(...selectGraphic);
relateDeviceConfig.value.combinationtypes[clickIndex].refDevicesCode =
selectGraphic.map((g) =>
(g as EsbButton).datas.code == '' ? g.id : (g as EsbButton).datas.code
);
relateDeviceConfig.value.combinationtypes[clickIndex].refDevices =
selectGraphic.map((g) => g.id) as string[];
}
}
);
onMounted(() => {
onReset();
});
const myForm = ref<QForm | null>(null);
let editRow: RelateDevicelistItem;
let handle = ref('');
let handleError = ref('');
async function onSubmit() {
myForm.value?.validate().then(async (res) => {
if (res) {
try {
const combinationtypes: graphicData.Combinationtype[] = [];
relateDeviceConfig.value.combinationtypes.forEach((combinationtype) => {
combinationtypes.push(
new graphicData.Combinationtype({
code: combinationtype.code,
refDevices: combinationtype.refDevices,
})
);
});
const stationRelateDevice = new graphicData.StationRelateDevice({
deviceType: relateDeviceConfig.value.deviceType,
code: relateDeviceConfig.value.code,
combinationtypes: combinationtypes,
});
if (handleState.value == '新建车站关联设备') {
handle.value = '创建成功';
handleError.value = '创建失败';
creatStationRelateDevice(stationRelateDevice);
} else {
handle.value = '更新成功';
handleError.value = '更新失败';
editStationRelateDevice(editRow, stationRelateDevice);
}
drawStore.table?.requestServerInteraction();
$q.notify({
type: 'positive',
message: handle.value,
});
onReset();
showRangeConfig.value = false;
} catch (err) {
$q.notify({
type: 'negative',
message: handleError.value,
});
} finally {
setTimeout(() => {
showRangeConfig.value = true;
}, 0);
}
}
});
}
async function editRelateDevices(row: RelateDevicelistItem) {
try {
const drawApp = drawStore.getDrawApp();
handleState.value = '编辑车站关联设备';
selectGraphic = [];
drawApp.updateSelected();
editRow = row;
relateDeviceConfig.value.deviceType = row.deviceType;
relateDeviceConfig.value.code = row.code;
row.combinationtypes.forEach((combinationtype) => {
const refCode: string[] = [];
combinationtype.refDevices.forEach((id) => {
const g = drawApp.queryStore.queryById(id);
refCode.push(g.code);
});
combinationtype.refDevicesCode = refCode;
combinationtype.expanded = false;
});
relateDeviceConfig.value.combinationtypes = [];
row.combinationtypes.forEach((combinationtype) => {
const { code, refDevices, refDevicesCode, expanded } = combinationtype;
relateDeviceConfig.value.combinationtypes.push({
code,
refDevices,
refDevicesCode: refDevicesCode as string[],
expanded: expanded as boolean,
});
});
} catch (err) {
$q.notify({
type: 'negative',
message: '没有需要编辑的详细信息',
});
}
}
let clickIndex: null | number = null;
function toggleItem(index: number) {
const drawApp = drawStore.getDrawApp();
selectGraphic = [];
drawApp.updateSelected();
const combinationtypes = relateDeviceConfig.value.combinationtypes;
if (combinationtypes[index].expanded == true) {
clickIndex = index;
const select: JlGraphic[] = [];
combinationtypes[index].refDevices.forEach((id: string) => {
const g = drawApp.queryStore.queryById(id);
select.push(g);
});
drawApp.updateSelected(...select);
} else {
clickIndex = null;
}
}
function removeSelect(code: string) {
const clickTarget =
relateDeviceConfig.value.combinationtypes[clickIndex as number];
const removeIndex = clickTarget.refDevicesCode.findIndex(
(item) => item == code
);
selectGraphic.splice(removeIndex, 1);
clickTarget.refDevicesCode.splice(removeIndex, 1);
clickTarget.refDevices.splice(removeIndex, 1);
drawStore.getDrawApp().updateSelected(...selectGraphic);
}
function clearAllSelect(index: number) {
relateDeviceConfig.value.combinationtypes[index].refDevices = [];
relateDeviceConfig.value.combinationtypes[index].refDevicesCode = [];
clearAllSelectAtCanvas();
}
function clearAllSelectAtCanvas() {
selectGraphic = [];
drawStore.getDrawApp().updateSelected();
}
function addCombinationtype() {
relateDeviceConfig.value.combinationtypes.push({
code: '组合类型',
refDevices: [],
refDevicesCode: [],
expanded: false,
});
}
function deleteCombinationtype(index: number) {
relateDeviceConfig.value.combinationtypes.splice(index, 1);
clearAllSelectAtCanvas();
}
function onReset() {
clickIndex = null;
handleState.value = '新建车站关联设备';
relateDeviceConfig.value = {
deviceType: undefined,
code: '',
combinationtypes: [
{ code: '组合类型', refDevices: [], refDevicesCode: [], expanded: false },
],
};
clearAllSelectAtCanvas();
}
function goBack() {
onReset();
drawStore.showRelateDeviceConfig = false;
}
</script>

View File

@ -7,14 +7,14 @@
label="id"
hint=""
/>
<q-input
<!-- <q-input
outlined
class="q-mt-sm"
v-model="textContentModel.code"
@blur="onUpdate"
label="Psl文字Code"
lazy-rules
/>
/> -->
<q-input
outlined
class="q-mt-sm"

View File

@ -1,76 +0,0 @@
<template>
<q-form>
<q-input
outlined
v-model.number="template.lineWidth"
type="number"
@blur="onUpdate"
label="线宽 *"
lazy-rules
:rules="[(val) => (val && val > 0) || '线宽必须大于0']"
/>
<q-input
outlined
v-model="template.lineColor"
@blur="onUpdate"
label="线色 *"
lazy-rules
:rules="[(val) => (val && val.length > 0) || '线色不能为空']"
>
<template v-slot:append>
<q-icon name="colorize" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-color
v-model="template.lineColor"
@change="
(val) => {
template.lineColor = val;
onUpdate();
}
"
/>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</q-form>
</template>
<script setup lang="ts">
import { PlatformTemplate } from 'src/graphics/platform/Platform';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive } from 'vue';
const drawStore = useDrawStore();
const template = reactive({
lineWidth: 1,
lineColor: '#0000ff',
curve: false,
segmentsCount: 10,
});
onMounted(() => {
const type = drawStore.drawGraphicType;
if (type) {
const gt = drawStore.drawGraphicTemplate;
if (gt) {
// const lt = gt as PlatformTemplate;
// template.lineWidth = lt.lineWidth;
// template.lineColor = lt.lineColor;
// template.curve = lt.curve;
// template.segmentsCount = lt.segmentsCount;
}
}
});
function onUpdate() {
const gt = drawStore.drawGraphicTemplate as PlatformTemplate;
if (gt) {
// gt.lineWidth = template.lineWidth;
// gt.lineColor = template.lineColor;
// gt.curve = template.curve;
// gt.segmentsCount = template.segmentsCount;
}
}
</script>

View File

@ -1,70 +0,0 @@
<template>
<q-form>
<q-input
outlined
v-model.number="template.lineWidth"
type="number"
@blur="onUpdate"
label="字体大小 *"
lazy-rules
:rules="[(val) => (val && val > 0) || '线宽必须大于0']"
/>
<q-input
outlined
v-model="template.lineColor"
@blur="onUpdate"
label="字体颜色 *"
lazy-rules
:rules="[(val) => (val && val.length > 0) || '线色不能为空']"
>
<template v-slot:append>
<q-icon name="colorize" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-color
v-model="template.lineColor"
@change="
(val) => {
template.lineColor = val;
onUpdate();
}
"
/>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</q-form>
</template>
<script setup lang="ts">
import { LinkTemplate } from 'src/graphics/link/Link';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive } from 'vue';
const drawStore = useDrawStore();
const template = reactive({
lineWidth: 1,
lineColor: '#0000ff',
});
onMounted(() => {
const type = drawStore.drawGraphicType;
if (type) {
const gt = drawStore.drawGraphicTemplate;
if (gt) {
const lt = gt as LinkTemplate;
template.lineWidth = lt.lineWidth;
template.lineColor = lt.lineColor;
}
}
});
function onUpdate() {
const gt = drawStore.drawGraphicTemplate as LinkTemplate;
if (gt) {
gt.lineWidth = template.lineWidth;
gt.lineColor = template.lineColor;
}
}
</script>

View File

@ -15,6 +15,12 @@ import { graphicData } from 'src/protos/stationLayoutGraphics';
import { Platform, PlatformTemplate } from 'src/graphics/platform/Platform';
import { PlatformData, PlatformState } from './graphics/PlatformInteraction';
import { PlatformDraw } from 'src/graphics/platform/PlatformDrawAssistant';
import {
ScreenDoor,
ScreenDoorTemplate,
} from 'src/graphics/screenDoor/ScreenDoor';
import { ScreenDoorData } from './graphics/ScreenDoorInteraction';
import { ScreenDoorDraw } from 'src/graphics/screenDoor/ScreenDoorDrawAssistant';
import { Station, StationTemplate } from 'src/graphics/station/Station';
import { StationDraw } from 'src/graphics/station/StationDrawAssistant';
import { StationData, StationState } from './graphics/StationInteraction';
@ -141,6 +147,7 @@ export const drawCommonLayerList = [
{ label: '区段', value: Section.Type, defaultShow: true },
{ label: '区段检测点', value: AxleCounting.Type, defaultShow: true },
{ label: '站台', value: Platform.Type, defaultShow: true },
{ label: '屏蔽门', value: ScreenDoor.Type, defaultShow: true },
{ label: '车站', value: Station.Type, defaultShow: true },
{ label: '道岔', value: Turnout.Type, defaultShow: true },
{ label: '信号机', value: Signal.Type, defaultShow: true },
@ -163,7 +170,7 @@ export function initCommonDrawApp(app: IDrawApp) {
app,
new PlatformTemplate(new PlatformData(), new PlatformState())
);
new ScreenDoorDraw(app, new ScreenDoorTemplate(new ScreenDoorData()));
new StationDraw(
app,
new StationTemplate(new StationData(), new StationState())
@ -238,6 +245,9 @@ export function loadCommonDrawDatas(
storage.Platforms.forEach((platform) => {
datas.push(new PlatformData(platform));
});
storage.screenDoors.forEach((screenDoor) => {
datas.push(new ScreenDoorData(screenDoor));
});
storage.stations.forEach((station) => {
datas.push(new StationData(station));
});
@ -289,7 +299,10 @@ export function loadCommonDrawDatas(
return datas;
}
export function saveCommonDrawDatas(app: IDrawApp) {
export function saveCommonDrawDatas(
app: IDrawApp,
refDevicesList?: graphicData.StationRelateDevice[]
) {
const storage = new graphicData.RtssGraphicStorage();
const canvasData = app.canvas.saveData();
storage.canvas = new graphicData.Canvas({
@ -304,6 +317,9 @@ export function saveCommonDrawDatas(app: IDrawApp) {
} else if (Station.Type === g.type) {
const stationData = (g as Station).saveData();
storage.stations.push((stationData as StationData).data);
} else if (ScreenDoor.Type === g.type) {
const screenDoor = (g as ScreenDoor).saveData();
storage.screenDoors.push((screenDoor as ScreenDoorData).data);
} else if (Turnout.Type === g.type) {
const turnoutData = (g as Turnout).saveData();
storage.turnouts.push((turnoutData as TurnoutData).data);
@ -355,6 +371,9 @@ export function saveCommonDrawDatas(app: IDrawApp) {
storage.curvatures.push((curvatureData as CurvatureData).data);
}
});
if (refDevicesList) {
storage.stationRelateDeviceList = refDevicesList;
}
storage.UniqueIdPrefix = UniqueIdPrefix;
storage.kilometerConvertList = kilometerConvertList;
return storage;

View File

@ -46,6 +46,12 @@ export class GatedBoxData extends GraphicDataBase implements IGatedBox {
set index(v: number) {
this.data.index = v;
}
get refScreenDoor(): string {
return this.data.refScreenDoor;
}
set refScreenDoor(v: string) {
this.data.refScreenDoor = v;
}
clone(): GatedBoxData {
return new GatedBoxData(this.data.cloneMessage());
}

View File

@ -7,8 +7,6 @@ import {
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_state';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import {
IGraphicScene,
GraphicInteractionPlugin,
@ -40,35 +38,17 @@ export class PlatformData extends GraphicDataBase implements IPlatformData {
set code(v: string) {
this.data.code = v;
}
get hasdoor(): boolean {
return this.data.hasdoor;
}
set hasdoor(v: boolean) {
this.data.hasdoor = v;
}
get direction(): string {
return this.data.direction;
}
set direction(v: string) {
this.data.direction = v;
}
get index(): number {
return this.data.index;
}
set index(v: number) {
this.data.index = v;
}
get refStation(): string {
return this.data.refStation;
get platformRef(): graphicData.RelatedRef[] {
return this.data.platformRef;
}
set refStation(v: string) {
this.data.refStation = v;
}
get sonDoorAmount(): number {
return this.data.sonDoorAmount;
}
set sonDoorAmount(v: number) {
this.data.sonDoorAmount = v;
set platformRef(points: graphicData.RelatedRef[]) {
this.data.platformRef = points;
}
clone(): PlatformData {
@ -110,86 +90,10 @@ export class PlatformState extends GraphicStateBase implements IPlatformState {
}
}
const holdConfig: MenuItemOptions = {
name: '扣车',
};
const removeHoldrConfig: MenuItemOptions = {
name: '取消扣车',
};
// const batchHoldConfig: MenuItemOptions = {
// name: '批量扣车',
// };
// const removeBatchHoldConfig: MenuItemOptions = {
// name: '批量取消扣车',
// };
// const earlyDepartureConfig: MenuItemOptions = {
// name: '提前发车',
// };
const skipStopConfig: MenuItemOptions = {
name: '设置跳停',
};
const removeSkipStopConfig: MenuItemOptions = {
name: '取消跳停',
};
const dockTimeConfig: MenuItemOptions = {
name: '设置停站时间',
};
const operatingLevelConfig: MenuItemOptions = {
name: '设置运行等级',
};
// const numberOfRegionalTrainsConfig: MenuItemOptions = {
// name: '区间列车数量限制',
// };
// const removeNumberOfRegionalTrainsConfig: MenuItemOptions = {
// name: '取消区间列车数量限制',
// };
// const platformMessadeConfig: MenuItemOptions = {
// name: '站台详细信息',
// };
const PlatformOperateMenu: ContextMenu = ContextMenu.init({
name: '站台操作菜单',
groups: [
{
items: [
holdConfig,
removeHoldrConfig,
skipStopConfig,
removeSkipStopConfig,
dockTimeConfig,
operatingLevelConfig,
],
},
],
});
// const dispatchPlatformOperateMenu: ContextMenu = ContextMenu.init({
// name: '调度仿真站台操作菜单',
// groups: [
// {
// items: [
// holdConfig,
// removeHoldrConfig,
// batchHoldConfig,
// removeBatchHoldConfig,
// earlyDepartureConfig,
// skipStopConfig,
// removeSkipStopConfig,
// dockTimeConfig,
// operatingLevelConfig,
// numberOfRegionalTrainsConfig,
// removeNumberOfRegionalTrainsConfig,
// platformMessadeConfig,
// ],
// },
// ],
// });
export class PlatformOperateInteraction extends GraphicInteractionPlugin<Platform> {
static Name = 'platform_operate_menu';
constructor(app: IGraphicScene) {
super(PlatformOperateInteraction.Name, app);
app.registerMenu(PlatformOperateMenu);
}
static init(app: IGraphicScene) {
return new PlatformOperateInteraction(app);
@ -214,37 +118,4 @@ export class PlatformOperateInteraction extends GraphicInteractionPlugin<Platfor
onLeftClick() {
useLineStore().stateProCountIncrease();
}
// onContextMenu(e: FederatedMouseEvent) {
// const target = e.target as DisplayObject;
// const platform = target.getGraphic() as Platform;
// this.app.updateSelected(platform);
// holdConfig.handler = () => {
// platform.states.upOccHold = true;
// platform.states.emergstop = true;
// platform.doRepaint();
// };
// removeHoldrConfig.handler = () => {
// platform.states.upOccHold = false;
// platform.states.emergstop = false;
// platform.doRepaint();
// };
// skipStopConfig.handler = () => {
// platform.states.upSkipstop = true;
// platform.doRepaint();
// };
// removeSkipStopConfig.handler = () => {
// platform.states.upSkipstop = false;
// platform.doRepaint();
// };
// dockTimeConfig.handler = () => {
// platform.states.stopTime = 30;
// platform.doRepaint();
// };
// operatingLevelConfig.handler = () => {
// platform.states.nextSectionRunLevel = 2;
// platform.doRepaint();
// };
// PlatformOperateMenu.open(e.global);
// }
}

View File

@ -0,0 +1,61 @@
import * as pb_1 from 'google-protobuf';
import {
IScreenDoorData,
ScreenDoor,
} from 'src/graphics/screenDoor/ScreenDoor';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
export class ScreenDoorData extends GraphicDataBase implements IScreenDoorData {
constructor(data?: graphicData.ScreenDoor) {
let screenDoor;
if (!data) {
screenDoor = new graphicData.ScreenDoor({
common: GraphicDataBase.defaultCommonInfo(ScreenDoor.Type),
});
} else {
screenDoor = data;
}
super(screenDoor);
}
public get data(): graphicData.ScreenDoor {
return this.getData<graphicData.ScreenDoor>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get refPlatform(): string {
return this.data.refPlatform;
}
set refPlatform(v: string) {
this.data.refPlatform = v;
}
get sonDoorAmount(): number {
return this.data.sonDoorAmount;
}
set sonDoorAmount(v: number) {
this.data.sonDoorAmount = v;
}
get screenDoorGroupList(): graphicData.ScreenDoorGroup[] {
return this.data.screenDoorGroupList.length > 0
? this.data.screenDoorGroupList
: (this.data.screenDoorGroupList = [new graphicData.ScreenDoorGroup()]);
}
set screenDoorGroupList(groupList: graphicData.ScreenDoorGroup[]) {
this.data.screenDoorGroupList = groupList;
}
clone(): ScreenDoorData {
return new ScreenDoorData(this.data.cloneMessage());
}
copyFrom(data: ScreenDoorData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: ScreenDoorData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -107,6 +107,9 @@ export function initPslDrawApp(): IDrawApp {
},
})
);
app.on('destroy', () => {
refDevicesList = [];
});
return drawApp;
}
@ -179,6 +182,7 @@ export function savePslDrawDatas(app: IDrawApp) {
storage.pslTexts.push((pslTextData as PslTextData).data);
}
});
storage.gatedRelateDeviceList = refDevicesList;
const base64 = fromUint8Array(storage.serialize());
console.log('保存数据', storage);
// localStorage.setItem(StorageKey, base64);
@ -213,8 +217,7 @@ export async function loadPslDrawDatas(): Promise<IGraphicStorage> {
storage.pslTexts.forEach((pslText) => {
datas.push(new PslTextData(pslText));
});
console.log(datas);
console.log(storage);
refDevicesList = storage.gatedRelateDeviceList;
return {
canvasProperty: storage.canvas,
datas: datas,
@ -225,3 +228,53 @@ export async function loadPslDrawDatas(): Promise<IGraphicStorage> {
});
}
}
//关联设备列表的增删改查
export interface RelateDevicelistItem {
deviceType: graphicData.RelatedRef.DeviceType | undefined;
code: string;
combinationtypes: {
code: string;
refDevices: string[];
refDevicesCode?: string[];
expanded?: boolean;
}[];
}
let refDevicesList: pslGraphicData.GatedRelateDevice[] = [];
export function loadGatedRelateDeviceList() {
return refDevicesList;
}
export function creatGatedRelateDevice(row: pslGraphicData.GatedRelateDevice) {
refDevicesList.push(row);
drawApp?.emit('postdataloaded');
}
export function editGatedRelateDevice(
editRow: RelateDevicelistItem,
newData: pslGraphicData.GatedRelateDevice
) {
for (let i = 0; i < refDevicesList.length; i++) {
if (
refDevicesList[i].deviceType == editRow.deviceType &&
refDevicesList[i].code == editRow.code
) {
refDevicesList[i] = newData;
break;
}
}
drawApp?.emit('postdataloaded');
}
export function deleteGatedRelateDevice(row: RelateDevicelistItem) {
for (let i = 0; i < refDevicesList.length; i++) {
if (
refDevicesList[i].deviceType == row.deviceType &&
refDevicesList[i].code == row.code
) {
refDevicesList.splice(i, 1);
break;
}
}
}

View File

@ -114,6 +114,7 @@ export async function loadThDrawDatas(): Promise<IGraphicStorage> {
storage.trackLogicSections.forEach((logicSection) => {
datas.push(new TrackLogicSectionData(logicSection));
});
refDevicesList = storage.stationRelateDeviceList;
return Promise.resolve({
canvasProperty: storage.canvas,
datas: datas,
@ -126,7 +127,7 @@ export async function loadThDrawDatas(): Promise<IGraphicStorage> {
}
export function saveThDrawDatas(app: IDrawApp) {
const storage = saveCommonDrawDatas(app);
const storage = saveCommonDrawDatas(app, refDevicesList);
console.log(storage, '保存数据');
const graphics = app.queryStore.getAllGraphics();
graphics.forEach((g) => {
@ -143,3 +144,53 @@ export function saveThDrawDatas(app: IDrawApp) {
const base64 = fromUint8Array(storage.serialize());
return base64;
}
//关联设备列表的增删改查
export interface RelateDevicelistItem {
deviceType: graphicData.RelatedRef.DeviceType | undefined;
code: string;
combinationtypes: {
code: string;
refDevices: string[];
refDevicesCode?: string[];
expanded?: boolean;
}[];
}
let refDevicesList: graphicData.StationRelateDevice[] = [];
export function loadStationRelateDeviceList() {
return refDevicesList;
}
export function creatStationRelateDevice(row: graphicData.StationRelateDevice) {
refDevicesList.push(row);
thDrawApp?.emit('postdataloaded');
}
export function editStationRelateDevice(
editRow: RelateDevicelistItem,
newData: graphicData.StationRelateDevice
) {
for (let i = 0; i < refDevicesList.length; i++) {
if (
refDevicesList[i].deviceType == editRow.deviceType &&
refDevicesList[i].code == editRow.code
) {
refDevicesList[i] = newData;
break;
}
}
thDrawApp?.emit('postdataloaded');
}
export function deleteStationRelateDevice(row: RelateDevicelistItem) {
for (let i = 0; i < refDevicesList.length; i++) {
if (
refDevicesList[i].deviceType == row.deviceType &&
refDevicesList[i].code == row.code
) {
refDevicesList.splice(i, 1);
break;
}
}
}

View File

@ -5,6 +5,8 @@ import { Turnout, TurnoutPort } from './turnout/Turnout';
import { Section, SectionPort } from './section/Section';
import { TrainWindow } from './trainWindow/TrainWindow';
import { AxleCounting } from './axleCounting/AxleCounting';
import { Station } from './station/Station';
import { ScreenDoor } from './screenDoor/ScreenDoor';
/**
*
* @param polygon
@ -85,6 +87,8 @@ export function createRelatedRefProto(
[Turnout.Type, graphicData.RelatedRef.DeviceType.Turnout],
[TrainWindow.Type, graphicData.RelatedRef.DeviceType.TrainWindow],
[AxleCounting.Type, graphicData.RelatedRef.DeviceType.AxleCounting],
[Station.Type, graphicData.RelatedRef.DeviceType.station],
[ScreenDoor.Type, graphicData.RelatedRef.DeviceType.ScreenDoor],
]);
const protoDeviceType = typeMap.get(type);
if (protoDeviceType === undefined) throw Error(`输入的type有误: ${type}`);

View File

@ -13,6 +13,8 @@ export interface IGatedBox extends GraphicData {
set flip(v: boolean);
get index(): number;
set index(v: number);
get refScreenDoor(): string;
set refScreenDoor(v: string);
clone(): IGatedBox;
copyFrom(data: IGatedBox): void;
eq(other: IGatedBox): boolean;

View File

@ -10,8 +10,7 @@ import Ibp_Key_JSON from './ibp-key-data.json';
import { Assets, Sprite, Spritesheet, Texture } from 'pixi.js';
interface IbpKeyTextures {
ibpKeyOn: Texture;
ibpKeyOff: Texture;
ibpKey: Texture;
}
export interface IIbpKeyData extends GraphicData {
@ -34,7 +33,7 @@ export class IbpKey extends JlGraphic {
super(IbpKey.Type);
this.ibpKeyTextures = ibpKeyTextures;
this._ibpKey = new Sprite();
this._ibpKey.texture = this.ibpKeyTextures.ibpKeyOn;
this._ibpKey.texture = this.ibpKeyTextures.ibpKey;
this._ibpKey.anchor.set(0.5);
this.addChild(this._ibpKey);
}
@ -43,7 +42,7 @@ export class IbpKey extends JlGraphic {
}
doRepaint(): void {
this._ibpKey.rotation = 0;
this._ibpKey.texture = this.ibpKeyTextures.ibpKeyOn;
this._ibpKey.texture = this.ibpKeyTextures.ibpKey;
}
}
@ -67,8 +66,7 @@ export class IbpKeyTemplate extends JlGraphicTemplate<IbpKey> {
const ibpKeySheet = new Spritesheet(texture, Ibp_Key_JSON);
const result = await ibpKeySheet.parse();
this.ibpKeyTextures = {
ibpKeyOn: result['ibp-key-on.png'],
ibpKeyOff: result['ibp-key-off.png'],
ibpKey: result['ibp-key.png'],
};
return this.ibpKeyTextures as IbpKeyTextures;
}

View File

@ -1,19 +1,11 @@
{
"frames": {
"ibp-key-on.png": {
"frame": { "x": 0, "y": 0, "w": 377, "h": 1032 },
"ibp-key.png": {
"frame": { "x": 0, "y": 0, "w": 378, "h": 393 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 377, "h": 1032 },
"sourceSize": { "w": 377, "h": 1032 },
"anchor": { "x": 0.5, "y": 0.5 }
},
"ibp-key-off.png": {
"frame": { "x": 378, "y": 0, "w": 377, "h": 1032 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 377, "h": 1032 },
"sourceSize": { "w": 377, "h": 1032 },
"spriteSourceSize": { "x": 0, "y": 0, "w": 378, "h": 393 },
"sourceSize": { "w": 378, "h": 393 },
"anchor": { "x": 0.5, "y": 0.5 }
}
},
@ -22,8 +14,8 @@
"version": "1.1",
"image": "ibp-key.png",
"format": "RGBA8888",
"size": { "w": 755, "h": 1032 },
"scale": "10",
"size": { "w": 378, "h": 393 },
"scale": "8",
"smartupdate": "$TexturePacker:SmartUpdate:e7620bd2d73cc0b3e2deea9704e7eefc:f129a1d9e4b9ba57720b3861c22b155b:eb2d421f7759984b7713aa4aa5354134$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -1,97 +1,38 @@
import { Color, Container, Graphics, Point, Rectangle } from 'pixi.js';
import { Color, Container, Graphics, Rectangle } from 'pixi.js';
import {
GraphicAnimation,
GraphicData,
GraphicState,
JlGraphic,
JlGraphicTemplate,
VectorText,
calculateMirrorPoint,
distance2,
getRectangleCenter,
} from 'src/jl-graphic';
import { Station } from '../station/Station';
import { createRelatedRefProto } from '../CommonGraphics';
import { IRelatedRefData } from '../CommonGraphics';
import { Section } from '../section/Section';
export interface IPlatformData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get hasdoor(): boolean; // 是否有屏蔽门
set hasdoor(v: boolean);
get direction(): string; // 屏蔽门上下
set direction(v: string);
get index(): number;
set index(v: number);
get refStation(): string; // 关联的车站
set refStation(v: string);
get sonDoorAmount(): number; //子屏蔽门的数量
set sonDoorAmount(v: number);
get platformRef(): IRelatedRefData[]; // 关联的车站和物理区段
set platformRef(v: IRelatedRefData[]);
clone(): IPlatformData;
copyFrom(data: IPlatformData): void;
eq(other: IPlatformData): boolean;
}
export interface IPlatformState extends GraphicState {
id?: string;
// get emergstop(): boolean; //紧急关闭
// set emergstop(v: boolean);
// get trainberth(): boolean; //列车停站
// set trainberth(v: boolean);
// get close(): boolean; //站台关闭,清客
// set close(v: boolean);
// get upHold(): boolean; //上行方向车站扣车
// set upHold(v: boolean);
// get downHold(): boolean; //下行方向车站扣车
// set downHold(v: boolean);
// get upOccHold(): boolean; //上行方向中心扣车
// set upOccHold(v: boolean);
// get downOccHold(): boolean; //下行方向中心扣车
// set downOccHold(v: boolean);
// get psdOpen(): boolean; //屏蔽门开
// set psdOpen(v: boolean);
// get psdCut(): boolean; //屏蔽门切除
// set psdCut(v: boolean);
// get upSkipstop(): boolean; //上行方向跳停
// set upSkipstop(v: boolean);
// get downSkipstop(): boolean; //下行方向跳停
// set downSkipstop(v: boolean);
// get upTrainSkipstop(): boolean; //上行方向指定列车跳停
// set upTrainSkipstop(v: boolean);
// get downTrainSkipstop(): boolean; //下行方向指定列车跳停
// set downTrainSkipstop(v: boolean);
// get nextSectionRunTime(): number; //下一区间运行时间
// set nextSectionRunTime(v: number);
// get nextSectionRunLevel(): number; //下一区间运行等级
// set nextSectionRunLevel(v: number);
// get stopTime(): number; //停站时间
// set stopTime(v: number);
}
//站台颜色
export enum PlatformColorEnum {
grey = '0x7F7F7F', //站台没有列车停站
yellow = '0xfbff00', //列车在站台停站
blue = '0xC0C0FE', //列车在站台跳停
white = '0xffffff',
lozengeRed = '0xff0000', //站台旁的菱形图标
whiteNumbers = '0xffffff', //站台旁白色数字
whiteCircle = '0xffffff', //H字符旁的圆圈
HCharYellow = '0xfbff00', //站台旁的扣字
HCharWhite = '0xffffff',
HCharRed = '0xff0000',
SCharBlue = '0x00FFCC', ////站台旁的跳字
doorGreen = '0x00FF00', //屏蔽门的颜色
doorRed = '0xff0000',
doorBlue = '0x4048C4',
}
const platformConsts = {
width: 90,
height: 20,
lineWidth: 3,
besideFontSize: 12,
doorOpenSpacing: 15,
doorPlatformSpacing: 17,
besideSpacing: 10,
circleRadius: 9,
smallDoorWidth: 10,
white: '0xffffff', //站台颜色
};
//子元素--矩形
@ -105,236 +46,22 @@ export class rectGraphic extends Container {
}
draw(state: IPlatformState): void {
const rectGraphic = this.rectGraphic;
rectGraphic.clear();
const fillColor = PlatformColorEnum.white;
if (state) {
// fillColor = PlatformColorEnum.yellow;
}
// if (state.upSkipstop || state.downSkipstop) {
// fillColor = PlatformColorEnum.grey;
// }
rectGraphic.lineStyle(platformConsts.lineWidth, new Color(fillColor));
rectGraphic.beginFill(fillColor, 1);
rectGraphic.drawRect(0, 0, platformConsts.width, platformConsts.height);
rectGraphic.endFill;
const rectP = new Rectangle(
0,
0,
platformConsts.width,
platformConsts.height
const fillColor = platformConsts.white;
rectGraphic
.clear()
.lineStyle(platformConsts.lineWidth, new Color(fillColor))
.beginFill(fillColor, 1)
.drawRect(0, 0, platformConsts.width, platformConsts.height).endFill;
rectGraphic.pivot = getRectangleCenter(
new Rectangle(0, 0, platformConsts.width, platformConsts.height)
);
rectGraphic.pivot = getRectangleCenter(rectP);
}
clear(): void {
this.rectGraphic.clear();
}
}
//子元素--门
class smallDoorGraphic extends Container {
smallDoorGraphic: Graphics;
labelGraphic: VectorText;
constructor() {
super();
this.smallDoorGraphic = new Graphics();
this.labelGraphic = new VectorText();
this.labelGraphic.setVectorFontSize(12);
this.labelGraphic.anchor.set(0.5);
this.addChild(this.smallDoorGraphic);
this.addChild(this.labelGraphic);
}
draw(data: IPlatformData, stateData: IPlatformState, i: number): void {
const start =
(-platformConsts.smallDoorWidth * data.sonDoorAmount) / 2 +
platformConsts.smallDoorWidth * i;
const smallDoorGraphic = this.smallDoorGraphic;
const lineColor = PlatformColorEnum.doorGreen;
// if (stateData.psdCut) {
// lineColor = PlatformColorEnum.doorRed;
// }
const direction = data.direction;
smallDoorGraphic
.lineStyle(platformConsts.lineWidth, new Color(lineColor))
.moveTo(start, 0)
.lineTo(start + platformConsts.smallDoorWidth - 3, 0);
if (direction == 'down') {
this.labelGraphic.text = data.sonDoorAmount - i;
} else {
this.labelGraphic.text = i + 1;
}
this.labelGraphic.style.fill = 'red';
if (i % 2 == 0) {
this.labelGraphic.position.set(start + 4, 7);
} else {
this.labelGraphic.position.set(start + 4, -7);
}
}
}
export class doorGraphic extends Container {
constructor() {
super();
}
draw(data: IPlatformData, stateData: IPlatformState): void {
for (let i = 0; i < data.sonDoorAmount; i++) {
const smallDoor = new smallDoorGraphic();
smallDoor.draw(data, stateData, i);
this.addChild(smallDoor);
}
}
clear(): void {
this.children.forEach((g) => {
(g as smallDoorGraphic).smallDoorGraphic.clear();
(g as smallDoorGraphic).labelGraphic.text = '';
});
}
// changeState(stateData: IPlatformState): void {
// // if (stateData.psdOpen) {
// // this.doorCloseGraphic.visible = false;
// // } else {
// // this.doorCloseGraphic.visible = true;
// // }
// }
}
//子元素--字符
class codeGraph extends Container {
static Type = 'Code';
hold: VectorText = new VectorText(''); //扣车
runLevel: VectorText = new VectorText(''); //运行等级
runTime: VectorText = new VectorText(''); //运行时间
stopTime: VectorText = new VectorText(''); //停站时间
skipStop: VectorText = new VectorText(''); //调停
circle: Graphics = new Graphics();
constructor() {
super();
this.addChild(this.hold);
this.addChild(this.runLevel);
this.addChild(this.stopTime);
this.addChild(this.runTime);
this.addChild(this.skipStop);
this.addChild(this.circle);
this.hold.setVectorFontSize(platformConsts.besideFontSize);
this.runLevel.setVectorFontSize(platformConsts.besideFontSize);
this.stopTime.setVectorFontSize(platformConsts.besideFontSize);
this.runTime.setVectorFontSize(platformConsts.besideFontSize);
this.skipStop.setVectorFontSize(platformConsts.besideFontSize);
}
draw(): void {
//扣车
const hold = this.hold;
hold.text = '扣';
hold.anchor.set(0.5);
hold.position.set(
-platformConsts.width / 2 -
platformConsts.lineWidth / 2 -
(platformConsts.besideSpacing * 2) / 3,
-(platformConsts.height * 3) / 4
);
hold.style.fill = PlatformColorEnum.HCharWhite;
//区间运行等级状态
const runLevel = this.runLevel;
runLevel.anchor.set(0.5);
runLevel.position.set(
-platformConsts.width / 2 -
platformConsts.lineWidth / 2 -
platformConsts.besideSpacing,
(-platformConsts.height * 4) / 5
);
runLevel.style.fill = PlatformColorEnum.yellow;
//区间运行时间
const runTime = this.runTime;
runTime.anchor.set(0.5);
runTime.position.set(
platformConsts.width / 2 +
platformConsts.lineWidth / 2 +
platformConsts.besideSpacing,
-platformConsts.besideSpacing
);
runTime.style.fill = PlatformColorEnum.whiteNumbers;
//停站时间
const stopTime = this.stopTime;
stopTime.anchor.set(0.5);
stopTime.position.set(
-platformConsts.width / 2 -
platformConsts.lineWidth / 2 -
platformConsts.besideSpacing,
0
);
stopTime.style.fill = PlatformColorEnum.whiteNumbers;
//跳停
const skipStop = this.skipStop;
skipStop.text = '跳';
skipStop.anchor.set(0.5);
const ps = calculateMirrorPoint(new Point(0, 0), hold.position);
skipStop.position.set(ps.x + 4, ps.y);
skipStop.style.fill = PlatformColorEnum.SCharBlue;
const circle = this.circle;
circle.clear();
circle.lineStyle(1, PlatformColorEnum.SCharBlue);
circle.drawCircle(0, 0, platformConsts.circleRadius);
circle.position.copyFrom(skipStop.position);
hold.visible = false;
runLevel.visible = false;
stopTime.visible = false;
runTime.visible = false;
skipStop.visible = false;
circle.visible = false;
}
clear(): void {
this.hold.destroy();
}
// changeState(stateData: IPlatformState): void {
// if (
// stateData.upHold ||
// stateData.upOccHold ||
// stateData.downHold ||
// stateData.downOccHold
// ) {
// this.hold.text = '扣';
// this.hold.visible = true;
// //上行扣车
// if (stateData.upHold) {
// this.hold.style.fill = PlatformColorEnum.HCharYellow;
// }
// if (stateData.upOccHold) {
// this.hold.style.fill = PlatformColorEnum.HCharWhite;
// }
// if (stateData.upHold && stateData.upOccHold) {
// this.hold.style.fill = PlatformColorEnum.HCharRed;
// }
// //下行扣车
// if (stateData.downHold) {
// this.hold.style.fill = PlatformColorEnum.HCharYellow;
// }
// if (stateData.downOccHold) {
// this.hold.style.fill = PlatformColorEnum.HCharWhite;
// }
// if (stateData.downHold && stateData.downOccHold) {
// this.hold.style.fill = PlatformColorEnum.HCharRed;
// }
// }
// //运行等级
// if (stateData.nextSectionRunLevel) {
// this.runLevel.visible = true;
// this.runLevel.text = stateData.nextSectionRunLevel;
// }
// //运行时间
// if (stateData.nextSectionRunTime) {
// this.runTime.visible = false;
// this.runTime.text = stateData.nextSectionRunTime;
// }
// //停站时间
// if (stateData.stopTime) {
// this.stopTime.visible = true;
// this.stopTime.text = stateData.stopTime;
// }
// //跳停
// if (stateData.upSkipstop || stateData.downSkipstop) {
// this.skipStop.visible = true;
// this.circle.visible = true;
// }
// }
}
//子元素--站台旁菱形图标
class emergClose extends JlGraphic {
/* class emergClose extends JlGraphic {
static Type = 'emergClose';
lozenge: Graphics;
deltaTime = 0;
@ -387,34 +114,28 @@ class emergClose extends JlGraphic {
});
return flashAnmiation;
}
// changeState(id: string, stateData: IPlatformState): void {
// let redFlash = this.animation(`${id}emergClose_red_flash`);
// if (stateData.emergstop) {
// if (!redFlash) {
// redFlash = this.createFlashAnmiation(`${id}emergClose_red_flash`);
// this.addAnimation(redFlash);
// }
// redFlash.resume();
// } else {
// if (redFlash) {
// redFlash.pause();
// }
// }
// }
}
changeState(id: string, stateData: IPlatformState): void {
let redFlash = this.animation(`${id}emergClose_red_flash`);
if (stateData.emergstop) {
if (!redFlash) {
redFlash = this.createFlashAnmiation(`${id}emergClose_red_flash`);
this.addAnimation(redFlash);
}
redFlash.resume();
} else {
if (redFlash) {
redFlash.pause();
}
}
}
} */
export class Platform extends JlGraphic {
static Type = 'Platform';
platformGraphic: rectGraphic = new rectGraphic();
doorGraphic: doorGraphic = new doorGraphic();
emergClose: emergClose = new emergClose();
codeGraph: codeGraph = new codeGraph();
rectGraphic: rectGraphic = new rectGraphic();
constructor() {
super(Platform.Type);
this.addChild(this.platformGraphic);
this.addChild(this.doorGraphic);
this.addChild(this.emergClose);
this.addChild(this.codeGraph);
this.addChild(this.rectGraphic);
}
get datas(): IPlatformData {
@ -427,38 +148,7 @@ export class Platform extends JlGraphic {
return this.datas.index + '';
}
doRepaint(): void {
this.datas.sonDoorAmount = this.datas?.sonDoorAmount || 30;
this.doorGraphic.clear();
if (this.datas.hasdoor) {
this.doorGraphic.draw(this.datas, this.states);
}
this.platformGraphic.draw(this.states);
this.emergClose.draw();
this.codeGraph.draw();
this.doorGraphic.position.set(
0,
-platformConsts.height / 2 - platformConsts.doorPlatformSpacing
);
this.emergClose.position.set(
0,
-platformConsts.height / 2 -
platformConsts.doorPlatformSpacing -
platformConsts.height / 3
);
this.codeGraph.position.set(0, 0);
//站台方向
if (this.datas.direction == 'down') {
const psChange = [
this.doorGraphic,
this.emergClose,
...this.codeGraph.children,
];
psChange.forEach((g) => {
g.position.copyFrom(calculateMirrorPoint(new Point(0, 0), g.position));
});
}
// this.changeState();
this.rectGraphic.draw(this.states);
}
buildRelation() {
const stationas = this.queryStore.queryByType<Station>(Station.Type);
@ -469,40 +159,58 @@ export class Platform extends JlGraphic {
break;
}
}
const sections = this.queryStore.queryByType<Section>(Section.Type);
const minDistanceRefSections: Section[] = [];
sections.forEach((section) => {
const sP = section.localBoundsToCanvasPoints();
if (this.x > sP[0].x && this.x < sP[1].x) {
minDistanceRefSections.push(section);
}
});
const refSection = minDistanceRefSections.reduce((prev, cur) => {
return distance2(prev.position, this.position) >
distance2(cur.position, this.position)
? cur
: prev;
});
if (refSection) {
this.relationManage.addRelation(this, refSection);
}
}
saveRelations() {
const platformRef = [];
const refStation = this.relationManage
.getRelationsOfGraphicAndOtherType(this, Station.Type)
.map((relation) => relation.getOtherGraphic<Station>(this).datas.id);
if (refStation.length) {
this.datas.refStation = refStation[0];
platformRef.push(createRelatedRefProto(Station.Type, refStation[0]));
}
const refSection = this.relationManage
.getRelationsOfGraphicAndOtherType(this, Section.Type)
.map((relation) => relation.getOtherGraphic<Section>(this).datas.id);
if (refSection.length) {
platformRef.push(createRelatedRefProto(Section.Type, refSection[0]));
}
this.datas.platformRef = platformRef;
}
loadRelations() {
if (this.datas.refStation) {
this.relationManage.addRelation(
this,
this.queryStore.queryById<Station>(this.datas.refStation)
);
if (this.datas.platformRef.length) {
this.datas.platformRef.forEach((device) => {
this.relationManage.addRelation(
this,
this.queryStore.queryById(device.id)
);
});
}
}
// changeState(): void {
// this.doorGraphic.changeState(this.states);
// this.emergClose.changeState(this.id, this.states);
// this.codeGraph.changeState(this.states);
// }
}
export class PlatformTemplate extends JlGraphicTemplate<Platform> {
hasdoor: boolean;
direction: string;
constructor(dataTemplate: IPlatformData, stateTemplate: IPlatformState) {
super(Platform.Type, {
dataTemplate,
stateTemplate,
});
this.hasdoor = true;
this.direction = 'up';
}
new(): Platform {
const platform = new Platform();

View File

@ -37,9 +37,6 @@ export class PlatformDraw extends GraphicDrawAssistant<
this.platformGraphic.doRepaint();
}
clearCache(): void {
//this.platformGraphic.clear();
}
onLeftDown(e: FederatedPointerEvent): void {
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
this.createAndStore(true);
@ -50,9 +47,6 @@ export class PlatformDraw extends GraphicDrawAssistant<
}
prepareData(data: IPlatformData): boolean {
const template = this.graphicTemplate;
data.hasdoor = template.hasdoor;
data.direction = template.direction;
data.transform = this.container.saveTransform();
return true;
}

View File

@ -0,0 +1,143 @@
import { Color, Container, Graphics } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
distance2,
} from 'src/jl-graphic';
import { Platform } from '../platform/Platform';
import { graphicData } from 'src/protos/stationLayoutGraphics';
export interface IScreenDoorData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get refPlatform(): string; // 关联的站台
set refPlatform(v: string);
get sonDoorAmount(): number; //子屏蔽门的数量
set sonDoorAmount(v: number);
get screenDoorGroupList(): graphicData.ScreenDoorGroup[]; //编组列表
set screenDoorGroupList(v: graphicData.ScreenDoorGroup[]);
clone(): IScreenDoorData;
copyFrom(data: IScreenDoorData): void;
eq(other: IScreenDoorData): boolean;
}
const screenDoorConsts = {
lineWidth: 3,
smallDoorWidth: 10,
doorGreen: '0x00FF00', //屏蔽门的颜色
doorRed: '0xff0000',
};
class smallDoorGraphic extends Container {
smallDoorGraphic: Graphics;
labelGraphic: VectorText;
constructor() {
super();
this.smallDoorGraphic = new Graphics();
this.labelGraphic = new VectorText();
this.labelGraphic.setVectorFontSize(12);
this.labelGraphic.anchor.set(0.5);
this.addChild(this.smallDoorGraphic);
this.addChild(this.labelGraphic);
}
draw(data: IScreenDoorData, i: number): void {
const start =
(-screenDoorConsts.smallDoorWidth * data.sonDoorAmount) / 2 +
screenDoorConsts.smallDoorWidth * i;
const smallDoorGraphic = this.smallDoorGraphic;
const lineColor = screenDoorConsts.doorGreen;
const direction = 'up';
smallDoorGraphic
.lineStyle(screenDoorConsts.lineWidth, new Color(lineColor))
.moveTo(start, 0)
.lineTo(start + screenDoorConsts.smallDoorWidth - 3, 0);
if (direction == 'up') {
this.labelGraphic.text = i + 1;
} else {
this.labelGraphic.text = data.sonDoorAmount - i;
}
this.labelGraphic.style.fill = 'red';
if (i % 2 == 0) {
this.labelGraphic.position.set(start + 4, 7);
} else {
this.labelGraphic.position.set(start + 4, -7);
}
}
}
export class ScreenDoor extends JlGraphic {
static Type = 'ScreenDoor';
doorGraphic = new Container();
constructor() {
super(ScreenDoor.Type);
this.addChild(this.doorGraphic);
}
get datas(): IScreenDoorData {
return this.getDatas<IScreenDoorData>();
}
doRepaint(): void {
const doorGraphic = this.doorGraphic;
doorGraphic.children.forEach((g) => {
(g as smallDoorGraphic).smallDoorGraphic.clear();
(g as smallDoorGraphic).labelGraphic.text = '';
});
this.datas.sonDoorAmount = this.datas?.sonDoorAmount || 30;
for (let i = 0; i < this.datas.sonDoorAmount; i++) {
const smallDoor = new smallDoorGraphic();
smallDoor.draw(this.datas, i);
doorGraphic.addChild(smallDoor);
}
}
buildRelation() {
const platforms = this.queryStore.queryByType<Platform>(Platform.Type);
const minDistanceRefPlatform: Platform[] = [];
platforms.forEach((platform) => {
const sP = platform.localBoundsToCanvasPoints();
if (this.x > sP[0].x && this.x < sP[1].x) {
minDistanceRefPlatform.push(platform);
}
});
const refPlatform = minDistanceRefPlatform.reduce((prev, cur) => {
return distance2(prev.position, this.position) >
distance2(cur.position, this.position)
? cur
: prev;
});
if (refPlatform) {
this.relationManage.addRelation(this, refPlatform);
}
}
saveRelations() {
const refStation = this.relationManage
.getRelationsOfGraphicAndOtherType(this, Platform.Type)
.map((relation) => relation.getOtherGraphic<Platform>(this).datas.id);
if (refStation.length) {
this.datas.refPlatform = refStation[0];
}
}
loadRelations() {
if (this.datas.refPlatform) {
this.relationManage.addRelation(
this,
this.queryStore.queryById<Platform>(this.datas.refPlatform)
);
}
}
}
export class ScreenDoorTemplate extends JlGraphicTemplate<ScreenDoor> {
constructor(dataTemplate: IScreenDoorData) {
super(ScreenDoor.Type, {
dataTemplate,
});
}
new(): ScreenDoor {
const screenDoor = new ScreenDoor();
screenDoor.loadData(this.datas);
return screenDoor;
}
}

View File

@ -0,0 +1,97 @@
import { FederatedPointerEvent, Point } from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
GraphicDrawAssistant,
GraphicInteractionPlugin,
IDrawApp,
JlGraphic,
} from 'src/jl-graphic';
import { IScreenDoorData, ScreenDoor, ScreenDoorTemplate } from './ScreenDoor';
import { Platform } from 'src/graphics/platform/Platform';
export interface IScreenDoorDrawOptions {
newData: () => IScreenDoorData;
}
export class ScreenDoorDraw extends GraphicDrawAssistant<
ScreenDoorTemplate,
IScreenDoorData
> {
screenDoorGraphic: ScreenDoor;
constructor(app: IDrawApp, template: ScreenDoorTemplate) {
super(app, template, 'sym_o_square', '屏蔽门ScreenDoor');
this.screenDoorGraphic = this.graphicTemplate.new();
this.container.addChild(this.screenDoorGraphic);
screenDoorInteraction.init(app);
}
bind(): void {
super.bind();
this.screenDoorGraphic.loadData(this.graphicTemplate.datas);
this.screenDoorGraphic.doRepaint();
}
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: IScreenDoorData): boolean {
data.transform = this.container.saveTransform();
return true;
}
}
function buildAbsorbablePositions(
screenDoor: ScreenDoor
): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const platforms = screenDoor.queryStore.queryByType<Platform>(Platform.Type);
const { height } = screenDoor.getGraphicApp().canvas;
platforms.forEach((platform) => {
const ps = platform.datas.transform.position;
const ys = new AbsorbableLine({ x: ps.x, y: 0 }, { x: ps.x, y: height });
aps.push(ys);
});
return aps;
}
export class screenDoorInteraction extends GraphicInteractionPlugin<ScreenDoor> {
static Name = 'screenDoor_transform';
constructor(app: IDrawApp) {
super(screenDoorInteraction.Name, app);
}
static init(app: IDrawApp) {
return new screenDoorInteraction(app);
}
filter(...grahpics: JlGraphic[]): ScreenDoor[] | undefined {
return grahpics
.filter((g) => g.type === ScreenDoor.Type)
.map((g) => g as ScreenDoor);
}
bind(g: ScreenDoor): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
g.on('selected', this.onSelected, this);
}
unbind(g: ScreenDoor): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
g.off('selected', this.onSelected, this);
}
onSelected(): void {
const screenDoor = this.app.selectedGraphics[0] as ScreenDoor;
this.app.setOptions({
absorbablePositions: buildAbsorbablePositions(screenDoor),
});
}
}

View File

@ -656,7 +656,6 @@ abstract class GraphicSceneBase
const storage = await this._options.dataLoader();
if (storage.canvasProperty) {
this.canvas.update(storage.canvasProperty);
console.log(this.canvas, 'canvas');
}
if (storage.datas) {
await this.loadGraphic(storage.datas);

View File

@ -64,6 +64,20 @@
</q-input>
</q-popup-edit>
</q-btn>
<q-btn-dropdown
v-if="drawStore.categoryType === CategoryType.TH"
color="orange"
label="数据管理"
style="margin-right: 10px"
>
<q-list>
<q-item clickable v-close-popup @click="openDeviceRelateList">
<q-item-section>
<q-item-label>关联设备列表</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn color="info" label="返回" @click="backConfirm" />
<q-btn dense flat round icon="menu" @click="toggleRightDrawer" />
</q-toolbar>
@ -76,7 +90,13 @@
<KilometerConvertConfig
v-if="drawStore.showEditKilometerConvert"
></KilometerConvertConfig>
<draw-properties v-else></draw-properties>
<draw-properties
v-else-if="!drawStore.showRelateDeviceConfig"
></draw-properties>
<station-relate-device-config
v-else-if="drawStore.showRelateDeviceConfig"
ref="relateDeviceConfigEdit"
></station-relate-device-config>
</q-drawer>
<q-page-container>
@ -153,7 +173,7 @@ import {
setUniqueIdPrefix,
} from 'src/drawApp/commonApp';
import { saveJkDrawDatas, loadLinkDatas } from 'src/drawApp/jkApp';
import { saveThDrawDatas } from 'src/drawApp/thApp';
import { RelateDevicelistItem, saveThDrawDatas } from 'src/drawApp/thApp';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
@ -173,7 +193,7 @@ 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 { DialogChainObject, useQuasar } from 'quasar';
import LayerControlDialog from 'src/components/draw-app/dialogs/LayerControlDialog.vue';
import { drawThLayerList } from 'src/drawApp/thApp';
import { drawJkLayerList } from 'src/drawApp/jkApp';
@ -183,6 +203,7 @@ import { CurvatureDraw } from 'src/graphics/curvature/CurvatureAssistant';
import { TrackSection } from 'src/graphics/trackSection/TrackSection';
import { TrackSectionDraw } from 'src/graphics/trackSection/TrackSectionDrawAssistant';
import { Platform } from 'src/graphics/platform/Platform';
import { ScreenDoor } from 'src/graphics/screenDoor/ScreenDoor';
import { Station } from 'src/graphics/station/Station';
import { Signal } from 'src/graphics/signal/Signal';
import { Turnout } from 'src/graphics/turnout/Turnout';
@ -197,6 +218,8 @@ import { CategoryType } from 'src/components/CategoryType';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import KilometerConvertList from 'src/components/draw-app/dialogs/KilometerConvertList.vue';
import KilometerConvertConfig from 'src/components/draw-app/properties/KilometerConvertConfig.vue';
import StationRelateDeviceConfig from 'src/components/draw-app/properties/StationRelateDeviceConfig.vue';
import StationRelateDeviceList from 'src/components/draw-app/dialogs/StationRelateDeviceList.vue';
const $q = useQuasar();
const route = useRoute();
@ -299,6 +322,7 @@ onMounted(() => {
}
const drawAssistantsTypes = [
Platform.Type,
ScreenDoor.Type,
Station.Type,
Signal.Type,
Section.Type,
@ -598,4 +622,23 @@ function openkilometerConvertList() {
drawStore.setEditKilometerConvertIndex(-1);
});
}
let relateDeviceDialogInstance: DialogChainObject | null = null;
const relateDeviceConfigEdit =
ref<InstanceType<typeof StationRelateDeviceConfig>>();
function openDeviceRelateList() {
if (relateDeviceDialogInstance) return;
relateDeviceDialogInstance = $q
.dialog({
component: StationRelateDeviceList,
componentProps: {
onEditClick: (row: RelateDevicelistItem) => {
relateDeviceConfigEdit.value?.editRelateDevices(row);
},
},
})
.onCancel(() => {
relateDeviceDialogInstance = null;
});
}
</script>

View File

@ -61,6 +61,19 @@
</q-input>
</q-popup-edit>
</q-btn>
<q-btn-dropdown
color="orange"
label="数据管理"
style="margin-right: 10px"
>
<q-list>
<q-item clickable v-close-popup @click="openDeviceRelateList">
<q-item-section>
<q-item-label>关联设备列表</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn color="info" label="返回" @click="backConfirm" />
<q-btn dense flat round icon="menu" @click="toggleRightDrawer" />
</q-toolbar>
@ -69,7 +82,13 @@
<q-drawer show-if-above bordered v-model="rightDrawerOpen" side="right">
<q-resize-observer @resize="onRightResize" />
<psl-draw-properties></psl-draw-properties>
<psl-draw-properties
v-if="!pslDrawStore.showRelateDeviceConfig"
></psl-draw-properties>
<relate-device-config
v-else-if="pslDrawStore.showRelateDeviceConfig"
ref="relateDeviceConfigEdit"
></relate-device-config>
</q-drawer>
<q-page-container>
@ -112,19 +131,22 @@ import {
savePslDrawDatas,
savePslDrawToServer,
checkPslDataToServer,
RelateDevicelistItem,
} from 'src/drawApp/pslApp';
import { IDrawApp } from 'src/jl-graphic';
import { usePslDrawStore } from 'src/stores/psl-draw-store';
import RelateDeviceConfig from 'src/components/draw-app/properties/RelateDeviceConfig.vue';
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
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 { useQuasar } from 'quasar';
import { DialogChainObject, useQuasar } from 'quasar';
import { PslButton } from 'src/graphics/pslButton/pslButton';
import { PslKey } from 'src/graphics/pslKey/pslKey';
import { PslLight } from 'src/graphics/pslLight/pslLight';
import { TextContent } from 'src/graphics/textContent/TextContent';
import GatedRelateDeviceList from 'src/components/draw-app/dialogs/GatedRelateDeviceList.vue';
const $q = useQuasar();
const route = useRoute();
@ -299,4 +321,22 @@ async function saveAs(name: string) {
onUnmounted(() => {
pslDrawStore.destroy();
});
let relateDeviceDialogInstance: DialogChainObject | null = null;
const relateDeviceConfigEdit = ref<InstanceType<typeof RelateDeviceConfig>>();
function openDeviceRelateList() {
if (relateDeviceDialogInstance) return;
relateDeviceDialogInstance = $q
.dialog({
component: GatedRelateDeviceList,
componentProps: {
onEditClick: (row: RelateDevicelistItem) => {
relateDeviceConfigEdit.value?.editRelateDevices(row);
},
},
})
.onCancel(() => {
relateDeviceDialogInstance = null;
});
}
</script>

View File

@ -1,5 +1,6 @@
import { defineStore } from 'pinia';
import { CategoryType } from 'src/components/CategoryType';
import { QTable } from 'quasar';
import {
destroyThDrawApp,
getThDrawApp,
@ -27,6 +28,8 @@ export const useDrawStore = defineStore('draw', {
categoryType: null as CategoryType | null,
oneClickType: '',
editKilometerConvertIndex: -1,
table: undefined as QTable | undefined,
showRelateDeviceConfig: false,
}),
getters: {
drawMode: (state) => state.drawAssistant != null,

View File

@ -1,4 +1,5 @@
import { defineStore } from 'pinia';
import { QTable } from 'quasar';
import {
destroyPslDrawApp,
getPslDrawApp,
@ -13,6 +14,8 @@ export const usePslDrawStore = defineStore('pslDraw', {
draftId: null as number | null,
draftType: 'Psl',
oneClickType: '',
table: undefined as QTable | undefined,
showRelateDeviceConfig: false,
}),
getters: {
drawMode: (state) => state.drawAssistant != null,