数据填报-审批记录页面
This commit is contained in:
parent
bb2173047f
commit
8b3ea08fc9
27
frontend/src/api/shengPiJiLu/index.ts
Normal file
27
frontend/src/api/shengPiJiLu/index.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
export function queryPageList(queryParams:any){
|
||||
return request({
|
||||
url: '/data/approvalMain/queryPageList' ,
|
||||
method: 'post',
|
||||
data:queryParams
|
||||
});
|
||||
}
|
||||
|
||||
// 查询审批操作日志列表
|
||||
export function getApprovalLogList(params: any) {
|
||||
return request({
|
||||
url: '/data/approvalLog/queryPageList',
|
||||
method: 'post',
|
||||
data: params
|
||||
});
|
||||
}
|
||||
|
||||
// 查询审批变更记录列表
|
||||
export function getApprovalChangeLogList(params: any) {
|
||||
return request({
|
||||
url: '/data/approvalChangeLog/queryPageList',
|
||||
method: 'post',
|
||||
data: params
|
||||
});
|
||||
}
|
||||
343
frontend/src/modules/EnvironmentalQuality/index.vue
Normal file
343
frontend/src/modules/EnvironmentalQuality/index.vue
Normal file
@ -0,0 +1,343 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem title="地表水水质达标率">
|
||||
<div class="body_item">
|
||||
<div class="tabs_all">
|
||||
<div :class="tabs == 1 ? 'zhong_tabs' : 'no_tabs'" @click="handleTabChange(1)">自建水质站</div>
|
||||
<div :class="tabs == 2 ? 'zhong_tabs' : 'no_tabs'" @click="handleTabChange(2)">国家水质站</div>
|
||||
</div>
|
||||
<div v-show="tabs == 1 || tabs == 2" class="tabs_body">
|
||||
<div ref="chartRef" class="chart-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</SidePanelItem>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||
|
||||
// 定义组件名(便于调试和递归)
|
||||
defineOptions({
|
||||
name: 'EnvironmentalQuality'
|
||||
});
|
||||
|
||||
const tabs = ref(1);
|
||||
const chartRef = ref<HTMLElement | null>(null);
|
||||
let chartInstance: echarts.ECharts | null = null;
|
||||
|
||||
// 静态数据 - 自建水质站(第1页)
|
||||
const selfBuiltData = [
|
||||
{ name: '雅砻江\n干流', current: 99, lastYear: 100 },
|
||||
{ name: '大渡河\n干流', current: 99, lastYear: 100 },
|
||||
{ name: '黄河上游\n干流', current: 99, lastYear: 100 }
|
||||
];
|
||||
|
||||
// 静态数据 - 国家水质站(第2页)
|
||||
const nationalData = [
|
||||
{ name: '长江\n干流', current: 98, lastYear: 99 },
|
||||
{ name: '珠江\n干流', current: 97, lastYear: 98 },
|
||||
{ name: '淮河\n干流', current: 96, lastYear: 97 }
|
||||
];
|
||||
|
||||
// 根据tab获取对应数据
|
||||
const getCurrentData = () => {
|
||||
return tabs.value === 1 ? selfBuiltData : nationalData;
|
||||
};
|
||||
|
||||
// 处理tab切换
|
||||
const handleTabChange = (tab: number) => {
|
||||
tabs.value = tab;
|
||||
};
|
||||
|
||||
// 监听tabs变化,处理图表刷新
|
||||
watch(tabs, (newVal) => {
|
||||
if (newVal === 1 || newVal === 2) {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
if (!chartInstance) {
|
||||
initChart();
|
||||
} else {
|
||||
// 更新图表数据
|
||||
updateChartData();
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (!chartRef.value) return;
|
||||
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
|
||||
const currentData = getCurrentData();
|
||||
|
||||
const option = {
|
||||
// 图例配置
|
||||
legend: {
|
||||
top: 10,
|
||||
itemWidth: 18,
|
||||
itemHeight: 12,
|
||||
itemGap: 20,
|
||||
icon: 'roundRect',
|
||||
data: [
|
||||
{ name: '2026-04 月度', itemStyle: { color: '#4A8BC2' } },
|
||||
{ name: '去年同期', itemStyle: { color: '#9B59B6' } }
|
||||
],
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
color: '#333'
|
||||
}
|
||||
},
|
||||
|
||||
// 提示框配置
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
shadowStyle: {
|
||||
color: 'rgba(200, 200, 200, 0.2)'
|
||||
},
|
||||
label: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
backgroundColor: '#fff',
|
||||
borderColor: '#e8e8e8',
|
||||
borderWidth: 1,
|
||||
padding: 12,
|
||||
textStyle: {
|
||||
color: '#333',
|
||||
fontSize: 12
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
const name = params[0].name.replace('\n', '');
|
||||
let result = `<div style="font-weight: bold; margin-bottom: 8px;">${name}</div>`;
|
||||
params.forEach((item: any) => {
|
||||
result += `<div style="display: flex; align-items: center; margin-bottom: 4px;">
|
||||
<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: ${item.color}; margin-right: 8px;"></span>
|
||||
<span>${item.seriesName}:</span>
|
||||
<span style="margin-left: auto; font-weight: bold;">${item.value} %</span>
|
||||
</div>`;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
// 网格配置
|
||||
grid: {
|
||||
left: 60,
|
||||
right: 10,
|
||||
top: 60,
|
||||
bottom: 50
|
||||
},
|
||||
|
||||
// X轴配置
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 100,
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#e8e8e8',
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
|
||||
// Y轴配置
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: currentData.map(item => item.name),
|
||||
inverse: true,
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#333',
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: true,
|
||||
length: 4,
|
||||
lineStyle: {
|
||||
color: '#333',
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
color: '#333',
|
||||
margin: 12
|
||||
},
|
||||
// 在Y轴底部添加"达标率(%)"标签
|
||||
name: '达标率(%)',
|
||||
nameLocation: 'end',
|
||||
nameGap: 20,
|
||||
nameTextStyle: {
|
||||
fontSize: 12,
|
||||
color: '#666',
|
||||
align: 'left'
|
||||
}
|
||||
},
|
||||
|
||||
// 系列配置
|
||||
series: [
|
||||
{
|
||||
name: '2026-04 月度',
|
||||
type: 'bar',
|
||||
data: currentData.map(item => item.current),
|
||||
barWidth: 10,
|
||||
barGap: '20%',
|
||||
itemStyle: {
|
||||
color: '#4A8BC2',
|
||||
borderRadius: [0, 3, 3, 0]
|
||||
},
|
||||
markArea: {
|
||||
silent: true,
|
||||
itemStyle: {
|
||||
color: 'rgba(240, 245, 250, 0.5)'
|
||||
},
|
||||
data: [
|
||||
[{ yAxis: 1 }, { yAxis: 2 }]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '去年同期',
|
||||
type: 'bar',
|
||||
data: currentData.map(item => item.lastYear),
|
||||
barWidth: 10,
|
||||
barGap: '20%',
|
||||
itemStyle: {
|
||||
color: '#9B59B6',
|
||||
borderRadius: [0, 3, 3, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 更新图表数据
|
||||
const updateChartData = () => {
|
||||
if (!chartInstance) return;
|
||||
|
||||
const currentData = getCurrentData();
|
||||
|
||||
chartInstance.setOption({
|
||||
yAxis: {
|
||||
data: currentData.map(item => item.name)
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: currentData.map(item => item.current)
|
||||
},
|
||||
{
|
||||
data: currentData.map(item => item.lastYear)
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 强制重新计算尺寸
|
||||
chartInstance.resize();
|
||||
};
|
||||
|
||||
// 页面加载时执行
|
||||
onMounted(() => {
|
||||
// 延迟初始化,确保容器已渲染
|
||||
setTimeout(() => {
|
||||
initChart();
|
||||
}, 100);
|
||||
|
||||
// 监听窗口resize
|
||||
window.addEventListener('resize', () => {
|
||||
chartInstance?.resize();
|
||||
});
|
||||
});
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
chartInstance?.dispose();
|
||||
window.removeEventListener('resize', () => {
|
||||
chartInstance?.resize();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.body_item {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.tabs_all {
|
||||
width: 28px;
|
||||
height: 600px;
|
||||
box-sizing: border-box;
|
||||
border: 2px solid #2f6b98;
|
||||
border-radius: 5px;
|
||||
|
||||
.zhong_tabs {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
background: #2f6b98;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
text-shadow: 0 0 .25px currentcolor;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.no_tabs {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
.no_tabs:hover {
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs_body {
|
||||
width: 368px;
|
||||
height: 600px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
124
frontend/src/modules/qixidibaohugongzuokaizhanQK/index.vue
Normal file
124
frontend/src/modules/qixidibaohugongzuokaizhanQK/index.vue
Normal file
@ -0,0 +1,124 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem title="栖息地保护工作开展情况">
|
||||
<div class="facility-grid">
|
||||
<div v-for="facility in facilities" :key="facility.name" class="facility-card">
|
||||
<div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;">
|
||||
<div class="facility-icon">
|
||||
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="facility-info">
|
||||
<div class="facility-name">{{ facility.name }}</div>
|
||||
<div style="font-size: 16px;"> <span class="facility-count">{{ facility.count
|
||||
}}</span><span>个</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SidePanelItem>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||
|
||||
// 定义组件名(便于调试和递归)
|
||||
defineOptions({
|
||||
name: 'qixidibaohugongzuokaizhanQK'
|
||||
});
|
||||
|
||||
// 设施数据
|
||||
const facilities = ref([
|
||||
{
|
||||
name: '栖息地',
|
||||
count: 56,
|
||||
icon: 'icon iconfont icon-qixidi'
|
||||
},
|
||||
{
|
||||
name: '水温监测',
|
||||
count: 1722,
|
||||
icon: 'icon iconfont icon-diwenshuijianhuan'
|
||||
},
|
||||
{
|
||||
name: '水文监测',
|
||||
count: 135,
|
||||
icon: 'icon iconfont icon-shuiwen-line'
|
||||
},
|
||||
{
|
||||
name: '视频监控',
|
||||
count: 135,
|
||||
icon: 'icon iconfont icon-shipinjiankongshebei'
|
||||
},
|
||||
|
||||
]);
|
||||
|
||||
// 页面加载时执行
|
||||
onMounted(() => {
|
||||
// 延迟初始化,确保容器已渲染
|
||||
|
||||
});
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.facility-grid {
|
||||
width: 406px;
|
||||
flex-flow: wrap;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
|
||||
}
|
||||
|
||||
.facility-card {
|
||||
width: 200px;
|
||||
height: 70px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 4px 0px;
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 2px;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.facility-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
// margin-right: 8px;
|
||||
background: #5389b5;
|
||||
border-radius: 50%;
|
||||
|
||||
.anticon {
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.facility-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.facility-name {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
// margin-bottom: 4px;
|
||||
// font-weight: 500;
|
||||
}
|
||||
|
||||
.facility-count {
|
||||
font-size: 18px;
|
||||
color: #2f6b98;
|
||||
// font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@ -1,6 +1,6 @@
|
||||
<!-- SidePanelItem.vue -->
|
||||
<template>
|
||||
<SidePanelItem title="环保设施情况">
|
||||
<SidePanelItem title="水质监测工作开展情况">
|
||||
<div class="facility-grid" >
|
||||
<div v-for="facility in facilities" :key="facility.name" class="facility-card">
|
||||
<div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;">
|
||||
|
||||
@ -1,5 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
|
||||
import RightDrawer from "@/components/RightDrawer/index.vue";
|
||||
import QiXiDiBaoHuGongZuoKaiZhan from "@/modules/qixidibaohugongzuokaizhanQK/index.vue"
|
||||
// import QixidijchuXx from "@/modules/qixidijchuXx"
|
||||
// import QiXiDiShuiWenBianHua from "@/modules/qixidishuiwenbianhua"
|
||||
// import QiXiDiLiuLiangBianHua from "@/modules/qixidiliuliangbianhua"
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2>栖息地</h2>
|
||||
<div class="moduleContent">
|
||||
<div class="leftContent">
|
||||
<JidiSelectorMod />
|
||||
</div>
|
||||
<div class="rightContent">
|
||||
<RightDrawer>
|
||||
<QiXiDiBaoHuGongZuoKaiZhan />
|
||||
<!-- <QiXiDiShuiWenBianHua /> -->
|
||||
<!-- <QiXiDiLiuLiangBianHua /> -->
|
||||
<!-- <QixidijchuXx /> -->
|
||||
</RightDrawer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
66
frontend/src/views/shuJuTianBao/approvalLogSearch.vue
Normal file
66
frontend/src/views/shuJuTianBao/approvalLogSearch.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div class="approval-log-search">
|
||||
<BasicSearch ref="basicSearchRef" :searchList="searchList" :initial-values="initSearchData"
|
||||
@finish="onSearchFinish" @values-change="onValuesChange" @reset="handleReset">
|
||||
</BasicSearch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue";
|
||||
|
||||
// --- Props & Emits ---
|
||||
interface Props {
|
||||
actionTypeDict: any[];
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const emit = defineEmits<{
|
||||
(e: "reset", values: any): void;
|
||||
(e: "searchFinish", values: any): void;
|
||||
}>();
|
||||
|
||||
|
||||
// 模拟 initSearchData
|
||||
const initSearchData = {
|
||||
action: '',
|
||||
};
|
||||
|
||||
const searchData = ref<any>({ ...initSearchData });
|
||||
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: "Select",
|
||||
name: "action",
|
||||
label: "操作类型",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
options: props.actionTypeDict || [],
|
||||
},
|
||||
]);
|
||||
|
||||
// --- Methods ---
|
||||
|
||||
// 2. 搜索表单逻辑
|
||||
const onSearchFinish = (values: any) => {
|
||||
console.log(values);
|
||||
emit("searchFinish", values);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emit("reset", initSearchData);
|
||||
};
|
||||
|
||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
// 同步更新本地 searchData,以便其他逻辑使用
|
||||
searchData.value = { ...searchData.value, ...allValues };
|
||||
};
|
||||
|
||||
// --- Lifecycle ---
|
||||
onMounted(() => {
|
||||
emit("searchFinish", initSearchData);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
66
frontend/src/views/shuJuTianBao/changeLogSearch.vue
Normal file
66
frontend/src/views/shuJuTianBao/changeLogSearch.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div class="change-log-search">
|
||||
<BasicSearch ref="basicSearchRef" :searchList="searchList" :initial-values="initSearchData"
|
||||
@finish="onSearchFinish" @values-change="onValuesChange" @reset="handleReset">
|
||||
</BasicSearch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue";
|
||||
|
||||
// --- Props & Emits ---
|
||||
interface Props {
|
||||
operationTypeDict: any[];
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const emit = defineEmits<{
|
||||
(e: "reset", values: any): void;
|
||||
(e: "searchFinish", values: any): void;
|
||||
}>();
|
||||
|
||||
|
||||
// 模拟 initSearchData
|
||||
const initSearchData = {
|
||||
operationType: '',
|
||||
};
|
||||
|
||||
const searchData = ref<any>({ ...initSearchData });
|
||||
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: "Select",
|
||||
name: "operationType",
|
||||
label: "操作类型",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
options: props.operationTypeDict || [],
|
||||
},
|
||||
]);
|
||||
|
||||
// --- Methods ---
|
||||
|
||||
// 2. 搜索表单逻辑
|
||||
const onSearchFinish = (values: any) => {
|
||||
console.log(values);
|
||||
emit("searchFinish", values);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emit("reset", initSearchData);
|
||||
};
|
||||
|
||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
// 同步更新本地 searchData,以便其他逻辑使用
|
||||
searchData.value = { ...searchData.value, ...allValues };
|
||||
};
|
||||
|
||||
// --- Lifecycle ---
|
||||
onMounted(() => {
|
||||
emit("searchFinish", initSearchData);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
439
frontend/src/views/shuJuTianBao/shengPiJiLu.vue
Normal file
439
frontend/src/views/shuJuTianBao/shengPiJiLu.vue
Normal file
@ -0,0 +1,439 @@
|
||||
<template>
|
||||
<div class="shengPiJiLu-page">
|
||||
<!-- 搜索区域组件,具体 props 需根据实际子组件调整 -->
|
||||
<GuoYuSheShiShuJuTianBaoSearch @search-finish="handleSearchFinish" @reset="handleReset" />
|
||||
<!-- 主表格 -->
|
||||
<BasicTable ref="tableRef" :columns="columns" :list-url="queryPageList" :search-params="{}">
|
||||
<!-- 使用 bodyCell 插槽自定义单元格渲染 -->
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'action' || column.dataIndex === 'action'">
|
||||
<div class="flex">
|
||||
<a-button type="link" size="small" @click="handleShowApprovalLog(record)">审批详情</a-button>
|
||||
<a-button type="link" size="small" @click="handleShowChangeLog(record)">变更详情</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'bizType'">
|
||||
{{ handName(record.bizType, yeWuType) }}
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
{{ handName(record.status, shenStatus) }}
|
||||
</template>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<!-- 审批操作日志弹框 -->
|
||||
<a-modal
|
||||
v-model:open="approvalLogVisible"
|
||||
title="审批操作日志"
|
||||
width="1600px"
|
||||
:footer="null"
|
||||
destroy-on-close="false"
|
||||
>
|
||||
<div class="approval-log-modal-content">
|
||||
<ApprovalLogSearch
|
||||
:action-type-dict="actionTypeDict"
|
||||
@search-finish="handleApprovalLogSearch"
|
||||
@reset="handleApprovalLogReset"
|
||||
/>
|
||||
<BasicTable
|
||||
ref="approvalLogTableRef"
|
||||
:columns="approvalLogColumns"
|
||||
:list-url="getApprovalLogList"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
{{ handName(record.action, actionTypeDict) }}
|
||||
</template>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</a-modal>
|
||||
|
||||
<!-- 数据变更记录弹框 -->
|
||||
<a-modal
|
||||
v-model:open="changeLogVisible"
|
||||
title="数据变更记录"
|
||||
width="1600px"
|
||||
:footer="null"
|
||||
destroy-on-close="false"
|
||||
>
|
||||
<div class="change-log-modal-content">
|
||||
<ChangeLogSearch
|
||||
:operation-type-dict="operationTypeDict"
|
||||
@search-finish="handleChangeLogSearch"
|
||||
@reset="handleChangeLogReset"
|
||||
/>
|
||||
<BasicTable
|
||||
ref="changeLogTableRef"
|
||||
:columns="changeLogColumns"
|
||||
:list-url="getApprovalChangeLogList"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'operationType'">
|
||||
{{ handName(record.operationType, operationTypeDict) }}
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'bizType'">
|
||||
{{ handName(record.bizType, yeWuType) }}
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'changeJson'">
|
||||
<pre style="max-height: 200px; overflow: auto; margin: 0;">{{ record.changeJson }}</pre>
|
||||
</template>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { queryPageList, getApprovalLogList, getApprovalChangeLogList } from '@/api/shengPiJiLu';
|
||||
import BasicTable from "@/components/BasicTable/index.vue";
|
||||
import GuoYuSheShiShuJuTianBaoSearch from "./shengPiJiLuSearch.vue";
|
||||
import ApprovalLogSearch from "./approvalLogSearch.vue";
|
||||
import ChangeLogSearch from "./changeLogSearch.vue";
|
||||
import { getDictItemsByCode } from '@/api/dict';
|
||||
let columns = ref([
|
||||
{
|
||||
title: '审批批次号',
|
||||
dataIndex: 'approvalNo',
|
||||
key: 'approvalNo',
|
||||
width: 180,
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
title: '业务类型',
|
||||
dataIndex: 'bizType',
|
||||
key: 'bizType',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '数据条数',
|
||||
dataIndex: 'dataCount',
|
||||
key: 'dataCount',
|
||||
width: 100,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '提交人',
|
||||
dataIndex: 'applyUserId',
|
||||
key: 'applyUserId',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '提交时间',
|
||||
dataIndex: 'applyTime',
|
||||
key: 'applyTime',
|
||||
width: 180,
|
||||
|
||||
},
|
||||
{
|
||||
title: '审批状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
|
||||
},
|
||||
{
|
||||
title: '审批人',
|
||||
dataIndex: 'approverId',
|
||||
key: 'approverId',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '审批时间',
|
||||
dataIndex: 'approveTime',
|
||||
key: 'approveTime',
|
||||
width: 180,
|
||||
|
||||
},
|
||||
{
|
||||
title: '审批备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
ellipsis: true,
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
align: 'center'
|
||||
}
|
||||
]);
|
||||
const tableRef = ref()
|
||||
const handleSearchFinish = (values: any) => {
|
||||
console.log(values);
|
||||
const filters = [
|
||||
values.approvalNo && {
|
||||
field: "approvalNo",
|
||||
operator: "contains",
|
||||
dataType: "string",
|
||||
value: values.approvalNo,
|
||||
},
|
||||
values.status && {
|
||||
field: "status",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: values.status,
|
||||
},
|
||||
].filter(Boolean);
|
||||
|
||||
|
||||
const filter = {
|
||||
logic: "and",
|
||||
filters: filters,
|
||||
};
|
||||
tableRef.value?.getList(filter);
|
||||
};
|
||||
const handleReset = (values) => {
|
||||
handleSearchFinish(values);
|
||||
};
|
||||
|
||||
// 审批操作日志弹框相关
|
||||
const approvalLogVisible = ref(false);
|
||||
const approvalLogTableRef = ref();
|
||||
|
||||
const approvalLogColumns = ref([
|
||||
{
|
||||
title: '操作类型',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '操作人',
|
||||
dataIndex: 'operatorId',
|
||||
key: 'operatorId',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '操作时间',
|
||||
dataIndex: 'operateTime',
|
||||
key: 'operateTime',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '审批意见',
|
||||
dataIndex: 'commentInfo',
|
||||
key: 'commentInfo',
|
||||
ellipsis: true,
|
||||
width: 300
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
key: 'createdAt',
|
||||
width: 180
|
||||
}
|
||||
]);
|
||||
|
||||
// 数据变更记录弹框相关
|
||||
const changeLogVisible = ref(false);
|
||||
const changeLogTableRef = ref();
|
||||
|
||||
const changeLogColumns = ref([
|
||||
{
|
||||
title: '业务类型',
|
||||
dataIndex: 'bizType',
|
||||
key: 'bizType',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '操作类型',
|
||||
dataIndex: 'operationType',
|
||||
key: 'operationType',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '变更内容',
|
||||
dataIndex: 'changeJson',
|
||||
key: 'changeJson',
|
||||
width: 400,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作人',
|
||||
dataIndex: 'operatorId',
|
||||
key: 'operatorId',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '操作时间',
|
||||
dataIndex: 'operateTime',
|
||||
key: 'operateTime',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
key: 'createdAt',
|
||||
width: 180
|
||||
}
|
||||
]);
|
||||
|
||||
const currentApprovalId = ref('');
|
||||
const actionTypeDict = ref([]);
|
||||
const operationTypeDict = ref([]);
|
||||
|
||||
// 显示审批操作日志弹框
|
||||
const handleShowApprovalLog = (record: any) => {
|
||||
currentApprovalId.value = record.id;
|
||||
approvalLogVisible.value = true;
|
||||
// 延迟调用,确保弹框和 BasicTable 组件完全渲染
|
||||
setTimeout(() => {
|
||||
const filter = {
|
||||
logic: "and",
|
||||
filters: [
|
||||
{
|
||||
field: "approvalId",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: record.id,
|
||||
}
|
||||
]
|
||||
};
|
||||
approvalLogTableRef.value?.getList(filter);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 审批日志搜索处理
|
||||
const handleApprovalLogSearch = (values: any) => {
|
||||
console.log('审批日志搜索:', values);
|
||||
const filters = [
|
||||
{
|
||||
field: "approvalId",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: currentApprovalId.value,
|
||||
},
|
||||
values.action && {
|
||||
field: "action",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: values.action,
|
||||
},
|
||||
].filter(Boolean);
|
||||
|
||||
const filter = {
|
||||
logic: "and",
|
||||
filters: filters,
|
||||
};
|
||||
approvalLogTableRef.value?.getList(filter);
|
||||
};
|
||||
|
||||
// 审批日志重置处理
|
||||
const handleApprovalLogReset = (values: any) => {
|
||||
console.log('审批日志重置:', values);
|
||||
handleApprovalLogSearch(values);
|
||||
};
|
||||
|
||||
// 显示数据变更记录弹框
|
||||
const handleShowChangeLog = (record: any) => {
|
||||
currentApprovalId.value = record.id;
|
||||
changeLogVisible.value = true;
|
||||
// 延迟调用,确保弹框和 BasicTable 组件完全渲染
|
||||
setTimeout(() => {
|
||||
const filter = {
|
||||
logic: "and",
|
||||
filters: [
|
||||
{
|
||||
field: "approvalId",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: record.id,
|
||||
}
|
||||
]
|
||||
};
|
||||
changeLogTableRef.value?.getList(filter);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 变更日志搜索处理
|
||||
const handleChangeLogSearch = (values: any) => {
|
||||
console.log('变更日志搜索:', values);
|
||||
const filters = [
|
||||
{
|
||||
field: "approvalId",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: currentApprovalId.value,
|
||||
},
|
||||
values.operationType && {
|
||||
field: "operationType",
|
||||
operator: "eq",
|
||||
dataType: "string",
|
||||
value: values.operationType,
|
||||
},
|
||||
].filter(Boolean);
|
||||
|
||||
const filter = {
|
||||
logic: "and",
|
||||
filters: filters,
|
||||
};
|
||||
changeLogTableRef.value?.getList(filter);
|
||||
};
|
||||
|
||||
// 变更日志重置处理
|
||||
const handleChangeLogReset = (values: any) => {
|
||||
console.log('变更日志重置:', values);
|
||||
handleChangeLogSearch(values);
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
dictNmae()
|
||||
});
|
||||
const shenStatus = ref([])
|
||||
const yeWuType = ref([])
|
||||
const dictNmae = () => {
|
||||
getDictItemsByCode({ dictCode: 'shenStatus' }).then((res) => {
|
||||
shenStatus.value = res.data;
|
||||
});
|
||||
getDictItemsByCode({ dictCode: 'yeWuType' }).then((res) => {
|
||||
yeWuType.value = res.data;
|
||||
});
|
||||
// TODO: 待补充操作类型字典
|
||||
getDictItemsByCode({ dictCode: 'caoType' }).then((res) => {
|
||||
actionTypeDict.value = res.data;
|
||||
});
|
||||
getDictItemsByCode({ dictCode: 'caoTypeTwo' }).then((res) => {
|
||||
operationTypeDict.value = res.data;
|
||||
});
|
||||
}
|
||||
const handName = (val: any, arr: any) => {
|
||||
let dictName1 = ''
|
||||
arr.forEach((item: any) => {
|
||||
if (item.itemCode == val) {
|
||||
dictName1 = item.dictName
|
||||
}
|
||||
})
|
||||
return dictName1
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.shengPiJiLu-page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.approval-log-modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.change-log-modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
85
frontend/src/views/shuJuTianBao/shengPiJiLuSearch.vue
Normal file
85
frontend/src/views/shuJuTianBao/shengPiJiLuSearch.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div class="guoYuSheShiShuJuTianBao-search">
|
||||
<BasicSearch ref="basicSearchRef" :searchList="searchList" :initial-values="initSearchData"
|
||||
@finish="onSearchFinish" @values-change="onValuesChange" @reset="handleReset">
|
||||
</BasicSearch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue"; // 确保路径正确
|
||||
import { getDictItemsByCode } from '@/api/dict';
|
||||
// --- Props & Emits ---
|
||||
interface Props {
|
||||
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const emit = defineEmits<{
|
||||
(e: "reset", values: any): void;
|
||||
(e: "searchFinish", values: any): void;
|
||||
}>();
|
||||
|
||||
|
||||
// 模拟 initSearchData
|
||||
const initSearchData = {
|
||||
approvalNo:'',
|
||||
status:'',
|
||||
};
|
||||
|
||||
const searchData = ref<any>({ ...initSearchData });
|
||||
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: "Input",
|
||||
name: "approvalNo",
|
||||
label: "审批批次号",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
type: "Select",
|
||||
name: "status",
|
||||
label: "审批状态",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
options: statusData.value,
|
||||
},
|
||||
|
||||
]);
|
||||
// --- Methods ---
|
||||
|
||||
|
||||
|
||||
// 2. 搜索表单逻辑
|
||||
const onSearchFinish = (values: any) => {
|
||||
console.log(values);
|
||||
|
||||
emit("searchFinish", values);
|
||||
};
|
||||
const handleReset = () => {
|
||||
emit("reset", initSearchData);
|
||||
};
|
||||
|
||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
// 同步更新本地 searchData,以便其他逻辑使用
|
||||
searchData.value = { ...searchData.value, ...allValues };
|
||||
};
|
||||
|
||||
// --- Lifecycle ---
|
||||
onMounted(() => {
|
||||
emit("searchFinish", initSearchData);
|
||||
getstatusData()
|
||||
});
|
||||
const statusData = ref(false)
|
||||
const getstatusData = () => {
|
||||
getDictItemsByCode({ dictCode: "shenStatus" }).then((res) => {
|
||||
statusData.value = res.data;
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
@ -2,7 +2,7 @@
|
||||
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
|
||||
import RightDrawer from "@/components/RightDrawer/index.vue";
|
||||
import ShuiZhiJianCeGongZuoQingKuang from "@/modules/shuizhijiancegongzuoQK/index.vue"
|
||||
// import EnvironmentalQuality from "@/modules/environmentalQuality/index.vue" // 环境质量满足度
|
||||
import EnvironmentalQuality from "@/modules/EnvironmentalQuality/index.vue" // 环境质量满足度
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -13,7 +13,7 @@ import ShuiZhiJianCeGongZuoQingKuang from "@/modules/shuizhijiancegongzuoQK/inde
|
||||
<div class="rightContent">
|
||||
<RightDrawer>
|
||||
<ShuiZhiJianCeGongZuoQingKuang />
|
||||
<!-- <EnvironmentalQuality /> -->
|
||||
<EnvironmentalQuality />
|
||||
</RightDrawer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user