Compare commits

..

29 Commits

Author SHA1 Message Date
joylink_fanyuhong
9a6d4efedb merge
Some checks failed
local-test分支构建发布 / Docker-Build (push) Failing after 56s
2024-11-20 09:19:18 +08:00
joylink_fanyuhong
e6f6ac2b7e 账号格式校验调整 2024-11-20 09:15:10 +08:00
joylink_fanyuhong
da04217a08 登录页注释注册按钮 2024-11-20 09:10:25 +08:00
joylink_fanyuhong
de64a23eb8 故障提示超宽调整 2024-11-20 09:08:19 +08:00
joylink_fanyuhong
2e19a66a6b Merge branch 'develop' of https://gitea.joylink.club/joylink/xian-ncc-da-client into develop 2024-11-19 14:05:54 +08:00
joylink_fanyuhong
fac62de1ae 等待时间调整 2024-11-19 14:05:48 +08:00
joylink_zhaoerwei
bfebe3e28d 列车报点 2024-11-19 10:50:42 +08:00
joylink_fanyuhong
e2faeb2d05 根据状态判断是否显示故障时间 2024-11-18 17:29:46 +08:00
joylink_fanyuhong
109a19527d protoc 2024-11-18 17:12:23 +08:00
joylink_fanyuhong
09b6dcbb19 Merge branch 'develop' of https://gitea.joylink.club/joylink/xian-ncc-da-client into develop 2024-11-18 16:59:55 +08:00
joylink_fanyuhong
539e8b7d01 代码调整 2024-11-18 16:59:39 +08:00
joylink_zhaoerwei
1cd4cb815c 告警弹框 2024-11-18 15:50:46 +08:00
joylink_zhaoerwei
a37e33d7d8 故障类型查询调整 2024-11-18 15:05:46 +08:00
joylink_zhaoerwei
f7634d7672 同步proto 2024-11-18 09:47:55 +08:00
joylink_zhaoerwei
550bd752f8 ncc应急处置 2024-11-15 16:47:08 +08:00
joylink_zhaoerwei
67bfc01f6e toolTip调整 2024-11-15 13:32:13 +08:00
joylink_zhaoerwei
35f41df852 微调 2024-11-15 11:29:34 +08:00
joylink_zhaoerwei
6888e20634 微调 2024-11-15 11:09:15 +08:00
joylink_fanyuhong
4a3c2fafbf 代码提交 2024-11-15 10:11:12 +08:00
joylink_zhaoerwei
2aad7d4139 流程表调整 2024-11-15 09:18:14 +08:00
joylink_fanyuhong
02e49ec6fa 报警调整 2024-11-15 09:08:22 +08:00
joylink_fanyuhong
2b3673485c Merge branch 'develop' of https://gitea.joylink.club/joylink/xian-ncc-da-client into develop 2024-11-15 09:03:41 +08:00
joylink_fanyuhong
0c1471f651 报警记录调整 2024-11-15 09:03:37 +08:00
joylink_zhaoerwei
e932e7d0ae 增加是否播报语音 2024-11-14 18:14:13 +08:00
joylink_zhaoerwei
05896cb241 添加应急处置流程表 2024-11-14 17:51:50 +08:00
joylink_fanyuhong
debaf97510 菜单调整 2024-11-14 15:59:51 +08:00
joylink_fanyuhong
99b7cba025 卡斯柯=》同方 2024-11-14 14:50:39 +08:00
joylink_fanyuhong
41e59960ee 公里表显示调整 2024-11-14 14:46:13 +08:00
joylink_zhaoerwei
0da7654efa 增加5个故障 2024-11-14 11:14:19 +08:00
17 changed files with 814 additions and 107 deletions

View File

@ -75,3 +75,20 @@ export async function faultQueryType(): Promise<Array<FaultTypeItem>> {
const response = await api.get(`${faultQueryUriBase}/type`);
return response.data;
}
export interface NccFaultQueryListItem {
nccTypeName: string;
nccData: { action: string; datas: string[] }[];
}
/**
* ncc故障查询
* @param params
* @returns
*/
export async function nccFaultQueryPageQuery(): Promise<
NccFaultQueryListItem[]
> {
const response = await api.post(`${faultQueryUriBase}/ncc`);
return response.data;
}

View File

@ -125,7 +125,11 @@ const list = reactive([
},
{
show: true,
<<<<<<< HEAD
path: '/sysManage/alarmRecord',
=======
path: '/alarmInfo/list',
>>>>>>> origin/develop
label: '报警管理',
icon: 'alarm_on',
},

View File

@ -30,6 +30,7 @@ export enum showAlertTypeData {
'列车完整性',
'列车故障救援',
'ats卡滞',
'列车报点',
I = 'I类信息',
II = 'II类信息',
III = 'III类信息',
@ -67,6 +68,7 @@ export enum showAlertTypeData {
TRAIN_INTEGRITY_ALARM = '列车完整性',
TRAIN_FAULT_HELP = '列车故障救援',
INTERLOCKED_ATS_STUCK = 'ats卡滞',
TRAIN_RECORD = '列车报点',
}
export enum saveAlertTypeData {
@ -103,6 +105,7 @@ export enum saveAlertTypeData {
= 'TRAIN_INTEGRITY_ALARM',
= 'TRAIN_FAULT_HELP',
ats卡滞 = 'INTERLOCKED_ATS_STUCK',
= 'TRAIN_RECORD',
}
export const GuardConfigTypeData = {

View File

@ -40,7 +40,9 @@
<q-card>
<q-item no-wrap class="column">
<q-input
v-if="setAlartTextData.alertType == '列车信号故障'"
v-if="
needShowTrainGroup.includes(setAlartTextData.alertType)
"
outlined
label="车组号"
v-model="configItem.groupId"
@ -81,7 +83,11 @@
@click="clearAllSelect(index)"
/>
<q-btn
v-if="setAlartTextData.alertType == '列车信号故障'"
v-if="
needShowTrainGroup.includes(
setAlartTextData.alertType
)
"
label="删除测试组"
color="secondary"
@click="deleteSelectConfig(index)"
@ -92,7 +98,7 @@
</q-expansion-item>
</q-list>
<q-btn
v-if="setAlartTextData.alertType == '列车信号故障'"
v-if="needShowTrainGroup.includes(setAlartTextData.alertType)"
class="q-mt-md"
label="增加测试组"
color="secondary"
@ -116,7 +122,7 @@
<script setup lang="ts">
import DraggableDialog from '../common/DraggableDialog.vue';
import { onMounted, onUnmounted, ref, watch } from 'vue';
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { JlGraphic } from 'jl-graphic';
import { Station } from 'src/graphics/station/Station';
import { useLineStore } from 'src/stores/line-store';
@ -124,6 +130,8 @@ import { QForm, useQuasar } from 'quasar';
import { ApiError } from 'src/boot/axios';
import { mockLocalDemoTestSet } from 'src/api/AlertMock';
import { isArraysEqual, saveAlertTypeData } from './alarmInfoEnum';
import { Section } from 'src/graphics/section/Section';
import { Platform } from 'src/graphics/platform/Platform';
const lineStore = useLineStore();
const setAlartTextData = ref<{
@ -152,6 +160,7 @@ const setAlartTextData = ref<{
},
],
});
const needShowTrainGroup = ['列车信号故障', '列车报点'];
const optionsAlertType = [
'蓝显',
'道岔失表',
@ -160,7 +169,8 @@ const optionsAlertType = [
'列车信号故障',
'应急触发',
'道岔挤岔',
'列车完整性'
'列车完整性',
'列车报点',
];
const mapAlertType = new Map([
['蓝显', ['station']],
@ -171,18 +181,30 @@ const mapAlertType = new Map([
['应急触发', ['Platform']],
['道岔挤岔', ['Turnout']],
['列车完整性', ['LogicSection']],
['列车报点', ['Section']],
]);
enum DeviceType {
station = 'DEVICE_TYPE_RTU',
Turnout = 'DEVICE_TYPE_SWITCH',
LogicSection = 'DEVICE_TYPE_TRACK',
Platform = 'DEVICE_TYPE_PLATFORM',
Section = 'DEVICE_TYPE_SECTION',
}
const optionsStatus = [
const optionsStatus = computed(() => {
if (setAlartTextData.value.alertType !== '列车报点') {
return [
{ label: '正常', value: 'NORMAL' },
{ label: '设置', value: 'BEGIN' },
{ label: '报警', value: 'ALERT' },
];
} else {
return [
{ label: '到站', value: 'NORMAL' },
{ label: '离站', value: 'BEGIN' },
];
}
});
let allplatformRefSection: number[] = [];
let selectGraphic: JlGraphic[] = [];
watch(
@ -212,16 +234,22 @@ watch(
setAlartTextData.value.alertType == '蓝显'
) {
select = true;
}
if (
} else if (
g.type == Section.Type &&
setAlartTextData.value.alertType == '列车报点' &&
allplatformRefSection.includes(g.id)
) {
select = true;
} else if (
g.type !== Station.Type &&
g.type !== Section.Type &&
mapAlertType.get(setAlartTextData.value.alertType)?.includes(g.type)
) {
select = true;
}
return select;
}) as JlGraphic[];
if (setAlartTextData.value.alertType !== '列车信号故障') {
if (!needShowTrainGroup.includes(setAlartTextData.value.alertType)) {
selectGraphic.push(...deviceFilter);
} else if (deviceFilter.length) {
selectGraphic = [deviceFilter[0]];
@ -242,6 +270,12 @@ watch(
);
onMounted(() => {
const platforms = lineStore
.getLineApp()
.queryStore.queryByType<Platform>(Platform.Type);
platforms.forEach((platform) =>
allplatformRefSection.push(platform.datas.refSectionId)
);
lineStore.getLineApp().emit('options-update', {
mouseToolOptions: {
boxSelect: true,

View File

@ -207,6 +207,12 @@ export class PlatformState extends GraphicStateBase implements IPlatformState {
set rtuId(value: number) {
this.states.rtuId = value;
}
get bizWaitTimeSec(): number {
return this.states.bizWaitTimeSec;
}
set bizWaitTimeSec(value: number) {
this.states.bizWaitTimeSec = value;
}
get states(): state.Platform {
return this.getState<state.Platform>();
}

View File

@ -11,6 +11,7 @@ import {
} from 'jl-graphic';
import { Station } from '../station/Station';
import { Section } from '../section/Section';
import { useLineStore } from 'src/stores/line-store';
export interface IPlatformData extends GraphicData {
get code(): string; // 编号
@ -66,6 +67,8 @@ export interface IPlatformState extends GraphicState {
set stopTime(v: number);
get rtuId(): number; // 集中站站号
set rtuId(v: number);
get bizWaitTimeSec(): number; //乘客等待秒数
set bizWaitTimeSec(v: number);
}
//站台颜色
@ -189,6 +192,8 @@ class codeGraph extends Container {
runLevel: VectorText = new VectorText(''); //运行等级
runTime: VectorText = new VectorText(''); //运行时间
stopTime: VectorText = new VectorText(''); //停站时间
waitSec: VectorText = new VectorText(); //VectorText
circle: Graphics = new Graphics();
constructor() {
super();
@ -197,12 +202,14 @@ class codeGraph extends Container {
this.addChild(this.circle);
this.addChild(this.stopTime);
this.addChild(this.runTime);
this.addChild(this.waitSec);
this.character.setVectorFontSize(platformConsts.besideFontSize);
this.runLevel.setVectorFontSize(platformConsts.besideFontSize);
this.stopTime.setVectorFontSize(platformConsts.besideFontSize);
this.runTime.setVectorFontSize(platformConsts.besideFontSize);
this.waitSec.setVectorFontSize(platformConsts.besideFontSize);
}
draw(): void {
draw(datas: IPlatformData): void {
//扣车
const character = this.character;
character.text = 'H';
@ -254,11 +261,25 @@ class codeGraph extends Container {
platformConsts.besideSpacing
);
stopTime.style.fill = PlatformColorEnum.whiteNumbers;
//乘客等待时间
const waitSec = this.waitSec;
waitSec.anchor.set(0.5);
let yPos = platformConsts.height / 2 + platformConsts.doorPlatformSpacing;
if (datas.direction == 'down') {
yPos = -platformConsts.height / 2 - platformConsts.doorPlatformSpacing;
}
waitSec.position.set(0, yPos);
waitSec.style.fill = PlatformColorEnum.whiteNumbers;
character.visible = false;
circle.visible = false;
runLevel.visible = false;
stopTime.visible = false;
runTime.visible = false;
waitSec.visible = false;
}
clear(): void {
this.character.destroy();
@ -309,6 +330,21 @@ class codeGraph extends Container {
this.stopTime.visible = true;
this.stopTime.text = stateData.stopTime;
}
if (stateData.bizWaitTimeSec && useLineStore().faultStatistics) {
const minutes = Math.floor(stateData.bizWaitTimeSec / 60);
const seconds = stateData.bizWaitTimeSec % 60;
let minutesString = '' + minutes;
let secondsString = '' + seconds;
if (minutes < 10) {
minutesString = `0${minutes}`;
}
if (seconds < 10) {
secondsString = `0${seconds}`;
}
this.waitSec.visible = true;
this.waitSec.text = `乘客已经等待了${minutesString}:${secondsString}`;
}
}
}
//子元素--站台旁菱形图标
@ -388,7 +424,7 @@ export class Platform extends JlGraphic {
}
this.platformGraphic.draw(this.states);
this.besideGraphic.draw();
this.codeGraph.draw();
this.codeGraph.draw(this.datas);
this.doorGraphic.position.set(
0,

View File

@ -51,6 +51,21 @@
label="返回"
@click="backConfirm"
/>
<q-toggle
v-model="lineStore.faultStatistics"
checked-icon="check"
color="red"
label="故障信息统计"
unchecked-icon="clear"
/>
<q-btn
round
dense
flat
:color="lineNetStore.handlePlayAble ? 'white' : 'red'"
:icon="lineNetStore.handlePlayAble ? 'alarm_on' : 'alarm_off'"
@click="changeCanPlayAlarmMusic"
/>
<q-btn
round
dense
@ -112,7 +127,7 @@
</q-scroll-area>
</q-page-container>
</q-layout>
<commonAlarm v-if="route.path.includes('alarmRecord')" />
<commonAlarm v-if="route.path.includes('alarmInfo')" />
</template>
<script setup lang="ts">

294
src/pages/AlarmRecord.vue Normal file
View File

@ -0,0 +1,294 @@
<template>
<div class="q-pa-md">
<q-table
ref="tableRef"
title="报警记录"
:style="{ height: tableHeight + 'px' }"
class="my-sticky-virtscroll-table"
: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:top-right>
<q-input
dense
class="q-mr-md"
debounce="1000"
v-model="filter.name"
label="操作人"
></q-input>
<q-input
v-model="filter.beginDate"
label="开始时间"
debounce="1000"
class="q-mr-md"
dense
>
<template v-slot:prepend>
<q-icon name="event" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-date v-model="filter.beginDate" mask="YYYY-MM-DD HH:mm:ss">
<div class="row items-center justify-end">
<q-btn v-close-popup label="关闭" color="primary" flat />
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
<template v-slot:append>
<q-icon name="access_time" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-time
v-model="filter.beginDate"
mask="YYYY-MM-DD HH:mm:ss"
format24h
with-seconds
>
<div class="row items-center justify-end">
<q-btn v-close-popup label="Close" color="primary" flat />
</div>
</q-time>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-input
v-model="filter.endDate"
label="截止时间"
debounce="1000"
class="q-mr-md"
dense
>
<template v-slot:prepend>
<q-icon name="event" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-date v-model="filter.endDate" mask="YYYY-MM-DD HH:mm:ss">
<div class="row items-center justify-end">
<q-btn v-close-popup label="关闭" color="primary" flat />
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
<template v-slot:append>
<q-icon name="access_time" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-time
v-model="filter.endDate"
mask="YYYY-MM-DD HH:mm:ss"
format24h
with-seconds
>
<div class="row items-center justify-end">
<q-btn v-close-popup label="关闭" color="primary" flat />
</div>
</q-time>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-btn flat round color="primary" icon="search" @click="searchQuery" />
</template>
<!-- <template v-slot:body-cell-subEventType="props">
<q-td :props="props">
<div class="q-gutter-sm row justify-center">
<q-chip outline size="sm" color="primary">
{{ getSubEventType(props.row.subEventType) }}
</q-chip>
</div>
</q-td>
</template> -->
<template v-slot:body-cell-requestSuccess="props">
<q-td :props="props">
<div class="q-gutter-sm row justify-center">
<q-chip outline size="sm" color="primary">
{{ props.row.requestSuccess === 1 ? '连接' : '断开' }}
</q-chip>
</div>
</q-td>
</template>
<!-- <template v-slot:top-right>
<q-input
dense
debounce="1000"
v-model="filter.name"
label="用户名"
></q-input>
<q-btn flat round color="primary" icon="search" />
</template> -->
<!-- <template v-slot:body-cell-roles="props">
<q-td :props="props">
<div class="q-gutter-sm row justify-center">
<q-chip
outline
size="sm"
color="primary"
v-for="(item, index) in props.row.roleList"
:key="index"
>
{{ item.roleName }}
</q-chip>
</div>
</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="编辑角色"
:disable="operateDisabled"
@click="edieUserData(props.row)"
/>
</div>
</q-td>
</template> -->
</q-table>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue';
import { type QTableColumn } from 'quasar';
import { pageQuery, Record } from '../api/LogApi';
import { errorNotify } from '../utils/CommonNotify';
// const $q = useQuasar(); useQuasar
const props = withDefaults(
defineProps<{
sizeHeight: number;
}>(),
{ sizeHeight: 500 }
);
const tableHeight = computed(() => {
return props.sizeHeight - 32;
});
onMounted(() => {
tableRef.value.requestServerInteraction();
});
const columnDefs: QTableColumn[] = [
{ name: 'id', label: 'ID', field: 'id', align: 'center' },
{
name: 'lineId',
label: '线路ID',
field: 'lineId',
align: 'center',
},
{
name: 'faceName',
label: '接口名称',
field: 'faceName',
align: 'center',
},
{
name: 'userName',
label: '操作人员',
field: 'userName',
align: 'center',
},
{
name: 'createDateTime',
label: '记录时间',
field: 'createDateTime',
align: 'center',
},
{
name: 'requestSuccess',
label: '连接断开',
field: 'requestSuccess',
align: 'center',
},
];
const tableRef = ref();
const rows = reactive([]);
const filter = reactive({
name: '',
beginDate: '',
endDate: '',
});
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
// eslint-disable-next-line
async function onRequest(props: any) {
const { page, rowsPerPage, sortBy, descending } = props.pagination;
loading.value = true;
try {
let response = await pageQuery({
current: page,
size: rowsPerPage,
logType: 'WARN',
name: filter.name,
beginDate: filter.beginDate,
endDate: filter.endDate,
});
pagination.value.rowsNumber = response.total;
pagination.value.page = page;
pagination.value.rowsPerPage = rowsPerPage;
pagination.value.sortBy = sortBy;
pagination.value.descending = descending;
rows.splice(0, rows.length, ...(response.records as []));
} catch (error: any) {
errorNotify('获取数据失败', error);
} finally {
loading.value = false;
}
}
function getSubEventType(type: string) {
switch (type) {
case 'LOGIN':
return '登录';
case 'LOGOUT':
return '登出';
case 'QUERY':
return '查询';
case 'SAVE_OR_UPDATE':
return '保存';
case 'DELETE':
return '删除';
case 'WARN':
return '报警';
default:
return '';
}
}
function searchQuery() {
tableRef.value.requestServerInteraction();
}
</script>

View File

@ -15,8 +15,8 @@
/>
</q-tabs>
<q-separator />
<q-tab-panel>
<div class="dialogContainer">
<q-tab-panel name="info">
<div class="occContainer" v-if="roleType == 'OCC'">
<q-table
ref="tableRef"
row-key="id"
@ -30,22 +30,8 @@
class="left"
>
<template v-slot:top-right>
<q-form ref="myForm" @submit="searchDecisionInfo" style="width: 100%">
<q-form ref="myForm" 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="故障类型"
@ -82,12 +68,11 @@
:key="col.name"
:props="props"
class="custom-column"
@mouseover="onMouseOver"
@mouseleave="showTooltip = false"
>
{{ col.value }}
<q-tooltip
anchor="bottom middle"
v-if="props.value && props.value.length > 20"
>
<q-tooltip v-if="showTooltip" anchor="bottom middle">
<div class="message-tip">
{{ col.value }}
</div>
@ -125,6 +110,26 @@
</div>
</q-scroll-area>
</div>
<div v-else class="nccContainer">
<q-btn-toggle
v-model="selectMenuName"
toggle-color="primary"
:options="menuOption"
@update:model-value="selectedMenu"
class="q-btn-toggle"
/>
<q-card
class="box-card"
v-for="nccData in showNccData"
:key="nccData.action"
>
<div class="head">{{ nccData.action }}</div>
<q-separator />
<div class="detail">
<div v-for="data in nccData.datas" :key="data">{{ data }}</div>
</div>
</q-card>
</div>
</q-tab-panel>
</template>
@ -136,16 +141,25 @@ import {
faultQueryPageQuery,
faultQueryType,
FaultTypeItem,
NccFaultQueryListItem,
nccFaultQueryPageQuery,
} from 'src/api/faultQuery';
import { pageQuery } from 'src/api/LineInfoApi';
import { ApiError } from 'src/boot/axios';
import { getMonitorPath } from 'src/router/routes';
import { useUserStore } from 'src/stores/user-store';
const props = withDefaults(
defineProps<{
sizeHeight: number;
sizeWidth: number;
}>(),
{ sizeHeight: 500, sizeWidth: 500 }
);
const $q = useQuasar();
const tab = ref('GUIDE');
const tableTitle = reactive({
faultNameShower: '',
faultDriverShower: '',
faultNameShower: '故障现象',
faultDriverShower: '司机处理结果',
});
const inputSearchName = ref('故障现象');
watch(tab, (tabVal) => {
@ -159,18 +173,8 @@ watch(tab, (tabVal) => {
tableTitle.faultDriverShower = '故障现象';
}
handleSelectFaultType();
searchTable();
});
const tabList = ref([
{
label: '故障指导',
value: 'GUIDE',
},
{
label: '退出服务',
value: 'SERVICE',
},
]);
const tabList = ref();
const tableRef = ref<QTable>();
const columns = computed(() => [
@ -334,6 +338,7 @@ function handleSelectFaultType() {
let allType = '';
searchOptionsFaultType.value = [{ label: '全部', value: '' }];
for (let i = 0; i < allOptionsFaultType.length; i++) {
if (allOptionsFaultType[i].lineId == filter.lineId) {
allOptionsFaultType[i].fts.forEach((item) => {
if (
(tab.value == 'GUIDE' &&
@ -352,42 +357,90 @@ function handleSelectFaultType() {
}
}
});
break;
}
}
filter.faultType = allType;
searchOptionsFaultType.value[0].value = allType;
}
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) => {
searchOptionsLineId.value.push({ label: info.name, value: info.lineId });
});
} catch (err) {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
}
}
function searchTable() {
tableRef.value?.requestServerInteraction();
}
//ncc
const nccDatas = ref<NccFaultQueryListItem[]>();
const selectMenuName = ref('');
const menuOption = ref<
{
label: string;
value: string;
}[]
>([]);
const showNccData = ref<{ action: string; datas: string[] }[]>();
function selectedMenu(name: string) {
showNccData.value = nccDatas.value?.find(
(nccData) => nccData.nccTypeName == name
)?.nccData;
}
async function nccFaultQueryPageQueryFn() {
try {
nccDatas.value = await nccFaultQueryPageQuery();
nccDatas.value.forEach((nccDta) =>
menuOption.value.push({
label: nccDta.nccTypeName,
value: nccDta.nccTypeName,
})
);
selectMenuName.value = nccDatas.value[0].nccTypeName;
showNccData.value = nccDatas.value[0].nccData;
} catch (err) {
$q.notify({
type: 'negative',
message: '无法获取ncc故障查询',
});
}
}
const showTooltip = ref(false);
function onMouseOver(e: MouseEvent) {
const target = e.target as HTMLElement;
if (target.scrollWidth > target.clientWidth) {
showTooltip.value = true;
}
}
const userStore = useUserStore();
const roleType = ref('');
onMounted(() => {
queryLineInfo();
const config = getMonitorPath(userStore.roles);
if (config.lineType == 'NCC') {
roleType.value = 'NCC';
tabList.value = [
{
label: 'ncc应急处置流程',
value: 'NCC',
},
];
tab.value = 'NCC';
nccFaultQueryPageQueryFn();
} else {
roleType.value = 'OCC';
tabList.value = [
{
label: '故障指导',
value: 'GUIDE',
},
{
label: '退出服务',
value: 'SERVICE',
},
];
filter.lineId = config.lineIds[0];
queryAllFaultType();
setTimeout(() => {
searchTable();
}, 1000);
}
});
</script>
@ -396,6 +449,7 @@ onMounted(() => {
background-color: #31ccec;
}
.custom-column {
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -412,15 +466,15 @@ onMounted(() => {
justify-content: center;
margin-top: 10px;
}
.dialogContainer {
.occContainer {
display: flex;
height: calc(100vh - 120px);
.left {
width: calc(50vw + 60px);
width: 67%;
}
.right {
flex: 1;
height: calc(100vh - 120px);
height: 100%;
.detaiRow {
margin: 10px 0 0 20px;
.text {
@ -453,4 +507,27 @@ onMounted(() => {
}
}
}
.nccContainer {
.q-btn-toggle {
margin-bottom: 15px;
}
.box-card {
width: 98%;
min-height: 150px;
margin-bottom: 15px;
padding: 0 5px;
.head {
padding: 5px 5px;
font-size: 20px;
font-weight: 600;
}
.detail {
margin-bottom: 10px;
padding: 5px 5px;
line-height: 28px;
white-space: pre-wrap;
font-size: 20px;
}
}
}
</style>

View File

@ -3,14 +3,42 @@
<q-page-container style="padding: 0; overflow: hidden">
<div id="line-app-container"></div>
</q-page-container>
<div
v-if="faultInfo"
style="position: fixed; right: 0; top: 10%; background: white"
>
<div style="width: 100%; text-align: right" class="bg-primary q-pa-ms">
<q-icon
name="close"
size="xs"
style="cursor: pointer"
@click="() => (faultInfo = false)"
/>
</div>
<div class="q-pa-ms column" style="background: white; max-width: 400px">
<template v-for="(item, index) in timeInfoLabel" :key="index">
<q-chip
removable
@remove="handleRemoveInfo(index)"
color="primary"
text-color="white"
square
:label="item"
>
<q-tooltip v-if="item.length > 34"> {{ item }} </q-tooltip>
</q-chip>
</template>
</div>
</div>
</q-page>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, ref, reactive } from 'vue';
import { useLineStore } from 'src/stores/line-store';
import { useRoute } from 'vue-router';
import { useLineNetStore } from 'src/stores/line-net-store';
import { AlarmInfo, useLineNetStore } from 'src/stores/line-net-store';
import { showAlertTypeData } from 'src/components/alarm/alarmInfoEnum';
const props = withDefaults(
defineProps<{
@ -22,6 +50,10 @@ const props = withDefaults(
const route = useRoute();
const lineStore = useLineStore();
const lineNetStore = useLineNetStore();
const faultInfo = ref(false);
const alarmInfoList: AlarmInfo[] = reactive([]);
let timeInterval = null;
let timeInfoLabel: string[] = reactive([]);
watch(
() => props.sizeHeight,
@ -36,11 +68,58 @@ watch(
}
);
watch(
() => faultInfo.value,
() => {
if (!faultInfo.value) {
alarmInfoList.splice(0, 1);
timeInfoLabel.splice(0);
timeInterval = null;
} else {
timeInterval = setInterval(() => {
const now = Date.now();
// const labels: string[] = [];
timeInfoLabel.splice(0);
alarmInfoList.forEach((info) => {
const date = info.alert_time.substring(0, 19).replace('T', ' ');
let infoTime = new Date(date).getTime();
console.log(date, new Date(date), infoTime, now, 'now');
const distance = formatTime((now - infoTime) / 1000);
const label = handleShowLabel(info);
timeInfoLabel.push(label + '--' + distance);
});
}, 1000);
}
}
);
watch(
() => lineNetStore.alarmInfo,
(val) => {
if (val.length) {
centerFaultDevice();
const lineState = lineNetStore.connectInfo?.msgs.find(
(msg) => msg.lineId == lineId
);
// console.log(lineState, 'line');
if (lineState?.atsWarnShowCounter) {
val.forEach((info) => {
alarmInfoList.push(info);
});
faultInfo.value = true;
}
}
}
);
watch(
() => lineNetStore.connectInfo,
(val) => {
if (val?.msgs) {
const lineState = val.msgs.find((msg) => msg.lineId == lineId);
if (!lineState?.atsWarnShowCounter) {
faultInfo.value = false;
}
}
}
);
@ -80,7 +159,41 @@ function centerFaultDevice() {
}
}
function handleShowLabel(alarmInfo: AlarmInfo) {
const type = (showAlertTypeData as never)[alarmInfo.alert_type + ''];
const device = alarmInfo.alert_object.replace(/\[|]/g, '');
return device + '[' + type + ']';
}
function handleRemoveInfo(index: number) {
alarmInfoList.splice(index, 1);
timeInfoLabel.splice(index, 1);
if (!alarmInfoList.length) {
faultInfo.value = false;
}
console.log(alarmInfoList, faultInfo.value);
}
function formatTime(seconds: number) {
//
seconds = Math.floor(seconds);
//
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = (seconds % 3600) % 60;
console.log(hours, minutes, secs, seconds, 'sec');
//
const hours1 = String(hours).padStart(2, '0');
const minutes1 = String(minutes).padStart(2, '0');
const secs1 = String(secs).padStart(2, '0');
//
return `${hours1}:${minutes1}:${secs1}`;
}
onUnmounted(() => {
lineStore.cancelSubscribe();
timeInterval = null;
});
</script>

View File

@ -24,8 +24,7 @@
label="账号"
lazy-rules
type="tel"
mask="###########"
:rules="[(val) => val.length == 11 || '请输入正确手机格式!']"
:rules="[(val) => val.length || '请输入账号!']"
/>
<q-input
@ -36,9 +35,9 @@
lazy-rules
/>
<div class="text-right">
<!-- <div class="text-right">
<q-btn flat label="注册" to="/register" color="primary" />
</div>
</div> -->
<div class="text-center">
<q-btn label="登录" type="submit" color="primary" />

View File

@ -42,7 +42,8 @@ export namespace alert {
TRAIN_LOST_LOCATION = 27,
TRAIN_INTEGRITY_ALARM = 28,
TRAIN_FAULT_HELP = 29,
INTERLOCKED_ATS_STUCK = 30
INTERLOCKED_ATS_STUCK = 30,
TRAIN_RECORD = 31
}
export enum TipTimeConfig {
HOLIDAYS_MORN_PEAK = 0,

View File

@ -3191,6 +3191,9 @@ export namespace state {
timestamp?: number;
lineId?: number;
receiveTime?: number;
bizWaitTimerGoing?: boolean;
bizWaitStartTimeSec?: number;
bizWaitTimeSec?: number;
}) {
super();
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
@ -3258,6 +3261,15 @@ export namespace state {
if ("receiveTime" in data && data.receiveTime != undefined) {
this.receiveTime = data.receiveTime;
}
if ("bizWaitTimerGoing" in data && data.bizWaitTimerGoing != undefined) {
this.bizWaitTimerGoing = data.bizWaitTimerGoing;
}
if ("bizWaitStartTimeSec" in data && data.bizWaitStartTimeSec != undefined) {
this.bizWaitStartTimeSec = data.bizWaitStartTimeSec;
}
if ("bizWaitTimeSec" in data && data.bizWaitTimeSec != undefined) {
this.bizWaitTimeSec = data.bizWaitTimeSec;
}
}
}
get emergstop() {
@ -3386,6 +3398,24 @@ export namespace state {
set receiveTime(value: number) {
pb_1.Message.setField(this, 21, value);
}
get bizWaitTimerGoing() {
return pb_1.Message.getFieldWithDefault(this, 22, false) as boolean;
}
set bizWaitTimerGoing(value: boolean) {
pb_1.Message.setField(this, 22, value);
}
get bizWaitStartTimeSec() {
return pb_1.Message.getFieldWithDefault(this, 23, 0) as number;
}
set bizWaitStartTimeSec(value: number) {
pb_1.Message.setField(this, 23, value);
}
get bizWaitTimeSec() {
return pb_1.Message.getFieldWithDefault(this, 24, 0) as number;
}
set bizWaitTimeSec(value: number) {
pb_1.Message.setField(this, 24, value);
}
static fromObject(data: {
emergstop?: boolean;
trainberth?: boolean;
@ -3408,6 +3438,9 @@ export namespace state {
timestamp?: number;
lineId?: number;
receiveTime?: number;
bizWaitTimerGoing?: boolean;
bizWaitStartTimeSec?: number;
bizWaitTimeSec?: number;
}): Platform {
const message = new Platform({});
if (data.emergstop != null) {
@ -3473,6 +3506,15 @@ export namespace state {
if (data.receiveTime != null) {
message.receiveTime = data.receiveTime;
}
if (data.bizWaitTimerGoing != null) {
message.bizWaitTimerGoing = data.bizWaitTimerGoing;
}
if (data.bizWaitStartTimeSec != null) {
message.bizWaitStartTimeSec = data.bizWaitStartTimeSec;
}
if (data.bizWaitTimeSec != null) {
message.bizWaitTimeSec = data.bizWaitTimeSec;
}
return message;
}
toObject() {
@ -3498,6 +3540,9 @@ export namespace state {
timestamp?: number;
lineId?: number;
receiveTime?: number;
bizWaitTimerGoing?: boolean;
bizWaitStartTimeSec?: number;
bizWaitTimeSec?: number;
} = {};
if (this.emergstop != null) {
data.emergstop = this.emergstop;
@ -3562,6 +3607,15 @@ export namespace state {
if (this.receiveTime != null) {
data.receiveTime = this.receiveTime;
}
if (this.bizWaitTimerGoing != null) {
data.bizWaitTimerGoing = this.bizWaitTimerGoing;
}
if (this.bizWaitStartTimeSec != null) {
data.bizWaitStartTimeSec = this.bizWaitStartTimeSec;
}
if (this.bizWaitTimeSec != null) {
data.bizWaitTimeSec = this.bizWaitTimeSec;
}
return data;
}
serialize(): Uint8Array;
@ -3610,6 +3664,12 @@ export namespace state {
writer.writeInt32(20, this.lineId);
if (this.receiveTime != 0)
writer.writeInt64(21, this.receiveTime);
if (this.bizWaitTimerGoing != false)
writer.writeBool(22, this.bizWaitTimerGoing);
if (this.bizWaitStartTimeSec != 0)
writer.writeInt64(23, this.bizWaitStartTimeSec);
if (this.bizWaitTimeSec != 0)
writer.writeInt64(24, this.bizWaitTimeSec);
if (!w)
return writer.getResultBuffer();
}
@ -3682,6 +3742,15 @@ export namespace state {
case 21:
message.receiveTime = reader.readInt64();
break;
case 22:
message.bizWaitTimerGoing = reader.readBool();
break;
case 23:
message.bizWaitStartTimeSec = reader.readInt64();
break;
case 24:
message.bizWaitTimeSec = reader.readInt64();
break;
default: reader.skipField();
}
}

View File

@ -78,6 +78,7 @@ export namespace state {
lineId?: number;
occRealConned?: boolean;
occUnrealConned?: boolean;
atsWarnShowCounter?: boolean;
}) {
super();
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
@ -91,6 +92,9 @@ export namespace state {
if ("occUnrealConned" in data && data.occUnrealConned != undefined) {
this.occUnrealConned = data.occUnrealConned;
}
if ("atsWarnShowCounter" in data && data.atsWarnShowCounter != undefined) {
this.atsWarnShowCounter = data.atsWarnShowCounter;
}
}
}
get lineId() {
@ -111,10 +115,17 @@ export namespace state {
set occUnrealConned(value: boolean) {
pb_1.Message.setField(this, 3, value);
}
get atsWarnShowCounter() {
return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean;
}
set atsWarnShowCounter(value: boolean) {
pb_1.Message.setField(this, 4, value);
}
static fromObject(data: {
lineId?: number;
occRealConned?: boolean;
occUnrealConned?: boolean;
atsWarnShowCounter?: boolean;
}): WarnMessage {
const message = new WarnMessage({});
if (data.lineId != null) {
@ -126,6 +137,9 @@ export namespace state {
if (data.occUnrealConned != null) {
message.occUnrealConned = data.occUnrealConned;
}
if (data.atsWarnShowCounter != null) {
message.atsWarnShowCounter = data.atsWarnShowCounter;
}
return message;
}
toObject() {
@ -133,6 +147,7 @@ export namespace state {
lineId?: number;
occRealConned?: boolean;
occUnrealConned?: boolean;
atsWarnShowCounter?: boolean;
} = {};
if (this.lineId != null) {
data.lineId = this.lineId;
@ -143,6 +158,9 @@ export namespace state {
if (this.occUnrealConned != null) {
data.occUnrealConned = this.occUnrealConned;
}
if (this.atsWarnShowCounter != null) {
data.atsWarnShowCounter = this.atsWarnShowCounter;
}
return data;
}
serialize(): Uint8Array;
@ -155,6 +173,8 @@ export namespace state {
writer.writeBool(2, this.occRealConned);
if (this.occUnrealConned != false)
writer.writeBool(3, this.occUnrealConned);
if (this.atsWarnShowCounter != false)
writer.writeBool(4, this.atsWarnShowCounter);
if (!w)
return writer.getResultBuffer();
}
@ -173,6 +193,9 @@ export namespace state {
case 3:
message.occUnrealConned = reader.readBool();
break;
case 4:
message.atsWarnShowCounter = reader.readBool();
break;
default: reader.skipField();
}
}

View File

@ -119,6 +119,21 @@ const routes: RouteRecordRaw[] = [
meta: {
description: '报警记录',
},
component: () => import('pages/AlarmRecord.vue'),
},
],
},
{
path: '/alarmInfo',
name: 'alarmInfo',
component: () => import('layouts/MainLayout.vue'),
children: [
{
path: 'list',
name: 'list',
meta: {
description: '报警信息',
},
component: () => import('pages/AlarmInfoList.vue'),
},
],

View File

@ -13,6 +13,7 @@ export const useLineStore = defineStore('line', {
selectedGraphics: null as JlGraphic[] | null,
lineId: null as number | null,
lineName: null as string | null,
faultStatistics: false,
}),
getters: {
selectedGraphicType: (state) => {

@ -1 +1 @@
Subproject commit 0f95f00449d14672b382f03727b34e339131786b
Subproject commit 7aef4b876fae6622d93a21c99fe293df7bf7d572