提交 7c850793 authored 作者: 张烨's avatar 张烨

Merge branch 'pre' into zy-dev

......@@ -14,7 +14,9 @@ build_pre:
stage: build
image: node:20-bullseye
tags:
- risk-monitor-frontend
- docker
- frontend
- linux
only:
- pre
script:
......@@ -37,39 +39,17 @@ deploy_pre:
stage: deploy
image: alpine:3.20
tags:
- risk-monitor-frontend
- docker
- frontend
- linux
only:
- pre
dependencies:
- build_pre
script:
- apk add --no-cache rsync curl jq
# 只允许“最新一次 pre pipeline”部署到 nginx(加二次确认,避免短时间多次推送导致重复 rsync)
- >
LATEST_PIPELINE_ID="$(
curl --silent --show-error --fail
--header "JOB-TOKEN: $CI_JOB_TOKEN"
"$CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/pipelines?ref=pre&order_by=id&sort=desc&per_page=1"
| jq -r '.[0].id'
)"
- >
if [ -z "$LATEST_PIPELINE_ID" ] || [ "$LATEST_PIPELINE_ID" != "$CI_PIPELINE_ID" ]; then
echo "skip deploy: not latest pipeline (latest=$LATEST_PIPELINE_ID current=$CI_PIPELINE_ID)";
exit 0;
fi
- sleep 20
- >
LATEST_PIPELINE_ID="$(
curl --silent --show-error --fail
--header "JOB-TOKEN: $CI_JOB_TOKEN"
"$CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/pipelines?ref=pre&order_by=id&sort=desc&per_page=1"
| jq -r '.[0].id'
)"
- >
if [ -z "$LATEST_PIPELINE_ID" ] || [ "$LATEST_PIPELINE_ID" != "$CI_PIPELINE_ID" ]; then
echo "skip deploy: not latest pipeline after debounce (latest=$LATEST_PIPELINE_ID current=$CI_PIPELINE_ID)";
exit 0;
fi
- apk add --no-cache rsync
- test -d dist || (echo "dist not found" && exit 1)
- test -d /nas/kjb_service/zm/pre-project/html || (echo "deploy target path not found" && exit 1)
- rsync -avz --delete dist/ /nas/kjb_service/zm/pre-project/html/
# 非 protected 分支:push 时先做 build 校验(避免合并 pre 时出现 build 报错)
......@@ -77,7 +57,9 @@ build_check:
stage: build
image: node:20-bullseye
tags:
- risk-monitor-frontend
- docker
- frontend
- linux
# 只在 push 时做构建校验,且排除 protected 分支与目标分支 pre
only:
- pushes
......
差异被折叠。
......@@ -335,99 +335,79 @@ export function getProgressPrediction(billId) {
* @returns {Promise<Object>} 相似法案列表
*/
export function getSimiBills(params = {}) {
// domains 如果是数组则用逗号拼接
const domains = Array.isArray(params.domains)
? params.domains.join(',')
: params.domains
return request('/api/BillProgressPrediction/simiBills', {
method: 'GET',
params: {
billIds: params.billIds,
domains: params.domains,
patternType: params.patternType ,
proposalType: params.proposalType ,
...params
domains: domains,
patternType: params.patternType,
proposalType: params.proposalType
}
})
}
/**
* 格式化日期 YYYY-MM-DD -> YYYY年M月D日
* @param {string} dateStr - 日期字符串
* @returns {string} 格式化后的日期
*/
function formatDate(dateStr) {
if (!dateStr) return ''
const match = dateStr.match(/(\d{4})-(\d{2})-(\d{2})/)
if (match) {
return `${match[1]}${parseInt(match[2])}${parseInt(match[3])}日`
}
return dateStr
}
/**
* 转换相似法案 API 返回的数据为组件所需格式
* @param {Object} apiData - API 返回的原始数据
* @returns {Object} 转换后的统计数据和法案列表
*/
export function transformSimiBillsData(apiData) {
if (!apiData || !apiData.data || !Array.isArray(apiData.data)) {
if (!apiData || !apiData.data) {
return { stats: null, bills: [] }
}
const bills = apiData.data
const data = apiData.data
const simiBills = data.simi_bills || []
// 计算统计数据
let becameLaw = 0
let notPassedOrShelved = 0
let totalDays = 0
let completedBills = 0
bills.forEach(bill => {
const actions = bill.bill_actions || []
const hasBecameLaw = actions.some(a =>
a.action_type === 'BecameLaw' ||
a.action_type === 'President' && a.action_desc?.includes('签署')
)
if (hasBecameLaw) {
becameLaw++
// 计算耗时
if (actions.length >= 2) {
const firstDate = new Date(actions[0].action_date)
const lastDate = new Date(actions[actions.length - 1].action_date)
const days = Math.ceil((lastDate - firstDate) / (1000 * 60 * 60 * 24))
if (days > 0) {
totalDays += days
completedBills++
}
}
} else {
notPassedOrShelved++
}
})
const medianDays = completedBills > 0 ? Math.round(totalDays / completedBills) : 223
const passRate = bills.length > 0 ? ((becameLaw / bills.length) * 100).toFixed(1) : '0'
// 直接使用 API 返回的统计数据
const stats = {
totalBills: bills.length,
becameLaw,
notPassedOrShelved,
medianDays,
passRate
totalBills: data.count || simiBills.length,
becameLaw: data.become_law || 0,
notPassedOrShelved: (data.count || simiBills.length) - (data.become_law || 0),
medianDays: data.become_law_avg_days || 0,
passRate: data.become_law_prop ? (data.become_law_prop * 100).toFixed(1) : '0'
}
// 转换法案列表格式
const transformedBills = bills.map(bill => ({
const transformedBills = simiBills.map(bill => ({
id: bill.bill_id,
title: bill.bill_name || bill.bill_id,
proposalDate: extractProposalDate(bill.poli_pattern_desc),
areas: bill.domain_name ? (Array.isArray(bill.domain_name) ? bill.domain_name : [bill.domain_name]) : [],
proposer: extractProposer(bill.bill_sponsors),
coProposers: bill.bill_proposal_desc || '',
proposalDate: bill.proposed_date ? formatDate(bill.proposed_date) : '',
areas: bill.bill_domain ? (Array.isArray(bill.bill_domain) ? bill.bill_domain : [bill.bill_domain]) : [],
proposer: bill.key_sponsor_name || extractProposer(bill.bill_sponsors),
proposerParty: bill.key_sponsor_party || '',
coProposers: bill.co_sponsor_desc || bill.bill_proposal_desc || '',
proposalType: bill.bill_proposal_type || '',
governmentType: formatGovernmentType(bill.poli_pattern_type, bill.poli_pattern_desc),
passDays: calculateTotalDays(bill.bill_actions),
patternType: bill.poli_pattern_type || '',
billStatus: bill.bill_status || '',
passDays: bill.bill_action_days || calculateTotalDays(bill.bill_actions),
yearsDifference: bill.years_difference || 0,
billActions: bill.bill_actions || [],
billSponsors: bill.bill_sponsors || [],
selected: true // 默认全选
}))
return { stats, bills: transformedBills }
}
/**
* 从政治格局描述中提取提案时间
* @param {string} desc - 政治格局描述
* @returns {string} 提案时间
*/
function extractProposalDate(desc) {
if (!desc) return ''
const match = desc.match(/(\d{4})-(\d{2})-(\d{2})/)
if (match) {
return `${match[1]}${parseInt(match[2])}${parseInt(match[3])}日`
}
return ''
}
/**
* 从提案人列表中提取主提案人
* @param {Array} sponsors - 提案人列表
......@@ -504,9 +484,9 @@ export function transformProposalInfo(apiData) {
return {
// 提案标题
title: data.bill_title || 'H.R.1-大而美法案',
title: data.bill_name_zh ,
// 提案时间 - 从政治格局描述中提取
date: extractDateFromDesc(data.poli_pattern_desc) || '2025年5月20日',
date: extractDateFromDesc(data.poli_pattern_desc) ,
// 涉及领域 TAG - 使用 domain_name
areas: Array.isArray(data.domain_name) ? data.domain_name : (data.domain_name ? [data.domain_name] : []),
// 政策领域完整选项列表 - 使用 bill_domain(用于筛选下拉框)
......
......@@ -10,9 +10,8 @@
<div class="title-box" v-show="!isShowSearchBar">
<!-- <div class="title-box" v-if="false"> -->
<div class="title" v-for="(item, index) in homeTitleList" :key="index"
@mouseenter="handleShowMenu(index, true)" @mouseleave="handleShowMenu(index, false)"
@click="handleClickTitle(item)">
<div class="text" :class="{ textActive: homeActiveTitleIndex === index }">
@mouseenter="handleShowMenu(index, true)" @click="handleClickTitle(item, index)">
<div class="text text-title-1-show" :class="{ textActive: homeActiveTitleIndex === index }">
{{ item.name }}
</div>
<div class="bottom-line" v-if="homeActiveTitleIndex === index"></div>
......@@ -28,13 +27,24 @@
<div class="user">
<img src="@/assets/icons/overview/user.png" alt="" />
</div>
<div class="name">{{ "管理员" }}</div>
<div class="name text-regular">{{ "管理员" }}</div>
</div>
</div>
<div class="menu-box" v-show="isShowMenu" @mouseenter="handleHoverMenu(true)"
@mouseleave="handleHoverMenu(false)">
<div class="menu-content">
<div class="menu-item" v-for="(item, index) in menuList" :key="index" @click="handleToModule(item)">
<div class="menu-item" v-for="(item, index) in menuList" :key="index" @click="handleToModule(item, 1)">
<div class="icon">
<img :src="item.icon" alt="" />
</div>
<div class="title">{{ item.title }}</div>
</div>
</div>
</div>
<div class="tool-box" v-show="isShowTool" @mouseenter="handleHoverTool(true)"
@mouseleave="handleHoverTool(false)">
<div class="menu-content">
<div class="menu-item" v-for="(item, index) in toolList" :key="index" @click="handleToModule(item, 2)">
<div class="icon">
<img :src="item.icon" alt="" />
</div>
......@@ -47,7 +57,7 @@
</template>
<script setup>
import { ref, computed, onMounted, watchEffect } from "vue";
import { ref, computed, onMounted, watchEffect, onUnmounted } from "vue";
import { useRouter } from "vue-router";
import { useRoute } from "vue-router";
import { getPersonType } from "@/api/common/index";
......@@ -65,6 +75,8 @@ import Menu9 from "@/assets/icons/overview/menu9.png";
import Menu10 from "@/assets/icons/overview/menu10.png";
import Menu11 from "@/assets/icons/overview/menu11.png";
import Menu12 from "@/assets/icons/overview/menu12.png";
import Tool1 from './tool1.svg'
import Tool2 from './tool2.svg'
import { ElMessage } from "element-plus";
import { useWrittingAsstaintStore } from "@/stores/writtingAsstaintStore";
const store = useWrittingAsstaintStore();
......@@ -91,29 +103,43 @@ const handleGetPersonType = async () => {
// 概览页标题列表
const homeTitleList = ref([
{
name: "中美科技博弈",
name: "首页",
path: "/ZMOverView",
disabled: false
},
// {
// name: "主要国家科技动向感知",
// path: "",
// disabled: true
// },
// {
// name: "主要国家竞争科技安全",
// path: "",
// disabled: true
// }
{
name: "中美科技博弈",
path: "/billHome",
disabled: false
},
{
name: "智能工具",
path: "/chat",
disabled: false
},
{
name: "数据资源库",
path: "/dataLibrary",
disabled: false
}
]);
const homeActiveTitleIndex = ref(0);
const isShowMenu = ref(false);
const handleShowMenu = (index, isShow) => {
if (index === 0) {
if (index === 1) {
isShowMenu.value = isShow;
isShowTool.value = false;
} else if (index === 2) {
isShowMenu.value = false
isShowTool.value = isShow;
} else {
isShowMenu.value = false
isShowTool.value = false;
}
};
......@@ -122,11 +148,11 @@ const handleHoverMenu = isShow => {
};
const menuList = ref([
{
title: "中美科技博弈概览",
icon: Menu1,
path: "/ZMOverView"
},
// {
// title: "中美科技博弈概览",
// icon: Menu1,
// path: "/ZMOverView"
// },
{
title: "科技法案",
icon: Menu2,
......@@ -184,29 +210,57 @@ const menuList = ref([
}
]);
const handleToModule = item => {
const curRoute = router.resolve({
path: item.path
});
window.open(curRoute.href, "_blank");
const isShowTool = ref(false);
const handleHoverTool = isShow => {
isShowTool.value = isShow;
};
const searchText = ref("");
const handleSearch = () => {
const curRoute = router.resolve({
path: "/searchResults",
query: {
searchText: searchText.value
}
});
window.open(curRoute.href, "_blank");
const toolList = ref([
{
title: "智能问答",
icon: Tool1,
path: "/chat"
},
{
title: "智能写报",
icon: Tool2,
path: "/writtingAsstaint"
},
])
const handleToModule = (item, index) => {
homeActiveTitleIndex.value = index
if (index === 1) {
router.push({
path: item.path
})
} else {
const curRoute = router.resolve({
path: item.path
});
window.open(curRoute.href, "_blank");
}
isShowMenu.value = false
isShowTool.value = false
};
const handleClickTitle = item => {
if (item.name === "主要国家科技动向感知" || item.name === "主要国家竞争科技安全") {
ElMessage.warning("当前功能正在开发中,敬请期待!");
const handleClickTitle = (item, index) => {
if (homeActiveTitleIndex.value === index) return
homeActiveTitleIndex.value = index
window.localStorage.setItem('homeActiveTitleIndex', homeActiveTitleIndex.value)
if (item.name === '智能工具') {
const curRoute = router.resolve({
path: item.path,
});
window.open(curRoute.href, "_blank");
} else {
router.push(item.path)
}
};
const handleClickToolBox = () => {
......@@ -215,7 +269,12 @@ const handleClickToolBox = () => {
onMounted(() => {
handleGetPersonType();
homeActiveTitleIndex.value = Number(window.localStorage.getItem('homeActiveTitleIndex'))
});
onUnmounted(() => {
window.localStorage.removeItem('homeActiveTitleIndex')
})
</script>
<style lang="scss" scoped>
......@@ -285,12 +344,7 @@ onMounted(() => {
}
.text {
color: rgba(59, 65, 75, 1);
font-family: YouSheBiaoTiHei;
font-style: Regular;
font-size: 30px;
font-weight: 400;
letter-spacing: 0px;
color: var(--text-primary-80-color);
}
.textActive {
......@@ -360,13 +414,7 @@ onMounted(() => {
.name {
width: 48px;
height: 30px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
color: var(--text-primary-80-color);
}
}
}
......@@ -406,18 +454,69 @@ onMounted(() => {
width: 562px;
height: 348px;
margin-top: 8px;
margin-left: 72px;
display: flex;
flex-wrap: wrap;
.menu-item {
margin-top: 36px;
width: 280px;
height: 24px;
display: flex;
cursor: pointer;
&:hover {
.title {
color: var(--color-main-active);
font-size: 20px;
}
}
.icon {
width: 24px;
height: 24px;
img {
width: 100%;
height: 100%;
}
}
.title {
margin-left: 16px;
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 18px;
font-weight: 700;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
}
}
}
}
.tool-box {
position: absolute;
z-index: 999999;
width: 273px;
height: 171px;
top: 52px;
left: 300px;
box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 1);
border-radius: 10px;
backdrop-filter: blur(30px);
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 0.8);
.menu-content {
width: 562px;
height: 348px;
margin-top: 8px;
margin-left: 72px;
.menu-item {
margin-top: 36px;
width: 280px;
height: 24px;
display: flex;
cursor: pointer;
&:hover {
.title {
color: var(--color-main-active);
......@@ -434,7 +533,6 @@ onMounted(() => {
height: 100%;
}
}
.title {
margin-left: 16px;
height: 24px;
......
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_1" x1="12" x2="12" y1="1" y2="23.0000019" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(0,91,244)" offset="0" stop-opacity="1" />
<stop stop-color="rgb(101,0,253)" offset="1" stop-opacity="1" />
</linearGradient>
</defs>
<rect id="ZM" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
<path id="合并" d="M16.1924 8.34956L17.265 9.39747C16.1916 12.5467 12.973 15.696 8.68258 16.2219C5.81801 16.5715 2.54479 19.4738 1 23C2.07341 16.7015 4.39054 1 20.4837 1C19.4119 4.1461 18.3401 6.24507 17.2683 7.29535L16.1924 8.34956ZM16.9643 4.86177C17.4797 3.85558 19.0242 2.51052 19.0242 1.83869C18.5092 2.17461 16.9643 2.84605 15.9343 4.35789C14.9044 5.86972 12.3295 6.87729 12.3295 6.87729C13.3594 6.54137 16.4489 5.86795 16.9643 4.86177ZM15.4194 8.8928C15.4194 9.56464 15.1104 11.1099 13.8744 11.9161C12.6385 12.7223 10.2696 13.5957 9.23961 13.9316C9.23961 13.9316 12.0205 12.6215 12.8445 11.4122C13.6684 10.2029 14.9044 9.22872 15.4194 8.8928ZM19.254 14.3913C19.254 14.3913 18.5049 16.1842 17.0059 17.2593C15.507 18.3345 13.2582 18.6917 13.2582 18.6917C13.2582 18.6917 15.3188 19.0509 16.2555 20.128C17.1923 21.205 17.0051 23 17.0051 23C17.0051 23 17.7544 21.205 19.2532 20.128C20.7519 19.0509 23 18.6919 23 18.6919C23 18.6919 20.9401 18.3345 20.0036 17.2593C19.0671 16.1842 19.254 14.3913 19.254 14.3913Z" fill="url(#paint_linear_1)" fill-rule="evenodd" />
</svg>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_2" x1="12" x2="12" y1="2" y2="22" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(0,91,244)" offset="0" stop-opacity="1" />
<stop stop-color="rgb(101,0,253)" offset="1" stop-opacity="1" />
</linearGradient>
</defs>
<rect id="法案" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
<path id="减去顶层" d="M1.00002 11.1429C1.00002 6.0934 5.66569 2 11.4211 2C17.1765 2 21.8421 6.0934 21.8421 11.1429C21.8421 16.1923 17.1765 20.2857 11.4211 20.2857C10.0795 20.2857 8.79726 20.0634 7.61946 19.6584C6.99335 19.443 5.83647 18.8635 5.83647 18.8635L1 19.6588L2.90775 16.417C2.90775 16.417 2.15952 15.3834 1.87639 14.8183C1.31279 13.6935 1.00002 12.4503 1.00002 11.1429ZM15.7969 6.57031C15.7969 6.57031 15.5142 7.22506 14.9487 7.61766C14.3831 8.01027 13.5347 8.14075 13.5347 8.14075C13.5347 8.14075 14.3121 8.2719 14.6656 8.66523C15.019 9.05855 14.9484 9.71404 14.9484 9.71404C14.9484 9.71404 15.2311 9.05854 15.7965 8.66523C16.362 8.27192 17.2102 8.14079 17.2102 8.14079C17.2102 8.14079 16.433 8.01028 16.0797 7.61766C15.7263 7.22505 15.7969 6.57031 15.7969 6.57031ZM12.5406 14.0703L11.6792 8.14197L7.22535 8.14197L7.55117 8.43609L5.05229 14.0703L6.89676 14.0703L7.65333 12.4565L10.3676 12.4565L10.594 14.0703L12.5406 14.0703ZM8.09512 11.4514L9.18027 9.14708L9.9396 9.14708L10.2654 11.4514L8.09512 11.4514ZM16.3866 9.83812L15.6492 14.0703L13.5921 14.0703L14.1004 10.2371L13.7718 9.83812L16.3866 9.83812ZM9.10525 20.5652C10.534 21.4701 12.266 22 14.1326 22C19.0299 22 23 18.3529 23 13.854C23 12.9035 22.8228 11.991 22.497 11.1429C22.5038 11.2826 22.5072 11.423 22.5072 11.5643C22.5072 16.7661 17.8755 20.9831 12.162 20.9831C11.0979 20.9831 10.0713 20.8368 9.10525 20.5652Z" fill="url(#paint_linear_2)" fill-rule="evenodd" />
</svg>
......@@ -13,8 +13,8 @@ import '@/assets/fonts/font.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
// import AreaTag from '@/components/base/AreaTag/index.vue'
// import LeftBtn from "@/components/base/pageBtn/leftBtn.vue";
// import RightBtn from "@/components/base/pageBtn/rightBtn.vue";
// import LeftBtn from "@/components/base/pageBtn/LeftBtn.vue";
// import RightBtn from "@/components/base/pageBtn/RightBtn.vue";
// import OverviewMainBox from "@/components/base/boxBackground/overviewMainBox.vue";
// import OverviewNormalBox from "@/components/base/boxBackground/overviewNormalBox.vue";
// import AnalysisBox from '@/components/base/boxBackground/analysisBox.vue'
......
......@@ -26,21 +26,33 @@ const routes = [
name: "Home",
component: Home,
children: [
...fileRoutes
...fileRoutes,
{
path: "/dataLibrary",
name: "DataLibrary",
redirect: "./dataLibrary/countryBill",
component: DataLibrary,
meta: {
title: '数据资源库'
},
children: [
...dataRoutes
]
},
]
},
{
path: "/dataLibrary",
name: "DataLibrary",
component: DataLibrary,
meta: {
title: '数据资源库'
},
children: [
...dataRoutes
]
},
// {
// path: "/dataLibrary",
// name: "DataLibrary",
// component: DataLibrary,
// meta: {
// title: '数据资源库'
// },
// children: [
// ...dataRoutes
// ]
// },
];
......
......@@ -27,8 +27,8 @@
<pre>
{{
`
import LeftBtn from '@/components/base/pageBtn/leftBtn.vue'
import RightBtn from '@/components/base/pageBtn/rightBtn.vue'
import LeftBtn from '@/components/base/pageBtn/LeftBtn.vue'
import RightBtn from '@/components/base/pageBtn/RightBtn.vue'
<LeftBtn />
<RightBtn />
......@@ -48,8 +48,8 @@
<script setup>
import '@/styles/common.scss'
import LeftBtn from '@/components/base/pageBtn/leftBtn.vue'
import RightBtn from '@/components/base/pageBtn/rightBtn.vue'
import LeftBtn from '@/components/base/pageBtn/LeftBtn.vue'
import RightBtn from '@/components/base/pageBtn/RightBtn.vue'
const span = 12
</script>
......
......@@ -83,7 +83,8 @@
</el-icon>
</div>
<div class="right-box1-main-bottom">
<WordCloudMap :data="wordCloudData" :selectedName="selectedIndustryName" shape="circle" @wordClick="handleWordClick" />
<WordCloudMap :data="wordCloudData" :selectedName="selectedIndustryName" shape="circle"
@wordClick="handleWordClick" />
</div>
</div>
<div class="right-box2">
......@@ -125,9 +126,11 @@ import defaultNew from "../assets/images/default-icon-news.png";
import defaultA from "../assets/images/default-icon1.png";
import { getBillBackground, getBillPersonAnalyze, getBillInfoEvent, getBillPersonAnalyzeDy } from "@/api/bill";
import { useGotoNewsDetail } from "@/router/modules/news";
const route = useRoute();
const router = useRouter();
const gotoNewsDetail = useGotoNewsDetail();
const handleNewsImgError = e => {
e.target.src = defaultNew;
......@@ -135,13 +138,9 @@ const handleNewsImgError = e => {
// 跳转到相关新闻
const handleClickEvent = item => {
const routeData = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
}
});
window.open(routeData.href, "_blank");
const newsId = item?.id || item?.newsId;
if (!newsId) return;
gotoNewsDetail(newsId);
};
......@@ -149,13 +148,19 @@ const handleClickEvent = item => {
// 跳转人员详情
const handleClickUser = item => {
window.sessionStorage.setItem('curTabName', item.name)
const routeData = router.resolve({
// const routeData = router.resolve({
// path: "/characterPage",
// query: {
// personId: item.id
// }
// });
// window.open(routeData.href, "_blank");
router.push({
path: "/characterPage",
query: {
personId: item.id
}
});
window.open(routeData.href, "_blank");
})
};
const box1BtnActive = ref(1);
......@@ -281,7 +286,7 @@ const handleGetBillPersonAnalyze = async isOppose => {
const { members, industryCounts } = res.data;
// 更新人员列表
personList.value = members || [];
personList.value.forEach((item, index) => {
personList.value.forEach(item => {
// 优先使用接口返回的图片,没有则使用默认头像 defaultA
item.image = item.imageUrl || defaultA;
item.icon = userIcon;
......@@ -400,6 +405,7 @@ onMounted(() => {
.left-box--background {
height: auto;
.box1-main {
.box1-main-center {
margin: 0 auto;
......@@ -497,6 +503,7 @@ onMounted(() => {
.left-box--event {
margin-top: 15px;
height: auto;
.box2-main {
--event-item-height: 60px;
......
......@@ -433,14 +433,21 @@ const handleClickAvatar = async member => {
return;
}
window.sessionStorage.setItem("curTabName", member.name || "");
const routeData = router.resolve({
// const routeData = router.resolve({
// path: "/characterPage",
// query: {
// type,
// personId: member.id
// }
// });
// window.open(routeData.href, "_blank");
router.push({
path: "/characterPage",
query: {
type,
personId: member.id
}
});
window.open(routeData.href, "_blank");
})
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
......
......@@ -25,7 +25,9 @@
</div>
<div class="committee-cards-row">
<div v-for="item in committeeCardList" :key="item.id" class="committee-card">
<div class="committee-card-icon"></div>
<div class="committee-card-icon">
<img :src="iconCommit" alt="委员会头像" />
</div>
<div class="committee-card-content">
<div class="committee-card-name">{{ item.name }}</div>
<div class="committee-card-chamber">{{ item.chamber }}</div>
......@@ -38,7 +40,7 @@
<DivideHeader id="position1" class="divide1" :titleText="'最新动态'"></DivideHeader>
<div class="home-content-center">
<div class="center-top">
<overviewMainBox class="box1" title="热门法案" @toDetail="handleClickToDetail">
<OverviewMainBox class="box1" title="热门法案" @toDetail="handleClickToDetail">
<template #headerIcon>
<img style="width: 100%; height: 100%" src="./assets/images/box1-header-icon.png" alt="" />
</template>
......@@ -114,14 +116,15 @@
</el-carousel-item>
</el-carousel>
</div>
</overviewMainBox>
</OverviewMainBox>
<RiskSignal :list="warningList" @more-click="handleToMoreRiskSignal" @item-click="handleClickToDetailO"
riskLevel="signalLevel" postDate="signalTime" name="signalTitle" />
</div>
<DivideHeader id="position2" class="divide2" :titleText="'资讯要闻'"></DivideHeader>
<div class="center-center">
<NewsList :newsList="newsList" img="newsImage" title="newsTitle" from="from" content="newsContent" />
<NewsList :newsList="newsList" img="newsImage" title="newsTitle" from="from" content="newsContent"
@item-click="handleClickNewsDetail" />
<MessageBubble :messageList="messageList" imageUrl="personImage" @more-click="handleToSocialDetail"
@person-click="handleClickToCharacter" name="personName" content="remarks" source="orgName" />
</div>
......@@ -287,10 +290,11 @@ import getDoublePieChart from "./utils/doublePieChart";
import box5HeaderIcon from "./assets/images/box5-header-icon.png";
import box6HeaderIcon from "./assets/images/box6-header-icon.png";
import box7HeaderIcon from "./assets/images/box7-header-icon.png";
import iconCommit from "./assets/icons/icon-commit.png";
import { ElMessage } from "element-plus";
import { Calendar } from "@element-plus/icons-vue";
import { useGotoNewsDetail } from "@/router/modules/news";
// 跳转人物主页
const handleClickToCharacter = async (id, name) => {
......@@ -327,14 +331,23 @@ const handleClickToCharacter = async (id, name) => {
return;
}
window.sessionStorage.setItem("curTabName", name);
const route = router.resolve({
path: "/characterPage",
query: {
type: type, // type=1为科技企业领袖,2为国会议员,3为智库研究人员
personId: id
// const route = router.resolve({
// path: "/characterPage",
// query: {
// type: type, // type=1为科技企业领袖,2为国会议员,3为智库研究人员
// personId: id
// }
// });
// window.open(route.href, "_blank");
router.push(
{
path: "/characterPage",
query: {
type: type, // type=1为科技企业领袖,2为国会议员,3为智库研究人员
personId: id
}
}
});
window.open(route.href, "_blank");
)
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
......@@ -420,28 +433,34 @@ const curBill = ref({
const handleClickToDetail = () => {
window.sessionStorage.setItem("billId", curBill.value.billId);
window.sessionStorage.setItem("curTabName", curBill.value.billName);
const route = router.resolve({
// const route = router.resolve({
// path: "/billLayout",
// query: {
// billId: curBill.value.billId
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/billLayout",
query: {
billId: curBill.value.billId
}
});
console.log(route);
window.open(route.href, "_blank");
})
};
// 查看详情 传递参数
const handleClickToDetailO = item => {
window.sessionStorage.setItem("billId", item.billId);
window.sessionStorage.setItem("curTabName", item.name || item.signalTitle);
const route = router.resolve("/billLayout?billId=" + item.billId);
window.open(route.href, "_blank");
// const route = router.resolve("/billLayout?billId=" + item.billId);
// window.open(route.href, "_blank");
router.push("/billLayout?billId=" + item.billId)
};
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
// const route = router.resolve("/viewRiskSignal");
// window.open(route.href, "_blank");
router.push("/viewRiskSignal")
};
// 风险信号
const warningList = ref([]);
......@@ -498,18 +517,21 @@ const aiPaneLoading = ref({
box9: false
});
const gotoNewsDetail = useGotoNewsDetail();
const handleClickNewsDetail = news => {
const newsId = news?.newsId || news?.id;
if (!newsId) return;
gotoNewsDetail(newsId);
};
const buildAiChartPayload = key => {
if (key === "box5") {
const title = Array.isArray(box5Data.value.title) ? box5Data.value.title : [];
const proposed = box5Data.value?.data?.[0]?.value || [];
const passed = box5Data.value?.data?.[1]?.value || [];
const rate =
box5Data.value.percent ||
title.map((_, i) => {
const p = Number(proposed[i] || 0);
const pass = Number(passed[i] || 0);
return p ? Number(((pass / p) * 100).toFixed(2)) : 0;
});
const housePassed = box5Data.value?.data?.[2]?.value || [];
const senatePassed = box5Data.value?.data?.[3]?.value || [];
const hsPassed = box5Data.value?.data?.[4]?.value || [];
return {
type: "折线图",
name: "涉华法案数量变化趋势",
......@@ -517,7 +539,9 @@ const buildAiChartPayload = key => {
month,
proposed: Number(proposed[i] || 0),
passed: Number(passed[i] || 0),
pass_rate: Number(rate[i] || 0)
house_passed: Number(housePassed[i] || 0),
senate_passed: Number(senatePassed[i] || 0),
hs_passed: Number(hsPassed[i] || 0)
}))
};
}
......@@ -750,6 +774,18 @@ const box5Data = ref({
{
name: "通过法案",
value: [6, 3, 4, 6, 11, 5, 2, 14, 16, 27, 28, 44]
},
{
name: "众议院通过",
value: []
},
{
name: "参议院通过",
value: []
},
{
name: "双院通过",
value: []
}
]
});
......@@ -772,11 +808,23 @@ const handleGetBillCount = async () => {
data: [
{
name: "提出法案",
value: sortedData.map(item => item.totalCount)
value: sortedData.map(item => item.proposedCount)
},
{
name: "通过法案",
value: sortedData.map(item => item.passCount)
},
{
name: "众议院通过",
value: sortedData.map(item => item.houseCount)
},
{
name: "参议院通过",
value: sortedData.map(item => item.senateCount)
},
{
name: "双院通过",
value: sortedData.map(item => item.hscount)
}
],
percent: sortedData.map(item => item.percent)
......@@ -788,7 +836,10 @@ const handleGetBillCount = async () => {
title: [],
data: [
{ name: "提出法案", value: [] },
{ name: "通过法案", value: [] }
{ name: "通过法案", value: [] },
{ name: "众议院通过", value: [] },
{ name: "参议院通过", value: [] },
{ name: "双院通过", value: [] }
],
percent: []
};
......@@ -801,7 +852,10 @@ const handleGetBillCount = async () => {
title: [],
data: [
{ name: "提出法案", value: [] },
{ name: "通过法案", value: [] }
{ name: "通过法案", value: [] },
{ name: "众议院通过", value: [] },
{ name: "参议院通过", value: [] },
{ name: "双院通过", value: [] }
],
percent: []
};
......@@ -814,13 +868,17 @@ const handleBox5 = async () => {
await nextTick();
const proposed = box5Data.value.data[0].value;
const passed = box5Data.value.data[1].value;
const rate =
box5Data.value.percent ||
proposed.map((p, i) => {
const pass = passed[i] || 0;
return p ? ((pass / p) * 100).toFixed(2) : 0;
});
const box5Chart = getMultiLineChart(box5Data.value.title, proposed, passed, rate);
const housePassed = box5Data.value.data[2].value;
const senatePassed = box5Data.value.data[3].value;
const hsPassed = box5Data.value.data[4].value;
const box5Chart = getMultiLineChart(
box5Data.value.title,
proposed,
passed,
housePassed,
senatePassed,
hsPassed
);
const domain = categoryList.value.filter(item => {
return item.id === box5Select.value
})[0]?.name
......@@ -901,13 +959,19 @@ watch(box7selectetedTime, () => {
});
// 查看社交媒体详情
const handleToSocialDetail = item => {
const route = router.resolve({
// const route = router.resolve({
// path: "/characterPage",
// query: {
// personId: item.id
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/characterPage",
query: {
personId: item.id
}
});
window.open(route.href, "_blank");
})
};
// 关键条款
const wordCloudData = ref([]);
......@@ -922,10 +986,10 @@ const handleGetKeyTK = async () => {
.sort((a, b) => (b.count ?? 0) - (a.count ?? 0))
.slice(0, 20)
.map(item => {
return {
name: item.clause,
value: item.count
};
return {
name: item.clause,
value: item.count
};
});
}
} catch (error) {
......@@ -1693,6 +1757,14 @@ onUnmounted(() => {
border-radius: 50%;
background: var(--color-primary-10);
flex-shrink: 0;
overflow: hidden;
img {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
}
.committee-card-content {
......
import * as echarts from 'echarts'
import { MUTICHARTCOLORS } from '../../../../common/constant'
const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData, hsData) => {
const lineColors = MUTICHARTCOLORS.slice(0, 5)
const hexToRgba = (hex, alpha) => {
if (typeof hex !== 'string' || !hex.startsWith('#')) return hex
const normalized = hex.replace('#', '')
const full = normalized.length === 3
? normalized.split('').map(c => c + c).join('')
: normalized
const r = parseInt(full.slice(0, 2), 16)
const g = parseInt(full.slice(2, 4), 16)
const b = parseInt(full.slice(4, 6), 16)
return `rgba(${r}, ${g}, ${b}, ${alpha})`
}
const getAreaColor = color => new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: hexToRgba(color, 0.35)
}, {
offset: 1,
color: hexToRgba(color, 0)
}])
const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
return {
tooltip: {
trigger: 'item',
......@@ -28,7 +49,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
containLabel: true
},
legend: {
data: ['提出法案', '通过法案', '通过率'],
data: ['提出法案', '通过法案', '众议院通过', '参议院通过', '双院通过'],
show: true,
top: 10,
icon: 'circle',
......@@ -38,7 +59,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
fontSize: '14px',
}
},
color: ['#1677FF', '#FA8C16', '#D9001B'],
color: lineColors,
xAxis: [
{
type: 'category',
......@@ -65,7 +86,6 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
{
type: 'value',
position: 'left',
// 纵轴单位只在纵轴上方显示一次(通过 axis.name),避免每个刻度重复显示
name: '项',
nameLocation: 'end',
nameGap: 12,
......@@ -73,51 +93,20 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
color: '#666',
fontSize: 14,
fontWeight: 400,
// 给单位一点点下移空间,使其更贴近顶部刻度数字的视觉基线
padding: [0, 0, 6, -20]
},
axisLabel: {
formatter: '{value}',
color: '#666',
fontSize: 14,
fontWeight: 400
},
splitLine: {
show: true,
lineStyle: {
color: '#e7f3ff',
type: 'dashed',
}
},
},
{
type: 'value',
position: 'right',
min: 0,
max: 100,
interval: 20,
// 通过率单位仅展示一次
name: '%',
nameLocation: 'end',
nameGap: 12,
nameTextStyle: {
formatter: '{value}',
color: '#666',
fontSize: 14,
fontWeight: 400,
padding: [0, 0, 6, 20]
},
axisLabel: {
formatter: '{value}',
color: '#666',
fontSize: 14,
fontWeight: 400
fontWeight: 400
},
splitLine: {
show: true,
lineStyle: {
color: '#e7f3ff',
type: 'dashed',
}
show: true,
lineStyle: {
color: '#e7f3ff',
type: 'dashed',
}
},
}
],
......@@ -129,18 +118,12 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
symbol: 'emptyCircle',
symbolSize: 6,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(22, 119, 255, 0.4)' // 起始颜色
}, {
offset: 1,
color: 'rgba(22, 119, 255, 0)' // 结束颜色
}])
color: getAreaColor(lineColors[0])
},
itemStyle: {
color: '#1677FF'
color: lineColors[0]
},
data: dataY1
data: proposedData
},
{
name: '通过法案',
......@@ -149,34 +132,54 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
symbol: 'emptyCircle',
symbolSize: 6,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(250, 140, 22, 0.4)' // 起始颜色
}, {
offset: 1,
color: 'rgba(250, 140, 22, 0)' // 结束颜色
}])
color: getAreaColor(lineColors[1])
},
itemStyle: {
color: '#FA8C16'
color: lineColors[1]
},
data: dataY2
data: passData
},
{
name: '通过率',
name: '众议院通过',
type: 'line',
yAxisIndex: 1,
smooth: true,
symbol: 'emptyCircle',
symbolSize: 4,
lineStyle: {
type: 'dashed',
width: 2
symbolSize: 6,
areaStyle: {
color: getAreaColor(lineColors[2])
},
itemStyle: {
color: lineColors[2]
},
data: houseData
},
{
name: '参议院通过',
type: 'line',
smooth: true,
symbol: 'emptyCircle',
symbolSize: 6,
areaStyle: {
color: getAreaColor(lineColors[3])
},
itemStyle: {
color: lineColors[3]
},
data: senateData
},
{
name: '双院通过',
type: 'line',
smooth: true,
symbol: 'emptyCircle',
symbolSize: 6,
areaStyle: {
color: getAreaColor(lineColors[4])
},
itemStyle: {
color: '#D9001B'
color: lineColors[4]
},
data: dataY3
data: hsData
}
]
}
......
......@@ -62,7 +62,6 @@
<div class="field-content">
<el-select
v-model="localValues.oppositionProposer"
multiple
placeholder="请选择"
style="width: 420px"
@change="handleChange"
......@@ -83,7 +82,6 @@
<div class="field-content">
<el-select
v-model="localValues.proposalTime"
multiple
placeholder="请选择"
style="width: 420px"
@change="handleChange"
......@@ -115,18 +113,18 @@ const props = defineProps<{
const localValues = ref({
policyArea: [] as string[],
governmentType: [] as string[],
oppositionProposer: [] as string[],
proposalTime: [] as string[],
oppositionProposer: '' as string,
proposalTime: '' as string,
})
// 根据 proposalInfo 计算初始筛选值(即"设置为当前提案"的目标状态)
function buildInitialValues(info?: ProposalInfo | null): Record<string, string[]> {
if (!info) return { policyArea: [], governmentType: [], oppositionProposer: [], proposalTime: [] }
function buildInitialValues(info?: ProposalInfo | null): Record<string, string[] | string> {
if (!info) return { policyArea: [], governmentType: [], oppositionProposer: '', proposalTime: '' }
return {
policyArea: info.defaultDomains?.length ? [...info.defaultDomains] : [...(info.areas || [])],
governmentType: info.patternType ? [info.patternType] : [],
oppositionProposer: [],
proposalTime: [],
oppositionProposer: '',
proposalTime: '',
}
}
......@@ -144,8 +142,8 @@ function reset() {
localValues.value = {
policyArea: [],
governmentType: [],
oppositionProposer: [],
proposalTime: [],
oppositionProposer: '',
proposalTime: '',
}
}
......
......@@ -2,8 +2,8 @@
<div v-if="phase" class="phase-card" :class="borderColorClass">
<div class="phase-header flex-display-start">
<div>
<h3 class="phase-title main-color text-title-2-bold">{{ phase.title }}</h3>
<p class="text-tip-2 text-primary-50-clor">{{ phase.description }}</p>
<div class="phase-title main-color text-title-2-bold">{{ phase.title }}</div>
<div class="text-tip-2 text-primary-50-clor">{{ phase.description }}</div>
</div>
<div class="phase-status">
<span class="risk-badge" :class="riskColorClass">{{ riskLabel }}</span>
......@@ -18,32 +18,41 @@
<p v-if="phase.riskLevel !== 'passed'" class="text-tip-2 text-primary-50-clor">{{ phase.estimatedDays }}</p>
</div>
</div>
<div style="display: flex;">
<div class="box-title-row"><img src="../assets/input.svg" />
<span class="text-compact-bold text-primary-80-clor" style="margin-left: 8px;">预测模型数据输入</span></div>
<div class="box-hint flex-display-center text-tip-2 text-primary-50-clor" style="margin-left: auto;">
<img src="../assets/importent.svg"/>
<span>此阶段预测基于以下多维特征</span>
</div>
</div>
<div class="model-inputs-box">
<div class="box-header flex-display-start">
<div class="box-title-row flex-display-center">
<img src="../assets/input.svg" />
<span class="text-compact-bold">预测模型数据输入</span>
</div>
<div class="box-hint flex-display-center text-tip-2 text-primary-50-clor">
<img src="../assets/importent.svg"/>
<span>此阶段预测基于以下多维特征</span>
</div>
</div>
<div class="model-inputs">
<p
<div
v-for="(input, index) in phase.modelInputs"
:key="index"
class="text-tip-2 text-primary-65-clor"
>
{{ input }}
</p>
</div>
</div>
</div>
<div v-if="phase.predictionBasis" class="facts-section">
<div class="box-header flex-display-start">
<div class="box-title-row flex-display-center">
<img src="../assets/icon1.svg"/>
<span class="text-compact-bold">通过性预测依据</span>
<span class="text-compact-bold text-primary-80-clor">通过性预测依据</span>
</div>
<div class="box-hint flex-display-center text-tip-2 text-primary-50-clor">
<img src="../assets/importent.svg"/>
......@@ -51,9 +60,11 @@
</div>
</div>
<div class="prediction-basis-content">
<p class="text-tip-2 text-primary-65-clor">{{ phase.predictionBasis }}</p>
<div class="text-tip-2 text-primary-65-clor">{{ phase.predictionBasis }}</div>
</div>
</div>
<!-- 底部虚线分隔 -->
<div class="phase-divider"></div>
</div>
</template>
......@@ -144,7 +155,8 @@ const riskLabel = computed(() => {
<style scoped>
.phase-card {
padding-left: 24px;
padding-bottom: 32px;
/* padding-bottom: 16px; */
/* padding-top: 16px; */
}
.border-primary {
......@@ -166,7 +178,7 @@ const riskLabel = computed(() => {
.phase-header {
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
/* margin-bottom: 16px; */
}
.phase-header > div:first-child {
......@@ -288,4 +300,10 @@ const riskLabel = computed(() => {
height: 16px;
color: var(--text-primary-65-color);
}
/* 底部虚线分隔 */
.phase-divider {
margin-top: 16px;
border-bottom: 1px solid var(--bg-black-10, #e5e5e5);
}
</style>
......@@ -125,22 +125,23 @@ async function loadData() {
// 使用真实 API,传入 billIds、domains、patternType、proposalType
const params = {
billIds: filterParams?.value.billIds,
domains:JSON.stringify(filterParams?.value.domains) || [],
domains: filterParams?.value.domains || [],
patternType: filterParams?.value.patternType || '统一政府',
proposalType: filterParams?.value.proposalType || '两党共同提案'
}
const response = await getSimiBills(params)
if (response && response.data) {
// 保存原始数据
rawBillsData.value = response.data
// 保存原始数据(新 API 返回结构中 simi_bills 是法案数组)
rawBillsData.value = response.data.simi_bills || []
const { stats: apiStats, bills: apiBills } = transformSimiBillsData(response)
stats.value = apiStats
bills.value = apiBills
} else {
stats.value = null
bills.value = []
rawBillsData.value = []
}
} catch (error) {
console.error('获取相似法案失败:', error)
......
......@@ -90,7 +90,7 @@ onMounted(async () => {
// 获取提案信息
const predictionData = await getProgressPrediction(billId.value).catch(err => {
console.error('[v0] 获取预测数据失败:', err)
console.error(' 获取预测数据失败:', err)
return null
})
......@@ -341,7 +341,7 @@ async function handleStep2Next(selectedBills: any[]) {
predictionResult.value = transformPredictionResult(response.data)
}
} catch (error) {
console.error('[v0] 获取预测分析失败:', error)
console.error(' 获取预测分析失败:', error)
} finally {
predictionLoading.value = false
}
......@@ -370,24 +370,26 @@ function transformPredictionResult(data: any) {
const factors = data?.factor_analysis || []
// 转换阶段分析
const phases = stages.map((stage: any, index: number) => ({
id: index + 1,
title: `阶段${index + 1}${stage.stage}`,
description: stage.stage,
riskLevel: probabilityToRisk(stage.predicted_pass_probability),
progressLevel: probabilityToProgressLevel(stage.predicted_pass_probability),
estimatedDays: `预计耗时${stage.predicted_passing_time}天`,
modelInputs: [stage.analysis],
supportingFacts: {
title: '通过性预测依据',
basedOn: '此阶段预测基于以下观点',
stats: [
{ value: `${stage.predicted_pass_probability}`, label: '通过概率' },
{ value: `${stage.predicted_passing_time}天`, label: '预计耗时' }
]
},
predictionBasis: stage.prediction_basis
}))
const chineseNum = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
const phases = stages.map((stage: any, index: number) => ({
id: index + 1,
title: `阶段${chineseNum[index] || index + 1}${stage.stage}`,
description: stage.stage,
riskLevel: probabilityToRisk(stage.predicted_pass_probability),
progressLevel: probabilityToProgressLevel(stage.predicted_pass_probability),
estimatedDays: `预计耗时${stage.predicted_passing_time}天`,
modelInputs: [stage.analysis],
supportingFacts: {
title: '通过性预测依据',
basedOn: '此阶段预测基于以下观点',
stats: [
{ value: `${stage.predicted_pass_probability}`, label: '通过概率' },
{ value: `${stage.predicted_passing_time}天`, label: '预计耗时' }
]
},
predictionBasis: stage.prediction_basis
}))
return {
title: '立法进展阶段预测分析',
......
......@@ -285,10 +285,22 @@ const onFormatNode = (item) => {
const onDecreeRelatedEntitie = async (id) => {
try {
const res = await getDecreeRelatedEntitie({ id });
const res = await getDecreeRelatedEntitie({
orgId: id,
rule: false,
withSanInfo: false,
});
if (res.code === 200) {
graphInfo.links = (res.data || []).map(onFormatLink);
graphInfo.nodes = (res.data || []).map(onFormatNode);
const data = res.data || {};
const parentList = Array.isArray(data.parentOrgList) ? data.parentOrgList : [];
const childrenList = Array.isArray(data.childrenOrgList) ? data.childrenOrgList : [];
const relationList = [...parentList, ...childrenList].map((item) => ({
...item,
relation: item.description || "",
companyName: item.companyName || item.name || "",
}));
graphInfo.links = relationList.map(onFormatLink);
graphInfo.nodes = relationList.map(onFormatNode);
if (entityInfo.node?.id) graphInfo.nodes.unshift(onFormatNode(entityInfo.node));
}
} catch (error) {
......
......@@ -30,8 +30,7 @@
<div class="box1-right-item">
<div class="item-left">委员会报告:</div>
<div class="item-right2" v-if="reportList.length">
<div class="right2-item" v-for="(item, index) in reportList"
:key="getReportKey(item, index)">
<div class="right2-item" v-for="(item, index) in reportList" :key="getReportKey(item, index)">
{{ item }}
</div>
</div>
......@@ -47,10 +46,9 @@
<div class="box1-right-item">
<div class="item-left">立案流程:</div>
<div class="item-right4">
<div v-for="(item, index) in reversedStageList" :key="getStageKey(item, index)"
class="step" :style="{ zIndex: getStageZIndex(index) }">
<div class="step-box"
:class="{ 'step-box-active': index === stageActiveIndex }">
<div v-for="(item, index) in reversedStageList" :key="getStageKey(item, index)" class="step"
:style="{ zIndex: getStageZIndex(index) }">
<div class="step-box" :class="{ 'step-box-active': index === stageActiveIndex }">
{{ item }}
</div>
</div>
......@@ -79,8 +77,7 @@
<div class="name-box">
<div class="person-box">
<div class="person-item" :class="{ nameItemActive: box3BtnActive === item.name }"
@click="handleClcikBox3Btn(item.name, index)"
v-for="(item, index) in personList" :key="index">
@click="handleClcikBox3Btn(item.name, index)" v-for="(item, index) in personList" :key="index">
{{ item.name }}
</div>
</div>
......@@ -197,14 +194,21 @@ const handleClickAvatar = async item => {
return;
}
window.sessionStorage.setItem("curTabName", item.name || "");
const routeData = router.resolve({
// const routeData = router.resolve({
// path: "/characterPage",
// query: {
// type,
// personId: item.id
// }
// });
// window.open(routeData.href, "_blank");
router.push({
path: "/characterPage",
query: {
type,
personId: item.id
}
});
window.open(routeData.href, "_blank");
})
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
......@@ -212,7 +216,7 @@ const handleClickAvatar = async item => {
} else {
ElMessage.warning("找不到当前人员的类型值!");
}
} catch (error) {}
} catch (error) { }
};
// 获取URL地址里面的billId
const billId = ref(route.query.billId);
......@@ -253,7 +257,7 @@ const partyIconUrl = computed(() => {
const reversedStageList = computed(() => {
const list = Array.isArray(basicInfo.value?.stageList) ? basicInfo.value.stageList : [];
return [...list].reverse();
return [...list];
});
const stageListLength = computed(() => (Array.isArray(basicInfo.value?.stageList) ? basicInfo.value.stageList.length : 0));
const stageActiveIndex = computed(() => stageListLength.value - 1);
......
<template>
<div class="data-library-wrapper">
<div class="data-library-header">
<!-- <div class="data-library-header">
<div class="header-left">
<div class="icon">
<img src="@/assets/icons/overview/logo.png" alt="">
......@@ -19,7 +19,7 @@
<div class="name">{{ "管理员" }}</div>
</div>
</div>
</div>
</div> -->
<div class="data-library-main">
<div class="data-library-sider">
<div class="sider-item-box" v-for="item, index in siderList" :key="index">
......@@ -96,7 +96,7 @@ const tagsViewStore = useTagsViewStore()
// 在路由全局守卫中处理
router.beforeEach((to, from, next) => {
// 路由允许添加标签(排除掉隐藏的布局页如 /404, /login 等)
if (to.meta?.title && !to.meta?.hiddenTag) {
if (to.path.indexOf('dataLibrary') > -1) {
tagsViewStore.addView({
path: to.path,
name: to.name, // 对应组件的 name,用于缓存
......@@ -479,7 +479,7 @@ const handleClickToolBox = () => {
onMounted(() => {
const path = route.path
console.log(decodeURI(route.fullPath));
switch (path) {
case '/dataLibrary/countryBill':
siderList.value[0].active = true
......
......@@ -3,13 +3,15 @@
<div class="container-box">
<div class="hard-box">
<div class="hard-name text-title-0-show">美国政府机构</div>
<div class="hard-num text-title-2-show">{{organizationInfo.total}}</div>
<div class="hard-num text-title-2-show">{{ organizationInfo.total }}</div>
<div style="width: 0px; flex: auto;"></div>
<div class="hard-input">
<el-input v-model="organizationInfo.keyWord" @keyup.enter="onAllOrganization()" style="width:100%; height:100%;" :suffix-icon="Search" placeholder="搜索机构" />
<el-input v-model="organizationInfo.keyWord" @keyup.enter="onAllOrganization()"
style="width:100%; height:100%;" :suffix-icon="Search" placeholder="搜索机构" />
</div>
<div class="hard-time">
<el-select v-model="organizationInfo.isSort" @change="onAllOrganization()" placeholder="发布时间" style="width:160px; margin-left:8px;">
<el-select v-model="organizationInfo.isSort" @change="onAllOrganization()" placeholder="发布时间"
style="width:160px; margin-left:8px;">
<template #prefix>
<div class="icon1">
<img v-if="isSort" src="@/assets/icons/shengxu1.png" alt="" />
......@@ -28,29 +30,36 @@
<TimeTabPane @time-click="handleDateChange" />
</div>
<div class="organization-list" ref="refOrganization" v-loading="organizationInfo.loading">
<div class="organization-item" v-for="(item, index) in organizationInfo.list" :key="index" @click="handleToInstitution(item)">
<div class="organization-item" v-for="(item, index) in organizationInfo.list" :key="index"
@click="handleToInstitution(item)">
<div class="item-left">
<img :src="item.orgImage || DefaultIcon2" alt="" />
</div>
<div class="item-right one-line-ellipsis">{{ item.orgName }}</div>
<div class="item-total">{{ item.total }}项</div>
<el-icon color="var(--color-primary-100)"><ArrowRightBold /></el-icon>
<div class="item-dot" v-if="item.totalRecent">+{{item.totalRecent}}</div>
<el-icon color="var(--color-primary-100)">
<ArrowRightBold />
</el-icon>
<div class="item-dot" v-if="item.totalRecent">+{{ item.totalRecent }}</div>
</div>
</div>
<div class="pagination-box">
<el-pagination @current-change="onAllOrganization" :pageSize="organizationInfo.pageSize" :current-page="organizationInfo.pageNum" background layout="prev, pager, next" :total="organizationInfo.total" />
<el-pagination @current-change="onAllOrganization" :pageSize="organizationInfo.pageSize"
:current-page="organizationInfo.pageNum" background layout="prev, pager, next"
:total="organizationInfo.total" />
</div>
</div>
<div class="back-bnt" @click="router.back()">
<el-icon><Back /></el-icon>
<el-icon>
<Back />
</el-icon>
<div style="margin-left: 6px;">返回</div>
</div>
</div>
</template>
<script setup name="index">
import {onMounted, reactive, ref} from "vue"
import { onMounted, reactive, ref } from "vue"
import { Search } from '@element-plus/icons-vue'
import router from "@/router";
......@@ -76,38 +85,44 @@ const onAllOrganization = async (num) => {
organizationInfo.pageNum = num || 1
organizationInfo.loading = true
try {
let {keyWord, pageNum, pageSize, day} = organizationInfo
const res = await getDepartmentList({day, pageNum:pageNum-1, pageSize, keyWord: keyWord||undefined});
console.log("机构列表", res);
if (res.code === 200) {
organizationInfo.list = res.data.orgList || [];
organizationInfo.total = res.data.total || 0;
}
} catch (error) {
let { keyWord, pageNum, pageSize, day } = organizationInfo
const res = await getDepartmentList({ day, pageNum: pageNum - 1, pageSize, keyWord: keyWord || undefined });
console.log("机构列表", res);
if (res.code === 200) {
organizationInfo.list = res.data.orgList || [];
organizationInfo.total = res.data.total || 0;
}
} catch (error) {
console.error("获取机构列表数据失败", error);
organizationInfo.list = [];
organizationInfo.total = 0;
organizationInfo.list = [];
organizationInfo.total = 0;
}
organizationInfo.loading = false
}
const handleDateChange = (event) => {
if (event?.time === '近一周') organizationInfo.day = 7
if (event?.time === '近一月') organizationInfo.day = 30
if (event?.time === '近一年') organizationInfo.day = 365
if (event?.time === '近一周') organizationInfo.day = 7
if (event?.time === '近一月') organizationInfo.day = 30
if (event?.time === '近一年') organizationInfo.day = 365
onAllOrganization()
}
// 跳转行政机构主页
const handleToInstitution = item => {
window.sessionStorage.setItem("curTabName", item.orgName);
const curRoute = router.resolve({
path: "/institution",
query: {
id: item.orgId
}
});
window.open(curRoute.href, "_blank");
window.sessionStorage.setItem("curTabName", item.orgName);
// const curRoute = router.resolve({
// path: "/institution",
// query: {
// id: item.orgId
// }
// });
// window.open(curRoute.href, "_blank");
router.push({
path: "/institution",
query: {
id: item.orgId
}
})
};
const refOrganization = ref()
......@@ -115,9 +130,9 @@ onMounted(() => {
// 根据元素的高度决定分页显示的机构数量
let height = 2;
if (refOrganization.value) {
height = Math.floor(refOrganization.value?.clientHeight/120)
height = Math.floor(refOrganization.value?.clientHeight / 120)
}
organizationInfo.pageSize = height*4
organizationInfo.pageSize = height * 4
onAllOrganization()
})
......@@ -157,7 +172,7 @@ onMounted(() => {
flex-direction: column;
.hard-box {
display: flex;
display: flex;
align-items: center;
width: 100%;
......@@ -166,6 +181,7 @@ onMounted(() => {
height: 62px;
line-height: 62px !important;
}
.hard-num {
height: 36px;
background-color: var(--color-primary-100);
......@@ -175,6 +191,7 @@ onMounted(() => {
padding: 0 16px;
margin-left: 16px;
}
.hard-input {
background-color: var(--el-fill-color-blank);
border-radius: var(--el-border-radius-base);
......@@ -184,6 +201,7 @@ onMounted(() => {
width: 160px;
height: 32px;
}
.hard-time {
height: 42px;
padding: 5px 0;
......@@ -192,6 +210,7 @@ onMounted(() => {
width: 11px;
height: 14px;
font-size: 0px;
img {
width: 100%;
height: 100%;
......@@ -202,7 +221,7 @@ onMounted(() => {
.date-box {
margin-top: 6px;
display: flex;
display: flex;
align-items: center;
width: 100%;
......@@ -211,11 +230,13 @@ onMounted(() => {
height: 16px;
font-size: 0px;
margin-right: 6px;
img {
width: 100%;
height: 100%;
}
}
.date-text {
width: 20px;
flex: auto;
......@@ -261,6 +282,7 @@ onMounted(() => {
width: 48px;
height: 48px;
font-size: 0px;
img {
width: 100%;
height: 100%;
......
......@@ -514,13 +514,19 @@ const handleGetDepartmentList = async () => {
// 跳转行政机构主页
const handleToInstitution = item => {
window.sessionStorage.setItem("curTabName", item.orgName);
const curRoute = router.resolve({
// const curRoute = router.resolve({
// path: "/institution",
// query: {
// id: item.orgId
// }
// });
// window.open(curRoute.href, "_blank");
router.push({
path: "/institution",
query: {
id: item.orgId
}
});
window.open(curRoute.href, "_blank");
})
};
// 跳转全部机构页面
const onNavigateTo = () => {
......@@ -529,14 +535,16 @@ const onNavigateTo = () => {
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
// const route = router.resolve("/viewRiskSignal");
// window.open(route.href, "_blank");
router.push("/viewRiskSignal")
};
// 查看更多新闻资讯
const handleToMoreNews = () => {
const route = router.resolve("/newsBrief");
window.open(route.href, "_blank");
// const route = router.resolve("/newsBrief");
// window.open(route.href, "_blank");
router.push("/newsBrief")
};
// 最新科技政令
......@@ -580,36 +588,55 @@ const handleClickToDetail = () => {
const id = box1DataList.value[activeIndex].id;
window.sessionStorage.setItem("curTabName", box1DataList.value[activeIndex].name);
const route = router.resolve({
// const route = router.resolve({
// path: "/decreeLayout",
// query: {
// id: id
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/decreeLayout",
query: {
id: id
}
});
window.open(route.href, "_blank");
})
};
// 点击政令库政令
const handleClickDecree = decree => {
window.sessionStorage.setItem("curTabName", decree.title);
const route = router.resolve({
// const route = router.resolve({
// path: "/decreeLayout",
// query: {
// id: decree.id
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/decreeLayout",
query: {
id: decree.id
}
});
window.open(route.href, "_blank");
})
};
const handleKeyDecree = item => {
window.sessionStorage.setItem("curTabName", item.title);
const route = router.resolve({
// const route = router.resolve({
// path: "/decreeLayout",
// query: {
// id: item.id
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/decreeLayout",
query: {
id: item.id
}
});
window.open(route.href, "_blank");
})
};
// 风险信号
......@@ -752,14 +779,23 @@ const handleClickPerson = async item => {
return;
}
window.sessionStorage.setItem("curTabName", item.name);
const route = router.resolve({
// const route = router.resolve({
// path: "/characterPage",
// query: {
// type: type, // type=1为科技企业领袖,2为国会议员,3为智库研究人员
// personId: item.personId
// }
// });
// window.open(route.href, "_blank");
router.push(
{
path: "/characterPage",
query: {
type: type, // type=1为科技企业领袖,2为国会议员,3为智库研究人员
personId: item.personId
}
});
window.open(route.href, "_blank");
}
)
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
......@@ -1029,13 +1065,21 @@ const handleGetDecreeTypeList = async () => {
};
// 查看社交媒体详情
const handleToSocialDetail = item => {
const route = router.resolve({
// const route = router.resolve({
// path: "/characterPage",
// query: {
// personId: item.id
// }
// });
// window.open(route.href, "_blank");
router.push(
{
path: "/characterPage",
query: {
personId: item.id
}
});
window.open(route.href, "_blank");
}
)
};
const handleChangeCheckedDecreeType = () => {
handleGetDecreeOrderList();
......@@ -1197,14 +1241,21 @@ const handleSwithCurDecree = name => {
const searchDecreeText = ref("");
const handleSearch = () => {
window.sessionStorage.setItem("curTabName", `搜索-${searchDecreeText.value}`);
const curRoute = router.resolve({
// const curRoute = router.resolve({
// path: "/searchResults",
// query: {
// searchText: searchDecreeText.value,
// areaName: "政令"
// }
// });
// window.open(curRoute.href, "_blank");
router.push({
path: "/searchResults",
query: {
searchText: searchDecreeText.value,
areaName: "政令"
}
});
window.open(curRoute.href, "_blank");
})
};
// 关键机构
......
......@@ -175,13 +175,19 @@ const onWordWrap = (word, num) => {
}
const handleClickDecree = decree => {
const route = router.resolve({
// const route = router.resolve({
// path: "/decreeLayout",
// query: {
// id: decree.id
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/decreeLayout",
query: {
id: decree.id
}
});
window.open(route.href, "_blank");
})
};
// 关联关系
......
......@@ -22,13 +22,8 @@
</div>
</div>
<div class="left-box-bottom">
<div
class="left-box-bottom-item"
:class="{ leftBoxBottomItemActive: activeTitle === item.name }"
v-for="(item, index) in mainHeaderBtnList"
:key="index"
@click="handleClickMainHeaderBtn(item)"
>
<div class="left-box-bottom-item" :class="{ leftBoxBottomItemActive: activeTitle === item.name }"
v-for="(item, index) in mainHeaderBtnList" :key="index" @click="handleClickMainHeaderBtn(item)">
<div class="icon">
<img v-if="activeTitle === item.name" :src="item.activeIcon" alt="" />
<img v-else :src="item.icon" alt="" />
......@@ -220,12 +215,12 @@ const handleClickMainHeaderBtn = item => {
const summaryInfo = ref({});
const handleGetSummary = async () => {
try {
const res = await getDecreeSummary({id: route.query.id});
const res = await getDecreeSummary({ id: route.query.id });
console.log("全局信息", res);
if (res.code === 200 && res.data) {
summaryInfo.value = res.data;
}
} catch (error) {}
} catch (error) { }
};
// 获取报告原文
......@@ -248,13 +243,19 @@ const handleGetSummary = async () => {
// };
const handleShowReport = () => {
const curRoute = router.resolve({
// const curRoute = router.resolve({
// path: "/decree/decreeOriginal",
// query: {
// id: route.query.id
// }
// });
// window.open(curRoute.href, "_blank");
router.push({
path: "/decree/decreeOriginal",
query: {
id: route.query.id
}
});
window.open(curRoute.href, "_blank");
})
};
const handleToInstitution = () => {
......@@ -297,6 +298,7 @@ onMounted(() => {
height: 100%;
overflow: hidden;
overflow-y: auto;
.report {
padding: 10px 150px;
position: absolute;
......@@ -306,6 +308,7 @@ onMounted(() => {
width: 100%;
height: 100%;
background: #f7f8f9;
.report-close {
position: absolute;
top: 20px;
......@@ -313,11 +316,13 @@ onMounted(() => {
width: 20px;
height: 20px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.report-header {
width: 100%;
height: 50px;
......@@ -332,12 +337,15 @@ onMounted(() => {
padding-left: 30px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
}
.report-main {
display: flex;
height: calc(100% - 100px);
justify-content: space-between;
.left {
width: 800px;
.noContent {
height: 100px;
line-height: 100px;
......@@ -349,8 +357,10 @@ onMounted(() => {
font-weight: 400;
}
}
.right {
width: 800px;
.noContent {
height: 100px;
line-height: 100px;
......@@ -364,17 +374,20 @@ onMounted(() => {
}
}
}
.layout-main {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.header-main {
width: 100%;
border-bottom: 1px solid rgba(234, 236, 238, 1);
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
}
.layout-main-header {
width: 1600px;
height: 137px;
......@@ -384,6 +397,7 @@ onMounted(() => {
justify-content: space-between;
position: sticky;
top: 0;
// z-index: 100;
.layout-main-header-container {
width: 1600px;
......@@ -392,28 +406,34 @@ onMounted(() => {
justify-content: space-between;
align-items: center;
}
.layout-main-header-left-box {
width: 20px;
flex: auto;
margin-top: 12px;
.left-box-top {
height: 64px;
display: flex;
align-items: center;
.icon {
width: 64px;
height: 40px;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
.info {
margin-left: 10px;
margin-right: 40px;
width: 20px;
flex: auto;
.info-box1 {
width: 100%;
color: rgba(59, 65, 75, 1);
......@@ -425,6 +445,7 @@ onMounted(() => {
text-align: left;
margin-top: 5px;
}
.info-box2 {
margin-top: 5px;
height: 22px;
......@@ -442,31 +463,37 @@ onMounted(() => {
white-space: nowrap;
padding: 0 10px;
}
.info-box2-item:first-child {
padding-left: 0px;
}
}
}
}
.left-box-bottom {
display: flex;
height: 40px;
margin-top: 21px;
.left-box-bottom-item {
display: flex;
margin-right: 32px;
margin-top: 3px;
height: 35px;
cursor: pointer;
.icon {
margin-top: 4px;
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.name {
height: 24px;
color: rgba(59, 65, 75, 1);
......@@ -478,20 +505,24 @@ onMounted(() => {
text-align: left;
margin-left: 3px;
}
.nameActive {
color: var(--color-main-active);
font-weight: 700;
}
}
.leftBoxBottomItemActive {
border-bottom: 3px solid var(--color-main-active);
}
}
}
.layout-main-header-right-box {
.right-box-top {
white-space: nowrap;
padding-top: 11px;
.time {
height: 24px;
line-height: 24px;
......@@ -503,6 +534,7 @@ onMounted(() => {
letter-spacing: 0px;
text-align: right;
}
.name {
height: 24px;
line-height: 24px;
......@@ -515,12 +547,14 @@ onMounted(() => {
text-align: right;
}
}
.right-box-bottom {
margin-top: 24px;
text-align: right;
display: flex;
justify-content: flex-end;
gap: 8px;
.btn {
width: 120px;
height: 36px;
......@@ -533,14 +567,17 @@ onMounted(() => {
gap: 8px;
align-items: center;
cursor: pointer;
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
width: 64px;
height: 24px;
......@@ -554,6 +591,7 @@ onMounted(() => {
text-align: left;
}
}
.btn-active {
width: 120px;
height: 36px;
......@@ -564,14 +602,17 @@ onMounted(() => {
align-items: center;
gap: 8px;
cursor: pointer;
.icon-active {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text-active {
width: 64px;
height: 24px;
......@@ -588,12 +629,14 @@ onMounted(() => {
}
}
}
.layout-main-center {
height: 20px;
flex: auto;
background-color: #f7f8f9;
}
}
.layout-report-box {
position: absolute;
z-index: 9999;
......@@ -602,6 +645,7 @@ onMounted(() => {
width: 100%;
height: 926px;
background: rgba(248, 249, 250, 1);
.report-close {
position: absolute;
top: 24px;
......@@ -609,11 +653,13 @@ onMounted(() => {
width: 32px;
height: 32px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.report-main {
width: 1600px;
height: 926px;
......@@ -621,13 +667,16 @@ onMounted(() => {
background: #fff;
box-sizing: border-box;
padding: 0 69px;
.report-header {
height: 77px;
border-bottom: 1px solid rgba(240, 242, 244, 1);
display: flex;
justify-content: space-between;
.report-header-left {
display: flex;
.text {
margin-top: 32px;
width: 70px;
......@@ -638,14 +687,17 @@ onMounted(() => {
font-weight: 400;
line-height: 14px;
}
.select-box {
margin-left: 8px;
margin-top: 23px;
}
}
.report-header-right {
display: flex;
margin-top: 24px;
.btn {
display: flex;
width: 88px;
......@@ -658,14 +710,17 @@ onMounted(() => {
display: flex;
justify-content: center;
align-items: center;
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
margin-left: 8px;
height: 32px;
......@@ -678,21 +733,26 @@ onMounted(() => {
}
}
}
.report-content {
display: flex;
margin-top: 35px;
.content-left {
width: 680px;
height: 786px;
img {
width: 100%;
height: 100%;
}
}
.content-right {
margin-left: 89px;
width: 680px;
height: 786px;
img {
width: 100%;
height: 100%;
......
......@@ -25,7 +25,8 @@
<div class="box1-footer" v-if="backgroundListNum > 10">
<div class="box1-footer-left">{{ `共 ${backgroundListNum} 项` }}</div>
<div class="box1-footer-right">
<el-pagination :page-size="10" @current-change="handleCurrentChange" :current-page="currentPage" background layout="prev, pager, next" :total="backgroundListNum" />
<el-pagination :page-size="10" @current-change="handleCurrentChange" :current-page="currentPage"
background layout="prev, pager, next" :total="backgroundListNum" />
</div>
</div>
</div>
......@@ -39,8 +40,12 @@
<el-collapse v-model="dependActive">
<el-collapse-item v-for="(item, index) in dependList" :key="item.billId" :name="item.billId">
<template #icon>
<el-icon v-if="dependActive.includes(item.billId)"><ArrowDownBold /></el-icon>
<el-icon v-else><ArrowUpBold /></el-icon>
<el-icon v-if="dependActive.includes(item.billId)">
<ArrowDownBold />
</el-icon>
<el-icon v-else>
<ArrowUpBold />
</el-icon>
</template>
<template #title>
<div class="custom-collapse-title">
......@@ -73,7 +78,9 @@
<div class="time-line-icon">
<img style="width: 100%; height: 100%;" :src="item.orgImage || DefaultIcon1" alt="">
</div>
<div class="time-line-name text-click-hover" @click="handleToInstitution(item)">{{ item.proposeOrgName }}</div>
<div class="time-line-name text-click-hover" @click="handleToInstitution(item)">{{
item.proposeOrgName
}}</div>
</div>
<div class="timeline-content" @click="handleClickDecree(item)">{{ item.describe }}</div>
</div>
......@@ -137,9 +144,9 @@ const handleGetBackground = async () => {
backgroundList.value = [];
}
} catch (error) {
backgroundListNum.value = 0;
backgroundList.value = [];
console.error("获取提出背景数据失败", error);
backgroundListNum.value = 0;
backgroundList.value = [];
console.error("获取提出背景数据失败", error);
}
};
......@@ -153,7 +160,7 @@ const prevList = ref([
]);
const handleGetPrev = async () => {
try {
const res = await getDecreePrev({id: decreeId.value});
const res = await getDecreePrev({ id: decreeId.value });
console.log("前序政令", res);
if (res.code === 200 && res.data) {
prevList.value = res.data;
......@@ -167,23 +174,35 @@ const handleGetPrev = async () => {
};
// 跳转行政机构主页
const handleToInstitution = item => {
const curRoute = router.resolve({
// const curRoute = router.resolve({
// path: "/institution",
// query: {
// id: item.orgId
// }
// });
// window.open(curRoute.href, "_blank");
router.push({
path: "/institution",
query: {
id: item.orgId
}
});
window.open(curRoute.href, "_blank");
})
};
// 跳转科技政令详情页
const handleClickDecree = item => {
const route = router.resolve({
// const route = router.resolve({
// path: "/decreeLayout",
// query: {
// id: item.id
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/decreeLayout",
query: {
id: item.id
}
});
window.open(route.href, "_blank");
})
};
// 法律依据
......@@ -191,7 +210,7 @@ const dependList = ref([]);
const dependActive = ref([]);
const handleGetLaws = async () => {
try {
const res = await getDecreeDepend({id: decreeId.value});
const res = await getDecreeDepend({ id: decreeId.value });
console.log("法律依据", res);
if (res.code === 200 && res.data) {
dependList.value = res.data;
......@@ -208,15 +227,21 @@ const handleGetLaws = async () => {
const handleClickBull = decree => {
window.sessionStorage.setItem("billId", decree.billId);
window.sessionStorage.setItem("curTabName", decree.title);
const route = router.resolve({
// const route = router.resolve({
// path: "/billLayout",
// query: {
// billId: decree.billId
// }
// });
// console.log(route);
// window.open(route.href, "_blank");
router.push({
path: "/billLayout",
query: {
billId: decree.billId
}
});
console.log(route);
window.open(route.href, "_blank");
})
};
onMounted(() => {
......@@ -345,20 +370,26 @@ onMounted(() => {
.box2-main {
padding: 16px 20px;
.custom-collapse {
padding-left: 32px;
:deep(.el-collapse),
:deep(.el-collapse-item__wrap) {
border: none !important;
}
:deep(.el-collapse-item__header) {
border-bottom: 1px solid rgba(234, 236, 238, 1);
}
:deep(.el-collapse-item__content) {
padding-bottom: 16px;
}
.custom-collapse-title {
position: relative;
.custom-collapse-index {
font-family: Microsoft YaHei;
font-size: var(--font-size-base);
......@@ -373,12 +404,14 @@ onMounted(() => {
background: #e7f3ff;
color: #0a57a6;
}
.custom-collapse-name {
font-weight: 600;
font-size: 18px;
color: var(--el-collapse-header-text-color);
}
}
.custom-collapse-content {
margin-top: 8px;
font-family: Microsoft YaHei;
......@@ -392,6 +425,7 @@ onMounted(() => {
.right {
width: 520px;
.box3 {
.box3-bottom-main {
......
......@@ -318,22 +318,32 @@ const handleGetOrgnization = async () => {
};
// 跳转行政机构主页
const handleToInstitution = item => {
const curRoute = router.resolve({
// const curRoute = router.resolve({
// path: "/institution",
// query: { id: item.id }
// });
// window.open(curRoute.href, "_blank");
router.push({
path: "/institution",
query: { id: item.id }
});
window.open(curRoute.href, "_blank");
})
};
// 跳转人员详情
const handleClickUser = item => {
window.sessionStorage.setItem('curTabName', item.name)
const routeData = router.resolve({
// const routeData = router.resolve({
// path: "/characterPage",
// query: {
// personId: item.id
// }
// });
// window.open(routeData.href, "_blank");
router.push({
path: "/characterPage",
query: {
personId: item.id
}
});
window.open(routeData.href, "_blank");
})
};
onMounted(() => {
......
......@@ -822,14 +822,20 @@ const handleToPosi = id => {
// 跳转到单项制裁页面
const handleToRiskSignalDetail = item => {
window.sessionStorage.setItem("curTabName", item.title);
const routeData = router.resolve({
// const routeData = router.resolve({
// path: "/exportControl/singleSanction",
// query: {
// id: item.sanId
// }
// });
// // 打开新页面
// window.open(routeData.href, "_blank");
router.push({
path: "/exportControl/singleSanction",
query: {
id: item.sanId
}
});
// 打开新页面
window.open(routeData.href, "_blank");
})
};
const sanctionList = ref([]);
......@@ -885,14 +891,21 @@ const checkedTime = ref(["全部时间"]);
// 跳转到单条制裁页面,单独打开一个新页面
const handleTitleClick = item => {
window.sessionStorage.setItem("curTabName", `${item.year}-${item.dateStr}${item.title}》`);
const route = router.resolve({
// const route = router.resolve({
// path: "/exportControl/singleSanction",
// query: {
// id: item.id,
// sanTypeId: item.sanTypeId
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/exportControl/singleSanction",
query: {
id: item.id,
sanTypeId: item.sanTypeId
}
});
window.open(route.href, "_blank");
})
};
const handleCompClick = item => {
......@@ -1034,13 +1047,19 @@ onMounted(async () => {
});
// 查看社交媒体详情
const handleToSocialDetail = item => {
const route = router.resolve({
// const route = router.resolve({
// path: "/characterPage",
// query: {
// personId: item.id
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/characterPage",
query: {
personId: item.id
}
});
window.open(route.href, "_blank");
})
};
// 获取趋势图数据
const fetchTrendData = async () => {
......@@ -1156,37 +1175,55 @@ const handleToEntityList = item => {
"curTabName",
entitiesDataInfoList.value[currentCarouselIndex.value].postDate + " 《实体清单新增条目》"
);
const routeData = router.resolve({
// const routeData = router.resolve({
// path: "/exportControl/singleSanction",
// query: {
// id: id
// }
// });
// // 打开一个新页面
// window.open(routeData.href, "_blank");
router.push({
path: "/exportControl/singleSanction",
query: {
id: id
}
});
// 打开一个新页面
window.open(routeData.href, "_blank");
})
};
// 跳转到V2.0实体清单无ID
const handleToEntityListNoId = item => {
console.log("这是什么数据 =>", item);
if (item.nameZh == "实体清单") {
const routeData = router.resolve({
// const routeData = router.resolve({
// path: "/exportControl/entityList",
// query: {
// sanTypeId: item.id
// }
// });
// // 打开一个新页面
// window.open(routeData.href, "_blank");
router.push({
path: "/exportControl/entityList",
query: {
sanTypeId: item.id
}
});
// 打开一个新页面
window.open(routeData.href, "_blank");
})
} else if (item.nameZh == "商业管制清单") {
const routeData = router.resolve({
// const routeData = router.resolve({
// path: "/exportControl/commercialControlList",
// query: {
// sanTypeId: item.id
// }
// });
// // 打开一个新页面
// window.open(routeData.href, "_blank");
router.push({
path: "/exportControl/commercialControlList",
query: {
sanTypeId: item.id
}
});
// 打开一个新页面
window.open(routeData.href, "_blank");
})
} else {
return;
}
......@@ -1660,14 +1697,21 @@ const fetchNewsInfo = async () => {
const handlePerClick = item => {
// console.log("点击了社交媒体消息:", item);
window.sessionStorage.setItem("curTabName", item.name);
const route = router.resolve({
// const route = router.resolve({
// path: "/characterPage",
// query: {
// type: item.type || [1, 2, 3][Math.floor(Math.random() * 3)],
// personId: item.personId
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/characterPage",
query: {
type: item.type || [1, 2, 3][Math.floor(Math.random() * 3)],
personId: item.personId
}
});
window.open(route.href, "_blank");
})
};
// 处理点击社交媒体消息的方法
// const handleInfoClick = item => {
......@@ -1749,26 +1793,35 @@ const chart1Data = ref({
const handleSanc = item => {
console.log(item);
window.sessionStorage.setItem("curTabName", `${item.postDate}${item.title}》`);
const route = router.resolve({
// const route = router.resolve({
// path: "/exportControl/singleSanction",
// query: {
// id: item.id,
// sanTypeId: activeResourceTabItem.value.id
// }
// });
// window.open(route.href, "_blank");
router.push({
path: "/exportControl/singleSanction",
query: {
id: item.id,
sanTypeId: activeResourceTabItem.value.id
}
});
window.open(route.href, "_blank");
})
};
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
// const route = router.resolve("/viewRiskSignal");
// window.open(route.href, "_blank");
router.push("/viewRiskSignal")
};
// 查看更多新闻资讯
const handleToMoreNews = () => {
const route = router.resolve("/newsBrief");
window.open(route.href, "_blank");
// const route = router.resolve("/newsBrief");
// window.open(route.href, "_blank");
router.push("/newsBrief")
};
const handleNewsInfoClick = item => {
......@@ -1795,14 +1848,21 @@ const handleSwithCurPolicy = name => {
const handleSearch = () => {
window.sessionStorage.setItem("curTabName", `搜索-${searchExportControlText.value}`);
const curRoute = router.resolve({
// const curRoute = router.resolve({
// path: "/searchResults",
// query: {
// searchText: searchExportControlText.value,
// areaName: "实体清单"
// }
// });
// window.open(curRoute.href, "_blank");
router.push({
path: "/searchResults",
query: {
searchText: searchExportControlText.value,
areaName: "实体清单"
}
});
window.open(curRoute.href, "_blank");
})
};
onMounted(async () => {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论