Compare commits

...

4 Commits

Author SHA1 Message Date
joylink_fanyuhong
a828c47e49 Merge remote-tracking branch 'origin/develop' into local-test
Some checks failed
local-test分支构建发布 / Docker-Build (push) Failing after 7m1s
2024-09-23 13:55:28 +08:00
joylink_fanyuhong
7b06dee5be 构建关联关系调整 2024-09-23 13:55:11 +08:00
joylink_fanyuhong
aaf8b932a5 区段放开目的地吗位置偏移 2024-09-23 09:12:28 +08:00
joylink_fanyuhong
49b94329f7 三个记录页面雏形(待接口完善) 2024-09-09 10:01:20 +08:00
8 changed files with 544 additions and 59 deletions

29
src/api/LogApi.ts Normal file
View File

@ -0,0 +1,29 @@
import { api } from 'src/boot/axios';
import { PageDto, PageQueryDto } from './ApiCommon';
const LogUriBase = '/api/log';
export interface Record {
id: number;
eventType: string;
fromUserId: number;
mobile: string;
userName: string;
createDateTime: string;
}
export class PagingQueryParams extends PageQueryDto {}
/**
*
* @param params
* @returns
*/
export async function pageQuery(
params: PagingQueryParams
): Promise<PageDto<Record>> {
const response = await api.get(`${LogUriBase}/paging`, {
params: params,
});
return response.data;
}

View File

@ -109,6 +109,21 @@ const list = reactive([
label: '权限接口管理',
icon: 'menu_open',
},
{
path: '/sysManage/loginRecord',
label: '登录记录',
icon: 'description',
},
{
path: '/sysManage/operateRecord',
label: '操作记录',
icon: 'receipt',
},
{
path: '/sysManage/alarmRecord',
label: '报警记录',
icon: 'alarm_on',
},
],
},
]);

View File

@ -8,7 +8,6 @@ import {
distance2,
splitLineEvenly,
ILineGraphic,
epsilon,
Vector2,
} from 'jl-graphic';
import {
@ -29,6 +28,8 @@ export enum SectionPort {
B = 'B',
}
const sectionEpsilon = 0.1;
export interface ISectionData extends GraphicData {
get code(): string; // 编号
set code(v: string);
@ -148,17 +149,17 @@ export class Section extends JlGraphic implements ILineGraphic {
const destinationCodePosition = this.datas.childTransforms?.find(
(t) => t.name === this.destinationCodeGraphic.name
)?.transform.position;
// if (destinationCodePosition) {
// this.destinationCodeGraphic.position.set(
// destinationCodePosition.x,
// destinationCodePosition.y
// );
// } else {
this.destinationCodeGraphic.position.set(
this.datas.points[0].x,
this.datas.points[0].y - 20
);
// }
if (destinationCodePosition) {
this.destinationCodeGraphic.position.set(
destinationCodePosition.x,
destinationCodePosition.y
);
} else {
this.destinationCodeGraphic.position.set(
this.datas.points[0].x,
this.datas.points[0].y - 20
);
}
}
}
@ -244,7 +245,7 @@ export class Section extends JlGraphic implements ILineGraphic {
distance2(
this.localToCanvasPoint(this.getStartPoint()),
section.localToCanvasPoint(section.getStartPoint())
) <= epsilon
) <= sectionEpsilon
) {
param = [SectionPort.A, SectionPort.A];
}
@ -252,7 +253,7 @@ export class Section extends JlGraphic implements ILineGraphic {
distance2(
this.localToCanvasPoint(this.getEndPoint()),
section.localToCanvasPoint(section.getStartPoint())
) <= epsilon
) <= sectionEpsilon
) {
param = [SectionPort.B, SectionPort.A];
}
@ -260,7 +261,7 @@ export class Section extends JlGraphic implements ILineGraphic {
distance2(
this.localToCanvasPoint(this.getStartPoint()),
section.localToCanvasPoint(section.getEndPoint())
) <= epsilon
) <= sectionEpsilon
) {
param = [SectionPort.A, SectionPort.B];
}
@ -268,7 +269,7 @@ export class Section extends JlGraphic implements ILineGraphic {
distance2(
this.localToCanvasPoint(this.getEndPoint()),
section.localToCanvasPoint(section.getEndPoint())
) <= epsilon
) <= sectionEpsilon
) {
param = [SectionPort.B, SectionPort.B];
}

View File

@ -10,7 +10,6 @@ import {
angleOfIncludedAngle,
distance2,
getParallelOfPolyline,
epsilon,
Vector2,
} from 'jl-graphic';
import { Section, SectionPort, SectionType } from '../section/Section';
@ -22,6 +21,7 @@ import {
import { KilometerSystem } from '../signal/Signal';
import { Station } from '../station/Station';
const turnoutEpsilon = 0.1;
export interface ITurnoutData extends GraphicData {
get code(): string;
set code(code: string);
@ -541,47 +541,45 @@ export class Turnout extends JlGraphic {
buildRelation(): void {
this.relationManage.deleteRelationOfGraphic(this);
/** 道岔和区段 */
this.queryStore.queryByType<Section>(Section.Type)
.forEach((section) => {
if (section.datas.sectionType === SectionType.TurnoutPhysical) {
if (section.datas.children.includes(this.datas.id)) {
this.relationManage.addRelation(this, section)
}
return
this.queryStore.queryByType<Section>(Section.Type).forEach((section) => {
if (section.datas.sectionType === SectionType.TurnoutPhysical) {
if (section.datas.children.includes(this.datas.id)) {
this.relationManage.addRelation(this, section);
}
return;
}
this.getPortPoints().forEach((port, i) => {
if (
distance2(
section.localToCanvasPoint(section.getStartPoint()),
this.localToCanvasPoint(port[port.length - 1])
) <= turnoutEpsilon
) {
this.relationManage.addRelation(
new GraphicRelationParam(
this,
[TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i]
),
new GraphicRelationParam(section, SectionPort.A)
);
}
if (
distance2(
section.localToCanvasPoint(section.getEndPoint()),
this.localToCanvasPoint(port[port.length - 1])
) <= turnoutEpsilon
) {
this.relationManage.addRelation(
new GraphicRelationParam(
this,
[TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i]
),
new GraphicRelationParam(section, SectionPort.B)
);
}
this.getPortPoints().forEach((port, i) => {
if (
distance2(
section.localToCanvasPoint(section.getStartPoint()),
this.localToCanvasPoint(port[port.length - 1])
) <= epsilon
) {
this.relationManage.addRelation(
new GraphicRelationParam(
this,
[TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i]
),
new GraphicRelationParam(section, SectionPort.A)
);
}
if (
distance2(
section.localToCanvasPoint(section.getEndPoint()),
this.localToCanvasPoint(port[port.length - 1])
) <= epsilon
) {
this.relationManage.addRelation(
new GraphicRelationParam(
this,
[TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i]
),
new GraphicRelationParam(section, SectionPort.B)
);
}
});
});
});
/** 道岔和道岔 */
this.getPortPoints().forEach((thisPort, i) => {
@ -594,7 +592,7 @@ export class Turnout extends JlGraphic {
distance2(
this.localToCanvasPoint(thisPort[thisPort.length - 1]),
turnout.localToCanvasPoint(otherPort[otherPort.length - 1])
) <= epsilon
) <= turnoutEpsilon
) {
const angle = angleOfIncludedAngle(
this.localToCanvasPoint(thisPort[thisPort.length - 1]) /* 交点 */,
@ -668,9 +666,13 @@ export class Turnout extends JlGraphic {
const pcRelation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) => relation.getRelationParam(this).param === TurnoutPort.C
&& (!(relation.getOtherGraphic(this) instanceof Section
&& relation.getOtherGraphic<Section>(this).datas.sectionType !== SectionType.TurnoutPhysical))
(relation) =>
relation.getRelationParam(this).param === TurnoutPort.C &&
!(
relation.getOtherGraphic(this) instanceof Section &&
relation.getOtherGraphic<Section>(this).datas.sectionType !==
SectionType.TurnoutPhysical
)
);
const pcDevice = pcRelation?.getOtherGraphic<Section | Turnout>(this);
if (pcDevice) {

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

@ -0,0 +1,138 @@
<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"
:filter="filter"
binary-state-sort
@request="onRequest"
>
<!-- <template v-slot:top-right>
<q-input
dense
debounce="1000"
v-model="filter.name"
label="用户名"
></q-input>
<q-btn flat round color="primary" icon="search" />
</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 { useQuasar, type QTableColumn } from 'quasar';
import { pageQuery, Record } from '../api/LogApi';
import { errorNotify } from '../utils/CommonNotify';
const $q = useQuasar();
const props = withDefaults(
defineProps<{
sizeHeight: number;
}>(),
{ sizeHeight: 500 }
);
const tableHeight = computed(() => {
return props.sizeHeight - 32;
});
onMounted(() => {
tableRef.value.requestServerInteraction();
});
const columnDefs: QTableColumn[] = [
{ name: 'id', label: 'ID', field: 'id', align: 'center' },
{
name: 'userName',
label: '操作人员',
field: 'userName',
align: 'center',
},
{
name: 'mobile',
label: '手机号',
field: 'mobile',
align: 'center',
},
{
name: 'createDateTime',
label: '记录时间',
field: 'createDateTime',
align: 'center',
},
];
const tableRef = ref();
const rows = reactive([]);
const filter = reactive({
name: '',
});
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
// 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,
});
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;
}
}
</script>

138
src/pages/LoginRecord.vue Normal file
View File

@ -0,0 +1,138 @@
<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"
:filter="filter"
binary-state-sort
@request="onRequest"
>
<!-- <template v-slot:top-right>
<q-input
dense
debounce="1000"
v-model="filter.name"
label="用户名"
></q-input>
<q-btn flat round color="primary" icon="search" />
</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 { useQuasar, type QTableColumn } from 'quasar';
import { pageQuery, Record } from '../api/LogApi';
import { errorNotify } from '../utils/CommonNotify';
const $q = useQuasar();
const props = withDefaults(
defineProps<{
sizeHeight: number;
}>(),
{ sizeHeight: 500 }
);
const tableHeight = computed(() => {
return props.sizeHeight - 32;
});
onMounted(() => {
tableRef.value.requestServerInteraction();
});
const columnDefs: QTableColumn[] = [
{ name: 'id', label: 'ID', field: 'id', align: 'center' },
{
name: 'userName',
label: '操作人员',
field: 'userName',
align: 'center',
},
{
name: 'mobile',
label: '手机号',
field: 'mobile',
align: 'center',
},
{
name: 'createDateTime',
label: '记录时间',
field: 'createDateTime',
align: 'center',
},
];
const tableRef = ref();
const rows = reactive([]);
const filter = reactive({
name: '',
});
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
// 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,
});
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;
}
}
</script>

138
src/pages/OperateRecord.vue Normal file
View File

@ -0,0 +1,138 @@
<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"
:filter="filter"
binary-state-sort
@request="onRequest"
>
<!-- <template v-slot:top-right>
<q-input
dense
debounce="1000"
v-model="filter.name"
label="用户名"
></q-input>
<q-btn flat round color="primary" icon="search" />
</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 { useQuasar, type QTableColumn } from 'quasar';
import { pageQuery, Record } from '../api/LogApi';
import { errorNotify } from '../utils/CommonNotify';
const $q = useQuasar();
const props = withDefaults(
defineProps<{
sizeHeight: number;
}>(),
{ sizeHeight: 500 }
);
const tableHeight = computed(() => {
return props.sizeHeight - 32;
});
onMounted(() => {
tableRef.value.requestServerInteraction();
});
const columnDefs: QTableColumn[] = [
{ name: 'id', label: 'ID', field: 'id', align: 'center' },
{
name: 'userName',
label: '操作人员',
field: 'userName',
align: 'center',
},
{
name: 'mobile',
label: '手机号',
field: 'mobile',
align: 'center',
},
{
name: 'createDateTime',
label: '记录时间',
field: 'createDateTime',
align: 'center',
},
];
const tableRef = ref();
const rows = reactive([]);
const filter = reactive({
name: '',
});
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
// 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,
});
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;
}
}
</script>

View File

@ -86,6 +86,30 @@ const routes: RouteRecordRaw[] = [
},
component: () => import('pages/AuthPathManage.vue'),
},
{
path: 'loginRecord',
name: 'loginRecord',
meta: {
description: '登录记录',
},
component: () => import('pages/LoginRecord.vue'),
},
{
path: 'operateRecord',
name: 'operateRecord',
meta: {
description: '操作记录',
},
component: () => import('pages/OperateRecord.vue'),
},
{
path: 'alarmRecord',
name: 'alarmRecord',
meta: {
description: '报警记录',
},
component: () => import('pages/AlarmRecord.vue'),
},
],
},
{