提交 7298bb9b authored 作者: 张伊明's avatar 张伊明

合并分支 'zym-dev' 到 'master'

Zym dev 查看合并请求 !156
<template>
<div class="background-wrap">
<div class="background-wrap-left">
<div class="background-wrap-left-box1">
<!-- <div class="box-header">
<div class="header-left"></div>
<div class="title">立法背景</div>
<AnalysisBox class="left-box left-box--background" title="立法背景" :showAllBtn="false">
<template #header-btn>
<div class="header-btn-box">
<div class="btn" @click="handleClickBox1Btn(1)">
<el-button type="primary" plain v-if="box1BtnActive === 1">涉华背景</el-button>
<el-button type="info" plain v-else>涉华背景</el-button>
</div>
<div class="btn" @click="handleClickBox1Btn(2)">
<el-button type="primary" plain v-if="box1BtnActive === 2">全部背景</el-button>
<el-button type="info" plain v-else>全部背景</el-button>
</div>
</div>
<div class="header-right">
<div class="icon">
<img src="@/assets/icons/box-header-icon2.png" alt="" />
</div>
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
<el-button :type="box1Btn1Type" plain @click="handleClickBox1Btn(1)">涉华背景</el-button>
<el-button :type="box1Btn2Type" plain @click="handleClickBox1Btn(2)">全部背景</el-button>
</div>
</div>
</template>
<div class="box1-main">
<div class="box1-main-center">
<div class="box1-main-item" v-for="(item, index) in backgroundList" :key="item.id">
<div class="id">{{ (currentPage - 1) * 10 + index + 1 }}</div>
<div class="box1-main-item" v-for="item in backgroundDisplayList" :key="item.id">
<div class="id">{{ item.displayIndex }}</div>
<div class="title">{{ item.backgroundTitle }}</div>
<div class="share">
<img src="./assets/icons/open.png" alt="打开" />
</div>
</div>
</div>
<div class="box1-main-footer">
<div class="info">
{{ `共 ${total} 项` }}
</div>
<div class="page-box">
<el-pagination background layout="prev, pager, next" :total="total" v-model:current-page="currentPage"
@current-change="handleGetBillBackground" />
</div>
</div>
</div> -->
<AnalysisBox title="立法背景" :showAllBtn="false">
<template #header-btn>
<div class="header-btn-box">
<div class="btn" @click="handleClickBox1Btn(1)">
<el-button type="primary" plain v-if="box1BtnActive === 1">涉华背景</el-button>
<el-button type="info" plain v-else>涉华背景</el-button>
</div>
<div class="btn" @click="handleClickBox1Btn(2)">
<el-button type="primary" plain v-if="box1BtnActive === 2">全部背景</el-button>
<el-button type="info" plain v-else>全部背景</el-button>
</div>
</div>
</template>
<div class="box1-main">
<div class="box1-main-center">
<div class="box1-main-item" v-for="(item, index) in backgroundList" :key="item.id">
<div class="id">{{ (currentPage - 1) * 10 + index + 1 }}</div>
<div class="title">{{ item.backgroundTitle }}</div>
<div class="share">
<!-- <img src="./assets/icons/open.png" alt="打开" /> -->
</div>
</div>
</div>
<div class="box1-main-footer">
<div class="info">
{{ `共 ${total} 项` }}
</div>
<div class="page-box">
<el-pagination background layout="prev, pager, next" :total="total" v-model:current-page="currentPage"
@current-change="handleGetBillBackground" />
</div>
</div>
</div>
</AnalysisBox>
</div>
<div class="background-wrap-left-box2">
<!-- <div class="box-header">
<div class="header-left"></div>
<div class="title">相关事件</div>
<div class="header-right">
<div class="icon">
<img src="@/assets/icons/box-header-icon2.png" alt="" />
</div>
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
{{ totalText }}
</div>
<el-pagination background layout="prev, pager, next" :total="total" v-model:current-page="currentPage"
@current-change="handleGetBillBackground" />
</div>
</div>
</AnalysisBox>
<AnalysisBox class="left-box left-box--event" title="相关事件" :showAllBtn="false">
<div class="box2-main">
<div class="box2-main-item" v-for="(item, index) in eventList" :key="index" @click="handleClickEvent(item)">
<div class="box2-main-item" v-for="item in eventDisplayList" :key="item.id" @click="handleClickEvent(item)">
<div class="left">
<img :src="item.imageUrl || defaultNew" @error="e => (e.target.src = defaultNew)" alt="" />
<img :src="item.imgSrc" @error="handleNewsImgError" alt="" />
</div>
<div class="center">
<CommonPrompt :content="item.sjbt">
......@@ -106,85 +44,46 @@
</div>
<div class="right">{{ item.sjsj }}</div>
</div>
</div> -->
<AnalysisBox title="相关事件" :showAllBtn="false">
<div class="box2-main">
<div class="box2-main-item" v-for="(item, index) in eventList" :key="index" @click="handleClickEvent(item)">
<div class="left">
<img :src="item.imageUrl || defaultNew" @error="e => (e.target.src = defaultNew)" alt="" />
</div>
<div class="center">
<CommonPrompt :content="item.sjbt">
<div class="title">{{ item.sjbt }}</div>
</CommonPrompt>
<CommonPrompt :content="item.sjnr">
<div class="content">{{ item.sjnr }}</div>
</CommonPrompt>
</div>
<div class="right">{{ item.sjsj }}</div>
</div>
</div>
</AnalysisBox>
</div>
</div>
</AnalysisBox>
</div>
<div class="background-wrap-right">
<!-- <div class="box-header">
<div class="header-left"></div>
<div class="title">议员相关性分析</div>
<AnalysisBox class="right-panel" title="议员相关性分析" :showAllBtn="false">
<template #header-btn>
<div class="header-btn-box">
<div class="btn" @click="handleClickBox2Btn(1)">
<el-button type="primary" plain v-if="box2BtnActive === 1">赞成议员</el-button>
<el-button type="info" plain v-else>赞成议员</el-button>
</div>
<div class="btn" @click="handleClickBox2Btn(2)">
<el-button type="primary" plain v-if="box2BtnActive === 2">反对议员</el-button>
<el-button type="info" plain v-else>反对议员</el-button>
</div>
<el-button :type="box2Btn1Type" plain @click="handleClickBox2Btn(1)">赞成议员</el-button>
<el-button :type="box2Btn2Type" plain @click="handleClickBox2Btn(2)">反对议员</el-button>
</div>
<div class="header-right">
<div class="icon">
<img src="@/assets/icons/box-header-icon2.png" alt="" />
</div>
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
</div>
</div>
</template>
<div class="background-wrap-right-main">
<div class="right-box1">
<div class="right-box1-main">
<div class="right-box1-main-top">
<el-icon style="margin-top: 20px; cursor: pointer" size="20"
:color="currentIndex > 0 ? '#5f656c' : '#ccc'" @click="handlePrev">
<CaretLeft />
</el-icon>
<div class="user-list-container">
<div class="user-list-wrapper" :style="{ transform: `translateX(-${currentIndex * 110}px)` }">
<div class="user-box" v-for="(item, index) in personList" :key="index" @click="handleClickUser(item)">
<div class="img-box">
<img :src="item.image" alt="" />
<div class="icon1">
<img :src="item.icon" alt="" />
</div>
<div class="icon2">
<img :src="item.icon1" alt="" />
</div>
<div class="right-box1-main-top">
<el-icon class="nav-icon" size="20" :color="prevIconColor" @click="handlePrev">
<CaretLeft />
</el-icon>
<div class="user-list-container">
<div class="user-list-wrapper" :style="userListWrapperStyle">
<div class="user-box" v-for="item in personList" :key="item.id" @click="handleClickUser(item)">
<div class="img-box">
<img :src="item.image" alt="" />
<div class="icon1">
<img :src="item.icon" alt="" />
</div>
<div class="icon2">
<img :src="item.icon1" alt="" />
</div>
<CommonPrompt :content="item.name">
<div class="name">{{ item.name }}</div>
</CommonPrompt>
</div>
<CommonPrompt :content="item.name">
<div class="name">{{ item.name }}</div>
</CommonPrompt>
</div>
</div>
<el-icon style="margin-top: 20px; cursor: pointer" size="20"
:color="currentIndex < personList.length - 4 ? '#5f656c' : '#ccc'" @click="handleNext">
<CaretRight />
</el-icon>
</div>
<div class="right-box1-main-bottom">
<WordCloudMap :data="wordCloudData" :selectedName="selectedIndustryName" shape="circle"
@wordClick="handleWordClick" />
</div>
<el-icon class="nav-icon" size="20" :color="nextIconColor" @click="handleNext">
<CaretRight />
</el-icon>
</div>
<div class="right-box1-main-bottom">
<WordCloudMap :data="wordCloudData" :selectedName="selectedIndustryName" shape="circle" @wordClick="handleWordClick" />
</div>
</div>
<div class="right-box2">
......@@ -194,7 +93,7 @@
</div>
</div>
<div class="right-box2-center">
<div class="user-box" v-for="(item, index) in aboutUserList" :key="index" @click="handleClickUser(item)">
<div class="user-box" v-for="item in aboutUserList" :key="item.id" @click="handleClickUser(item)">
<div class="user-left">
<div class="img-box">
<img :src="item.img" alt="" />
......@@ -209,111 +108,30 @@
</div>
</div>
</div>
</div> -->
<AnalysisBox title="议员相关性分析" :showAllBtn="false">
<template #header-btn>
<div class="header-btn-box">
<div class="btn" @click="handleClickBox2Btn(1)">
<el-button type="primary" plain v-if="box2BtnActive === 1">赞成议员</el-button>
<el-button type="info" plain v-else>赞成议员</el-button>
</div>
<div class="btn" @click="handleClickBox2Btn(2)">
<el-button type="primary" plain v-if="box2BtnActive === 2">反对议员</el-button>
<el-button type="info" plain v-else>反对议员</el-button>
</div>
</div>
</template>
<div class="background-wrap-right-main">
<div class="right-box1">
<div class="right-box1-main">
<div class="right-box1-main-top">
<el-icon style="margin-top: 20px; cursor: pointer" size="20"
:color="currentIndex > 0 ? '#5f656c' : '#ccc'" @click="handlePrev">
<CaretLeft />
</el-icon>
<div class="user-list-container">
<div class="user-list-wrapper" :style="{ transform: `translateX(-${currentIndex * 110}px)` }">
<div class="user-box" v-for="(item, index) in personList" :key="index"
@click="handleClickUser(item)">
<div class="img-box">
<img :src="item.image" alt="" />
<div class="icon1">
<img :src="item.icon" alt="" />
</div>
<div class="icon2">
<img :src="item.icon1" alt="" />
</div>
</div>
<CommonPrompt :content="item.name">
<div class="name">{{ item.name }}</div>
</CommonPrompt>
</div>
</div>
</div>
<el-icon style="margin-top: 20px; cursor: pointer" size="20"
:color="currentIndex < personList.length - 4 ? '#5f656c' : '#ccc'" @click="handleNext">
<CaretRight />
</el-icon>
</div>
<div class="right-box1-main-bottom">
<WordCloudMap :data="wordCloudData" :selectedName="selectedIndustryName" shape="circle"
@wordClick="handleWordClick" />
</div>
</div>
</div>
<div class="right-box2">
<div class="right-box2-header">
<div class="title">
<span class="title-active">"{{ selectedIndustryName }}"</span>涉及议员动态 >
</div>
</div>
<div class="right-box2-center">
<div class="user-box" v-for="(item, index) in aboutUserList" :key="index" @click="handleClickUser(item)">
<div class="user-left">
<div class="img-box">
<img :src="item.img" alt="" />
</div>
</div>
<div class="user-right">
<div class="name">{{ item.name }}</div>
<CommonPrompt :content="item.content">
<div class="content">{{ item.content }}</div>
</CommonPrompt>
</div>
</div>
</div>
</div>
</div>
</AnalysisBox>
</div>
</div>
</AnalysisBox>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
import { computed, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import WordCloudMap from "./WordCloudMap.vue";
import CommonPrompt from "../commonPrompt/index.vue";
const route = useRoute();
const router = useRouter();
import event1 from "./assets/images/event1.png";
import event2 from "./assets/images/event2.png";
import event3 from "./assets/images/event3.png";
import event4 from "./assets/images/event4.png";
import event5 from "./assets/images/event5.png";
import user1 from "./assets/images/user1.png";
import user2 from "./assets/images/user2.png";
import user3 from "./assets/images/user3.png";
import user4 from "./assets/images/user4.png";
import user5 from "./assets/images/user5.png";
import userIcon from "./assets/icons/user-icon.png";
import userIcon1 from "./assets/icons/user-icon1.png";
import userIcon2 from "./assets/icons/user-icon2.png";
import defaultNew from "../assets/images/default-icon-news.png";
import defaultA from "../assets/images/default-icon1.png";
import { getBillBackground, getBillEvent, getBillPersonAnalyze, getBillInfoEvent, getBillPersonAnalyzeDy } from "@/api/bill";
import { getBillBackground, getBillPersonAnalyze, getBillInfoEvent, getBillPersonAnalyzeDy } from "@/api/bill";
const route = useRoute();
const router = useRouter();
const handleNewsImgError = e => {
e.target.src = defaultNew;
};
// 跳转到相关新闻
const handleClickEvent = item => {
......@@ -397,6 +215,34 @@ const handleWordClick = word => {
const wordCloudData = ref([]);
const totalText = computed(() => `共 ${total.value} 项`);
const backgroundDisplayList = computed(() =>
backgroundList.value.map((item, index) => ({
...item,
displayIndex: (currentPage.value - 1) * 10 + index + 1
}))
);
const eventDisplayList = computed(() =>
eventList.value.map(item => ({
...item,
imgSrc: item.imageUrl || defaultNew
}))
);
const userListWrapperStyle = computed(() => ({
transform: `translateX(-${currentIndex.value * 110}px)`
}));
const box1Btn1Type = computed(() => (box1BtnActive.value === 1 ? "primary" : "info"));
const box1Btn2Type = computed(() => (box1BtnActive.value === 2 ? "primary" : "info"));
const box2Btn1Type = computed(() => (box2BtnActive.value === 1 ? "primary" : "info"));
const box2Btn2Type = computed(() => (box2BtnActive.value === 2 ? "primary" : "info"));
const prevIconColor = computed(() => (currentIndex.value > 0 ? "#5f656c" : "#ccc"));
const nextIconColor = computed(() => (currentIndex.value < personList.value.length - 4 ? "#5f656c" : "#ccc"));
// 获取立法背景内容
const handleGetBillBackground = async () => {
const cRelated = box1BtnActive.value === 1 ? "Y" : "N";
......@@ -408,7 +254,6 @@ const handleGetBillBackground = async () => {
};
try {
const res = await getBillBackground(params);
console.log("立法背景", res);
backgroundList.value = res.data.content;
total.value = res.data.totalElements; // 假设API返回totalElements
} catch (error) { }
......@@ -421,21 +266,7 @@ const handleGetRelatedEvent = async () => {
};
try {
const res = await getBillInfoEvent(params);
console.log("相关事件", res);
eventList.value = res.data;
eventList.value.forEach((item, index) => {
if (index === 0) {
item.image = event1;
} else if (index === 1) {
item.image = event2;
} else if (index === 2) {
item.image = event3;
} else if (index === 3) {
item.image = event4;
} else {
item.image = event5;
}
});
} catch (error) { }
};
......@@ -447,7 +278,6 @@ const handleGetBillPersonAnalyze = async isOppose => {
};
try {
const res = await getBillPersonAnalyze(params);
console.log("议员相关性分析", res);
const { members, industryCounts } = res.data;
// 更新人员列表
personList.value = members || [];
......@@ -490,7 +320,6 @@ const handleGetBillPersonAnalyzeDy = async () => {
};
try {
const res = await getBillPersonAnalyzeDy(params);
console.log("议员相关性分析领域人物动态", res);
aboutUserList.value = (res.data || []).map(m => ({
id: m.id,
img: m.imageUrl || defaultA,
......@@ -512,10 +341,7 @@ onMounted(() => {
<style lang="scss" scoped>
.header-btn-box {
display: flex;
.btn {
margin-left: 8px;
}
gap: 8px;
:deep(.el-button) {
height: 28px;
......@@ -562,127 +388,45 @@ onMounted(() => {
height: 100%;
box-sizing: border-box;
display: flex;
.box-header {
height: 56px;
display: flex;
position: relative;
.header-left {
margin-top: 18px;
width: 8px;
height: 20px;
border-radius: 0 4px 4px 0;
background: var(--color-main-active);
}
.title {
margin-left: 14px;
margin-top: 14px;
height: 26px;
line-height: 26px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 20px;
font-weight: 700;
}
.header-btn-box {
position: absolute;
top: 14px;
right: 84px;
display: flex;
.btn {
margin-left: 8px;
}
:deep(.el-button) {
height: 28px;
padding: 2px 8px;
border-radius: 4px;
font-size: 16px;
font-weight: 400;
font-family: Microsoft YaHei;
line-height: 24px;
}
:deep(.el-button--primary.is-plain) {
background-color: #f0f7ff;
border-color: rgb(5, 95, 194);
color: rgb(5, 95, 194);
border-width: 1px;
&:hover,
&:focus {
background-color: #f0f7ff;
border-color: rgb(5, 95, 194);
color: rgb(5, 95, 194);
}
}
:deep(.el-button--info.is-plain) {
background-color: #fff;
border-color: rgb(230, 231, 232);
color: rgb(59, 65, 75);
&:hover,
&:focus {
background-color: #fff;
border-color: rgb(230, 231, 232);
color: rgb(59, 65, 75);
}
}
}
.header-right {
position: absolute;
top: 14px;
right: 12px;
display: flex;
justify-content: flex-end;
gap: 4px;
.icon {
width: 28px;
height: 28px;
img {
width: 100%;
height: 100%;
}
}
}
}
align-items: flex-start;
.background-wrap-left {
width: 1064px;
margin-top: 16px;
.background-wrap-left-box1 {
.left-box {
width: 1064px;
height: 415px;
}
.left-box--background {
height: auto;
.box1-main {
.box1-main-center {
margin: 0 auto;
width: 1016px;
height: 280px;
height: auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-content: flex-start;
flex-direction: column;
gap: 8px;
padding: 8px 0;
box-sizing: border-box;
.box1-main-item {
width: 500px;
height: 48px;
width: 100%;
box-sizing: border-box;
border: 1px solid rgba(243, 243, 244, 1);
border-radius: 2px;
background: rgba(255, 255, 255, 1);
border: none;
background: #fff;
display: flex;
margin-top: 8px;
align-items: center;
padding: 12px 16px 12px 18px;
&:nth-child(odd) {
background: rgb(247, 248, 249);
}
&:nth-child(even) {
background: #fff;
}
.id {
width: 24px;
......@@ -694,28 +438,34 @@ onMounted(() => {
line-height: 24px;
font-size: 12px;
font-weight: 400;
margin: 12px 16px 12px 18px;
margin-right: 16px;
flex: 0 0 auto;
}
.title {
width: 440px;
height: 48px;
line-height: 48px;
flex: 1 1 auto;
min-width: 0;
line-height: 24px;
color: rgb(59, 65, 75);
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
text-align: left;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
word-break: break-word;
}
.share {
margin-left: 13px;
margin-top: 16px;
margin-left: 12px;
width: 16px;
height: 16px;
padding: 2px;
cursor: pointer;
flex: 0 0 auto;
img {
width: 100%;
......@@ -726,7 +476,7 @@ onMounted(() => {
}
.box1-main-footer {
margin: 30px 22px 0 22px;
margin: 28px 22px;
height: 22px;
display: flex;
justify-content: space-between;
......@@ -744,18 +494,20 @@ onMounted(() => {
}
}
.background-wrap-left-box2 {
.left-box--event {
margin-top: 15px;
width: 1064px;
height: 415px;
height: auto;
.box2-main {
width: 1010px;
margin: 0 auto;
height: 349px;
--event-item-height: 60px;
width: calc(100% - 44px);
margin: 22px 22px;
height: auto;
max-height: calc(var(--event-item-height) * 5);
overflow-y: auto;
.box2-main-item {
width: 1005px;
width: 100%;
height: 60px;
border-radius: 2px;
box-sizing: border-box;
......@@ -779,7 +531,8 @@ onMounted(() => {
.center {
margin-left: 14px;
width: 805px;
flex: 1 1 auto;
min-width: 0;
.title {
height: 22px;
......@@ -813,6 +566,7 @@ onMounted(() => {
.right {
margin-left: 25px;
flex: 0 0 auto;
line-height: 60px;
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
......@@ -824,233 +578,141 @@ onMounted(() => {
}
}
}
.box2-footer {
margin-top: 7px;
display: flex;
justify-content: center;
.btn-more {
width: 108px;
height: 32px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
}
}
}
.background-wrap-right {
.right-panel {
margin-right: 18px;
margin-left: 16px;
margin-top: 16px;
width: 520px;
height: 845px;
max-height: 824px;
padding-bottom: 30px;
height: auto !important;
display: flex;
flex-direction: column;
overflow: hidden;
:deep(.wrapper-main) {
height: auto !important;
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
}
.background-wrap-right-main {
.right-box1 {
height: 365px;
height: auto;
overflow: hidden;
.right-box1-header {
height: 22px;
margin: 0 auto;
.nav-icon {
margin-top: 20px;
cursor: pointer;
}
.right-box1-main-top {
margin-top: 17px;
margin-left: 16px;
width: 490px;
display: flex;
justify-content: space-between;
.icon {
margin: 1px 12px 3px 0;
width: 16px;
height: 16px;
.user-list-container {
width: 440px; // 4个 user-box 的宽度 (110 * 4)
overflow: hidden;
img {
width: 100%;
height: 100%;
.user-list-wrapper {
display: flex;
transition: transform 0.3s ease;
}
}
.title {
height: 22px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 600;
line-height: 22px;
letter-spacing: 0px;
text-align: left;
}
}
.right-box1-main {
width: 502px;
margin-top: 17px;
.right-box1-main-top {
margin-left: 16px;
width: 490px;
display: flex;
justify-content: space-between;
.user-box {
width: 110px;
flex-shrink: 0;
height: 80px;
.user-list-container {
width: 440px; // 4个 user-box 的宽度 (110 * 4)
overflow: hidden;
.img-box {
width: 48px;
height: 48px;
position: relative;
margin: 0 auto;
.user-list-wrapper {
display: flex;
transition: transform 0.3s ease;
img {
width: 100%;
height: 100%;
border-radius: 50%; // 圆形头像
object-fit: cover;
}
}
.user-box {
width: 110px;
flex-shrink: 0;
height: 80px;
.img-box {
width: 48px;
height: 48px;
position: relative;
margin: 0 auto;
.icon1 {
position: absolute;
left: 5px;
bottom: -8px;
width: 16px;
height: 16px;
border-radius: 10px;
padding: 2px;
background: rgba(255, 255, 255, 0.8);
img {
width: 100%;
height: 100%;
border-radius: 50%; // 圆形头像
object-fit: cover;
}
.icon1 {
position: absolute;
left: 5px;
bottom: -8px;
width: 16px;
height: 16px;
border-radius: 10px;
padding: 2px;
background: rgba(255, 255, 255, 0.8);
img {
width: 100%;
height: 100%;
}
}
}
.icon2 {
position: absolute;
right: 5px;
bottom: -8px;
width: 16px;
height: 16px;
border-radius: 10px;
padding: 2px;
background: rgba(255, 255, 255, 0.8);
.icon2 {
position: absolute;
right: 5px;
bottom: -8px;
width: 16px;
height: 16px;
border-radius: 10px;
padding: 2px;
background: rgba(255, 255, 255, 0.8);
img {
width: 100%;
height: 100%;
}
img {
width: 100%;
height: 100%;
}
}
.name {
margin-top: 10px;
height: 14px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 14px;
letter-spacing: 0px;
text-align: center;
// 名字过长处理
width: 100px;
margin-left: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.right-box1-main-bottom {
margin: 17px 16px 0 16px;
border-top: 1px solid rgba(243, 243, 244, 1);
border-bottom: 1px solid rgba(243, 243, 244, 1);
width: 490px;
height: 266px;
background: rgba(249, 250, 252, 1);
border-radius: 5px;
display: flex;
justify-content: space-between;
}
}
.right-box1-footer {
display: flex;
.left {
width: 70px;
height: 18px;
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
margin-left: 26px;
margin-top: 23px;
}
.right {
flex: 1;
display: flex;
margin-left: 10px;
margin-right: 20px;
margin-top: 20px;
justify-content: space-between;
.right-tag {
padding: 1px 8px 1px 8px;
// box-sizing: border-box;
border-radius: 4px;
text-align: center;
height: 20px;
line-height: 20px;
.name {
margin-top: 10px;
height: 14px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
}
.tag1 {
border: 1px solid rgba(186, 224, 255, 1);
background: rgba(230, 244, 255, 1);
color: rgba(22, 119, 255, 1);
}
.tag2 {
border: 1px solid rgba(217, 247, 190, 1);
background: rgba(246, 255, 237, 1);
color: rgba(82, 196, 26, 1);
}
.tag3 {
border: 1px solid rgba(255, 204, 199, 1);
background: rgba(255, 241, 240, 1);
color: rgba(255, 77, 79, 1);
}
.tag4 {
border: 1px solid rgba(255, 241, 184, 1);
background: rgba(255, 251, 230, 1);
color: rgba(250, 173, 20, 1);
line-height: 14px;
letter-spacing: 0px;
text-align: center;
// 名字过长处理
width: 100px;
margin-left: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.right-box1-main-bottom {
margin: 17px 16px 0 16px;
border-top: 1px solid rgba(243, 243, 244, 1);
border-bottom: 1px solid rgba(243, 243, 244, 1);
width: 490px;
height: 266px;
background: rgba(249, 250, 252, 1);
border-radius: 5px;
display: flex;
justify-content: space-between;
}
}
.right-box2 {
height: 423px;
height: auto;
.right-box2-header {
height: 22px;
......@@ -1089,9 +751,8 @@ onMounted(() => {
}
.right-box2-center {
height: 345px;
overflow: auto;
overflow-y: auto;
height: auto;
overflow: visible;
margin-top: 19px;
margin-left: 16px;
width: 544px;
......@@ -1199,52 +860,15 @@ onMounted(() => {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
// .right-box2-footer {
// margin-top: 7px;
// display: flex;
// justify-content: center;
// .btn-more {
// width: 108px;
// height: 32px;
// cursor: pointer;
// img {
// width: 100%;
// height: 100%;
// }
// }
// }
}
}
}
}
:deep(.el-steps--simple) {
padding: 6px 10px;
}
:deep(.el-timeline-item) {
padding-bottom: 5px !important;
}
:deep(.el-timeline-item__timestamp) {
color: rgba(95, 101, 108, 1) !important;
font-family: Microsoft YaHei !important;
font-size: 14px !important;
font-weight: 600 !important;
}
.timeline-content {
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
</style>
......@@ -2,76 +2,22 @@
<div class="resource-library-section">
<div class="home-content-footer-header">
<div class="btn-box">
<div class="btn" :class="{ btnActive: activeTabName === cate.name, disabled: cate.active === false}"
v-for="(cate, index) in tabList" :key="index" @click="cate.active === true && handleClickTab(cate)">
<div class="btn" :class="{ btnActive: activeTabName === cate.name }" v-for="cate in tabList" :key="cate.name" @click="handleClickTab(cate)">
{{ cate.name }}
</div>
</div>
</div>
<div class="home-content-footer-main" :class="{ 'committee-full-layout': activeTabName === '委员会' }">
<div class="left" v-if="['国会法案', '国会议员', '议员合作关系'].includes(activeTabName)">
<div class="select-box">
<div class="left" v-if="leftFilters.length">
<div class="select-box" v-for="group in leftFilters" :key="group.key">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">科技领域</div>
<div class="title">{{ group.title }}</div>
</div>
<div class="select-main">
<el-checkbox-group class="checkbox-group" v-model="activeAreaList" @change="handleAreaChange">
<el-checkbox class="filter-checkbox" label="全部领域"> 全部领域 </el-checkbox>
<el-checkbox v-for="(area, index) in cateKuList" :key="index" :label="area.id" class="filter-checkbox">
{{ area.name }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
<div class="select-box" v-if="activeTabName !== '议员合作关系'">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">党派</div>
</div>
<div class="select-main">
<el-checkbox-group class="checkbox-group" v-model="activeDpList" @change="handleDpChange">
<el-checkbox v-for="(dp, index) in dpList" :key="index" :label="dp.id" class="filter-checkbox">
{{ dp.name }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
<div class="select-box" v-if="activeTabName !== '议员合作关系'">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">议院</div>
</div>
<div class="select-main">
<el-checkbox-group class="checkbox-group" v-model="activeYyList" @change="handleYyChange">
<el-checkbox v-for="(yy, index) in yyList" :key="index" :label="yy.id" class="filter-checkbox">
{{ yy.name }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
<div class="select-box" v-if="activeTabName === '国会法案'">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">发布时间</div>
</div>
<div class="select-main">
<el-checkbox-group class="checkbox-group" v-model="activePubTime" @change="handlePubTimeChange">
<el-checkbox v-for="(time, index) in pubTime" :key="index" :label="time.id" class="filter-checkbox">
{{ time.name }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
<div class="select-box" v-if="activeTabName === '议员合作关系'">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">合作关系</div>
</div>
<div class="select-main">
<el-checkbox-group class="checkbox-group" v-model="activeCoopList" @change="handleCoopChange">
<el-checkbox v-for="(coop, index) in coopList" :key="index" :label="coop.id" class="filter-checkbox">
{{ coop.name }}
<el-checkbox-group class="checkbox-group" v-model="group.model.value" @change="group.onChange">
<el-checkbox v-for="opt in group.options" :key="opt.id" :label="opt.id" class="filter-checkbox">
{{ opt.name }}
</el-checkbox>
</el-checkbox-group>
</div>
......@@ -105,21 +51,27 @@
</div>
<div class="right-main" v-loading="loading">
<template v-if="activeTabName === '国会法案'">
<div class="right-main-box" v-for="(item, index) in bills" :key="index">
<div class="right-main-box" v-for="item in bills" :key="item.billId">
<div v-if="item.riskSignal" class="risk-tag" :class="getRiskTagClass(item.riskSignal)">{{ item.riskSignal }}</div>
<div class="header">
<div class="title" @click="onClickToDetail(item)" :title="item.name">{{ item.name }}</div>
<div class="en-title" :title="item.eName">{{ item.eName }}</div>
<div class="bill-cover">
<img class="bill-image" :src="getBillImageUrl(item)" alt="" @error="handleBillImageError" />
<div class="bill-id" :title="item.billId">{{ item.billId || "-" }}</div>
</div>
<div class="main">
<div class="item"><div class="item-left">提案人:</div><div class="item-right">{{ item.tcr }}</div></div>
<div class="item"><div class="item-left">委员会:</div><div class="item-right">{{ item.wyh }}</div></div>
<div class="item"><div class="item-left">相关领域:</div><div class="item-right1"><div class="tag" v-for="(val, idx) in item.areaList" :key="idx">{{ val }}</div></div></div>
<div class="item"><div class="item-left">最新动议:</div><div class="item-right"><CommonPrompt :content="item.zxdy" /></div></div>
<div class="item">
<div class="item-left">法案进展:</div>
<div class="item-right2">
<div class="tag" v-for="(val, idx) in [...item.progress].reverse()" :key="idx" :style="{ zIndex: item.progress.length - idx }">{{ val }}</div>
<div class="bill-content">
<div class="header">
<div class="title" @click="onClickToDetail(item)" :title="item.name">{{ item.name }}</div>
<div class="en-title" :title="item.eName">{{ item.eName }}</div>
</div>
<div class="main">
<div class="item"><div class="item-left">提案人:</div><div class="item-right">{{ item.tcr }}</div></div>
<div class="item"><div class="item-left">委员会:</div><div class="item-right">{{ item.wyh }}</div></div>
<div class="item"><div class="item-left">相关领域:</div><div class="item-right1"><div class="tag" v-for="(val, idx) in item.areaList" :key="`${item.billId}-${val}-${idx}`">{{ val }}</div></div></div>
<div class="item"><div class="item-left">最新动议:</div><div class="item-right"><CommonPrompt :content="item.zxdy" /></div></div>
<div class="item">
<div class="item-left">法案进展:</div>
<div class="item-right2">
<div class="tag" v-for="(val, idx) in getReversedProgress(item.progress)" :key="`${item.billId}-${val}-${idx}`" :style="{ zIndex: item.progress.length - idx }">{{ val }}</div>
</div>
</div>
</div>
</div>
......@@ -150,7 +102,7 @@
<div class="member-meta">{{ item.partyText || '-' }} · {{ item.chamberText || '-' }} · {{ item.termText || '-' }}</div>
<div class="member-committee">{{ item.committeeText || '-' }}</div>
<div class="member-tags">
<div class="member-tag" v-for="(tag, idx) in item.focusTags" :key="idx">{{ tag }}</div>
<div class="member-tag" v-for="(tag, idx) in item.focusTags" :key="`${item.id}-${tag}-${idx}`">{{ tag }}</div>
</div>
</div>
</div>
......@@ -167,28 +119,91 @@
</div>
</div>
</div>
<div v-else-if="activeTabName === '议员合作关系'" class="coop-list">
<div class="member-card" v-for="item in memberList" :key="`coop-${item.id}`">
<div class="member-name">{{ item.name || '-' }}</div>
<div class="member-info">党派:{{ item.party || '-' }}</div>
<div class="member-info">议院:{{ item.chamber || '-' }}</div>
<div class="member-info">任期:{{ item.term || '-' }}</div>
<div class="member-info">委员会:{{ item.committee || '-' }}</div>
<div class="member-info">关注领域:{{ item.focus || '-' }}</div>
<div v-else-if="activeTabName === '议员合作关系'">
<div class="coop-list">
<div class="coop-card" v-for="item in coopPagedList" :key="item.id">
<div class="coop-card-header">
<div class="coop-members">
<div class="coop-member">
<img class="coop-avatar" :src="item.left.avatar || defaultAvatar" alt="avatar-left" />
<div class="coop-member-name" :title="item.left.name">{{ item.left.name }}</div>
</div>
<div class="coop-dot">·</div>
<div class="coop-member">
<img class="coop-avatar" :src="item.right.avatar || defaultAvatar" alt="avatar-right" />
<div class="coop-member-name" :title="item.right.name">{{ item.right.name }}</div>
</div>
</div>
<div class="coop-summary" :title="item.summary">
{{ item.summary }}
</div>
<div class="coop-count">
{{ item.totalText }}
</div>
<slot name="coop-extra" :relation="item" />
</div>
<div class="coop-proposals">
<div
class="coop-proposal-item"
v-for="proposal in item.proposals"
:key="proposal.billId"
@click="handleClickCoopProposal(proposal)"
>
<div class="coop-proposal-main">
<div class="coop-proposal-title">
<span class="year">{{ proposal.year }}</span>
<span class="code">{{ proposal.code }}</span>
</div>
<div class="coop-proposal-subtitle" :title="proposal.title">
{{ proposal.title }}
</div>
</div>
<div class="coop-proposal-arrow">></div>
</div>
</div>
</div>
</div>
<div class="right-footer">
<div class="footer-left">{{ `共 ${coopTotal} 项` }}</div>
<div class="footer-right">
<el-pagination
@current-change="handleCoopCurrentChange"
:page-size="coopPageSize"
:current-page="coopCurrentPage"
background
layout="prev, pager, next"
:total="coopTotal"
/>
</div>
</div>
</div>
<div v-else-if="activeTabName === '委员会'" class="committee-list">
<div class="committee-card" v-for="item in committeeList" :key="item.id">
<div class="committee-info">
<img class="committee-avatar" :src="item.avatar || defaultAvatar" alt="committee-avatar" />
<div class="committee-text">
<div class="committee-name">{{ item.name }}</div>
<div class="committee-desc">{{ item.desc }}</div>
<div v-else-if="activeTabName === '委员会'">
<div class="coop-list committee-list">
<div class="coop-card" v-for="item in committeeList" :key="item.id">
<div class="coop-card-header">
<div class="coop-members">
<div class="coop-member">
<img class="coop-avatar" :src="item.avatar || defaultAvatar" alt="committee-avatar" />
<div class="coop-member-name" :title="item.name">{{ item.name }}</div>
</div>
</div>
<div class="coop-summary" :title="item.desc">
{{ item.desc }}
</div>
<div class="coop-count">
{{ `${(item.bills || []).length}项重点法案` }}
</div>
<slot name="committee-extra" :committee="item" />
</div>
</div>
<div class="committee-bill-grid">
<div class="committee-bill-item" v-for="(bill, idx) in item.bills" :key="`${item.id}-bill-${idx}`">
{{ bill }}
<div class="coop-proposals">
<div class="coop-proposal-item" v-for="bill in item.bills" :key="`${item.id}-${bill}`">
<div class="coop-proposal-main">
<div class="coop-proposal-subtitle" :title="bill">
{{ bill }}
</div>
</div>
<div class="coop-proposal-arrow">></div>
</div>
</div>
</div>
</div>
......@@ -200,11 +215,12 @@
</template>
<script setup>
import { onMounted, ref } from "vue";
import { computed, onMounted, ref } from "vue";
import { getHylyList, getPostOrgList, getPostMemberList, getBills, getBillsPerson } from "@/api/bill/billHome";
import CommonPrompt from "../commonPrompt/index.vue";
import desc from "./assets/icons/icon-desc.png";
import defaultAvatar from "./assets/images/user.png";
import defaultBill from "../assets/images/image1.png";
import zyyIcon from "@/assets/icons/zyy.png";
import cyyIcon from "@/assets/icons/cyy.png";
import ghdIcon from "@/assets/icons/ghd.png";
......@@ -215,12 +231,12 @@ const props = defineProps({
onAfterPageChange: { type: Function, default: null }
});
const tabList = ref([
{ name: "国会法案", active: true },
{ name: "国会议员", active: false },
{ name: "议员合作关系", active: false },
{ name: "委员会", active: false }
]);
const tabList = [
{ name: "国会法案" },
{ name: "国会议员" },
{ name: "议员合作关系" },
{ name: "委员会" }
];
const activeTabName = ref("国会法案");
const handleClickTab = tab => {
activeTabName.value = tab.name;
......@@ -234,6 +250,11 @@ const handleClickTab = tab => {
handleGetBills();
return;
}
if (tab.name === "议员合作关系") {
coopCurrentPage.value = 1;
handleGetCoopList();
return;
}
if (tab.name === "委员会") {
handleGetCommitteeList();
}
......@@ -251,14 +272,24 @@ const yyList = ref([{ id: "全部议院", name: "全部议院" }, { id: "S", nam
const activeYyList = ref(["全部议院"]);
const pubTime = ref([{ id: "全部时间", name: "全部时间" }, { id: "2025", name: "2025年" }, { id: "2024", name: "2024年" }, { id: "2023", name: "2023年" }, { id: "2022", name: "2022年" }, { id: "2021", name: "2021年" }]);
const activePubTime = ref(["全部时间"]);
const coopList = ref([
{ id: "全部合作关系", name: "全部合作关系" },
{ id: "跨党派合作", name: "跨党派合作" },
{ id: "同党派合作", name: "同党派合作" },
{ id: "地域利益合作", name: "地域利益合作" },
{ id: "委员会内合作", name: "委员会内合作" }
]);
const activeCoopList = ref(["全部合作关系"]);
const areaOptions = computed(() => [{ id: "全部领域", name: "全部领域" }, ...(cateKuList.value || [])]);
const leftFilters = computed(() => {
if (activeTabName.value === "委员会") {
return [{ key: "chamber", title: "议院", model: activeYyList, options: yyList.value, onChange: handleYyChange }];
}
const filters = [{ key: "area", title: "科技领域", model: activeAreaList, options: areaOptions.value, onChange: handleAreaChange }];
if (activeTabName.value !== "议员合作关系") {
filters.push({ key: "party", title: "党派", model: activeDpList, options: dpList.value, onChange: handleDpChange });
filters.push({ key: "chamber", title: "议院", model: activeYyList, options: yyList.value, onChange: handleYyChange });
}
if (activeTabName.value === "国会法案") {
filters.push({ key: "pubTime", title: "发布时间", model: activePubTime, options: pubTime.value, onChange: handlePubTimeChange });
}
return filters;
});
const footerSelect1 = ref("全部委员会");
const footerSelect2 = ref("全部提出议员");
......@@ -269,6 +300,16 @@ const memberTotal = ref(0);
const memberPageSize = ref(15);
const memberCurrentPage = ref(1);
// 议员合作关系列表(预留接口插槽,当前为示例数据)
const coopList = ref([]);
const coopTotal = ref(0);
const coopPageSize = ref(6);
const coopCurrentPage = ref(1);
const coopPagedList = computed(() => {
const start = (coopCurrentPage.value - 1) * coopPageSize.value;
return coopList.value.slice(start, start + coopPageSize.value);
});
const committeeList = ref([
{
id: "committee-1",
......@@ -299,6 +340,20 @@ const pageSize = ref(4);
const currentPage = ref(1);
const loading = ref(false);
const abortController = ref(null);
let requestToken = 0;
const beginAbortableRequest = () => {
if (abortController.value) abortController.value.abort();
abortController.value = new AbortController();
requestToken += 1;
const token = requestToken;
loading.value = true;
return { token, signal: abortController.value.signal };
};
const endAbortableRequest = token => {
if (token === requestToken) loading.value = false;
};
const getRiskTagClass = riskSignal => {
if (riskSignal === "特别重大风险") return "risk-tag-critical";
......@@ -307,6 +362,17 @@ const getRiskTagClass = riskSignal => {
return "";
};
const getBillImageUrl = item => item?.imageUrl || defaultBill;
const handleBillImageError = e => {
const img = e?.target;
if (!img) return;
if (img.dataset?.fallbackApplied === "1") return;
img.dataset.fallbackApplied = "1";
img.src = defaultBill;
};
const getReversedProgress = progress => (Array.isArray(progress) ? [...progress].reverse() : []);
// 获取委员会列表(占位)
const handleGetCommitteeList = async () => {
loading.value = true;
......@@ -321,6 +387,64 @@ const handleGetCommitteeList = async () => {
}
};
// 获取议员合作关系数据(占位)
const handleGetCoopList = async () => {
loading.value = true;
try {
// TODO: 接入“议员合作关系”接口后,在此替换为真实请求并赋值 coopList
// 示例结构:每项包含两名议员及不超过 4 条共同提案
const list = [
{
id: "coop-1",
left: {
name: "查克·舒默",
avatar: ""
},
right: {
name: "林赛·格雷厄姆",
avatar: ""
},
total: 8,
totalText: "8项共同提案",
summary: "跨党派在国防、安全与科技议题上保持长期合作。",
proposals: [
{
billId: "2025-HR-3501",
year: "2025",
code: "H.R.3501",
title: "2026财年国防授权法案"
},
{
billId: "2025-HR-327",
year: "2025",
code: "H.R.327",
title: "汽车零部件25%关税实施规则"
},
{
billId: "2025-HR-1176",
year: "2025",
code: "H.R.1176",
title: "GENIUS稳定币法案"
},
{
billId: "2025-HR-2057",
year: "2025",
code: "H.R.2057",
title: "小额额免包装政策调整"
}
]
}
];
coopList.value = list;
coopTotal.value = list.length;
} catch (error) {
coopList.value = [];
coopTotal.value = 0;
} finally {
loading.value = false;
}
};
const handleGetHylyList = async () => {
try {
const res = await getHylyList();
......@@ -350,9 +474,7 @@ const handleGetPostMemberList = async () => {
// 获取资源库法案列表
const handleGetBills = async () => {
if (abortController.value) abortController.value.abort();
abortController.value = new AbortController();
loading.value = true;
const { token, signal } = beginAbortableRequest();
const params = {
currentPage: currentPage.value,
......@@ -369,7 +491,7 @@ const handleGetBills = async () => {
if (!activePubTime.value.includes("全部时间")) params.years = activePubTime.value.join(",");
try {
const res = await getBills(params, abortController.value.signal);
const res = await getBills(params, signal);
if (res.code === 200 && res.data && res.data.content) {
bills.value = res.data.content.map(item => ({
billId: item.billId,
......@@ -380,7 +502,8 @@ const handleGetBills = async () => {
areaList: item.hylyList || [],
zxdy: item.latestAction,
progress: item.stageList || [],
riskSignal: item.riskSignal || ""
riskSignal: item.riskSignal || "",
imageUrl: item.imageUrl || ""
}));
total.value = res.data.totalElements;
} else {
......@@ -393,15 +516,13 @@ const handleGetBills = async () => {
total.value = 0;
}
} finally {
loading.value = false;
endAbortableRequest(token);
}
};
// 获取资源库国会议员列表
const handleGetBillsPerson = async () => {
if (abortController.value) abortController.value.abort();
abortController.value = new AbortController();
loading.value = true;
const { token, signal } = beginAbortableRequest();
const params = {
currentPage: memberCurrentPage.value,
......@@ -422,7 +543,7 @@ const handleGetBillsPerson = async () => {
};
try {
const res = await getBillsPerson(params, abortController.value.signal);
const res = await getBillsPerson(params, signal);
if (res.code === 200 && res.data && res.data.content) {
memberList.value = res.data.content.map(item => {
const partyMap = { Democratic: "民主党", Republican: "共和党" };
......@@ -467,10 +588,32 @@ const handleGetBillsPerson = async () => {
memberTotal.value = 0;
}
} finally {
loading.value = false;
endAbortableRequest(token);
}
};
const resetPages = () => {
currentPage.value = 1;
memberCurrentPage.value = 1;
coopCurrentPage.value = 1;
};
const refreshByActiveTab = () => {
if (activeTabName.value === "议员合作关系") {
handleGetCoopList();
return;
}
if (activeTabName.value === "委员会") {
handleGetCommitteeList();
return;
}
if (activeTabName.value === "国会议员") {
handleGetBillsPerson();
return;
}
handleGetBills();
};
const normalizeWithAll = (val, allLabel, targetRef) => {
if (val.includes(allLabel) && val.length > 1) {
targetRef.value = val[val.length - 1] === allLabel ? [allLabel] : val.filter(item => item !== allLabel);
......@@ -479,30 +622,19 @@ const normalizeWithAll = (val, allLabel, targetRef) => {
} else {
targetRef.value = val;
}
currentPage.value = 1;
memberCurrentPage.value = 1;
if (activeTabName.value === "国会议员") {
handleGetBillsPerson();
return;
}
handleGetBills();
resetPages();
refreshByActiveTab();
};
const handleAreaChange = val => normalizeWithAll(val, "全部领域", activeAreaList);
const handleDpChange = val => normalizeWithAll(val, "全部党派", activeDpList);
const handleYyChange = val => normalizeWithAll(val, "全部议院", activeYyList);
const handlePubTimeChange = val => normalizeWithAll(val, "全部时间", activePubTime);
const handleCoopChange = val => normalizeWithAll(val, "全部合作关系", activeCoopList);
const handleFooterSelect1Change = val => {
footerSelect1.value = val;
currentPage.value = 1;
memberCurrentPage.value = 1;
if (activeTabName.value === "国会议员") {
handleGetBillsPerson();
return;
}
handleGetBills();
resetPages();
refreshByActiveTab();
};
const handleFooterSelect2Change = val => {
footerSelect2.value = val;
......@@ -534,6 +666,19 @@ const handleClickLatestProposal = item => {
});
};
const handleClickCoopProposal = proposal => {
if (!proposal?.billId) return;
props.onClickToDetail({
billId: proposal.billId,
name: proposal.title || proposal.code || ""
});
};
const handleCoopCurrentChange = page => {
coopCurrentPage.value = page;
// 如后续改为后端分页,可在此调用 handleGetCoopList();
};
const handleMemberCurrentChange = page => {
memberCurrentPage.value = page;
handleGetBillsPerson();
......@@ -589,15 +734,6 @@ onMounted(() => {
background: var(--color-main-active);
}
}
.disabled {
cursor: not-allowed;
opacity: 0.5;
&:hover {
background: transparent;
}
}
}
}
......@@ -611,9 +747,6 @@ onMounted(() => {
&.committee-full-layout {
.right {
margin-left: 0;
width: 1600px;
.right-main {
height: auto;
}
......@@ -621,7 +754,7 @@ onMounted(() => {
}
.left {
width: 300px;
width: 360px;
padding-bottom: 33px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
......@@ -647,9 +780,9 @@ onMounted(() => {
.title {
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 20px;
font-size: 16px;
font-weight: 700;
line-height: 26px;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
}
......@@ -683,7 +816,8 @@ onMounted(() => {
.right {
margin-left: 20px;
width: 1280px;
width: calc(100% - 380px);
min-width: 0;
.right-header {
height: 48px;
......@@ -909,6 +1043,165 @@ onMounted(() => {
.coop-list {
grid-template-columns: 1fr;
.coop-card {
padding: 16px 20px 14px;
box-sizing: border-box;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: #fff;
display: flex;
flex-direction: column;
gap: 12px;
}
.coop-card-header {
display: flex;
align-items: center;
gap: 16px;
}
.coop-members {
display: flex;
align-items: center;
gap: 12px;
min-width: 0;
}
.coop-member {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.coop-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
flex-shrink: 0;
}
.coop-member-name {
max-width: 130px;
color: #3b414b;
font-family: "Source Han Sans CN";
font-size: 16px;
font-weight: 700;
line-height: 24px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.coop-dot {
color: #9da3ac;
font-size: 18px;
line-height: 1;
}
.coop-summary {
flex: 1;
min-width: 0;
color: #5f656c;
font-family: "Microsoft YaHei";
font-size: 14px;
font-weight: 400;
line-height: 22px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.coop-count {
flex-shrink: 0;
color: #1459bb;
font-family: "Microsoft YaHei";
font-size: 14px;
font-weight: 500;
line-height: 22px;
}
.coop-proposals {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid #eaeced;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
column-gap: 14px;
row-gap: 12px;
}
.coop-proposal-item {
position: relative;
height: 64px;
padding: 8px 34px 8px 20px;
box-sizing: border-box;
border-radius: 8px;
background: rgb(247, 248, 249);
display: flex;
align-items: center;
cursor: pointer;
transition: background 0.15s ease;
&::before {
content: "";
position: absolute;
left: 0px;
top: 12px;
bottom: 12px;
width: 3px;
background: rgb(5, 95, 194);
}
}
.coop-proposal-item:hover {
background: rgba(20, 89, 187, 0.06);
}
.coop-proposal-main {
flex: 1;
min-width: 0;
}
.coop-proposal-title {
display: flex;
align-items: center;
gap: 8px;
color: #3b414b;
font-family: "Microsoft YaHei";
font-size: 15px;
font-weight: 700;
line-height: 22px;
}
.coop-proposal-title .year {
color: #9da3ac;
font-weight: 400;
}
.coop-proposal-subtitle {
margin-top: 2px;
color: #5f656c;
font-family: "Microsoft YaHei";
font-size: 14px;
font-weight: 400;
line-height: 22px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.coop-proposal-arrow {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
color: #c0c4cc;
font-size: 16px;
line-height: 1;
}
}
.committee-list {
......@@ -979,19 +1272,23 @@ onMounted(() => {
.right-main-box {
position: relative;
width: 1280px;
height: 300px;
padding-bottom: 24px;
width: 100%;
height: 320px;
padding: 12px 16px;
box-sizing: border-box;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
margin-bottom: 16px;
overflow: hidden;
display: flex;
gap: 16px;
align-items: center;
.risk-tag {
position: absolute;
top: 16px;
right: 40px;
top: 12px;
right: 16px;
height: 28px;
border-radius: 20px;
display: inline-flex;
......@@ -1030,12 +1327,70 @@ onMounted(() => {
color: rgb(232, 189, 11);
}
.bill-cover {
width: 240px;
flex-shrink: 0;
position: relative;
height: 100%;
margin: 0;
overflow: hidden;
&::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 33.333%;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.92) 60%, rgba(255, 255, 255, 1));
pointer-events: none;
}
}
.bill-image {
width: 240px;
height: 100%;
object-fit: none;
display: block;
}
.bill-id {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 33.333%;
display: flex;
align-items: center;
justify-content: center;
padding: 0 12px;
box-sizing: border-box;
color: rgba(59, 65, 75, 1);
font-family: "Source Han Sans CN";
font-size: 20px;
font-weight: 700;
line-height: 26px;
letter-spacing: 0px;
text-align: center;
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
z-index: 1;
}
.bill-content {
flex: 1;
min-width: 0;
overflow: hidden;
box-sizing: border-box;
}
.header {
height: 91px;
width: 1200px;
margin: 0 auto;
width: 100%;
border-bottom: 1px solid rgba(234, 236, 238, 1);
padding-top: 19px;
padding-bottom: 14px;
padding-right: 120px;
.title {
cursor: pointer;
......@@ -1069,16 +1424,16 @@ onMounted(() => {
}
.main {
width: 1200px;
margin: 0 auto;
margin-top: 2px;
width: 100%;
margin-top: 10px;
.item {
margin-top: 12px;
display: flex;
align-items: flex-start;
.item-left {
width: 100px;
width: 88px;
color: rgb(59, 65, 75);
font-family: "Microsoft YaHei";
font-size: 16px;
......@@ -1104,6 +1459,7 @@ onMounted(() => {
margin-left: 10px;
display: flex;
gap: 8px;
flex-wrap: wrap;
.tag {
height: 24px;
......@@ -1122,6 +1478,7 @@ onMounted(() => {
margin-left: 10px;
display: flex;
align-items: center;
flex-wrap: wrap;
.tag {
height: 24px;
......
......@@ -264,23 +264,13 @@ const handleClickToCharacter = async (id, name) => {
} catch (error) { }
};
const currentPage = ref(1);
// 处理页码改变事件
const handleCurrentChange = page => {
currentPage.value = page;
handleGetBills();
handleToPosi("position4");
};
const containerRef = ref(null);
const { isShow } = useContainerScroll(containerRef);
const hotBillList = ref([]); // 热门法案列表
const curHotBillListIndex = ref(0); // 当前热门法案索引
const carouselRef = ref(null);
const handleCarouselChange = index => {
curHotBillListIndex.value = index;
if (hotBillList.value && hotBillList.value.length > 0) {
curBill.value = hotBillList.value[index];
}
......@@ -380,23 +370,8 @@ const box8YearList = ref([
value: "2022"
}
]);
// 排序方式
const releaseTime = ref(true);
const releaseTimeList = ref([
{
label: "正序",
value: true
},
{
label: "倒序",
value: false
}
]);
// 涉华法案数量使用的领域分类列表
const categoryList = ref([]);
// 资源库使用的领域分类列表
const cateKuList = ref([]);
// 获取领域分类
const handleGetHylyList = async () => {
......@@ -404,7 +379,6 @@ const handleGetHylyList = async () => {
const res = await getHylyList();
console.log("行业领域列表", res);
categoryList.value = res.data;
cateKuList.value = res.data;
} catch (error) { }
};
// 新闻资讯
......@@ -478,146 +452,6 @@ const handleGetRemarks = async () => {
} catch (error) { }
};
// 获取提出部门列表
const postOrgList = ref([{ departmentName: "全部委员会", departmentId: "全部委员会" }]);
const handleGetPostOrgList = async () => {
try {
const res = await getPostOrgList();
console.log("提出部门列表", res);
if (res.code === 200) {
const list = res.data.filter(item => item.departmentId);
postOrgList.value = [{ departmentName: "全部委员会", departmentId: "全部委员会" }, ...list];
}
} catch (error) { }
};
// 获取提出议员列表
const postMemberList = ref([{ memberName: "全部提出议员", memberId: "全部提出议员" }]);
const handleGetPostMemberList = async () => {
try {
const res = await getPostMemberList();
console.log("提出议员列表", res);
if (res.code === 200) {
const list = res.data.filter(item => item.memberId);
postMemberList.value = [{ memberName: "全部提出议员", memberId: "全部提出议员" }, ...list];
}
} catch (error) { }
};
// 获取资源库
const bills = ref([]);
const total = ref(0);
const pageSize = ref(4);
const loading = ref(false);
const abortController = ref(null);
const handleGetBills = async () => {
// 取消上一次未完成的请求
if (abortController.value) {
abortController.value.abort();
}
// 创建新的 AbortController
abortController.value = new AbortController();
loading.value = true;
const params = {
currentPage: currentPage.value - 1, // Standard Spring Boot page index is 0-based
pageSize: pageSize.value
};
if (!activeYyList.value.includes("全部议院")) {
params.congressIds = activeYyList.value.join(",");
}
if (footerSelect1.value !== "全部委员会") {
params.departmentId = footerSelect1.value;
}
if (!activeDpList.value.includes("全部党派")) {
params.partyIds = activeDpList.value.join(",");
}
if (footerSelect2.value !== "全部提出议员") {
params.personId = footerSelect2.value;
}
if (!activeAreaList.value.includes("全部领域")) {
params.researchIds = activeAreaList.value.join(",");
}
if (releaseTime.value !== true) {
params.sortFun = releaseTime.value;
}
if (!activePubTime.value.includes("全部时间")) {
params.years = activePubTime.value.join(",");
}
try {
const res = await getBills(params, abortController.value.signal);
console.log("资源库列表", res);
if (res.code === 200) {
if (res.data && res.data.content) {
bills.value = res.data.content.map(item => ({
billId: item.billId,
name: item.billName,
eName: item.billNameEn,
tcr: item.personName,
wyh: item.congressName,
areaList: item.hylyList || [],
zxdy: item.latestAction,
progress: item.stageList || []
}));
total.value = res.data.totalElements;
} else {
bills.value = [];
total.value = 0;
}
} else {
bills.value = [];
total.value = 0;
}
loading.value = false;
} catch (error) {
if (error.name !== "AbortError") {
console.error(error);
loading.value = false;
}
}
};
// 处理选择委员会变化
const handleFooterSelect1Change = val => {
console.log("选择委员会变化", val);
// 等会再做处理
handleGetBills();
};
// 处理选择议员变化
const handleFooterSelect2Change = val => {
console.log("选择议员变化", val);
// 等会再做处理
handleGetBills();
};
// 处理选择排序方式变化
const handlePxChange = val => {
console.log("选择排序方式变化", val);
// 等会再做处理
handleGetBills();
};
// 根据法案类型获取法案列表
// const handleGetBillsByType = async () => {
// const params = {
// type: activeHylyId.value
// };
// try {
// const res = await getBillsByType(params);
// console.log("根据法案类型获取法案列表", res);
// billList.value = res.data.map(item => {
// return {
// billId: item.billId,
// billName: item.billName,
// introductionDate: item.introductionDate,
// img: bill1
// };
// });
// } catch (error) {}
// };
// 涉华法案数量
const box5Select = ref("全部领域");
const box5Data = ref({
......@@ -1078,145 +912,8 @@ const handleToPosi = id => {
}
};
const tabList = ref([
{
name: "国会法案",
active: true
},
{
name: "国会议员",
active: false
},
{
name: "议员合作关系",
active: false
},
{
name: "涉华委员会",
active: false
}
]);
const activeTabName = ref("国会法案");
const handleClickTab = tab => {
activeTabName.value = tab.name;
};
const activeAreaList = ref(["全部领域"]);
const handleAreaChange = val => {
if (val.includes("全部领域") && val.length > 1) {
if (val[val.length - 1] === "全部领域") {
activeAreaList.value = ["全部领域"];
} else {
activeAreaList.value = val.filter(item => item !== "全部领域");
}
} else if (val.length === 0) {
activeAreaList.value = ["全部领域"];
}
// 打印 activeAreaList.value
console.log(activeAreaList.value);
handleGetBills();
};
const dpList = ref([
{ id: "全部党派", name: "全部党派" },
{ id: "Democratic", name: "民主党" },
{ id: "Republican", name: "共和党" }
]);
const activeDpList = ref(["全部党派"]);
// 处理选择党派变化
const handleDpChange = val => {
if (val.includes("全部党派") && val.length > 1) {
if (val[val.length - 1] === "全部党派") {
activeDpList.value = ["全部党派"];
} else {
activeDpList.value = val.filter(item => item !== "全部党派");
}
} else if (val.length === 0) {
activeDpList.value = ["全部党派"];
}
console.log("选择党派变化", activeDpList.value);
handleGetBills();
};
const yyList = ref([
{ id: "全部议院", name: "全部议院" },
{ id: "S", name: "参议院" },
{ id: "H", name: "众议院" }
]);
const activeYyList = ref(["全部议院"]);
// 处理选择议院变化
const handleYyChange = val => {
if (val.includes("全部议院") && val.length > 1) {
if (val[val.length - 1] === "全部议院") {
activeYyList.value = ["全部议院"];
} else {
activeYyList.value = val.filter(item => item !== "全部议院");
}
} else if (val.length === 0) {
activeYyList.value = ["全部议院"];
}
console.log("选择议院变化", activeYyList.value);
handleGetBills();
};
const pubTime = ref([
{ id: "全部时间", name: "全部时间" },
{ id: "2025", name: "2025年" },
{ id: "2024", name: "2024年" },
{ id: "2023", name: "2023年" },
{ id: "2022", name: "2022年" },
{ id: "2021", name: "2021年" }
// { id: "更早时间", name: "更早时间" }
]);
const activePubTime = ref(["全部时间"]);
// 处理选择时间变化
const handlePubTimeChange = val => {
if (val.includes("全部时间") && val.length > 1) {
if (val[val.length - 1] === "全部时间") {
activePubTime.value = ["全部时间"];
} else {
activePubTime.value = val.filter(item => item !== "全部时间");
}
} else if (val.length === 0) {
activePubTime.value = ["全部时间"];
}
console.log("选择时间变化", activePubTime.value);
handleGetBills();
};
const footerSelect1 = ref("全部委员会");
const footerSelect2 = ref("全部提出议员");
// const footerBillList = ref([
// {
// name: "H.R.1-大而美法案",
// eName: "One Big Beautiful Bill Act",
// tcr: "乔迪·阿灵顿等2人",
// wyh: "众议院-预算委员会",
// areaList: ["集成电路", "人工智能"],
// zxdy: "2025.07.04 成为公法 No: 119-21",
// progress: []
// },
// {
// name: "H.R.1-大而美法案",
// eName: "One Big Beautiful Bill Act",
// tcr: "乔迪·阿灵顿等2人",
// wyh: "众议院-预算委员会",
// areaList: ["集成电路", "人工智能"],
// zxdy: "2025.07.04 成为公法 No: 119-21",
// progress: []
// },
// {
// name: "H.R.1-大而美法案",
// eName: "One Big Beautiful Bill Act",
// tcr: "乔迪·阿灵顿等2人",
// wyh: "众议院-预算委员会",
// areaList: ["集成电路", "人工智能"],
// zxdy: "2025.07.04 成为公法 No: 119-21",
// progress: []
// }
// ]);
// 资源库分页变更后滚动到资源库区域
const handlePageChange = () => handleToPosi("position4");
const handleResize = () => {
box8ChartInstance && box8ChartInstance.resize();
......@@ -1226,20 +923,9 @@ const handleResize = () => {
onMounted(async () => {
window.addEventListener("resize", handleResize);
handleGetHylyList();
// 获取风险信号
handleGetBillRiskSignal();
// 获取新闻资讯
handleGetNews();
// 获取社交媒体
handleGetRemarks();
// 获取提出部门列表
handleGetPostOrgList();
// 获取提出议员列表
handleGetPostMemberList();
// 获取资源库
handleGetBills();
// handleGetBillsByType();
handleBox5(); //涉华法案统计
handleBox6(); // 关键条款
......
......@@ -148,11 +148,12 @@
</div>
</div> -->
<AnalysisBox title="政治献金流向">
<div class="box2-main">
<div class="box2-main" :class="{ 'box2-main-no-footer': !showHardcodedTips }">
<el-empty v-if="!fullSourceList.length" description="暂无数据" :image-size="100" />
<div v-else class="chart-box2" id="chart1"></div>
</div>
<div class="box-footer">
<!-- 该提示文案后续改为接口返回,当前按需求先隐藏展示 -->
<div v-if="showHardcodedTips" class="box-footer">
<div class="box-footer-left">
<img src="@/assets/icons/box-footer-left-icon.png" alt="" />
</div>
......@@ -210,7 +211,7 @@
</div>
</div> -->
<AnalysisBox title="政治献金领域分布">
<div class="box3-main">
<div class="box3-main" :class="{ 'box3-main-no-footer': !showHardcodedTips }">
<div class="box3-main-left" id="chart2"></div>
<div class="box3-main-right">
<el-empty v-if="!areaList.length" description="暂无数据" :image-size="100" />
......@@ -225,7 +226,8 @@
</div>
</div>
</div>
<div class="box-footer">
<!-- 该提示文案后续改为接口返回,当前按需求先隐藏展示 -->
<div v-if="showHardcodedTips" class="box-footer">
<div class="box-footer-left">
<img src="@/assets/icons/box-footer-left-icon.png" alt="" />
</div>
......@@ -271,6 +273,9 @@ import Mzd from "@/assets/icons/mzd.png";
const activeBtnIndex = ref(0);
const itemActiveIndex = ref(0);
// 写死提示文案先保留逻辑,默认不展示;后续接口完成后改为 true 或替换为接口控制
const showHardcodedTips = ref(false);
const currentPersonName = computed(() => {
if (mainPoliContribution.value && mainPoliContribution.value[itemActiveIndex.value]) {
return mainPoliContribution.value[itemActiveIndex.value].name;
......@@ -1104,6 +1109,14 @@ onMounted(() => {
margin: 0 auto;
margin-bottom: 9px;
&.box2-main-no-footer {
height: 351px;
.chart-box2 {
height: 351px;
}
}
.chart-box2 {
width: 1020px;
height: 302px;
......@@ -1128,6 +1141,10 @@ onMounted(() => {
margin-bottom: 9px;
display: flex;
&.box3-main-no-footer {
height: 349px;
}
.box3-main-left {
width: 492px;
}
......
......@@ -34,12 +34,12 @@
<AnalysisBox title="典型阶段耗时">
<div class="box1-main">
<div class="box1-main-center" id="chart1"></div>
<div class="box1-main-footer">
<div v-if="timeFooterText" class="box1-main-footer">
<div class="box-footer-left">
<img src="@/assets/icons/box-footer-left-icon.png" alt="" />
</div>
<div class="box-footer-center">
从立法耗时角度分析,大而美法案从提交到签署仅39天,远快于历史同类法案(通常需6个月以上),立法速度极快。
{{ timeFooterText }}
</div>
<div class="box-footer-right">
<img src="../assets/icons/arrow-right.png" alt="" />
......@@ -82,13 +82,12 @@
<AnalysisBox title="修正案次数分析">
<div class="box2-main">
<div class="box2-main-center" id="chart2"></div>
<div class="box2-main-footer">
<div v-if="amendFooterText" class="box2-main-footer">
<div class="box-footer-left">
<img src="@/assets/icons/box-footer-left-icon.png" alt="" />
</div>
<div class="box-footer-center">
法案本质是共和党与资本集团的深度联盟,共和党获超
​80%利益集团献金,以减税、松监管、军工扩张为核心回报。
{{ amendFooterText }}
</div>
<div class="box-footer-right">
<img src="../assets/icons/arrow-right.png" alt="" />
......@@ -367,6 +366,16 @@
</div>
</div> -->
<AnalysisBox title="投票分析">
<div class="vote-legend">
<div class="vote-legend-item">
<span class="vote-legend-dot agree"></span>
<span>赞成票</span>
</div>
<div class="vote-legend-item">
<span class="vote-legend-dot against"></span>
<span>反对票</span>
</div>
</div>
<div class="box3-main">
<div class="box3-main-center">
<div class="box3-main-center-header">
......@@ -658,12 +667,12 @@
</div> -->
</div>
</div>
<div class="box3-main-footer">
<div v-if="voteFooterText" class="box3-main-footer">
<div class="box-footer-left">
<img src="@/assets/icons/box-footer-left-icon.png" alt="" />
</div>
<div class="box-footer-center">
法案以218:214​(众议院)和51:50​(副总统决胜票)微弱优势强行通过,暴露两党极端对立、党内倒戈频发的特点。
{{ voteFooterText }}
</div>
<div class="box-footer-right">
<img src="../assets/icons/arrow-right.png" alt="" />
......@@ -881,6 +890,11 @@ const voteAnalysisList4 = ref([
}
]);
// 底部说明文案(接口预留,默认不展示)
const timeFooterText = ref("");
const amendFooterText = ref("");
const voteFooterText = ref("");
// 绘制echarts图表
const setChart = (option, chartId) => {
let chartDom = document.getElementById(chartId);
......@@ -1093,7 +1107,7 @@ onMounted(async () => {
.box1-main-center {
width: 792px;
height: 300px;
height: 340px;
margin: 0 5px;
overflow: hidden;
......@@ -1231,7 +1245,7 @@ onMounted(async () => {
height: 359px;
.box2-main-center {
height: 300px;
height: 340px;
margin: 0 5px;
display: flex;
......@@ -1345,7 +1359,7 @@ onMounted(async () => {
#chart2 {
position: relative;
width: 330px;
height: 300px;
height: 340px;
z-index: 0;
}
......@@ -1471,11 +1485,48 @@ onMounted(async () => {
.box3 {
width: 100%;
height: 100%;
position: relative;
.vote-legend {
position: absolute;
top: 15px;
left: 50%;
transform: translateX(-50%);
display: inline-flex;
align-items: center;
gap: 20px;
z-index: 2;
.vote-legend-item {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: rgba(95, 101, 108, 1);
line-height: 22px;
}
.vote-legend-dot {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
&.agree {
background: rgb(33, 129, 57);
}
&.against {
background: rgb(206, 79, 81);
}
}
}
.box3-main {
height: 791px;
.box3-main-center {
height: 732px;
height: 772px;
margin: 0 20px;
overflow-x: hidden;
......@@ -1529,7 +1580,7 @@ onMounted(async () => {
}
.box3-main-center-content {
height: 682px;
height: 722px;
overflow-y: auto;
overflow-x: hidden;
......
......@@ -16,10 +16,10 @@
>
<div class="item-title">{{ item.actionTitle }}</div>
</el-tooltip>
<!-- <div class="right">
<div class="risk-tag" :class="item.riskClass">{{ item.riskText }}</div>
<div class="right">
<div v-if="item.riskText" class="risk-tag" :class="item.riskClass">{{ item.riskText }}</div>
<div class="arrow">></div>
</div> -->
</div>
</div>
</div>
......@@ -41,6 +41,27 @@ const RISK_CLASS_MAP = {
"低风险": "risk-low"
};
const normalizeRiskSignal = riskSignal => {
if (riskSignal === null || riskSignal === undefined) return "";
if (typeof riskSignal === "number" && Number.isFinite(riskSignal)) {
const idx = Math.max(0, Math.min(RISK_LEVELS.length - 1, Math.floor(riskSignal)));
return RISK_LEVELS[idx];
}
const text = String(riskSignal).trim();
if (!text) return "";
if (RISK_CLASS_MAP[text]) return text;
const numeric = Number(text);
if (Number.isFinite(numeric)) {
const idx = Math.max(0, Math.min(RISK_LEVELS.length - 1, Math.floor(numeric)));
return RISK_LEVELS[idx];
}
return text;
};
export default {
name: "SBillProgressList",
data() {
......@@ -81,7 +102,7 @@ export default {
formattedDate = `${dateObj.getMonth() + 1}${dateObj.getDate()}日`;
}
const riskText = RISK_LEVELS[Math.min(index, RISK_LEVELS.length - 1)];
const riskText = normalizeRiskSignal(item?.level);
const riskClass = RISK_CLASS_MAP[riskText] || "risk-low";
return {
......
<template>
<div class="temp-wrap">
<div class="left">
<div class="side">
<div class="side-box side-box-domain">
<AnalysisBox title="涉及领域" width="520px" height="415px">
<div class="right-box2-main" id="chart2"></div>
<div v-if="domainFooterText" class="right-box2-footer">
<div class="right-box2-footer-left">
<img src="./assets/icons/right-icon1.png" alt="" />
</div>
<div class="right-box2-footer-center">
{{ domainFooterText }}
</div>
<div class="right-box2-footer-right">
<img src="./assets/icons/arrow-right.png" alt="" />
</div>
</div>
</AnalysisBox>
</div>
<div class="side-box side-box-limit">
<AnalysisBox title="限制手段" width="520px" height="415px">
<div class="right-box1-main" id="chart1"></div>
<div v-if="limitFooterText" class="right-box1-footer">
<div class="right-box1-footer-left">
<img src="./assets/icons/right-icon1.png" alt="" />
</div>
<div class="right-box1-footer-center">
{{ limitFooterText }}
</div>
<div class="right-box1-footer-right">
<img src="./assets/icons/arrow-right.png" alt="" />
</div>
</div>
</AnalysisBox>
</div>
</div>
<div class="terms">
<!-- <div class="box-header">
<div class="box-header-left"></div>
<div class="box-header-title">主要条款</div>
......@@ -91,7 +125,7 @@
</div>
</div>
<div class="left-main">
<div class="left-main-item" v-for="(term, index) in mainTermsList" :key="index">
<div class="left-main-item" v-for="(term, index) in mainTermsList" :key="getTermKey(term, index)">
<div class="id">{{ (currentPage - 1) * pageSize + index + 1 }}</div>
<div class="info">
<div class="title">
......@@ -104,7 +138,7 @@
</div>
</div>
<div class="tags-box">
<div class="tag" v-for="(val, idx) in (term.hylyList || []).slice(0, 2)" :key="idx" :class="{
<div class="tag" v-for="(val, idx) in (term.hylyList || []).slice(0, 2)" :key="getTagKey(val, idx)" :class="{
tag1: val === '人工智能',
tag2: val === '新一代信息技术' || !['人工智能', '政治', '经济', '军事', '科技'].includes(val),
tag3: val === '政治',
......@@ -131,86 +165,6 @@
</div>
</AnalysisBox>
</div>
<div class="right">
<div class="right-box1">
<!-- <div class="box-header">
<div class="box-header-left"></div>
<div class="box-header-title">限制手段</div>
<div class="header-right">
<div class="icon">
<img src="@/assets/icons/box-header-icon1.png" alt="" />
</div>
<div class="icon">
<img src="@/assets/icons/box-header-icon2.png" alt="" />
</div>
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
</div>
</div>
<div class="right-box1-main" id="chart1"></div>
<div class="right-box1-footer">
<div class="right-box1-footer-left">
<img src="./assets/icons/right-icon1.png" alt="" />
</div>
<div class="right-box1-footer-center">通过关税壁垒、技术脱钩、新能源打压、地缘捆绑遏制中国产业链发展</div>
<div class="right-box1-footer-right">
<img src="./assets/icons/arrow-right.png" alt="" />
</div>
</div> -->
<AnalysisBox title="限制手段">
<div class="right-box1-main" id="chart1"></div>
<div class="right-box1-footer">
<div class="right-box1-footer-left">
<img src="./assets/icons/right-icon1.png" alt="" />
</div>
<div class="right-box1-footer-center">通过关税壁垒、技术脱钩、新能源打压、地缘捆绑遏制中国产业链发展</div>
<div class="right-box1-footer-right">
<img src="./assets/icons/arrow-right.png" alt="" />
</div>
</div>
</AnalysisBox>
</div>
<div class="right-box2">
<!-- <div class="box-header">
<div class="box-header-left"></div>
<div class="box-header-title">涉及领域</div>
<div class="header-right">
<div class="icon">
<img src="@/assets/icons/box-header-icon1.png" alt="" />
</div>
<div class="icon">
<img src="@/assets/icons/box-header-icon2.png" alt="" />
</div>
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
</div>
</div>
<div class="right-box2-main" id="chart2"></div>
<div class="right-box2-footer">
<div class="right-box2-footer-left">
<img src="./assets/icons/right-icon1.png" alt="" />
</div>
<div class="right-box2-footer-center">系统性挤压中国新能源、跨境电商及高端制造的在美生存空间。</div>
<div class="right-box2-footer-right">
<img src="./assets/icons/arrow-right.png" alt="" />
</div>
</div> -->
<AnalysisBox title="涉及领域">
<div class="right-box2-main" id="chart2"></div>
<div class="right-box2-footer">
<div class="right-box2-footer-left">
<img src="./assets/icons/right-icon1.png" alt="" />
</div>
<div class="right-box2-footer-center">系统性挤压中国新能源、跨境电商及高端制造的在美生存空间。</div>
<div class="right-box2-footer-right">
<img src="./assets/icons/arrow-right.png" alt="" />
</div>
</div>
</AnalysisBox>
</div>
</div>
</div>
</template>
......@@ -234,11 +188,21 @@ const pageSize = ref(10);
const total = ref(0);
const mainTermsList = ref([]);
const domainFooterText = ref("");
const limitFooterText = ref("");
const btnActiveIndex = ref(1);
const handleSelectBtn = index => {
btnActiveIndex.value = index;
};
const getTermKey = (term, index) => {
return term?.ywid ?? term?.id ?? term?.tkxh ?? index;
};
const getTagKey = (val, idx) => {
return `${val}-${idx}`;
};
const chart1Data = ref([]);
const chart1ColorList = ref(["#4096ff", "#b37feb", "#ff7875", "#85a5ff", "#69b1ff", "#ffc069", "#87e8de"]);
......@@ -478,8 +442,9 @@ onMounted(async () => {
}
}
.left {
.terms {
margin-top: 16px;
margin-left: 16px;
width: 1064px;
height: 845px;
.left-top {
......@@ -668,19 +633,23 @@ onMounted(async () => {
}
}
.right {
.side {
width: 520px;
margin-top: 16px;
margin-left: 16px;
.right-box1 {
.side-box {
width: 520px;
height: 415px;
.right-box1-main {
}
.side-box-limit {
margin-top: 15px;
width: 520px;
height: 315px;
padding: 16px;
}
height: 415px;
.right-box1-main {
width: 520px;
height: 375px;
padding: 16px;
}
.right-box1-footer {
width: 493px;
......@@ -735,15 +704,14 @@ onMounted(async () => {
}
}
.right-box2 {
margin-top: 15px;
width: 520px;
height: 415px;
.right-box2-main {
.side-box-domain {
width: 520px;
height: 315px;
padding: 16px;
}
height: 415px;
.right-box2-main {
width: 520px;
height: 375px;
padding: 16px;
}
.right-box2-footer {
width: 493px;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论