数字督察一体化平台-前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

758 lines
21 KiB

<template>
<el-scrollbar height="100vh">
<div class="wrapper">
<datav-header />
<main>
<el-row :gutter="16">
<el-col :span="6">
<datav-card title="审计整改结果"
sub-title="已整改问题数/查处问题数"
>
<datav-tabs
type="bottom-button"
v-model="auditSuperRankTab"
ref="auditSuperRankTabs"
>
<datav-tab-item label="分县市局" name="1">
<el-scrollbar height="350px">
<datav-chart-bar
size="small"
:data="fxData"
unit="%"
remark-font-size="12px"
spanClass="right-aligned"
:color="colors"
/>
</el-scrollbar>
</datav-tab-item>
<datav-tab-item label="局属单位" name="2">
<el-scrollbar height="350px">
<datav-chart-bar
size="small"
:data="jsData"
unit="%"
remark-font-size="12px"
spanClass="right-aligned"
:color="colors"
/>
</el-scrollbar>
</datav-tab-item>
</datav-tabs>
</datav-card>
<datav-card title="审计项目类型">
<v-charts
style="height: 300px"
:option="option2"
autoresize
/>
</datav-card>
</el-col>
<el-col :span="12">
<datav-date-picker v-model="time" />
<div class="flex gap-42">
<datav-statistic
:value="overview.projectNumber"
title="审计单位/项目"
style="width: 20%"
/>
<datav-statistic
:value="overview.auditAmount"
:title="`审计总金额\n(万元)`"
:isDecimal="true"
style="width: 20%"
/>
<datav-statistic
:value="`${overview.auditSjAmount}/${overview.auditWtAmount}`"
:title="`审减/问题金额\n(万元)`"
:isDecimal="true"
style="width: 20%"
/>
<datav-statistic
:value="overview.negativeNumber"
title="查处问题数"
style="width: 20%"
/>
<datav-statistic
:value="overview.accountableNumber"
title="追责问责数"
style="width: 20%"
/>
</div>
<v-charts
style="height: 450px"
:option="option"
autoresize
/>
<datav-card title="审计工作趋势">
<v-charts
style="height: 300px"
:option="option1"
autoresize
ref="auditTrend"
/>
<div class="gobal-dropdown-container">
<el-dropdown
class="test"
@command="handleCommand"
>
<span
class="el-dropdown-link my-gobal-yearselect"
>
{{ selectedYear + " 年" }}
</span>
<template #dropdown>
<el-dropdown-menu
style="width: 90px"
>
<el-dropdown-item
v-for="year in years"
:key="year"
:command="year"
>{{ year + " 年" }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</datav-card>
</el-col>
<el-col :span="6">
<datav-card title="审计查出问题" style="height: 350px">
<v-charts
style="height: 300px"
:option="problemOptions"
autoresize
/>
</datav-card>
<datav-card title="审计工作动态">
<el-scrollbar height="470px">
<datav-message
v-for="(msg, index) in messages"
:key="index"
:type="msg.type"
:title="msg.workType"
:content="msg.contentTxt"
:date="msg.releaseTime"
>
<template #link>
<div class="message-link" @click="handlePerviewFile(msg)" v-if="msg.files">查看图片</div>
</template>
</datav-message>
</el-scrollbar>
</datav-card>
</el-col>
</el-row>
</main>
</div>
</el-scrollbar>
<file-preview :files="files" v-model:show="filePreviewShow" />
</template>
<script setup>
import vCharts from "vue-echarts";
import changshaMap from "@/assets/data/changsha.json";
import * as echarts from "echarts/core";
import moment from "moment/moment.js";
import {
getWorkDynamics,
getAuditNegativeVo,
getAuditMap,
getAuditType,
getAuditTrend, getOverview
} from "@/api/data/aduit.ts";
import { workDynamicColorMapping } from "@/enums/workDynamicColorMapping.js";
import { getAuditOverview, getAuditProblems } from '@/api/datav'
import { onMounted } from "vue";
import {mapOrgNameMapping} from "@/enums/orgMapping.js";
const messages = ref([]);
const time = ref([
moment().startOf("year").format("YYYY-MM-DD"),
moment().format("YYYY-MM-DD"),
]);
watch(time, () => {
getData();
});
const overview = ref({
negativeNumber: 0,
accountableNumber: 0,
projectNumber: 0,
auditAmount: 0,
auditSjAmount: 0,
auditWtAmount: 0,
});
const problemOptions = ref({
series: [
{
type: "pie",
radius: ["40%", "70%"],
label: {
color: "#fff",
},
data: [],
},
],
tooltip: {
trigger: "item",
},
});
onMounted(() => {
getData()
})
function getData() {
getOverviewFun();
getAuditProblems(time.value).then(data => {
console.log(data)
problemOptions.value.series[0].data = data
});
getWorkDynamicsData();
getAuditNegativeVoFun();
getAuditMapData();
getAuditTypeFun();
getAuditTrendFun();
}
const fxData =ref([])
const jsData =ref([])
const getAuditNegativeVoFun =async ()=>{
const res = await getAuditNegativeVo(time.value);
if(res){
fxData.value=res.fxData;
jsData.value=res.jsData;
}
}
/**
* 项目类型
* @returns {Promise<void>}
*/
const getAuditTypeFun = async ()=>{
const body = {
beginTime: time.value[0],
endTime: time.value[1]
}
const res = await getAuditType(body);
if(res){
option2.value.series[0].data = res.barData;
}
}
/**
* 总览数据
* @returns {Promise<void>}
*/
const getOverviewFun = async()=>{
const body = {
beginTime: time.value[0],
endTime: time.value[1]
}
overview.value = await getOverview(body);
}
const auditTrend = ref(null);
const currentYear = new Date().getFullYear();
const years = ref([
currentYear.toString(),
(currentYear - 1).toString(),
(currentYear - 2).toString(),
]); // 年份列表
const selectedYear = ref(currentYear); // 当前选中的年份
// 更换年份事件
const handleCommand = (year) => {
selectedYear.value = year; // 更新当前选中的年份
// 这里可以添加获取对应年份数据的逻辑
getAuditTrendFun();
};
/**
* 审计工作趋势
* @type {Ref<UnwrapRef<string>, UnwrapRef<string> | string>}
*/
const getAuditTrendFun = async (year = selectedYear.value) => {
const res = await getAuditTrend(year);
// // 更新图表数据
option1.value.xAxis.data = res.auditTrend.map((item) => item.name);
option1.value.series[0].data = res.auditTrend.map((item) => item.value);
}
const auditSuperRankTab = ref('1');
const auditMapData = ref([
{
originalName: "浏阳市局",
name: "浏阳市",
reportProjectNumber: 135,
checkProNumber: 135,
rushProNumber: 89,
rectifyNumber: 152,
},
]);
echarts.registerMap("changsha", changshaMap);
const option = ref({
geo: {
map: "changsha",
},
tooltip: {
trigger: "item",
formatter: function (params) {
const dataItem = auditMapData.value.find((item) =>
item.name.includes(params.name.substring(0, 2))
);
if (dataItem) {
return `
<div class="tooltip">
<div class="tooltip-title">${dataItem.name}</div>
<div class="tooltip-content">
<ul class="tooltip-ul" >
<li>审计单位/项目数<span>${dataItem.reportProjectNumber}</span></li>
<li>查处问题数 <span>${dataItem.checkProNumber}</span></li>
<li>追责问责数 <span>${dataItem.rushProNumber}</span></li>
<li>整改问题数 <span>${dataItem.rectifyNumber}</span></li>
</ul>
</div>
</div>`;
} else {
return `<div class="tooltip">
<div class="tooltip-title">${params.name}</div>
<div class="tooltip-content">
<ul class="tooltip-ul"">
<li>审计单位/项目 <span>-</span></li>
<li>查处问题数 <span>-</span></li>
<li>追责问责数 <span>-</span></li>
<li>整改问题数 <span>-</span></li>
</ul>
</div>
</div>`;
}
},
},
visualMap: {
type: "piecewise",
bottom: 10,
pieces: [
{ min: 0, max: 500, label: "问题数低于500" },
{ min: 501, max: 1000, label: "问题数介于500-1000" },
{
min: 1001,
label: "问题数高于1000",
},
],
right: 10,
realtime: false,
orient: "horizontal",
textStyle: {
color: "#fff",
},
calculable: true,
inRange: {
color: ["#4987F6", "#F6A149", "#D34343"],
},
},
series: [
{
name: "长沙",
type: "map",
map: "changsha",
hoverAnimation: true,
label: {
show: true,
color: "white",
},
itemStyle: {
normal: {
areaColor: "#02215E",
borderColor: "#24D2EE",
borderWidth: 1, // 高亮时边框宽度
},
},
emphasis: {
areaColor: "#FFD700", // 高亮时区域颜色
borderColor: "#FF0000", // 高亮时边框颜色
borderWidth: 4, // 高亮时边框宽度
},
data: [],
},
],
});
const option1 = ref({
xAxis: {
type: "category",
boundaryGap: false,
data: [
"1月",
"2月",
"3月",
"4月",
"5月",
"6月",
"7月",
"8月",
"9月",
"10月",
"11月",
],
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "line",
label: {
backgroundColor: "#6a7985",
},
},
},
yAxis: {
type: "value",
splitLine: {
show: true,
lineStyle: {
color: "#193775",
},
},
},
series: [
{
type: "line",
smooth: true,
label: {
show: false,
},
lineStyle: {
color: "#28E6FF",
width: 4,
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "rgba(40,230,255,0.47)", // 渐变起始颜色
},
{
offset: 1,
color: "rgba(40,230,255,0)", // 渐变结束颜色
},
]),
},
data: [27, 39, 26, 16, 0, 0, 0, 0, 0, 0, 0],
},
],
});
const data1 = [
{
label: "公交分局",
value: 100,
numerator: 7,
denominator: 8,
},
{
label: "岳麓分局",
value: 100,
numerator: 2,
denominator: 2,
},
{
label: "交警支队",
value: 100,
numerator: 2,
denominator: 2,
},
{
label: "高新分局",
value: 100,
numerator: 1,
denominator: 1,
},
];
const data2 = [
{
name: "开福分局",
value: 9700,
},
{
name: "芙蓉分局",
value: 9021,
},
{
name: "岳麓分局",
value: 8512,
},
{
name: "雨花分局",
value: 8021,
},
{
name: "望城分局",
value: 7111,
},
{
name: "浏阳市局",
value: 6622,
},
{
name: "长沙县局",
value: 6221,
},
];
const option2 = ref({
series: [
{
type: "pie",
radius: ["40%", "70%"],
label: {
color: "#fff",
},
data: [
{ value: 7, name: "执法活动财物审计" },
{ value: 1, name: "经济责任审计" },
{ value: 110, name: "政府投资审计" },
{ value: 1, name: "专项审计" },
],
},
],
tooltip: {
trigger: "item",
},
});
const colors = [
{
// 绿色
color: "linear-gradient( 270deg, #63E700 0%, #19674C 100%)",
percentage: 90,
},
{
// 黄色
color: "linear-gradient( 270deg, #FFB90E 0%, #71501D 100%)",
percentage: 80,
},
{
// 红色
color: "linear-gradient( 270deg, #FB002D 0%, #822232 100%)",
percentage: 70,
},
];
const getWorkDynamicsData = async () => {
const data = await getWorkDynamics(time.value);
const colorNewsVoList = workDynamicColorMapping(data);
messages.value = colorNewsVoList;
}
const files = ref([])
const filePreviewShow = ref(false)
function handlePerviewFile(msg) {
if (msg.files) {
filePreviewShow.value = true
files.value = JSON.parse(msg.files)
}
}
const getAuditMapData = async ()=>{
const body = {
beginTime: time.value[0],
endTime: time.value[1]
}
const res = await getAuditMap(body);
const mappedData = mapOrgNameMapping(res.auditSuperviseMapIconVoList,"checkProNumber");
// 总数
const maxItem = mappedData.reduce(
(max, item) => (Number(item.value) > Number(max.value) ? item : max),
mappedData[0]
);
const range60Percent = maxItem.value * 0.6; // 不用取整,小数也可以
const range80Percent = maxItem.value * 0.8; // 不用取整,小数也可以
console.log("============================")
console.log(mappedData)
auditMapData.value = mappedData;
option.value.series[0].data = mappedData;
option.value.visualMap.pieces = [
{
gte: 0,
lte: range60Percent,
label: "低于最大问题数的60%",
color: "#4987F6",
},
{
gte: range60Percent,
lte: range80Percent,
label: "介于最大问题数的60%~80%",
color: "#F6A149",
},
{ gte: range80Percent, label: "高于最大问题数的80%", color: "#D34343" },
];
}
</script>
<style lang="scss" scoped>
@import "@/style/datav.scss";
:deep() {
// 弹框整体
.tooltip {
position: relative;
width: 169.88px;
height: 155px;
background: linear-gradient(
180deg,
rgba(1, 4, 87, 0.8) 0%,
rgba(3, 21, 119, 0.8) 100%
);
border: 1px solid #4e8fff;
margin: -10px -10px -10px -10px;
}
//浏阳市局
.tooltip-title {
width: 169.88px;
height: 43px;
background: linear-gradient(
180deg,
rgba(1, 4, 87, 0.8) 0%,
rgba(3, 21, 119, 0.8) 100%
);
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
text-align: center; /* 水平居中 */
font-weight: 400;
font-size: 16px;
color: #ffffff;
line-height: 22px;
border-bottom: 1px solid #253755; /* 设置下边框 */
}
.tooltip-content {
width: 170px;
height: 106px;
//font-size: 11px;
margin-top: -12px;
background: linear-gradient(180deg, #010457 0%, #031577 100%);
}
.tooltip-content ul {
list-style-type: none; /* 移除默认的小圆点 */
padding: 0;
}
.tooltip-content ul li {
margin-left: 5px;
height: 25px;
color: #597ae9;
font-size: 13px;
}
// 数字的span
.tooltip-ul span {
float: right;
width: 50px;
text-align: right;
margin-right: 15px;
color: #fff;
font-size: 13px;
}
/* 小尖角 */
.tooltip::before {
content: "";
position: absolute;
top: 90px; /* 调整尖角的垂直位置 */
left: -10px; /* 调整尖角的水平位置 */
width: 0;
height: 0;
//border-top: 10px solid red; /* 顶边颜色 */
//border-bottom: 10px solid green; /* 底边颜色 */
//border-right: 10px solid blue; /* 右边颜色,与背景颜色相同 */
}
}
.message {
padding: 10px;
margin-bottom: 10px;
background: linear-gradient(
270deg,
rgba(16, 151, 255, 0.1) 0%,
rgba(0, 55, 236, 0.87) 100%
);
&[type="warning"] {
background: linear-gradient(
270deg,
rgba(255, 190, 16, 0.1) 0%,
rgba(236, 84, 0, 0.87) 100%
);
}
&[type="success"] {
background: linear-gradient(
270deg,
rgba(91, 216, 9, 0.14) 0%,
#28813d 100%
);
}
.message-title {
font-size: 14px;
margin-bottom: 10px;
}
.message-content {
margin-bottom: 10px;
}
}
.message-link {
font-size: 12px;
color: #eee;
&:hover {
cursor: pointer;
text-decoration: underline;
}
}
.test {
width: 95px;
height: 25px;
background: #1c3472;
}
.gobal-dropdown-container {
position: absolute;
right: 20px;
top: 15px;
}
.my-gobal-yearselect {
font-size: 14px;
padding-top: 6px;
padding-left: 20px;
width: 90px;
color: #fff;
}
</style>