merge
All checks were successful
local-test分支构建发布 / Docker-Build (push) Successful in 1m57s

This commit is contained in:
joylink_fanyuhong 2024-11-11 09:17:57 +08:00
commit bdaa3507e9
46 changed files with 1038 additions and 48 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/alarmMusic/4/red.mp3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

77
src/api/faultQuery.ts Normal file
View File

@ -0,0 +1,77 @@
import { api } from 'src/boot/axios';
import { PageDto, PageQueryDto } from './ApiCommon';
const faultQueryUriBase = '/api/fault/query';
export interface FaultQueryListItem {
id?: number;
lineId: number;
faultType: string;
faultNameShower: string;
faultDriverShower: string;
resultMsg: string;
}
export interface FaultQueryInfo<T = unknown> {
data: T;
}
export class PagingQueryParams extends PageQueryDto {
lineId?: string;
faultType?: string;
faultName?: string;
}
/**
*
* @param params
* @returns
*/
export async function faultQueryPageQuery(
params: PagingQueryParams
): Promise<PageDto<FaultQueryListItem>> {
const response = await api.get(`${faultQueryUriBase}/page`, {
params: params,
});
return response.data;
}
/**
*
* @param params
* @returns
*/
export function createFaultQuery(faultData: FaultQueryListItem) {
return api.post(`${faultQueryUriBase}`, faultData);
}
/**
*
* @param id 稿id
*/
export function deleteFaultQueryById(id: number) {
return api.delete(`${faultQueryUriBase}/${id}`);
}
/**
* id获取故障查询
* @param id 稿id
*/
export function faultQueryById(
id: number
): Promise<FaultQueryInfo<FaultQueryListItem>> {
return api.get(`${faultQueryUriBase}/${id}`);
}
export interface FaultTypeItem {
fts: { faultType: string; typeName: string }[];
lineId: number;
}
/**
*
*/
export async function faultQueryType(): Promise<Array<FaultTypeItem>> {
const response = await api.get(`${faultQueryUriBase}/type`);
return response.data;
}

View File

@ -77,6 +77,11 @@ const list = reactive([
label: '决策信息管理',
icon: 'format_align_center',
},
{
path: '/dataManage/faultQuery',
label: '故障查询管理',
icon: 'disabled_by_default',
},
{
path: '/dataManage/thresholdValue',
label: '报警故障阈值配置',

View File

@ -24,6 +24,7 @@ export enum showAlertTypeData {
'联锁区失表',
'一级联锁',
'应急触发',
'道岔挤岔',
I = 'I类信息',
II = 'II类信息',
III = 'III类信息',
@ -55,6 +56,7 @@ export enum showAlertTypeData {
SWITCH_LOST_INTERLOCK_AREA = '联锁区失表',
INTERLOCK_LEVEL_ONE = '一级联锁',
PLATFORM_EMERG_STOP = '应急触发',
SWITCH_JAMMED = '道岔挤岔',
}
export enum saveAlertTypeData {
@ -85,6 +87,7 @@ export enum saveAlertTypeData {
= 'SWITCH_LOST_INTERLOCK_AREA',
= 'INTERLOCK_LEVEL_ONE',
= 'PLATFORM_EMERG_STOP',
= 'SWITCH_JAMMED',
}
export const GuardConfigTypeData = {

View File

@ -12,17 +12,33 @@ import { AlarmInfo, useLineNetStore } from 'src/stores/line-net-store';
import { DialogChainObject, useQuasar } from 'quasar';
import alarmInfoDialog from 'src/components/alarm/alarmInfoDialog.vue';
import { showAlertTypeData } from './alarmInfoEnum';
import allLineBlue from '/alarmMusic/all-line-blue.mp3';
import atpcut from '/alarmMusic/atp-cut.mp3';
import blue from '/alarmMusic/blue.mp3';
import cannotClose from '/alarmMusic/cannot-close.mp3';
import cannotOpen from '/alarmMusic/cannot-open.mp3';
import orangeMost from '/alarmMusic/orange-most.mp3';
import orange from '/alarmMusic/orange.mp3';
import redMost from '/alarmMusic/red-most.mp3';
import red from '/alarmMusic/red.mp3';
import switchLostMost from '/alarmMusic/switch-lost-most.mp3';
import switchLost from '/alarmMusic/switch-lost.mp3';
import allLineBlue3 from '/alarmMusic/3/all-line-blue.mp3';
import atpcut3 from '/alarmMusic/3/atp-cut.mp3';
import blue3 from '/alarmMusic/3/blue.mp3';
import cannotClose3 from '/alarmMusic/3/cannot-close.mp3';
import cannotOpen3 from '/alarmMusic/3/cannot-open.mp3';
import orangeMost3 from '/alarmMusic/3/orange-most.mp3';
import orange3 from '/alarmMusic/3/orange.mp3';
import redMost3 from '/alarmMusic/3/red-most.mp3';
import red3 from '/alarmMusic/3/red.mp3';
import switchLostMost3 from '/alarmMusic/3/switch-lost-most.mp3';
import switchLost3 from '/alarmMusic/3/switch-lost.mp3';
import switchJammed3 from '/alarmMusic/3/switch_jammed.mp3';
import platformEmergStop3 from '/alarmMusic/3/platform_emerg_stop.mp3';
//4线
import allLineBlue4 from '/alarmMusic/4/all-line-blue.mp3';
import atpcut4 from '/alarmMusic/4/atp-cut.mp3';
import blue4 from '/alarmMusic/4/blue.mp3';
import cannotClose4 from '/alarmMusic/4/cannot-close.mp3';
import cannotOpen4 from '/alarmMusic/4/cannot-open.mp3';
import orangeMost4 from '/alarmMusic/4/orange-most.mp3';
import orange4 from '/alarmMusic/4/orange.mp3';
import redMost4 from '/alarmMusic/4/red-most.mp3';
import red4 from '/alarmMusic/4/red.mp3';
import switchLostMost4 from '/alarmMusic/4/switch-lost-most.mp3';
import switchLost4 from '/alarmMusic/4/switch-lost.mp3';
import switchJammed4 from '/alarmMusic/4/switch_jammed.mp3';
import platformEmergStop4 from '/alarmMusic/4/platform_emerg_stop.mp3';
import buzzer from '/alarmMusic/buzzer.mp3';
const lineNetStore = useLineNetStore();
@ -39,8 +55,8 @@ watch(
const hasShow = countHasShowFiveDialog();
if (!hasShow) {
const alarmType = val[0].alert_type;
alarm(alarmType, val[0].id);
playAlarmMusic(alarmType);
alarm(alarmType, val[0].id, +val[0].line_id);
playAlarmMusic(alarmType, +val[0].line_id);
} else {
waitShowDialog.push(toRaw(lineNetStore.alarmInfo[0]));
}
@ -58,7 +74,7 @@ watch(
}
);
function playAlarmMusic(type: number) {
function playAlarmMusic(type: number, lineId: number) {
for (let i = 0; i < dialogInstance.length; i++) {
if (dialogInstance[i].show == false) {
dialogInstance.splice(i, 1);
@ -67,19 +83,43 @@ function playAlarmMusic(type: number) {
}
if (lineNetStore.playAble && audio.value.paused) {
const alarmType = (showAlertTypeData as never)[type + ''];
const mapAlarmMusic = new Map([
['蓝显', blue],
['全线蓝显', allLineBlue],
['整侧站台门无法打开', cannotOpen],
['整侧站台门无法关闭', cannotClose],
['道岔失表', switchLost],
['道岔大面积失表', switchLostMost],
['计轴红光带', red],
['计轴大面积红光带', redMost],
['计轴橙光带', orange],
['计轴大面积橙光带', orangeMost],
['列车信号故障', atpcut],
]);
let mapAlarmMusic = new Map();
switch (lineId) {
case 3:
mapAlarmMusic = new Map([
['蓝显', blue3],
['全线蓝显', allLineBlue3],
['整侧站台门无法打开', cannotOpen3],
['整侧站台门无法关闭', cannotClose3],
['道岔失表', switchLost3],
['道岔大面积失表', switchLostMost3],
['计轴红光带', red3],
['计轴大面积红光带', redMost3],
['计轴橙光带', orange3],
['计轴大面积橙光带', orangeMost3],
['列车信号故障', atpcut3],
['应急触发', platformEmergStop3],
['道岔挤岔', switchJammed3],
]);
break;
case 4:
mapAlarmMusic = new Map([
['蓝显', blue4],
['全线蓝显', allLineBlue4],
['整侧站台门无法打开', cannotOpen4],
['整侧站台门无法关闭', cannotClose4],
['道岔失表', switchLost4],
['道岔大面积失表', switchLostMost4],
['计轴红光带', red4],
['计轴大面积红光带', redMost4],
['计轴橙光带', orange4],
['计轴大面积橙光带', orangeMost4],
['列车信号故障', atpcut4],
['应急触发', platformEmergStop4],
['道岔挤岔', switchJammed4],
]);
break;
}
const music = mapAlarmMusic.get(alarmType);
if (music !== undefined) {
audioSrc.value = music;
@ -102,7 +142,7 @@ function timingPlayAlarmMusic(dialog: DialogChainObject) {
!dialogInstance[i].hasHandle &&
dialogInstance[i].dialog == dialog
) {
playAlarmMusic(dialogInstance[i].alarmType);
playAlarmMusic(dialogInstance[i].alarmType, dialogInstance[i].lineId);
timingPlayAlarmMusic(dialog);
}
}
@ -116,6 +156,7 @@ const dialogInstance: {
timer: string | number | NodeJS.Timeout | undefined;
id: string;
hasHandle: boolean;
lineId: number;
}[] = [];
function countHasShowFiveDialog(): boolean {
@ -129,7 +170,12 @@ function countHasShowFiveDialog(): boolean {
return hasShow > 4 ? true : false;
}
function alarm(alarmType: number, id: string, waitAlarmMeaasge?: AlarmInfo) {
function alarm(
alarmType: number,
id: string,
lineId: number,
waitAlarmMeaasge?: AlarmInfo
) {
const dialogInstanceItem = $q
.dialog({
component: alarmInfoDialog,
@ -160,6 +206,7 @@ function alarm(alarmType: number, id: string, waitAlarmMeaasge?: AlarmInfo) {
timer,
hasHandle: false,
id,
lineId,
});
timingPlayAlarmMusic(dialogInstanceItem);
}
@ -169,9 +216,10 @@ function alarmWaitDialog() {
alarm(
waitShowDialog[0].alert_type,
waitShowDialog[0].id,
+waitShowDialog[0].line_id,
waitShowDialog[0]
);
playAlarmMusic(waitShowDialog[0].alert_type);
playAlarmMusic(waitShowDialog[0].alert_type, +waitShowDialog[0].line_id);
waitShowDialog.shift();
}
}

View File

@ -104,6 +104,7 @@ const optionsAlertType = [
'计轴大面积橙光带',
'列车信号故障',
'应急触发',
'道岔挤岔',
];
const mapAlertType = new Map([
['蓝显', ['station']],
@ -117,6 +118,7 @@ const mapAlertType = new Map([
['计轴大面积橙光带', ['Section']],
['列车信号故障', ['LogicSection', 'Turnout']],
['应急触发', ['Platform']],
['道岔挤岔', ['Turnout']],
]);
let selectGraphic: JlGraphic[] = [];

View File

@ -159,6 +159,7 @@ const optionsAlertType = [
'计轴橙光带',
'列车信号故障',
'应急触发',
'道岔挤岔',
];
const mapAlertType = new Map([
['蓝显', ['station']],
@ -167,6 +168,7 @@ const mapAlertType = new Map([
['计轴橙光带', ['LogicSection', 'Turnout']],
['列车信号故障', ['LogicSection', 'Turnout']],
['应急触发', ['Platform']],
['道岔挤岔', ['Turnout']],
]);
enum DeviceType {
station = 'DEVICE_TYPE_RTU',

View File

@ -0,0 +1,311 @@
<template>
<draggable-dialog
seamless
ref="dialogRef"
@show="onDialogShow"
:title="props.dialogTitle"
:width="990"
: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="[10, 20, 50, 100]"
>
<template v-slot:body-cell="props">
<q-td :props="props" class="custom-column">
{{ props.value }}
<q-tooltip
anchor="bottom middle"
v-if="props.value && props.value.length > 20"
>
<div class="message-tip">
{{ props.value }}
</div>
</q-tooltip>
</q-td>
</template>
</q-table>
</template>
<template v-slot:titleButton>
<q-btn
square
color="purple"
style="margin-right: 10px"
icon="search"
@click="reset"
>
<q-popup-edit
ref="popupEdit"
v-model="noUse"
:cover="false"
:offset="[0, 10]"
>
<q-select
dense
label="故障类型"
v-model="filter.faultType"
emit-value
map-options
:options="searchOptionsFaultType"
style="min-width: 130px"
/>
<q-input
dense
:label="inputSearchName"
v-model="filter.faultName"
lazy-rules
/>
<div class="button-container">
<q-btn
color="primary"
label="查询"
type="submit"
style="margin-top: 10px"
@click="searchTable"
/>
</div>
</q-popup-edit>
</q-btn>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import DraggableDialog from '../common/DraggableDialog.vue';
import { QTable, useQuasar } from 'quasar';
import {
FaultQueryListItem,
faultQueryPageQuery,
faultQueryType,
FaultTypeItem,
} from 'src/api/faultQuery';
const props = defineProps<{
dialogTitle: string;
}>();
const $q = useQuasar();
const lineId = useRoute().params.lineId as string;
const tableTitle = reactive({
faultNameShower: '',
faultDriverShower: '',
resultMsg: '',
});
const tableRef = ref<QTable>();
const columns = computed(() => [
{
name: 'id',
label: '编号',
field: 'id',
required: true,
align: 'center',
},
{
name: 'lineId',
label: '线路',
field: 'lineId',
required: true,
align: 'center',
},
{
name: 'faultType',
label: '故障类型',
field: (row: FaultQueryListItem) => {
if (row.faultType) {
return getFaultTypeName(row);
}
},
align: 'center',
},
{
name: 'faultNameShower',
label: tableTitle.faultNameShower,
field: 'faultNameShower',
required: true,
align: 'center',
},
{
name: 'faultDriverShower',
label: tableTitle.faultDriverShower,
field: 'faultDriverShower',
required: true,
align: 'center',
},
{
name: 'resultMsg',
label: tableTitle.resultMsg,
field: 'resultMsg',
required: true,
align: 'center',
},
]);
const rows = reactive([]);
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
const filter = reactive({
faultType: '',
faultName: '',
});
const onRequest: QTable['onRequest'] = async (props) => {
const { page, rowsPerPage } = props.pagination;
loading.value = true;
try {
const params = {
current: page,
size: rowsPerPage,
lineId,
};
if (filter.faultType !== '') {
Object.assign(params, {
faultType: filter.faultType,
});
}
if (filter.faultName !== '') {
Object.assign(params, {
faultName: filter.faultName,
});
}
let resp = await faultQueryPageQuery(params);
pagination.value.page = resp.current;
pagination.value.rowsNumber = resp.total;
pagination.value.rowsPerPage = resp.size;
rows.splice(0, rows.length, ...(resp.records as []));
} catch (err) {
$q.notify({
type: 'negative',
message: '无法获取范围列表',
});
} finally {
loading.value = false;
}
};
async function queryAllFaultType() {
try {
allOptionsFaultType = await faultQueryType();
handleSelectFaultType();
} catch (err) {
$q.notify({
type: 'negative',
message: '无法获取指定线路的故障类型配置',
});
}
}
let allOptionsFaultType: FaultTypeItem[] = [];
function getFaultTypeName(row: FaultQueryListItem) {
for (let i = 0; i < allOptionsFaultType.length; i++) {
if (allOptionsFaultType[i].lineId == row.lineId) {
const fts = allOptionsFaultType[i].fts;
for (let j = 0; i < fts.length; j++) {
if (fts[j].faultType == row.faultType) {
return fts[j].typeName;
}
}
}
}
}
const searchOptionsFaultType = ref([{ label: '全部', value: '' }]);
function handleSelectFaultType() {
let allType = '';
for (let i = 0; i < allOptionsFaultType.length; i++) {
if (allOptionsFaultType[i].lineId == +lineId) {
allOptionsFaultType[i].fts.forEach((item) => {
if (
(props.dialogTitle == '故障指导' &&
item.faultType.includes('FAULT_EMERGENCY_GUIDE')) ||
(props.dialogTitle == '退出服务' &&
item.faultType.includes('FAULT_EXIT_SERVICE'))
) {
searchOptionsFaultType.value.push({
label: item.typeName,
value: item.faultType,
});
if (allType == '') {
allType = item.faultType;
} else {
allType = allType + ',' + item.faultType;
}
}
});
filter.faultType = allType;
searchOptionsFaultType.value[0].value = allType;
break;
}
}
}
function searchTable() {
tableRef.value?.requestServerInteraction();
}
const noUse = ref('');
function reset() {
filter.faultType = '';
filter.faultName = '';
}
const onDialogShow = () => {
queryAllFaultType();
setTimeout(() => {
tableRef.value?.requestServerInteraction();
}, 1000);
};
const inputSearchName = ref('');
onMounted(() => {
if (props.dialogTitle == '故障指导') {
inputSearchName.value = '故障现象';
tableTitle.faultNameShower = '故障现象';
tableTitle.faultDriverShower = '司机处理结果';
tableTitle.resultMsg = '行调提醒司机关键点';
} else {
inputSearchName.value = '故障名称';
tableTitle.faultNameShower = '故障名称';
tableTitle.faultDriverShower = '故障现象';
tableTitle.resultMsg = '退出服务地点';
}
});
</script>
<style scoped>
.custom-column {
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.message-tip {
width: 300px;
overflow: auto;
line-height: 22px;
white-space: pre-wrap;
font-size: 14px;
}
.button-container {
display: flex;
justify-content: center;
margin-top: 10px;
}
</style>

View File

@ -131,6 +131,7 @@ const optionsAlertType = [
'列车信号故障',
'一级联锁',
'应急触发',
'道岔挤岔',
];
enum DeviceType {

View File

@ -77,21 +77,25 @@ import { useUserStore } from 'src/stores/user-store';
import { getMonitorPath } from 'src/router/routes';
let lineApp: IGraphicApp | null = null;
const lineAppMap = new Map<number, IGraphicApp>();
export function getLineApp() {
return lineApp;
}
export function destroyLineApp(): void {
if (lineApp) {
lineApp.destroy();
lineApp = null;
for (const key of lineAppMap.keys()) {
const app = lineAppMap.get(key);
if (app) {
app.destroy();
}
}
lineApp = null;
}
export function initLineApp(): IGraphicApp {
export function initLineApp(lineId: number): IGraphicApp {
lineApp = lineAppMap.get(lineId) || null;
if (lineApp) return lineApp;
lineApp = newGraphicApp({
interactiveGraphicTypeIncludes: [
Signal.Type,
@ -109,6 +113,7 @@ export function initLineApp(): IGraphicApp {
},
dataLoader: loadLineDatas,
});
lineAppMap.set(lineId, lineApp);
const graphicTemplate = [
new TrainTemplate(new TrainData(), new TrainState()),

View File

@ -52,6 +52,7 @@ export function destroyLineNetApp(): void {
}
export function initLineNetApp(): IGraphicApp {
if (lineNetApp) return lineNetApp;
lineNetApp = newGraphicApp({
interactiveGraphicTypeIncludes: [
RunLine.Type,

View File

@ -15,7 +15,20 @@
<img :src="NCC" style="width: 80px" />
</div>
<q-toolbar-title> 西安NCC调度辅助决策系统 </q-toolbar-title>
<q-btn
v-show="route.path.includes('line/monitor')"
color="info"
label="故障指导"
class="q-mr-sm"
@click="openFaultQueryDialog('故障指导')"
/>
<q-btn
v-show="route.path.includes('line/monitor')"
color="info"
label="退出服务"
class="q-mr-sm"
@click="openFaultQueryDialog('退出服务')"
/>
<q-btn
v-show="route.path.includes('line/monitor')"
color="info"
@ -128,6 +141,7 @@ import { logout } from 'src/api/UserApi';
import { ApiError } from 'src/boot/axios';
import { useUserStore } from 'src/stores/user-store';
import { getMonitorPath } from 'src/router/routes';
import FaultQueryDialog from 'src/components/dialog/FaultQueryDialog.vue';
const leftDrawerOpen = ref(false);
const router = useRouter();
@ -180,6 +194,15 @@ onMounted(() => {
socket = webSocketConnect(destination, handler);
});
function openFaultQueryDialog(dialogTitle: string) {
$q.dialog({
component: FaultQueryDialog,
componentProps: {
dialogTitle,
},
});
}
//
const $q = useQuasar();
function openSetAlarmMockDialog() {

View File

@ -496,6 +496,7 @@ const optionsAlertType = [
'联锁区红光带',
'联锁区橙光带',
'应急触发',
'道岔挤岔',
];
//

View File

@ -412,6 +412,7 @@ const optionsAlertType = [
'联锁区橙光带',
'联锁区失表',
'应急触发',
'道岔挤岔',
];
const searchOptionsAlertType = ['全部', ...optionsAlertType];
let optionsLocationType = ref<string[]>([]);
@ -419,7 +420,10 @@ let optionsLocationList: AreaConfigItem[] = [];
async function searchLocationType() {
try {
const alertType = (saveAlertTypeData as never)[creatForm.alertType];
optionsLocationList = await getDeviceAreaByAlarmType(+creatForm.lineId, alertType);
optionsLocationList = await getDeviceAreaByAlarmType(
+creatForm.lineId,
alertType
);
optionsLocationType.value = optionsLocationList.map(
(item) => item.areaName
);

View File

@ -0,0 +1,501 @@
<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"
binary-state-sort
@request="onRequest"
>
<template v-slot:body-cell="props">
<q-td :props="props" class="custom-column">
{{ props.value }}
<q-tooltip
anchor="bottom middle"
v-if="props.value && props.value.length > 20"
>
<div class="message-tip">
{{ props.value }}
</div>
</q-tooltip>
</q-td>
</template>
<template v-slot:top-right>
<q-form ref="myForm" @submit="searchDecisionInfo" style="width: 100%">
<div class="q-gutter-md q-mt-none row justify-center items-start">
<q-select
dense
v-model="filter.lineId"
:options="searchOptionsLineId"
emit-value
map-options
options-dense
label="线路ID"
style="width: 75px"
no-error-icon
lazy-rules
@update:model-value="handleSelectSearchLineId"
:rules="[(val) => val >= 0 || '请选择线路ID']"
/>
<q-select
dense
label="故障类型"
v-model="filter.faultType"
emit-value
map-options
:options="searchOptionsFaultType"
style="min-width: 130px"
/>
<q-btn color="primary" label="查询" type="submit" />
<q-btn
color="primary"
label="新建"
@click="createFormShow = true"
/>
</div>
</q-form>
</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: 500px">
<q-form
ref="myForm"
@submit="onCreate"
@reset="onReset"
class="q-gutter-md"
>
<q-card-section class="q-gutter-sm">
<div class="text-h6">
{{ creatForm.id ? '编辑故障查询' : '新建故障查询' }}
</div>
<q-select
outlined
label="线路ID"
v-model="creatForm.lineId"
:options="optionsLineId"
emit-value
map-options
lazy-rules
@update:model-value="handleSelectLineId"
:rules="[(val) => val > 0 || '请选择线路ID']"
/>
<q-select
outlined
label="故障类型"
v-model="creatForm.faultType"
:options="optionsFaultType"
emit-value
map-options
:rules="[(val) => val.length > 0 || '请选择故障类型!']"
/>
<q-input
outlined
label="消息名称(故障现象)"
v-model="creatForm.faultNameShower"
lazy-rules
:rules="[(val) => val.length > 0 || '请输入消息名称!']"
/>
<q-input
outlined
type="textarea"
label="司机处理结果(服务故障现象)"
v-model="creatForm.faultDriverShower"
lazy-rules
:rules="[(val) => val.length > 0 || '请输入司机处理结果!']"
/>
<q-input
outlined
type="textarea"
label="司机关键点(退出服务地点)"
v-model="creatForm.resultMsg"
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="取消" type="reset" v-close-popup />
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue';
import { useQuasar, type QTableColumn, QForm, QTable } from 'quasar';
import {
faultQueryPageQuery,
deleteFaultQueryById,
createFaultQuery,
FaultQueryListItem,
faultQueryType,
FaultTypeItem,
} from '../api/faultQuery';
import { ApiError } from 'src/boot/axios';
import { pageQuery } from 'src/api/LineInfoApi';
const $q = useQuasar();
const props = withDefaults(
defineProps<{
sizeHeight: number;
}>(),
{ sizeHeight: 500 }
);
const tableHeight = computed(() => {
return props.sizeHeight - 32;
});
const columnDefs: QTableColumn[] = [
{
name: 'id',
label: '编号',
field: 'id',
required: true,
align: 'center',
},
{
name: 'lineId',
label: '线路',
field: 'lineId',
required: true,
align: 'center',
},
{
name: 'faultType',
label: '故障类型',
field: (row) => {
if (row.faultType) {
return getFaultTypeName(row);
}
},
align: 'center',
},
{
name: 'faultNameShower',
label: '消息名称(故障现象)',
field: 'faultNameShower',
required: true,
align: 'center',
},
{
name: 'faultDriverShower',
label: '司机处理结果(服务故障现象)',
field: 'faultDriverShower',
required: true,
align: 'center',
},
{
name: 'resultMsg',
label: '司机关键点(退出服务地点)',
field: 'resultMsg',
required: true,
align: 'center',
},
{ name: 'operations', label: '操作', field: 'operations', align: 'center' },
];
const operateDisabled = ref(false);
const tableRef = ref();
const rows = reactive([]);
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
const filter = ref({
faultType: '',
lineId: 0,
});
const onRequest: QTable['onRequest'] = async (props) => {
const { page, rowsPerPage, sortBy, descending } = props.pagination;
loading.value = true;
try {
const params = {
current: page,
size: rowsPerPage,
};
if (filter.value.lineId !== 0) {
Object.assign(params, {
lineId: filter.value.lineId,
});
}
if (filter.value.faultType!=='') {
Object.assign(params, {
faultType: filter.value.faultType,
});
}
let response = await faultQueryPageQuery(params);
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) {
$q.notify({
type: 'negative',
message: '无法获取故障查询列表',
});
} finally {
loading.value = false;
}
};
onMounted(() => {
queryLineInfo();
queryAllFaultType();
setTimeout(() => {
tableRef.value.requestServerInteraction();
});
});
function searchDecisionInfo() {
tableRef.value.requestServerInteraction();
}
const createFormShow = ref(false);
const myForm = ref<QForm | null>(null);
const creatForm = reactive({
id: '',
lineId: '',
faultType: '',
faultNameShower: '',
faultDriverShower: '',
resultMsg: '',
});
const optionsLineId = ref<{ label: string; value: number }[]>([]);
const searchOptionsLineId = ref<{ label: string; value: number }[]>([
{ label: '全部', value: 0 },
]);
async function queryLineInfo() {
try {
let response = await pageQuery({
current: 1,
size: 50,
});
response.records.forEach((info) => {
optionsLineId.value.push({ label: info.name, value: info.lineId });
searchOptionsLineId.value.push({ label: info.name, value: info.lineId });
});
} catch (err) {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
}
}
let allOptionsFaultType: FaultTypeItem[] = [];
let optionsFaultType = ref<{ label: string; value: string }[]>([]);
async function queryAllFaultType() {
try {
allOptionsFaultType = await faultQueryType();
handleSelectAllFaultType();
} catch (err) {
$q.notify({
type: 'negative',
message: '无法获取指定线路的故障类型配置',
});
}
}
function getFaultTypeName(row: FaultQueryListItem) {
for (let i = 0; i < allOptionsFaultType.length; i++) {
if (allOptionsFaultType[i].lineId == row.lineId) {
const fts = allOptionsFaultType[i].fts;
for (let j = 0; i < fts.length; j++) {
if (fts[j].faultType == row.faultType) {
return fts[j].typeName;
}
}
}
}
}
function handleSelectLineId() {
optionsFaultType.value = [];
creatForm.faultType = '';
for (let i = 0; i < allOptionsFaultType.length; i++) {
if (allOptionsFaultType[i].lineId == +creatForm.lineId) {
allOptionsFaultType[i].fts.forEach((item) => {
optionsFaultType.value.push({
label: item.typeName,
value: item.faultType,
});
});
break;
}
}
}
const searchOptionsFaultType = ref<{ label: string; value: string }[]>([
{ label: '全部', value: '' },
]);
function handleSelectSearchLineId() {
filter.value.faultType = '';
searchOptionsFaultType.value = [{ label: '全部', value: '' }];
if (filter.value.lineId == 0) {
handleSelectAllFaultType();
}
for (let i = 0; i < allOptionsFaultType.length; i++) {
if (allOptionsFaultType[i].lineId == filter.value.lineId) {
allOptionsFaultType[i].fts.forEach((item) => {
searchOptionsFaultType.value.push({
label: item.typeName,
value: item.faultType,
});
});
break;
}
}
}
function handleSelectAllFaultType() {
allOptionsFaultType.forEach((faultTypeOption) => {
faultTypeOption.fts.forEach((fault) =>
searchOptionsFaultType.value.push({
label: fault.typeName,
value: fault.faultType,
})
);
});
}
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
operateDisabled.value = true;
try {
const params = {
lineId: +creatForm.lineId,
faultType: creatForm.faultType,
faultNameShower: creatForm.faultNameShower,
faultDriverShower: creatForm.faultDriverShower,
resultMsg: creatForm.resultMsg,
};
if (creatForm.id !== '') {
Object.assign(params, {
id: +creatForm.id,
});
}
await createFaultQuery(params);
onReset();
createFormShow.value = false;
tableRef.value.requestServerInteraction(); //
} catch (err) {
const apiErr = err as ApiError;
$q.notify({
type: 'negative',
message: apiErr.title,
});
} finally {
operateDisabled.value = false;
}
}
});
}
function editData(row: FaultQueryListItem) {
creatForm.id = row.id + '';
creatForm.lineId = row.lineId + '';
creatForm.faultType = row.faultType;
creatForm.faultNameShower = row.faultNameShower;
creatForm.faultDriverShower = row.faultDriverShower;
creatForm.resultMsg = row.resultMsg;
createFormShow.value = true;
}
async function deleteData(row: FaultQueryListItem) {
operateDisabled.value = true;
$q.dialog({
title: '确认',
message: `确认删除编号是"${row.id}"的决策信息吗?`,
cancel: true,
})
.onOk(async () => {
try {
await deleteFaultQueryById(row.id as number);
tableRef.value.requestServerInteraction(); //
} catch (err) {
$q.notify({
type: 'negative',
message: '无法删除决策信息',
});
}
})
.onDismiss(() => {
operateDisabled.value = false;
});
}
function onReset() {
creatForm.id = '';
creatForm.lineId = '';
creatForm.faultType = '';
creatForm.faultNameShower = '';
creatForm.faultDriverShower = '';
creatForm.resultMsg = '';
myForm.value?.resetValidation();
}
</script>
<style scoped>
.custom-column {
max-width: 300px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.message-tip {
width: 300px;
max-height: 250px;
overflow: auto;
line-height: 22px;
white-space: pre-wrap;
font-size: 14px;
}
</style>

View File

@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { onMounted, watch, onUnmounted } from 'vue';
import { onMounted, watch } from 'vue';
import { useLineStore } from 'src/stores/line-store';
import { useRoute } from 'vue-router';
import { useLineNetStore } from 'src/stores/line-net-store';
@ -80,7 +80,7 @@ function centerFaultDevice() {
}
}
onUnmounted(() => {
lineStore.destroy();
});
// onUnmounted(() => {
// lineStore.destroy();
// });
</script>

View File

@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { onMounted, watch, onUnmounted } from 'vue';
import { onMounted, watch } from 'vue';
import { useLineNetStore } from 'src/stores/line-net-store';
import { RunLine } from 'src/graphics/runLine/RunLine';
import { useRouter } from 'vue-router';
@ -73,7 +73,7 @@ onMounted(() => {
}
});
onUnmounted(() => {
lineNetStore.destroy();
});
// onUnmounted(() => {
// lineNetStore.destroy();
// });
</script>

View File

@ -36,7 +36,8 @@ export namespace alert {
AXLE_LED_ORANGE_INTERLOCK_AREA = 21,
SWITCH_LOST_INTERLOCK_AREA = 22,
INTERLOCK_LEVEL_ONE = 23,
PLATFORM_EMERG_STOP = 24
PLATFORM_EMERG_STOP = 24,
SWITCH_JAMMED = 25
}
export enum TipTimeConfig {
HOLIDAYS_MORN_PEAK = 0,

View File

@ -46,6 +46,11 @@ const routes: RouteRecordRaw[] = [
name: 'decisionInfo',
component: () => import('pages/DecisionInfoManage.vue'),
},
{
path: 'faultQuery',
name: 'faultQuery',
component: () => import('pages/FaultQueryManage.vue'),
},
{
path: 'thresholdValue',
name: 'thresholdValue',

View File

@ -39,7 +39,7 @@ export const useLineStore = defineStore('line', {
},
initLineApp(lineId: number) {
this.setLineId(lineId);
const app = initLineApp();
const app = initLineApp(lineId);
app.on('graphicselected', (graphics) => {
this.selectedGraphics = markRaw(graphics);
});

@ -1 +1 @@
Subproject commit c8ca17875615e4fd3483a7b15c11a1bc2f2f9cd5
Subproject commit a7b726826b89520f047c268415702df8116d225f