提交 09ce28e5 authored 作者: 朱政's avatar 朱政

完善智库详情,按照样式图基本实现智库概览样式

上级 7e49bd72
...@@ -83,6 +83,15 @@ export function getThinkTankReport(params) { ...@@ -83,6 +83,15 @@ export function getThinkTankReport(params) {
}) })
} }
// 智库概览:政策建议(资源库-政策建议)
export function getThinkTankOverviewPolicy(params) {
return request({
method: 'GET',
url: `/api/thinkTankOverview/policy`,
params
})
}
/********* 智库信息 */ /********* 智库信息 */
//智库百科:获取全局信息 //智库百科:获取全局信息
export function getThinkTankSummary(params) { export function getThinkTankSummary(params) {
...@@ -119,6 +128,13 @@ export function getThinkPolicyIndustry(params) { ...@@ -119,6 +128,13 @@ export function getThinkPolicyIndustry(params) {
url: `/api/thinkTankInfo/policyIndustry/${params.id}/${params.year}`, url: `/api/thinkTankInfo/policyIndustry/${params.id}/${params.year}`,
}) })
} }
//提出政策建议涉及部门分布
export function getPolicyAdviceDeptDistribution(params){
return request({
method: 'GET',
url: `/api/thinkTankInfo/policyDepartment/${params.id}/${params.year}`,
})
}
//获取相关政策领域分布 //获取相关政策领域分布
export function getThinkPolicyIndustryTotal(params) { export function getThinkPolicyIndustryTotal(params) {
......
...@@ -73,6 +73,7 @@ const handleToNewsAnalysis = (item, index) => { ...@@ -73,6 +73,7 @@ const handleToNewsAnalysis = (item, index) => {
flex-direction: column; flex-direction: column;
gap: 0 !important; gap: 0 !important;
overflow: hidden; overflow: hidden;
border: 1px solid rgba(234, 236, 238, 1) !important;
.news-header { .news-header {
height: 48px !important; height: 48px !important;
...@@ -142,6 +143,7 @@ const handleToNewsAnalysis = (item, index) => { ...@@ -142,6 +143,7 @@ const handleToNewsAnalysis = (item, index) => {
&:hover { &:hover {
background: var(--color-bg-hover); background: var(--color-bg-hover);
.right-top .title { .right-top .title {
text-decoration: underline; text-decoration: underline;
color: rgb(5, 95, 194) !important; color: rgb(5, 95, 194) !important;
......
...@@ -3,13 +3,8 @@ ...@@ -3,13 +3,8 @@
<div class="main-content" ref="homeMainRef"> <div class="main-content" ref="homeMainRef">
<div class="home-top-bg"></div> <div class="home-top-bg"></div>
<!-- 搜索栏部分 --> <!-- 搜索栏部分 -->
<SearchContainer <SearchContainer v-if="homeMainRef" :countInfo="statCountInfo" placeholder="搜索规则限制" :containerRef="homeMainRef"
v-if="homeMainRef" areaName="" />
:countInfo="statCountInfo"
placeholder="搜索规则限制"
:containerRef="homeMainRef"
areaName=""
/>
<!-- 最新动态 --> <!-- 最新动态 -->
<div class="newdata" id="position1"> <div class="newdata" id="position1">
<com-title title="最新动态" /> <com-title title="最新动态" />
......
...@@ -215,9 +215,11 @@ onMounted(async () => { ...@@ -215,9 +215,11 @@ onMounted(async () => {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.coop-page { .coop-page {
width: 100%; width: 100%;
height: 100%; height: 100%;
// .breadcrumb { // .breadcrumb {
// width: 100%; // width: 100%;
// height: 64px; // height: 64px;
...@@ -245,6 +247,7 @@ onMounted(async () => { ...@@ -245,6 +247,7 @@ onMounted(async () => {
width: 960px; width: 960px;
height: 168px; height: 168px;
margin: 0 auto 68px auto; margin: 0 auto 68px auto;
.search-center { .search-center {
width: 688px; width: 688px;
height: 48px; height: 48px;
...@@ -284,6 +287,7 @@ onMounted(async () => { ...@@ -284,6 +287,7 @@ onMounted(async () => {
} }
} }
} }
.search-main { .search-main {
display: flex; display: flex;
padding-right: 3px; padding-right: 3px;
...@@ -295,9 +299,11 @@ onMounted(async () => { ...@@ -295,9 +299,11 @@ onMounted(async () => {
background-color: rgba(255, 255, 255, 0.65); background-color: rgba(255, 255, 255, 0.65);
border-radius: 10px; border-radius: 10px;
border: 1px solid #fff; border: 1px solid #fff;
&:hover { &:hover {
border: 1px solid var(--color-main-active); border: 1px solid var(--color-main-active);
} }
.search-input { .search-input {
border: none; border: none;
outline: none; outline: none;
...@@ -315,6 +321,7 @@ onMounted(async () => { ...@@ -315,6 +321,7 @@ onMounted(async () => {
color: #a8abb2; color: #a8abb2;
} }
} }
.search-btn { .search-btn {
cursor: pointer; cursor: pointer;
display: flex; display: flex;
...@@ -330,6 +337,7 @@ onMounted(async () => { ...@@ -330,6 +337,7 @@ onMounted(async () => {
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
line-height: 22px; line-height: 22px;
color: #fff; color: #fff;
img { img {
width: 18px; width: 18px;
height: 18px; height: 18px;
...@@ -337,6 +345,7 @@ onMounted(async () => { ...@@ -337,6 +345,7 @@ onMounted(async () => {
} }
} }
} }
.search-bottom { .search-bottom {
width: 688px; width: 688px;
height: 48px; height: 48px;
...@@ -344,6 +353,7 @@ onMounted(async () => { ...@@ -344,6 +353,7 @@ onMounted(async () => {
margin-top: 36px; margin-top: 36px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
// gap: 16px; // gap: 16px;
.btn { .btn {
display: flex; display: flex;
...@@ -357,9 +367,11 @@ onMounted(async () => { ...@@ -357,9 +367,11 @@ onMounted(async () => {
background: #e7f3ff; background: #e7f3ff;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
&:hover { &:hover {
background: #cae3fc; background: #cae3fc;
} }
.btn-text { .btn-text {
width: 80px; width: 80px;
color: var(--color-main-active); color: var(--color-main-active);
...@@ -370,12 +382,14 @@ onMounted(async () => { ...@@ -370,12 +382,14 @@ onMounted(async () => {
margin-left: 36px; margin-left: 36px;
text-align: center; text-align: center;
} }
.btn-icon { .btn-icon {
position: absolute; position: absolute;
top: 16px; top: 16px;
right: 19px; right: 19px;
width: 6px; width: 6px;
height: 12px; height: 12px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
...@@ -384,40 +398,48 @@ onMounted(async () => { ...@@ -384,40 +398,48 @@ onMounted(async () => {
} }
} }
} }
.newdata { .newdata {
width: 1600px; width: 1600px;
height: 538px; height: 538px;
margin: 36px auto 64px auto; margin: 36px auto 64px auto;
.newdata-main { .newdata-main {
width: 1600px; width: 1600px;
height: 460px; height: 460px;
margin-top: 36px; margin-top: 36px;
} }
} }
.ask { .ask {
width: 1600px; width: 1600px;
height: 528px; height: 528px;
margin: 0 auto 64px auto; margin: 0 auto 64px auto;
.ask-main { .ask-main {
width: 1600px; width: 1600px;
height: 450px; height: 450px;
margin-top: 36px; margin-top: 36px;
} }
} }
.datasub { .datasub {
width: 1600px; width: 1600px;
height: 538px; height: 538px;
margin: 0 auto 88px auto; margin: 0 auto 88px auto;
.datasub-main { .datasub-main {
width: 1600px; width: 1600px;
height: 460px; height: 460px;
margin-top: 36px; margin-top: 36px;
} }
} }
.reslib { .reslib {
width: 1600px; width: 1600px;
height: 1633px; height: 1633px;
margin: 0 auto 0px auto; margin: 0 auto 0px auto;
.reslib-main { .reslib-main {
width: 1600px; width: 1600px;
height: 1565px; height: 1565px;
...@@ -486,6 +508,7 @@ onMounted(async () => { ...@@ -486,6 +508,7 @@ onMounted(async () => {
.search-icon { .search-icon {
width: 18px; width: 18px;
height: 18px; height: 18px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
...@@ -522,9 +545,11 @@ onMounted(async () => { ...@@ -522,9 +545,11 @@ onMounted(async () => {
background: #e7f3ff; background: #e7f3ff;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
&:hover { &:hover {
background: #cae3fc; background: #cae3fc;
} }
.btn-text { .btn-text {
width: 80px; width: 80px;
color: var(--color-main-active); color: var(--color-main-active);
...@@ -535,12 +560,14 @@ onMounted(async () => { ...@@ -535,12 +560,14 @@ onMounted(async () => {
margin-left: 36px; margin-left: 36px;
text-align: center; text-align: center;
} }
.btn-icon { .btn-icon {
position: absolute; position: absolute;
top: 16px; top: 16px;
right: 19px; right: 19px;
width: 6px; width: 6px;
height: 12px; height: 12px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
......
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
</div> </div>
</div> </div>
<div class="header-top-right"> <div class="header-top-right">
<div class="image-name-box">
<div class="image"> <img :src=thinkInfo.thinkTankLogoUrl alt="" /></div>
<div class="name">{{ thinkInfo.thinkTankName }}</div> <div class="name">{{ thinkInfo.thinkTankName }}</div>
</div>
<div class="time">{{ thinkInfo.times }}</div> <div class="time">{{ thinkInfo.times }}</div>
</div> </div>
</div> </div>
...@@ -199,6 +202,20 @@ onMounted(async () => { ...@@ -199,6 +202,20 @@ onMounted(async () => {
} }
.header-top-right { .header-top-right {
display: flex;
flex-direction: column;
text-align: right;
align-items: flex-end;
.image-name-box {
width: 118px;
height: 24px;
gap: 6px;
text-align: right;
display: flex;
justify-content: flex-end;
.name { .name {
height: 24px; height: 24px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
...@@ -208,6 +225,23 @@ onMounted(async () => { ...@@ -208,6 +225,23 @@ onMounted(async () => {
line-height: 24px; line-height: 24px;
letter-spacing: 0px; letter-spacing: 0px;
text-align: right; text-align: right;
}
.image {
width: 16px;
height: 16px;
margin-top: 5px;
img {
width: 100%;
height: 100%;
}
}
} }
.time { .time {
......
...@@ -27,9 +27,9 @@ ...@@ -27,9 +27,9 @@
<div class="title">{{ "政策建议涉及部门分布" }}</div> <div class="title">{{ "政策建议涉及部门分布" }}</div>
<!-- <div class="box-header-right">{{ "查看数据源 >" }}</div> --> <!-- <div class="box-header-right">{{ "查看数据源 >" }}</div> -->
<div class="select-box"> <div class="select-box">
<el-select v-model="box1SelectYear" placeholder="选择时间" style="width: 100px"> <el-select v-model="box2SelectYear" placeholder="选择时间" style="width: 100px">
<el-option v-for="(item, index) in box1YearList" :key="index" :label="item.label + '年'" <el-option v-for="(item, index) in box2YearList" :key="index" :label="item.label + '年'"
:value="item.value" @click="handleGetThinkPolicyIndustry()" /> :value="item.value" @click="handleGetPolicyAdviceDeptDistribution()" />
</el-select> </el-select>
</div> </div>
</div> </div>
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
</el-select> </el-select>
</div> </div>
</div> </div>
<div class="box-main"> <div class="box3-main">
<div id="box3Chart"></div> <div id="box3Chart"></div>
</div> </div>
</div> </div>
...@@ -223,7 +223,8 @@ import { ...@@ -223,7 +223,8 @@ import {
getThinkPolicyIndustryTotal, getThinkPolicyIndustryTotal,
getThinkPolicyIndustryChange, getThinkPolicyIndustryChange,
getHylyList, getHylyList,
getThinkPolicy getThinkPolicy,
getPolicyAdviceDeptDistribution
} from "@/api/thinkTank/overview"; } from "@/api/thinkTank/overview";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
...@@ -272,9 +273,11 @@ const box1Data = ref([ ...@@ -272,9 +273,11 @@ const box1Data = ref([
// color: "#D6E4FF" // color: "#D6E4FF"
// } // }
]); ]);
const relationBillsList = ref([{ billName: "2025《人工智能安全与评估法案》" }]) const relationBillsList = ref([{ billName: "2025《人工智能安全与评估法案》" }])
const relationAdList = ref([{ adName: "2025《人工智能安全与评估法案》" }]) const relationAdList = ref([{ adName: "2025《人工智能安全与评估法案》" }])
const box1SelectYear = ref("2025"); const box1SelectYear = ref("2025");
const box1YearList = ref([ const box1YearList = ref([
{ {
label: "2025", label: "2025",
...@@ -299,23 +302,45 @@ const handleGetThinkPolicyIndustry = async () => { ...@@ -299,23 +302,45 @@ const handleGetThinkPolicyIndustry = async () => {
const res = await getThinkPolicyIndustry(parmas); const res = await getThinkPolicyIndustry(parmas);
console.log("提出建议领域分布", res); console.log("提出建议领域分布", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
let data = []; const list = Array.isArray(res.data) ? res.data.slice(0, 7) : [];
res.data.map(item => { const data = list.map(item => ({
data.push({
name: item.industry, name: item.industry,
value: item.amount, value: item.amount,
percent: item.percent percent: item.percent
}); }));
});
box1Data.value = data; box1Data.value = data;
const box1Chart = getPieChart(box1Data.value); const box1Chart = getPieChart(box1Data.value);
setChart(box1Chart, "box1Chart"); setChart(box1Chart, "box1Chart");
setChart(box1Chart, "box2Chart");
} }
} catch (error) { } catch (error) {
console.error("获取提出建议领域分布error", error); console.error("获取提出建议领域分布error", error);
} }
}; };
const handleGetPolicyAdviceDeptDistribution = async () => {
try {
const parmas = {
id: router.currentRoute._value.params.id,
year: box2SelectYear.value
};
const res = await getPolicyAdviceDeptDistribution(parmas);
console.log("政策建议涉及部门分布", res);
if (res.code === 200 && res.data && Array.isArray(res.data.series)) {
// 接口新结构:data.series 为 [{ name, value, percent, extra }]
const list = res.data.series.slice(0, 7);
box2Data.value = list.map(item => ({
name: item.name,
value: item.value,
percent: item.percent
}));
const box2Chart = getPieChart(box2Data.value);
setChart(box2Chart, "box2Chart");
}
} catch (error) {
console.error("获取政策建议涉及部门分布 error", error);
}
};
// 相关政策领域分布 // 相关政策领域分布
const box2Data = ref([ const box2Data = ref([
...@@ -657,6 +682,7 @@ onMounted(() => { ...@@ -657,6 +682,7 @@ onMounted(() => {
handleGetThinkPolicyIndustryChange(); handleGetThinkPolicyIndustryChange();
handleGetHylyList(); handleGetHylyList();
handleGetThinkPolicy(); handleGetThinkPolicy();
handleGetPolicyAdviceDeptDistribution();
}); });
</script> </script>
...@@ -811,20 +837,45 @@ onMounted(() => { ...@@ -811,20 +837,45 @@ onMounted(() => {
} }
.box-main { .box-main {
height: 360px; height: 372px;
width: 520px;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
box-sizing: border-box;
padding: 24px 24px 0;
#box1Chart { #box1Chart {
height: 360px; height: 309px;
width: 446.5px;
} }
#box2Chart { #box2Chart {
height: 360px; height: 309px;
width: 446.5px;
} }
#box3Chart { #box3Chart {
height: 360px; height: 309px;
width: 446.5px;
}
}
.box3-main {
height: 372px;
width: 520px;
position: relative;
overflow: hidden;
box-sizing: border-box;
padding-top: 24px;
#box3Chart {
height: 300px;
width: 520px;
} }
...@@ -1366,22 +1417,4 @@ onMounted(() => { ...@@ -1366,22 +1417,4 @@ onMounted(() => {
height: 8px !important; height: 8px !important;
margin-right: 4px; margin-right: 4px;
} }
/* PolicyTracking 分页按钮样式:1px 描边 + 白底 + 6px 圆角 */
:deep(.right-footer .el-pagination.is-background .btn-prev),
:deep(.right-footer .el-pagination.is-background .btn-next),
:deep(.right-footer .el-pagination.is-background .el-pager li) {
border: 1px solid rgba(0, 0, 0, 0.15) !important;
background-color: rgba(255, 255, 255, 1) !important;
border-radius: 6px !important;
box-sizing: border-box;
}
// 选中状态的页码样式(描边+文字颜色改为指定蓝色)
:deep(.right-footer .el-pagination.is-background .el-pager li.is-active) {
border-color: rgba(22, 119, 255, 1) !important; // 选中后描边颜色
color: rgba(22, 119, 255, 1) !important; // 选中后页码文字颜色
background-color: rgba(255, 255, 255, 1) !important; // 保持白色背景
font-weight: 400;
}
</style> </style>
\ No newline at end of file
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { size, split } from 'lodash'
const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
return { return {
...@@ -19,23 +20,55 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { ...@@ -19,23 +20,55 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
containLabel: true containLabel: true
}, },
legend: { legend: {
icon:'circle',
show: true, show: true,
top: 10, top: 10,
left:'10%', left:'10%',
textStyle: { textStyle: {
fontSize: 16 fontSize: 16,
} fontFamily: 'Source Han Sans CN',
fontWeight: 400,
lineHeight: 24,
letterSpacing: 0,
align: 'left',
color:'rgb(95, 101, 108)'
},
itemWidth:12,
itemHeight:12,
}, },
xAxis: [ xAxis: [
{ {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: dataX data: dataX,
axisLine: {
lineStyle: {
color: 'rgb(231, 243, 255)',
},
},
axisLabel: {
color: 'rgb(132, 136, 142)',
fontFamily: 'Microsoft YaHei',
fontWeight: 400,
fontSize:12,
},
} }
], ],
yAxis: [ yAxis: [
{ {
type: 'value' type: 'value',
splitLine:{
show:true,
lineStyle:{
color:"rgb(231, 243, 255)",
type:'dashed'
}
}
} }
], ],
series: [ series: [
......
...@@ -13,21 +13,31 @@ const getPieChart = (data) => { ...@@ -13,21 +13,31 @@ const getPieChart = (data) => {
}, },
label: { label: {
alignTo: 'edge', alignTo: 'edge',
formatter: '{name|{b}} {time|{c} 条 {d}%}\n', formatter: params => {
const name = params.name || "";
const value = params.value ?? "";
const percent = params.percent != null ? Math.round(params.percent) : 0;
return `{name|${name}}\n{time|${value}${percent}%}`;
},
minMargin: 10, minMargin: 10,
edgeDistance: 20, edgeDistance: 20,
lineHeight: 20, lineHeight: 20,
rich: { rich: {
name: { name: {
fontSize: 16, fontSize: 16,
color: 'rgba(59, 65, 75, 1)', color: 'rgba(59, 65, 75, 1)',
fontFamily: 'Microsoft YaHei', fontFamily: 'Source Han Sans CN',
fontWeight: 700 fontWeight: 700,
lineHeight:24,
}, },
time: { time: {
fontSize: 16, fontSize: 14,
color: 'rgba(95, 101, 108, 1)', color: 'rgba(95, 101, 108, 1)',
fontFamily: 'Microsoft YaHei', fontFamily: 'Source Han Sans CN',
} }
} }
}, },
......
...@@ -601,8 +601,4 @@ const handleToReportDetail = item => { ...@@ -601,8 +601,4 @@ const handleToReportDetail = item => {
margin-right: 0 !important; margin-right: 0 !important;
} }
:deep(.el-checkbox__inner) {
border-radius: 4px !important;
}
</style> </style>
\ No newline at end of file
...@@ -431,26 +431,4 @@ const handleToReportDetail = item => { ...@@ -431,26 +431,4 @@ const handleToReportDetail = item => {
margin-right: 0 !important; margin-right: 0 !important;
} }
/* PolicyTracking 分页按钮样式:1px 描边 + 白底 + 6px 圆角 */
:deep(.right-footer .el-pagination.is-background .btn-prev),
:deep(.right-footer .el-pagination.is-background .btn-next),
:deep(.right-footer .el-pagination.is-background .el-pager li) {
border: 1px solid rgba(0, 0, 0, 0.15) !important;
background-color: rgba(255, 255, 255, 1) !important;
border-radius: 6px !important;
box-sizing: border-box;
}
// 选中状态的页码样式(描边+文字颜色改为指定蓝色)
:deep(.right-footer .el-pagination.is-background .el-pager li.is-active) {
border-color: rgba(22, 119, 255, 1) !important; // 选中后描边颜色
color: rgba(22, 119, 255, 1) !important; // 选中后页码文字颜色
background-color: rgba(255, 255, 255, 1) !important; // 保持白色背景
font-weight: 400;
}
:deep(.el-checkbox__inner) {
border-radius: 4px !important;
}
</style> </style>
\ No newline at end of file
...@@ -431,26 +431,4 @@ const handleToReportDetail = item => { ...@@ -431,26 +431,4 @@ const handleToReportDetail = item => {
margin-right: 0 !important; margin-right: 0 !important;
} }
/* PolicyTracking 分页按钮样式:1px 描边 + 白底 + 6px 圆角 */
:deep(.right-footer .el-pagination.is-background .btn-prev),
:deep(.right-footer .el-pagination.is-background .btn-next),
:deep(.right-footer .el-pagination.is-background .el-pager li) {
border: 1px solid rgba(0, 0, 0, 0.15) !important;
background-color: rgba(255, 255, 255, 1) !important;
border-radius: 6px !important;
box-sizing: border-box;
}
// 选中状态的页码样式(描边+文字颜色改为指定蓝色)
:deep(.right-footer .el-pagination.is-background .el-pager li.is-active) {
border-color: rgba(22, 119, 255, 1) !important; // 选中后描边颜色
color: rgba(22, 119, 255, 1) !important; // 选中后页码文字颜色
background-color: rgba(255, 255, 255, 1) !important; // 保持白色背景
font-weight: 400;
}
:deep(.el-checkbox__inner) {
border-radius: 4px !important;
}
</style> </style>
\ No newline at end of file
...@@ -72,25 +72,22 @@ ...@@ -72,25 +72,22 @@
<div v-if="isThinkTankReport"> <div v-if="isThinkTankReport">
<ThinkTankReport :research-type-list="researchTypeList" :research-time-list="researchTimeList" <ThinkTankReport :research-type-list="researchTypeList" :research-time-list="researchTimeList"
:key="`智库报告-${tabResetKey}`" :selected-filters="selectedFilters" :cur-footer-list="curFooterList" :total="total" :key="`智库报告-${tabResetKey}`" :selected-filters="selectedFilters" :cur-footer-list="curFooterList" :total="total"
:current-page="currentPage" :current-page="currentPage" @update:selected-filters="handleSelectedFiltersUpdate"
@update:selected-filters="handleSelectedFiltersUpdate"
@filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange" @filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange"
@report-click="handleToReportDetail" /> @report-click="handleToReportDetail" />
</div> </div>
<div v-if="isCongressHearing"> <div v-if="isCongressHearing">
<CongressHearing :research-type-list="researchTypeList" :research-time-list="researchTimeList" <CongressHearing :research-type-list="researchTypeList" :research-time-list="researchTimeList"
:key="`国会听证会-${tabResetKey}`" :research-hearing-list="researchHearingList" :key="`国会听证会-${tabResetKey}`" :research-hearing-list="researchHearingList" :selected-filters="selectedFilters"
:selected-filters="selectedFilters" :selected-year="selectedYear" :cur-footer-list="curFooterList" :total="total" :selected-year="selectedYear" :cur-footer-list="curFooterList" :total="total" :current-page="currentPage"
:current-page="currentPage" :hearing-data="hearingData" :hearing-data="hearingData" @update:selected-filters="handleSelectedFiltersUpdate"
@update:selected-filters="handleSelectedFiltersUpdate"
@filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange" @filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange"
@report-click="handleToReportDetail" /> @report-click="handleToReportDetail" />
</div> </div>
<div> <div>
<SurveyForm v-if="isSurveyForm" :research-type-list="researchTypeList" :research-time-list="researchTimeList" <SurveyForm v-if="isSurveyForm" :research-type-list="researchTypeList" :research-time-list="researchTimeList"
:key="`调查项目-${tabResetKey}`" :selected-filters="selectedFilters" :cur-footer-list="curFooterList" :total="total" :key="`调查项目-${tabResetKey}`" :selected-filters="selectedFilters" :cur-footer-list="curFooterList" :total="total"
:current-page="currentPage" :current-page="currentPage" @update:selected-filters="handleSelectedFiltersUpdate"
@update:selected-filters="handleSelectedFiltersUpdate"
@filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange" @filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange"
@report-click="handleToReportDetail" /> @report-click="handleToReportDetail" />
</div> </div>
...@@ -889,62 +886,4 @@ onMounted(async () => { ...@@ -889,62 +886,4 @@ onMounted(async () => {
} }
} }
:deep(.el-pagination) {
display: flex;
align-items: center;
}
:deep(.el-pagination.is-background .el-pager li) {
min-width: 32px;
height: 32px;
line-height: 32px;
border-radius: 6px;
margin: 0 6px;
border: 1px solid rgba(0, 0, 0, 0.15);
background-color: #fff;
color: rgb(95, 101, 108);
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
}
:deep(.el-pagination.is-background .el-pager li.is-active) {
background-color: #fff;
color: rgba(22, 119, 255, 1);
border-color: rgba(22, 119, 255, 1);
}
:deep(.el-pagination.is-background .el-pager li.is-ellipsis) {
border: none;
background-color: transparent;
color: rgb(95, 101, 108);
min-width: 16px;
margin: 0 6px;
}
:deep(.el-pagination.is-background .btn-prev),
:deep(.el-pagination.is-background .btn-next) {
min-width: 32px;
height: 32px;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.15);
background-color: #fff;
color: rgb(95, 101, 108);
font-size: 16px;
font-family: "Microsoft YaHei";
margin: 0 6px;
}
:deep(.el-pagination.is-background .btn-prev.is-disabled),
:deep(.el-pagination.is-background .btn-next.is-disabled) {
color: rgba(95, 101, 108, 0.45);
border-color: rgb(235, 238, 242);
background-color: #fff;
}
</style> </style>
\ No newline at end of file
...@@ -392,13 +392,11 @@ const handleGetThinkTankFundsSource = async () => { ...@@ -392,13 +392,11 @@ const handleGetThinkTankFundsSource = async () => {
console.log("获取经费来源", res); console.log("获取经费来源", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
let data = [] const topList = Array.isArray(res.data) ? res.data.slice(0, 7) : []
res.data.map(item => { const data = topList.map(item => ({
data.push({
name: item.institution, name: item.institution,
value: item.amount, value: item.amount,
}) }))
})
box1ChartData.value = data box1ChartData.value = data
const box1Chart = getPieChart(box1ChartData.value); const box1Chart = getPieChart(box1ChartData.value);
...@@ -1144,7 +1142,8 @@ onMounted(() => { ...@@ -1144,7 +1142,8 @@ onMounted(() => {
width: 536px; width: 536px;
height: 326px; height: 326px;
margin-left: 9px; margin-left: 9px;
box-sizing: border-box;
padding: 24px 24px 0;
} }
.box3-main-right { .box3-main-right {
......
<template>
<div class="home-main-footer-main">
<div class="left">
<div class="select-box">
<div class="header">
<div class="icon"></div>
<div class="title">{{ "科技领域" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-model="checkAllModel" :indeterminate="isIndeterminate" class="all-checkbox"
@change="emit('check-all-change', $event)">
全部领域
</el-checkbox>
<el-checkbox v-for="research in areaList" :key="research.id" v-model="selectedAreaListModel"
:label="research.id" @change="emit('checked-area-change')" class="filter-checkbox">
{{ research.name }}
</el-checkbox>
</div>
</div>
</div>
<div class="select-box">
<div class="header">
<div class="icon"></div>
<div class="title">{{ "发布时间" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-model="checkAllTimeModel" class="all-checkbox" :indeterminate="isIndeterminateTime"
@change="emit('check-all-time-change', $event)">
全部时间
</el-checkbox>
<el-checkbox-group v-model="selectedPubTimeListModel">
<el-checkbox v-for="time in pubTimeList" :key="time.id" :label="time.id" class="filter-checkbox"
@change="emit('checked-area-time-change')">
{{ time.name }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
</div>
<div class="right">
<div class="card-box">
<div class="footer-card" v-for="(item, index) in curFooterList" :key="index"
@click="emit('report-click', item)">
<div class="footer-card-top">
<img :src="item.imageUrl" alt="" />
</div>
<div class="footer-card-title">
{{ item.name }}
</div>
<div class="footer-card-footer">
<div class="time">{{ item.times }}</div>
<div class="from">{{ item.thinkTankName }}</div>
</div>
</div>
</div>
<div class="right-footer">
<div class="info">{{ total }} 篇政府报告</div>
<div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="emit('page-change', $event)" :current-page="currentPage" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
checkAll: { type: Boolean, default: false },
isIndeterminate: { type: Boolean, default: false },
areaList: { type: Array, default: () => [] },
selectedAreaList: { type: Array, default: () => [] },
checkAllTime: { type: Boolean, default: false },
isIndeterminateTime: { type: Boolean, default: false },
pubTimeList: { type: Array, default: () => [] },
selectedPubTimeList: { type: Array, default: () => [] },
curFooterList: { type: Array, default: () => [] },
total: { type: Number, default: 0 },
currentPage: { type: Number, default: 1 }
});
const emit = defineEmits([
"update:checkAll",
"update:selectedAreaList",
"check-all-change",
"checked-area-change",
"update:checkAllTime",
"update:selectedPubTimeList",
"check-all-time-change",
"checked-area-time-change",
"report-click",
"page-change"
]);
const checkAllModel = computed({
get: () => props.checkAll,
set: val => emit("update:checkAll", val)
});
const selectedAreaListModel = computed({
get: () => props.selectedAreaList,
set: val => emit("update:selectedAreaList", val)
});
const checkAllTimeModel = computed({
get: () => props.checkAllTime,
set: val => emit("update:checkAllTime", val)
});
const selectedPubTimeListModel = computed({
get: () => props.selectedPubTimeList,
set: val => emit("update:selectedPubTimeList", val)
});
</script>
<style lang="scss" scoped>
.home-main-footer-main {
margin: 0 auto;
margin-top: 36px;
width: 1600px;
display: flex;
gap: 16px;
.left {
width: 360px;
height: 100%;
padding-bottom: 36px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(94, 95, 95, 0.1);
background: rgba(255, 255, 255, 1);
position: relative;
.select-box {
margin-top: 21px;
.header {
display: flex;
gap: 17px;
.icon {
margin-top: 4px;
width: 8px;
height: 16px;
background: var(--color-main-active);
border-radius: 0 4px 4px 0;
}
.title {
height: 24px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
}
}
.select-main {
margin-left: 25px;
}
.select-main1 {
width: 100px;
}
}
}
.right {
width: 1284px;
max-height: 1377px;
.card-box {
width: 1226px;
max-height: 1248px;
min-height: 616px;
display: flex;
flex-wrap: wrap;
gap: 16px 16px;
.footer-card {
width: 398px;
height: 300px;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
.footer-card-top {
width: 364px;
height: 180px;
margin: 0 auto;
margin-top: 15px;
img {
width: 100%;
height: 100%;
}
}
.footer-card-title {
margin: 0 auto;
margin-top: 13px;
width: 376px;
height: 48px;
/* 修改高度为两行的高度 */
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 18px;
font-weight: 700;
line-height: 24px;
overflow: hidden;
/* 隐藏超出部分 */
text-overflow: ellipsis;
/* 显示省略号 */
display: -webkit-box;
/* 使用弹性盒模型 */
-webkit-line-clamp: 2;
/* 限制显示两行 */
-webkit-box-orient: vertical;
/* 设置盒模型方向为垂直 */
}
.footer-card-footer {
margin: 0 auto;
margin-top: 5px;
width: 376px;
height: 22px;
display: flex;
justify-content: space-between;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
}
}
.right-footer {
height: 50px;
margin-top: 43px;
display: flex;
justify-content: space-between;
.info {
height: 19px;
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0px;
text-align: left;
}
}
}
}
.all-checkbox {
width: 220px;
}
.filter-checkbox {
width: 105px;
}
</style>
<template>
<!-- 调查项目:结构/样式与智库报告一致,但组件独立,避免互相影响 -->
<div class="home-main-footer-main">
<div class="left">
<div class="select-box">
<div class="header">
<div class="icon"></div>
<div class="title">{{ "科技领域" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-model="checkAllModel" :indeterminate="isIndeterminate" class="all-checkbox"
@change="emit('check-all-change', $event)">
全部领域
</el-checkbox>
<el-checkbox v-for="research in areaList" :key="research.id" v-model="selectedAreaListModel"
:label="research.id" @change="emit('checked-area-change')" class="filter-checkbox">
{{ research.name }}
</el-checkbox>
</div>
</div>
</div>
<div class="select-box">
<div class="header">
<div class="icon"></div>
<div class="title">{{ "发布时间" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-model="checkAllTimeModel" class="all-checkbox" :indeterminate="isIndeterminateTime"
@change="emit('check-all-time-change', $event)">
全部时间
</el-checkbox>
<el-checkbox-group v-model="selectedPubTimeListModel">
<el-checkbox v-for="time in pubTimeList" :key="time.id" :label="time.id" class="filter-checkbox"
@change="emit('checked-area-time-change')">
{{ time.name }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
</div>
<div class="right">
<div class="card-box">
<div class="footer-card" v-for="(item, index) in curFooterList" :key="index"
@click="emit('report-click', item)">
<div class="footer-card-top">
<img :src="item.imageUrl" alt="" />
</div>
<div class="footer-card-title">
{{ item.name }}
</div>
<div class="footer-card-footer">
<div class="time">{{ item.times }}</div>
<div class="from">{{ item.thinkTankName }}</div>
</div>
</div>
</div>
<div class="right-footer">
<div class="info">{{ total }} 篇调查项目</div>
<div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="emit('page-change', $event)" :current-page="currentPage" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
checkAll: { type: Boolean, default: false },
isIndeterminate: { type: Boolean, default: false },
areaList: { type: Array, default: () => [] },
selectedAreaList: { type: Array, default: () => [] },
checkAllTime: { type: Boolean, default: false },
isIndeterminateTime: { type: Boolean, default: false },
pubTimeList: { type: Array, default: () => [] },
selectedPubTimeList: { type: Array, default: () => [] },
curFooterList: { type: Array, default: () => [] },
total: { type: Number, default: 0 },
currentPage: { type: Number, default: 1 }
});
const emit = defineEmits([
"update:checkAll",
"update:selectedAreaList",
"check-all-change",
"checked-area-change",
"update:checkAllTime",
"update:selectedPubTimeList",
"check-all-time-change",
"checked-area-time-change",
"report-click",
"page-change"
]);
const checkAllModel = computed({
get: () => props.checkAll,
set: val => emit("update:checkAll", val)
});
const selectedAreaListModel = computed({
get: () => props.selectedAreaList,
set: val => emit("update:selectedAreaList", val)
});
const checkAllTimeModel = computed({
get: () => props.checkAllTime,
set: val => emit("update:checkAllTime", val)
});
const selectedPubTimeListModel = computed({
get: () => props.selectedPubTimeList,
set: val => emit("update:selectedPubTimeList", val)
});
</script>
<style lang="scss" scoped>
/* 复制 HomeMainFooterMain 的样式,保证完全不影响外观 */
.home-main-footer-main {
margin: 0 auto;
margin-top: 36px;
width: 1600px;
display: flex;
gap: 16px;
.left {
width: 360px;
height: 100%;
padding-bottom: 36px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(94, 95, 95, 0.1);
background: rgba(255, 255, 255, 1);
position: relative;
.select-box {
margin-top: 21px;
.header {
display: flex;
gap: 17px;
.icon {
margin-top: 4px;
width: 8px;
height: 16px;
background: var(--color-main-active);
border-radius: 0 4px 4px 0;
}
.title {
height: 24px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
}
}
.select-main {
margin-left: 25px;
}
.select-main1 {
width: 100px;
}
}
}
.right {
width: 1284px;
max-height: 1377px;
.card-box {
width: 1226px;
max-height: 1248px;
min-height: 616px;
display: flex;
flex-wrap: wrap;
gap: 16px 16px;
.footer-card {
width: 398px;
height: 300px;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
.footer-card-top {
width: 364px;
height: 180px;
margin: 0 auto;
margin-top: 15px;
img {
width: 100%;
height: 100%;
}
}
.footer-card-title {
margin: 0 auto;
margin-top: 13px;
width: 376px;
height: 48px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 18px;
font-weight: 700;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.footer-card-footer {
margin: 0 auto;
margin-top: 5px;
width: 376px;
height: 22px;
display: flex;
justify-content: space-between;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
}
}
.right-footer {
height: 50px;
margin-top: 43px;
display: flex;
justify-content: space-between;
.info {
height: 19px;
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0px;
text-align: left;
}
}
}
}
.all-checkbox {
width: 220px;
}
.filter-checkbox {
width: 105px;
}
</style>
<template>
<div class="home-main-footer-main">
<div class="left">
<div class="select-box-science">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">{{ "科技领域" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox class="filter-checkbox" :model-value="isAllSelected(typeIds)"
@change="val => toggleAll(val, typeIds)">
全部领域
</el-checkbox>
<el-checkbox class="filter-checkbox" v-for="t in (researchTypeList || [])" :key="t.id"
v-model="selectedTypeIds" :label="t.id" @change="emitChange">
{{ t.name }}
</el-checkbox>
</div>
</div>
</div>
<div class="select-box-publish">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">{{ "发布时间" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox class="filter-checkbox" :model-value="isAllSelected(yearIds)"
@change="val => toggleAll(val, yearIds)">
全部时间
</el-checkbox>
<el-checkbox class="filter-checkbox" v-for="y in (researchTimeList || [])" :key="y.id"
v-model="selectedYearIds" :label="y.id" @change="emitChange">
{{ y.name }}
</el-checkbox>
</div>
</div>
</div>
</div>
<div class="right">
<div class="right-main">
<div class="right-main-item" v-for="(item, index) in list" :key="index" @click="emit('item-click', item)">
<div class="item-left">
<img :src="item.coverImage" alt="" />
</div>
<div class="item-right">
<div class="title">{{ item.content }}</div>
<div class="info">
<span class="info-text">{{ item.date }} · {{ item.title }}</span>
<div class="more">
<img src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image open.png" alt="" />
</div>
</div>
<div class="tag-box" v-if="item.domains && item.domains.length">
<AreaTag v-for="d in item.domains" :key="d" :tagName="d" />
</div>
</div>
</div>
</div>
<div class="right-footer">
<div class="info">{{ total }}条政策建议</div>
<div class="page-box">
<el-pagination :page-size="pageSize" background layout="prev, pager, next" :total="total"
@current-change="p => emit('page-change', p)" :current-page="currentPage" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed, ref } from "vue";
import AreaTag from "@/components/base/AreaTag/index.vue";
const props = defineProps({
researchTypeList: { type: Array, default: () => [] },
researchTimeList: { type: Array, default: () => [] },
list: { type: Array, default: () => [] },
total: { type: Number, default: 0 },
currentPage: { type: Number, default: 1 },
pageSize: { type: Number, default: 7 },
});
const emit = defineEmits(["filter-change", "page-change", "item-click"]);
const selectedTypeIds = ref([]);
const selectedYearIds = ref([]);
const typeIds = computed(() => (props.researchTypeList || []).map(i => i.id));
const yearIds = computed(() => (props.researchTimeList || []).map(i => i.id));
const isAllSelected = ids => ids.length > 0 && ids.every(id => {
const target = ids === typeIds.value ? selectedTypeIds.value : selectedYearIds.value
return target.includes(id)
});
const toggleAll = (checked, ids) => {
const target = ids === typeIds.value ? selectedTypeIds : selectedYearIds
target.value = checked ? [...ids] : []
emitChange()
}
const emitChange = () => {
emit("filter-change", {
researchTypeIds: [...selectedTypeIds.value],
researchTimeIds: [...selectedYearIds.value],
})
}
</script>
<style lang="scss" scoped>
/* 最外层对齐智库报告资源库布局 */
.home-main-footer-main {
margin: 0 auto;
margin-top: 36px;
width: 1600px;
display: flex;
gap: 16px;
.left {
width: 360px;
height: 100%;
padding-bottom: 36px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
.select-box-science,
.select-box-publish {
margin-top: 16px;
.select-box-header {
display: flex;
.icon {
margin-top: 4px;
width: 8px;
height: 16px;
background: var(--color-main-active);
border-radius: 0 4px 4px 0;
}
.title {
margin-left: 17px;
font-family: "Source Han Sans CN";
font-weight: 700;
font-size: 16px;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
color: rgba(5, 95, 194, 1);
}
}
.select-main {
margin-top: 12px;
}
.checkbox-group {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px 4px;
margin-left: 24px;
.filter-checkbox {
width: 160px;
margin: 0;
font-family: "Source Han Sans CN", sans-serif;
font-weight: 400;
font-size: 16px;
line-height: 24px;
letter-spacing: 0px;
text-align: justify;
}
}
}
}
.right {
width: 1224px;
height: 1200px;
margin-bottom: 20px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
.right-main {
height: 1100px;
margin-top: 17px;
margin-left: 0;
width: 100%;
box-sizing: border-box;
padding-left: 37px;
padding-right: 0;
.right-main-item {
box-sizing: border-box;
padding-top: 16px;
padding-bottom: 16px;
margin-left: -37px;
padding-left: 37px;
padding-right: 36px;
width: calc(100% + 37px - 36px);
border-bottom: 1px solid rgba(234, 236, 238, 1);
display: flex;
align-items: center;
cursor: pointer;
.item-left {
width: 112px;
height: 76px;
margin-right: 22px;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
}
}
.item-right {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
.title {
color: rgba(59, 65, 75, 1);
font-family: "Source Han Sans CN";
font-size: 18px;
font-weight: 700;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.info {
margin-top: 7px;
color: rgba(95, 101, 108, 1);
font-family: "Source Han Sans CN";
font-size: 14px;
font-weight: 400;
line-height: 22px;
display: flex;
align-items: center;
.info-text {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.more {
flex-shrink: 0;
img {
width: 16px;
height: 16px;
display: block;
margin-left: 9px;
margin-top: 3px;
}
}
}
.tag-box {
margin-top: 6px;
display: flex;
flex-wrap: wrap;
gap: 8px;
}
}
}
}
.right-footer {
margin-top: 24px;
padding: 0 37px 24px 37px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
}
</style>
...@@ -2,31 +2,73 @@ import * as echarts from 'echarts'; ...@@ -2,31 +2,73 @@ import * as echarts from 'echarts';
const getMultiLineChart = (data) => { const getMultiLineChart = (data) => {
// 提取标题和系列数据 // 提取标题和系列数据
// const { title, series } = data;
const title = data.title const title = data.title
const series = data.data const series = data.data
// 定义配色数组
const colorList = [
'rgba(5, 95, 194, 1)', // #055fc2
'rgba(19, 168, 168, 1)', // #13a8a8
'rgba(250, 140, 22, 1)', // #fa8c16
'rgba(114, 46, 209, 1)', // #722ed1
'rgba(115, 209, 61, 1)', // #73d13d
'rgba(206, 79, 81, 1)', // #ce4f51
'rgba(145, 202, 255, 1)', // #91caff
'rgba(95, 101, 108, 1)', // #5f656c
'rgba(250, 84, 28, 1)', // #fa541c
'rgba(47, 84, 235, 1)', // #2f54eb
'rgba(64, 150, 255, 1)', // #4096ff
'rgba(34, 41, 52, 1)', // #222934
'rgba(173, 198, 255, 1)', // #adc6ff
'rgba(255, 169, 64, 1)' // #ffa940
];
// 解析 RGBA 颜色的辅助函数
const parseRgba = (colorStr) => {
// 匹配 rgba(r, g, b, a) 格式
const match = colorStr.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)/);
if (match) {
return {
r: parseInt(match[1]),
g: parseInt(match[2]),
b: parseInt(match[3]),
a: parseFloat(match[4])
};
}
// 默认返回黑色
return { r: 0, g: 0, b: 0, a: 1 };
};
// 动态生成 series 配置 // 动态生成 series 配置
const echartsSeries = series.map((item, index) => ({ const echartsSeries = series.map((item, index) => {
// 获取当前系列的颜色(优先使用item.color,否则用预设颜色,再否则随机)
const baseColor = item.color || colorList[index % colorList.length] || `rgba(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 1)`;
const { r, g, b } = parseRgba(baseColor);
return ({
name: item.name, name: item.name,
type: 'line', type: 'line',
// areaStyle: { // 新增/优化:面积填充渐变效果
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ areaStyle: {
// { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// offset: 0, {
// color: item.color || `rgba(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 0.7)` // 随机颜色 offset: 0, // 顶部
// }, color: `rgba(${r}, ${g}, ${b}, 0.3)` // 0.3 透明度
// { },
// offset: 1, {
// color: item.color ? `${item.color.replace('0.7', '0')}` : `rgba(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 0)` // 随机颜色 offset: 1, // 底部
// } color: `rgba(${r}, ${g}, ${b}, 0)` // 0 透明度
// ]) }
// }, ])
},
symbolSize: 8,
emphasis: { emphasis: {
focus: 'series' focus: 'series'
}, },
data: item.value data: item.value
})); });
});
return { return {
tooltip: { tooltip: {
...@@ -50,9 +92,16 @@ const getMultiLineChart = (data) => { ...@@ -50,9 +92,16 @@ const getMultiLineChart = (data) => {
top: 10, top: 10,
left: 'center', left: 'center',
icon: 'circle', icon: 'circle',
textStyle: {
fontFamily: 'Source Han Sans CN', // 字体
fontWeight: 400, // 字重值(Regular对应400)
fontSize: 14, // 字号
lineHeight: 24, // 行高
letterSpacing: 0, // 字间距
align: 'left' // 文本左对齐
}
}, },
// color: series.map(item => item.color || `rgba(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 0.7)`), // 动态颜色 color: colorList, // 使用预设的配色数组
color: ['#055fc2', '#13a8a8', '#fa8c16', '#722ed1', '#73d13d', '#ce4f51', '#91caff', '#5f656c', '#fa541c', '#2f54eb', '#4096ff', '#222934', '#adc6ff', '#ffa940'], // 色彩调和的折线图配色方案
xAxis: [ xAxis: [
{ {
type: 'category', type: 'category',
...@@ -62,7 +111,15 @@ const getMultiLineChart = (data) => { ...@@ -62,7 +111,15 @@ const getMultiLineChart = (data) => {
], ],
yAxis: [ yAxis: [
{ {
type: 'value' type: 'value',
splitLine: {
show: true, // 显示网格线
lineStyle: {
color: 'rgba(231, 241, 255, 1)',
type: 'dashed',
width: 1
}
}
} }
], ],
series: echartsSeries series: echartsSeries
......
...@@ -20,7 +20,13 @@ const getPieChart = (data) => { ...@@ -20,7 +20,13 @@ const getPieChart = (data) => {
}, },
label: { label: {
alignTo: 'edge', alignTo: 'edge',
formatter: '{name|{b}}\n{time|{c} 条 {d}%}', formatter: params => {
const name = params.name || "";
const value = params.value ?? "";
const percent = params.percent != null ? Math.round(params.percent) : 0;
return `{name|${name}}\n{time|${value}${percent}%}`;
},
minMargin: 5, minMargin: 5,
edgeDistance: 10, edgeDistance: 10,
lineHeight: 20, lineHeight: 20,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论