提交 49d4b995 authored 作者: 张伊明's avatar 张伊明

feat 接入议员合作关系接口 新增议员查询正序倒序按钮

style 优化议员合作关系列表样式
上级 a28f1990
......@@ -135,6 +135,16 @@ export function getBillsPerson(params, signal) {
})
}
// 获取议员合作关系
export function getBillsPersonRel(params, signal) {
return request({
method: 'GET',
url: `/api/BillOverview/billsPersonRel`,
params,
signal
})
}
// 获取提出部门列表
export function getPostOrgList() {
return request({
......
......@@ -38,7 +38,7 @@
</div>
<div class="right-header-box right-header-sort" style="margin-left: auto">
<el-checkbox v-model="isInvolveCn" true-label="Y" false-label="N" class="involve-checkbox" @change="handleInvolveCnChange">只看涉华法案</el-checkbox>
<el-select v-model="releaseTime" placeholder="选择排序方式" style="width: 120px" @change="handlePxChange">
<el-select v-model="releaseTime" placeholder="选择排序方式" style="width: 150px" @change="handlePxChange">
<template #prefix>
<div style="display: flex; align-items: center; height: 100%">
<img :src="desc" style="width: 14px; height: 14px" />
......@@ -48,6 +48,18 @@
</el-select>
</div>
</template>
<template v-else-if="activeTabName === '国会议员'">
<div class="right-header-box right-header-sort" style="margin-left: auto">
<el-select v-model="memberSortFun" placeholder="选择排序方式" style="width: 150px" @change="handleMemberSortFunChange">
<template #prefix>
<div style="display: flex; align-items: center; height: 100%">
<img :src="desc" style="width: 14px; height: 14px" />
</div>
</template>
<el-option v-for="item in memberSortFunList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</template>
</div>
<div class="right-main" v-loading="loading">
<template v-if="activeTabName === '国会法案'">
......@@ -134,9 +146,6 @@
<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>
......@@ -216,10 +225,10 @@
<script setup>
import { computed, onMounted, ref } from "vue";
import { getHylyList, getPostOrgList, getPostMemberList, getBills, getBillsPerson } from "@/api/bill/billHome";
import { getHylyList, getPostOrgList, getPostMemberList, getBills, getBillsPerson, getBillsPersonRel } 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 defaultAvatar from "@/assets/icons/default-icon1.png";
import defaultBill from "../assets/images/image1.png";
import zyyIcon from "@/assets/icons/zyy.png";
import cyyIcon from "@/assets/icons/cyy.png";
......@@ -260,8 +269,12 @@ const handleClickTab = tab => {
}
};
const releaseTime = ref(false);
const releaseTimeList = ref([{ label: "正序", value: true }, { label: "倒序", value: false }]);
// sortFun: true 正序 / false 倒序(法案接口字段)
const releaseTime = ref(true);
const releaseTimeList = ref([
{ label: "发布时间正序", value: true },
{ label: "发布时间倒序", value: false }
]);
const isInvolveCn = ref("Y");
const cateKuList = ref([]);
......@@ -296,19 +309,22 @@ const footerSelect2 = ref("全部提出议员");
const postOrgList = ref([{ departmentName: "全部委员会", departmentId: "全部委员会" }]);
const postMemberList = ref([{ memberName: "全部提出议员", memberId: "全部提出议员" }]);
const memberList = ref([]);
// sortFun: boolean(议员接口字段),当前接口表现与“正序/倒序”相反,发参时取反
const memberSortFun = ref(true);
const memberSortFunList = ref([
{ label: "提案数量正序", value: true },
{ label: "提案数量倒序", value: false }
]);
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 coopPagedList = computed(() => coopList.value || []);
const committeeList = ref([
{
......@@ -387,61 +403,70 @@ const handleGetCommitteeList = async () => {
}
};
// 获取议员合作关系数据(占位)
// 获取议员合作关系数据
const handleGetCoopList = async () => {
loading.value = true;
const { token, signal } = beginAbortableRequest();
const params = {
currentPage: coopCurrentPage.value,
pageSize: coopPageSize.value
};
if (!activeAreaList.value.includes("全部领域")) params.domainIds = activeAreaList.value;
try {
// TODO: 接入“议员合作关系”接口后,在此替换为真实请求并赋值 coopList
// 示例结构:每项包含两名议员及不超过 4 条共同提案
const list = [
{
id: "coop-1",
const res = await getBillsPersonRel(params, signal);
if (res.code === 200 && res.data && Array.isArray(res.data.content)) {
const list = res.data.content.map(item => {
const memberInfoList = item.memberInfoList || [];
const left = memberInfoList[0] || {};
const right = memberInfoList[1] || {};
const billsNum = Number(item.billsNum || 0);
const proposals = (item.billInfoList || []).slice(0, 4).map(bill => {
const proposedDate = bill.proposedDate ? String(bill.proposedDate) : "";
const year = proposedDate ? proposedDate.slice(0, 4) : "";
const codeParts = [];
if (bill.type) codeParts.push(bill.type);
if (bill.number) codeParts.push(bill.number);
return {
billId: bill.billId,
year,
code: codeParts.join("."),
title: bill.billName
};
});
const id = [left.id, right.id].filter(Boolean).join("-");
const leftName = left.name || "-";
const rightName = right.name || "-";
return {
id: id || Math.random().toString(36).slice(2),
left: {
name: "查克·舒默",
avatar: ""
name: leftName,
avatar: left.imageUrl || ""
},
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稳定币法案"
name: rightName,
avatar: right.imageUrl || ""
},
{
billId: "2025-HR-2057",
year: "2025",
code: "H.R.2057",
title: "小额额免包装政策调整"
}
]
}
];
total: billsNum,
totalText: `${billsNum}项共同提案`,
summary: `${leftName} 与 ${rightName} 在 ${billsNum} 项法案上合作`,
proposals
};
});
coopList.value = list;
coopTotal.value = list.length;
coopTotal.value = res.data.totalElements || list.length;
} else {
coopList.value = [];
coopTotal.value = 0;
}
} catch (error) {
if (error.name !== "AbortError") {
coopList.value = [];
coopTotal.value = 0;
}
} finally {
loading.value = false;
endAbortableRequest(token);
}
};
......@@ -487,7 +512,7 @@ const handleGetBills = async () => {
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;
params.sortFun = releaseTime.value;
if (!activePubTime.value.includes("全部时间")) params.years = activePubTime.value.join(",");
try {
......@@ -526,7 +551,8 @@ const handleGetBillsPerson = async () => {
const params = {
currentPage: memberCurrentPage.value,
pageSize: memberPageSize.value
pageSize: memberPageSize.value,
sortFun: !memberSortFun.value
};
if (footerSelect1.value !== "全部委员会") params.committeeId = footerSelect1.value;
......@@ -562,6 +588,7 @@ const handleGetBillsPerson = async () => {
avatar: item.imageUrl || "",
partyIcon,
chamberIcon,
proposalSize,
billCountText: `${proposalSize.toLocaleString()}项提案 >`,
partyText,
chamberText,
......@@ -666,6 +693,12 @@ const handleClickLatestProposal = item => {
});
};
const handleMemberSortFunChange = val => {
memberSortFun.value = val;
memberCurrentPage.value = 1;
handleGetBillsPerson();
};
const handleClickCoopProposal = proposal => {
if (!proposal?.billId) return;
props.onClickToDetail({
......@@ -676,7 +709,8 @@ const handleClickCoopProposal = proposal => {
const handleCoopCurrentChange = page => {
coopCurrentPage.value = page;
// 如后续改为后端分页,可在此调用 handleGetCoopList();
handleGetCoopList();
props.onAfterPageChange && props.onAfterPageChange();
};
const handleMemberCurrentChange = page => {
......@@ -739,11 +773,12 @@ onMounted(() => {
.home-content-footer-main {
width: 1600px;
height: 1401px;
min-height: 1401px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: flex-start;
padding-bottom: 39px;
&.committee-full-layout {
.right {
......@@ -830,6 +865,46 @@ onMounted(() => {
gap: 20px;
}
.proposal-sort-btn {
height: 40px;
padding: 0 12px;
border-radius: 6px;
border: 1px solid #dcdfe6;
background: var(--bg-white-100);
display: inline-flex;
align-items: center;
gap: 8px;
cursor: pointer;
user-select: none;
transition: background 0.15s ease;
&:hover {
background: rgba(20, 89, 187, 0.04);
}
}
.proposal-sort-icon {
width: 14px;
height: 14px;
flex-shrink: 0;
}
.proposal-sort-text {
color: var(--text-primary-65-color);
font-family: "Microsoft YaHei";
font-size: var(--font-size-base);
line-height: 24px;
white-space: nowrap;
}
.proposal-sort-order {
color: var(--text-primary-80-color);
font-family: "Microsoft YaHei";
font-size: var(--font-size-base);
line-height: 24px;
white-space: nowrap;
}
.involve-checkbox {
height: 40px;
display: inline-flex;
......@@ -863,7 +938,7 @@ onMounted(() => {
}
.right-main {
height: 1264px;
min-height: 1264px;
.member-grid,
.coop-list,
......@@ -1121,6 +1196,7 @@ onMounted(() => {
font-size: 14px;
font-weight: 500;
line-height: 22px;
margin-left: auto;
}
.coop-proposals {
......
......@@ -560,31 +560,24 @@ const handleBox7Data = async () => {
try {
const res = await getBillPostOrg({ year: box7selectetedTime.value });
console.log("法案提出部门", res);
if (res.code === 200 && res.data && res.data.length > 0) {
const orgBillNumList = res?.data?.orgBillNumList || [];
const orgBillNumMap = res?.data?.orgBillNumMap || {};
if (res.code === 200 && Array.isArray(orgBillNumList) && orgBillNumList.length > 0) {
box7HasData.value = true;
// 必须等待DOM更新,因为v-if切换可能导致元素刚被创建
await nextTick();
const apiData = res.data;
const houseItems = apiData.filter(i => i.congressName === "House");
const senateItems = apiData.filter(i => i.congressName === "Senate");
const houseTotal = houseItems.reduce((sum, i) => sum + i.countBill, 0);
const senateTotal = senateItems.reduce((sum, i) => sum + i.countBill, 0);
const data1 = [];
if (houseItems.length > 0) {
data1.push({ name: "众议院", value: houseTotal });
}
if (senateItems.length > 0) {
data1.push({ name: "参议院", value: senateTotal });
}
const data2 = [...houseItems, ...senateItems].map(item => ({
name: item.originDepart,
value: item.countBill,
type: item.congressName === "House" ? "众议院" : "参议院"
const houseTotal = Number(orgBillNumMap?.H || 0);
const senateTotal = Number(orgBillNumMap?.S || 0);
if (houseTotal > 0) data1.push({ name: "众议院", value: houseTotal });
if (senateTotal > 0) data1.push({ name: "参议院", value: senateTotal });
const data2 = orgBillNumList.map(item => ({
name: item.orgName,
value: Number(item.count || 0),
percent: typeof item.percent === "number" ? item.percent : Number(item.percent || 0),
type: item.orgType === "S" ? "参议院" : "众议院"
}));
const box7Chart = getDoublePieChart(data1, data2);
......@@ -719,6 +712,14 @@ const box8MockDataByYear = {
};
const getBox8ChartOption = stageList => {
const truncateLabel = (value, maxLen = 6) => {
if (value === null || value === undefined) return "";
const str = String(value);
const chars = Array.from(str);
if (chars.length <= maxLen) return str;
return `${chars.slice(0, maxLen).join("")}...`;
};
const axisMax = 100;
const countList = stageList.map(item => item.count || 0);
const totalCount = countList.reduce((sum, cur) => sum + cur, 0);
......@@ -774,6 +775,7 @@ const getBox8ChartOption = stageList => {
axisTick: { show: false },
axisLine: { show: false },
axisLabel: {
formatter: value => truncateLabel(value, 6),
color: "#3b414b",
fontSize: 16
}
......@@ -2049,16 +2051,13 @@ onUnmounted(() => {
.box9-main {
height: 100%;
box-sizing: border-box;
}
.box5-main {
padding: 8px 16px;
padding: 8px 30px;
}
.box8-main {
height: 100%;
box-sizing: border-box;
padding: 12px 20px 18px;
padding: 12px 30px 18px;
.box8-desc {
height: 24px;
......@@ -2077,18 +2076,18 @@ onUnmounted(() => {
}
.box9-main {
padding: 10px 20px;
padding: 10px 30px;
}
}
}
.home-content-footer {
width: 100%;
height: 1740px;
min-height: 1740px;
background: rgba(248, 249, 250, 1);
margin-bottom: 20px;
overflow: hidden;
margin-top: 36px;
overflow: visible;
.divide4 {
margin: 0 auto;
......
const truncateLabel = (value, maxLen = 6) => {
if (value === null || value === undefined) return ''
const str = String(value)
const chars = Array.from(str)
if (chars.length <= maxLen) return str
return `${chars.slice(0, maxLen).join('')}...`
}
const getDoublePieChart = (data1, data2) => {
const colorList = ['#8AC4FF', '#FFD591']
const colorList1 = ['#055FC2', '#FFA940']
......@@ -42,7 +50,12 @@ const getDoublePieChart = (data1, data2) => {
},
label: {
alignTo: 'edge',
formatter: '{name|{b}}\n{time|{c} 条 {d}%}',
formatter: params => {
const name = truncateLabel(params?.name, 6)
const value = params?.value ?? 0
const percent = typeof params?.percent === 'number' ? params.percent : 0
return `{name|${name}}\n{time|${value}${percent}%}`
},
minMargin: 5,
edgeDistance: 10,
lineHeight: 20,
......@@ -82,6 +95,7 @@ const getDoublePieChart = (data1, data2) => {
return {
name: item.name,
value: item.value,
percent: item.percent,
itemStyle: {
color: item.type === '参议院' ? '#8AC4FF' : '#FFD591'
......
......@@ -68,8 +68,15 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
axisLabel: {
formatter: '{value}项',
color: '#666'
},
splitLine: {
show: true,
lineStyle: {
color: '#e7f3ff',
type: 'dashed',
}
},
},
{
type: 'value',
position: 'right',
......@@ -84,6 +91,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
show: true,
lineStyle: {
color: '#e7f3ff',
type: 'dashed',
}
},
}
......@@ -92,6 +100,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
{
name: '提出法案',
type: 'line',
smooth: true,
symbol: 'emptyCircle',
symbolSize: 6,
areaStyle: {
......@@ -111,6 +120,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
{
name: '通过法案',
type: 'line',
smooth: true,
symbol: 'emptyCircle',
symbolSize: 6,
areaStyle: {
......@@ -131,6 +141,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
name: '通过率',
type: 'line',
yAxisIndex: 1,
smooth: true,
symbol: 'emptyCircle',
symbolSize: 4,
lineStyle: {
......
const truncateLabel = (value, maxLen = 6) => {
if (value === null || value === undefined) return ''
const str = String(value)
const chars = Array.from(str)
if (chars.length <= maxLen) return str
return `${chars.slice(0, maxLen).join('')}...`
}
const getPieChart = (data, colorList) => {
let option = {
// color: colorList,
......@@ -14,7 +22,12 @@ const getPieChart = (data, colorList) => {
},
label: {
alignTo: 'edge',
formatter: '{name|{b}}\n{time|{c} 条 {d}%}',
formatter: params => {
const name = truncateLabel(params?.name, 6)
const value = params?.value ?? 0
const percent = typeof params?.percent === 'number' ? params.percent : 0
return `{name|${name}}\n{time|${value}${percent}%}`
},
minMargin: 5,
edgeDistance: 10,
lineHeight: 22,
......
......@@ -2,6 +2,14 @@ import "echarts-wordcloud";
const getWordCloudChart = (data = []) => {
const option = {
tooltip: {
show: true,
formatter: params => {
const name = params?.data?.fullName ?? params?.name ?? ''
const value = params?.value ?? ''
return `${name}${value !== '' ? `:${value}` : ''}`
},
},
grid: {
left: 0,
top: 0,
......@@ -57,7 +65,14 @@ const getWordCloudChart = (data = []) => {
},
},
// 设置词云数据
data: data,
data: (Array.isArray(data) ? data : []).map(item => {
const name = item?.name ?? ''
return {
...item,
fullName: name,
name,
}
}),
},
],
}
......
......@@ -228,10 +228,10 @@ const mainHeaderBtnList = ref([
const activeTitle = ref("法案概况");
const handleClickMainHeaderBtn = item => {
if (["影响分析", "相关情况"].includes(item.name)) {
ElMessage.warning("当前功能正在开发中,敬请期待!");
return;
}
// if (["影响分析", "相关情况"].includes(item.name)) {
// ElMessage.warning("当前功能正在开发中,敬请期待!");
// return;
// }
activeTitle.value = item.name;
window.sessionStorage.setItem("activeTitle", activeTitle.value);
router.push({
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论