超期预警,到期预警画面,详情,及菜单显示数量修改

main
zhufu 2025-05-22 16:53:10 +08:00
parent 96d1b934e2
commit dd550b7c52
10 changed files with 1664 additions and 5 deletions

View File

@ -0,0 +1,30 @@
import { defHttp } from '@/utils/http/axios';
enum Api {
TimeoutWarning = '/api/DroneSsny/TimeoutWarning',
TimeOutAlarmList = '/api/DroneSsny/TimeOutAlarmList',
TimeoutWarningExport = '/api/DroneSsny/TimeoutWarningExport',
TimeoutAlarmExport = '/api/DroneSsny/TimeoutAlarmExport'
}
export function TimeoutWarning(params) {
return defHttp.get({ url: Api.TimeoutWarning, params });
}
export function TimeOutAlarmList(params) {
return defHttp.get({ url: Api.TimeOutAlarmList, params });
}
export function TimeoutWarningExport(params) {
let paramsString = new URLSearchParams(params).toString();
return defHttp.post({
url: `${Api.TimeoutWarningExport}?${paramsString}`,
params,
responseType: 'blob',
});
}
export function TimeoutAlarmExport(params) {
let paramsString = new URLSearchParams(params).toString();
return defHttp.post({
url: `${Api.TimeoutAlarmExport}?${paramsString}`,
params,
responseType: 'blob',
});
}

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@
import type { MenuState } from './types';
import type { Menu as MenuType } from '@/router/types';
import type { RouteLocationNormalizedLoaded } from 'vue-router';
import { computed, ref, unref, reactive, toRefs, watch, PropType, useAttrs } from 'vue';
import { computed, ref, unref, reactive, toRefs, watch, PropType, useAttrs, onMounted } from 'vue';
import { useDesign } from '@/hooks/web/useDesign';
import Menu from './components/Menu.vue';
import SimpleSubMenu from './SimpleSubMenu.vue';
@ -32,6 +32,9 @@
import { isFunction, isHttpUrl } from '@/utils/is';
import { openWindow } from '@/utils';
import { useOpenKeys } from './useOpenKeys';
import { useEarlyWarningStore } from '@/store/modules/earlywarning'
const earlyWarningStore = useEarlyWarningStore();
defineOptions({ name: 'SimpleMenu', inheritAttrs: false });
@ -78,6 +81,10 @@
const getBindValues = computed(() => ({ ...attrs, ...props }));
onMounted(() =>{
earlyWarningStore.getWarning()
})
watch(
() => props.collapse,
(collapse) => {

View File

@ -3,7 +3,7 @@
:name="item.path"
v-if="!menuHasChildren(item) && getShowMenu"
v-bind="$props"
:class="getLevelClass"
:class="[getLevelClass, 'sub_menu']"
>
<img v-if="getImg" :src="getImg" class="w-16px h-16px align-top" />
<Icon v-if="getIcon" :icon="getIcon" :size="16" />
@ -11,8 +11,8 @@
{{ getI18nName }}
</div>
<template #title>
<span :class="['ml-2', `${prefixCls}-sub-title`]">
{{ getI18nName }}
<span :class="['ml-2', `${prefixCls}-sub-title`, 'sub-menu-item']">
<div class="menu-label">{{ getI18nName }}</div><div v-if="showWarning(item)" class="menu-number">{{showWarningNumber(item)}}</div>
</span>
<SimpleMenuTag :item="item" :collapseParent="getIsCollapseParent" />
</template>
@ -48,7 +48,7 @@
import type { PropType } from 'vue';
import type { Menu } from '@/router/types';
import { computed } from 'vue';
import { computed, onMounted } from 'vue';
import { useDesign } from '@/hooks/web/useDesign';
import Icon from '@/components/Icon/Icon.vue';
@ -57,8 +57,10 @@
import { propTypes } from '@/utils/propTypes';
import { useI18n } from '@/hooks/web/useI18n';
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
import { useEarlyWarningStore } from '@/store/modules/earlywarning'
const SimpleMenuTag = createAsyncComponent(() => import('./SimpleMenuTag.vue'));
const earlyWarningStore = useEarlyWarningStore();
defineOptions({ name: 'SimpleSubMenu' });
@ -99,4 +101,44 @@
menuTreeItem.children.length > 0
);
}
const showWarning = (item) => {
if(['/overduewarning','/expirationwarning'].includes(item.path)){
return true
}
return false
}
const showWarningNumber = (item) => {
switch(item.path){
case '/overduewarning':
return earlyWarningStore.overdueWarning
case '/expirationwarning':
return earlyWarningStore.ExpirationWarning
}
}
</script>
<style lang="less" scoped>
.sub_menu{
padding: 0px 24px !important;
height: 45px;
}
.sub-menu-item{
display: flex;
width: 100%;
justify-content: space-between;
}
.menu-label{
display: flex;
align-items: center;
}
.menu-number{
width: 20px;
height: 20px;
border-radius: 50%;
background-color: red;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: white;
}
</style>

View File

@ -0,0 +1,19 @@
import { defineStore } from 'pinia';
import { TimeoutWarning, TimeOutAlarmList } from '@/api/earlywarning/index'
export const useEarlyWarningStore = defineStore({
id: 'earlyWarning',
state: () => ({
overdueWarning: 0,
ExpirationWarning: 0,
}),
actions:{
async getWarning(){
TimeoutWarning({}).then(res => {
this.ExpirationWarning = res.total
})
TimeOutAlarmList({}).then(res => {
this.overdueWarning = res.total
})
}
}
})

View File

@ -0,0 +1,103 @@
<template>
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
<BasicTable class="w-4/4 xl:w-5/5" @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="download"></a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
label: '详情',
onClick: () => {
handleInfo(record);
},
}
]"
/>
</template>
</template>
</BasicTable>
<a-modal
style="width: 100vw; top: 0px; left: 0px; margin: 0px; padding: 0px"
wrap-class-name="full-modal"
v-model:open="showInfoOpen"
title="详情"
:footer="null"
:maskClosable="true"
:destroyOnClose="true"
@cancel="showInfoOpen = false"
>
<ShowInfoModal :showInfoData="showInfoData"/>
</a-modal>
</PageWrapper>
</template>
<script setup lang="ts">
import { ref } from "vue"
import { PageWrapper } from '@/components/Page';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { columns, searchFormSchema } from './utils';
import { TimeoutWarning, TimeoutWarningExport } from '@/api/earlywarning/index'
import ShowInfoModal from '@/components/EarlyWarning/InfoModal/index.vue'
const showInfoOpen = ref(false)
const showInfoData = ref();
const [registerTable, { getForm }] = useTable({
title: '到期预警',
api: TimeoutWarning,
columns,
rowKey: 'id',
useSearchForm: true,
showTableSetting: true,
bordered: true,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
fixed: 'right',
},
});
function handleInfo(record) {
showInfoData.value = record
showInfoOpen.value = true
}
const download = () => {
const form = getForm();
const filterValues = form.getFieldsValue();
TimeoutWarningExport(filterValues).then(res => {
const elink = document.createElement('a');
elink.download = '到期预警数据' + new Date().getTime() + '.xls';
elink.style.display = 'none';
elink.href = URL.createObjectURL(res);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
})
}
</script>
<style lang="scss" scoped>
.full-modal {
.ant-modal {
min-width: 100vw;
top: 0px;
padding: 0px;
margin: 0px;
}
.ant-modal-content {
display: flex;
flex-direction: column;
}
.ant-modal-body {
flex: 1;
}
}
</style>

View File

@ -0,0 +1,76 @@
import { BasicColumn, FormSchema } from '@/components/Table';
import { getChildrenTree } from '@/api/demo/system';
export const columns: BasicColumn[] = [
{
title: '项目编号',
dataIndex: 'xiangmu_no',
},
{
title: '项目名称',
dataIndex: 'xiangmu_name',
width: 200,
},
{
title: '行政区划',
dataIndex: 'xingzhengquhua',
},
{
title: '备案编号',
dataIndex: 'beian_no',
},
{
title: '项目开始时间',
dataIndex: 'start_time',
width: 200,
},
{
title: '项目结束时间',
dataIndex: 'end_time',
},
{
title: '项目当前用途',
dataIndex: 'xiangmu_yt',
width: 110,
},
{
title: '设施农业申请用地面积(公顷)',
dataIndex: 'shenqing_area',
width: 200,
},
{
title: '生产设施用地(公顷)',
dataIndex: 'shengchan_area',
width: 200,
},
{
title: '辅助设施用地(公顷)',
dataIndex: 'fuzhu_area',
width: 200,
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'xiangmumc',
component: 'Input',
colProps: { span: 5 },
label: '项目名称',
},
{
field: 'streetid',
label: '乡镇',
component: 'ApiSelect',
colProps: { span: 4 },
componentProps: ({ formModel }) => {
return {
api: getChildrenTree,
params: { parentId: 371324 },
// 接口参数
resultField: 'result',
labelField: 'name',
valueField: 'id',
};
},
},
];

View File

@ -0,0 +1,103 @@
<template>
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
<BasicTable class="w-4/4 xl:w-5/5" @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="download"></a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
label: '详情',
onClick: () => {
handleInfo(record);
},
}
]"
/>
</template>
</template>
</BasicTable>
<a-modal
style="width: 100vw; top: 0px; left: 0px; margin: 0px; padding: 0px"
wrap-class-name="full-modal"
v-model:open="showInfoOpen"
title="详情"
:footer="null"
:maskClosable="true"
:destroyOnClose="true"
@cancel="showInfoOpen = false"
>
<ShowInfoModal :showInfoData="showInfoData"/>
</a-modal>
</PageWrapper>
</template>
<script setup lang="ts">
import { ref } from "vue"
import { PageWrapper } from '@/components/Page';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { columns, searchFormSchema } from './utils';
import { TimeOutAlarmList, TimeoutAlarmExport } from '@/api/earlywarning/index'
import ShowInfoModal from '@/components/EarlyWarning/InfoModal/index.vue'
const showInfoOpen = ref(false)
const showInfoData = ref();
const [registerTable, { getForm }] = useTable({
title: '超期预警',
api: TimeOutAlarmList,
columns,
rowKey: 'id',
useSearchForm: true,
showTableSetting: true,
bordered: true,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
fixed: 'right',
},
});
function handleInfo(record) {
showInfoData.value = record
showInfoOpen.value = true
}
const download = () => {
const form = getForm();
const filterValues = form.getFieldsValue();
TimeoutAlarmExport(filterValues).then(res => {
const elink = document.createElement('a');
elink.download = '超期预警数据' + new Date().getTime() + '.xls';
elink.style.display = 'none';
elink.href = URL.createObjectURL(res);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
})
}
</script>
<style lang="scss" scoped>
.full-modal {
.ant-modal {
min-width: 100vw;
top: 0px;
padding: 0px;
margin: 0px;
}
.ant-modal-content {
display: flex;
flex-direction: column;
}
.ant-modal-body {
flex: 1;
}
}
</style>

View File

@ -0,0 +1,76 @@
import { BasicColumn, FormSchema } from '@/components/Table';
import { getChildrenTree } from '@/api/demo/system';
export const columns: BasicColumn[] = [
{
title: '项目编号',
dataIndex: 'xiangmu_no',
},
{
title: '项目名称',
dataIndex: 'xiangmu_name',
width: 200,
},
{
title: '行政区划',
dataIndex: 'xingzhengquhua',
},
{
title: '备案编号',
dataIndex: 'beian_no',
},
{
title: '项目开始时间',
dataIndex: 'start_time',
width: 200,
},
{
title: '项目结束时间',
dataIndex: 'end_time',
},
{
title: '项目当前用途',
dataIndex: 'xiangmu_yt',
width: 110,
},
{
title: '设施农业申请用地面积(公顷)',
dataIndex: 'shenqing_area',
width: 200,
},
{
title: '生产设施用地(公顷)',
dataIndex: 'shengchan_area',
width: 200,
},
{
title: '辅助设施用地(公顷)',
dataIndex: 'fuzhu_area',
width: 200,
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'xiangmumc',
component: 'Input',
colProps: { span: 5 },
label: '项目名称',
},
{
field: 'streetid',
label: '乡镇',
component: 'ApiSelect',
colProps: { span: 4 },
componentProps: ({ formModel }) => {
return {
api: getChildrenTree,
params: { parentId: 371324 },
// 接口参数
resultField: 'result',
labelField: 'name',
valueField: 'id',
};
},
},
];