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

合并分支 'liuyuqi' 到 'pre'

Liuyuqi 查看合并请求 !313
流水线 #353 已通过 于阶段
in 2 分 21 秒
...@@ -259,26 +259,7 @@ export async function getHistoryBillListWithStage(personId, params = {}) { ...@@ -259,26 +259,7 @@ export async function getHistoryBillListWithStage(personId, params = {}) {
} }
} }
// /**
// * 获取潜在提案举措分析
// * GET /api/personHomepage/historyBill/clause/{personId}
// * @param {string} personId - 人物ID
// * @param {Object} params - 查询参数
// */
// export async function getPotentialClauseAnalysis(personId, params = {}) {
// const queryString = Object.entries(params)
// .filter(([, value]) => value !== undefined && value !== null && value !== '')
// .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
// .join('&')
// const url = queryString
// ? `/api/personHomepage/historyBill/clause/${personId}?${queryString}`
// : `/api/personHomepage/historyBill/clause/${personId}`
// return request(url, {
// method: 'GET',
// })
// }
/** /**
* 获取排序选项 * 获取排序选项
...@@ -331,31 +312,32 @@ export function getProgressPrediction(billId) { ...@@ -331,31 +312,32 @@ export function getProgressPrediction(billId) {
}) })
} }
/** /**
* 获取相似法案列表 * 获取相似法案列表
* @param {Object} params - 查询参数 * @param {Object} params - 查询参数
* @param {string} params.billIds - 当前法案的ID * @param {string} params.billIds - 当前法案的ID
* @param {string[]} params.domains - 领域名称列表 * @param {string} params.domains - 领域名称,多个用逗号拼接
* @param {string} params.patternType - 政府结构类型,如 "统一政府"/"分裂政府"/"微弱多数" * @param {string} params.patternType - 政府结构类型
* @param {string} params.proposalType - 提案类型,如 "两党共同提案"/"单政党提案(共和党提案)"/"单政党提案(民主党提案)" * @param {string} params.proposalType - 提案类型
* @param {string} params.timeFrame - 时间范围(单个字符串)
* @param {number} params.maxNum - 返回最大数量
* @returns {Promise<Object>} 相似法案列表 * @returns {Promise<Object>} 相似法案列表
*/ */
export function getSimiBills(params = {}) { export function getSimiBills(params = {}) {
// domains 如果是数组则用逗号拼接
const domains = Array.isArray(params.domains)
? params.domains.join(',')
: params.domains
return request('/api/BillProgressPrediction/simiBills', { return request('/api/BillProgressPrediction/simiBills', {
method: 'GET', method: 'GET',
params: { params: {
billIds: params.billIds, billIds: params.billIds,
domains: domains, domains: params.domains,
patternType: params.patternType, patternType: params.patternType,
proposalType: params.proposalType proposalType: params.proposalType,
timeFrame: params.timeFrame,
maxNum: params.maxNum || 50
} }
}) })
} }
/** /**
* 格式化日期 YYYY-MM-DD -> YYYY年M月D日 * 格式化日期 YYYY-MM-DD -> YYYY年M月D日
* @param {string} dateStr - 日期字符串 * @param {string} dateStr - 日期字符串
......
...@@ -201,3 +201,16 @@ export async function getSubjectList(params) { ...@@ -201,3 +201,16 @@ export async function getSubjectList(params) {
params params
}) })
} }
/**
* 获取调研项目列表
* @param {string} personId
* @param {Object} params
*/
export function getInvestigationProject(personId, params) {
return request({
method: 'GET',
url: `/api/personHomepage/investigationProject/${personId}`,
params,
})
}
\ No newline at end of file
...@@ -123,18 +123,8 @@ const billRoutes = [ ...@@ -123,18 +123,8 @@ const billRoutes = [
component: BillInfluenceScientificResearch, component: BillInfluenceScientificResearch,
// meta: { title: "对华科研影响" } // meta: { title: "对华科研影响" }
}, },
// {
// path: "ProgressForecast",
// name: "BillProgressForecast",
// component: BillProgressForecast,
// // meta: { title: "对华科研影响" }
// }
] ]
}, {
path: "ProgressForecast/:id",
name: "BillProgressForecast",
component: BillProgressForecast,
// meta: { title: "对华科研影响" }
}, },
{ {
...@@ -155,6 +145,14 @@ const billRoutes = [ ...@@ -155,6 +145,14 @@ const billRoutes = [
} }
] ]
}, },
{
path: "ProgressForecast/:id",
name: "BillProgressForecast",
component: BillProgressForecast,
meta: {
title: "法案预测"
}
},
] ]
export default billRoutes export default billRoutes
\ No newline at end of file
// 规则限制 // 规则限制
const RuleRestriction = () => import('@/views/ruleRestriction/index.vue') const RuleRestriction = () => import('@/views/ruleRestriction/index.vue')
const RuleRestrictionDetail = () => import('@/views/ruleRestriction/detail/index.vue') const RuleRestrictionDetail = () => import('@/views/ruleRestriction/detail/index.vue')
const RuleRestrictionsAlliance = () => import('@/views/ruleRestriction/alliance/index.vue')
const ruleRestrictionsRoutes = [ const ruleRestrictionsRoutes = [
// 规则限制 // 规则限制
...@@ -22,6 +23,14 @@ const ruleRestrictionsRoutes = [ ...@@ -22,6 +23,14 @@ const ruleRestrictionsRoutes = [
title: "规则限制详情", title: "规则限制详情",
dynamicTitle: true dynamicTitle: true
} }
}, {
path: "/ruleRestrictions/alliance",
name: "RuleRestrictionsAlliance",
component: RuleRestrictionsAlliance,
meta: {
title: "规则限制联盟详情",
dynamicTitle: true
}
}, },
] ]
......
<template> <template>
<div class="action-buttons"> <div class="action-buttons">
<div class="action-left">
<button class="btn-secondary" @click="emit('reset')"> <button class="btn-secondary" @click="emit('reset')">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /> <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
...@@ -7,6 +8,10 @@ ...@@ -7,6 +8,10 @@
</svg> </svg>
<span>重置筛选条件</span> <span>重置筛选条件</span>
</button> </button>
<button v-if="showSetAsCurrent" class="btn-secondary" @click="emit('setAsCurrent')">
<span>设置为当前提案</span>
</button>
</div>
<div class="action-right"> <div class="action-right">
<button <button
v-if="showPrevious" v-if="showPrevious"
...@@ -36,12 +41,14 @@ defineProps<{ ...@@ -36,12 +41,14 @@ defineProps<{
previousText?: string previousText?: string
nextText?: string nextText?: string
nextDisabled?: boolean nextDisabled?: boolean
showSetAsCurrent?: boolean
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
reset: [] reset: []
previous: [] previous: []
next: [] next: []
setAsCurrent: []
}>() }>()
</script> </script>
...@@ -53,6 +60,12 @@ const emit = defineEmits<{ ...@@ -53,6 +60,12 @@ const emit = defineEmits<{
padding-top: 24px; padding-top: 24px;
} }
.action-left {
display: flex;
align-items: center;
gap: 12px;
}
.action-right { .action-right {
display: flex; display: flex;
align-items: center; align-items: center;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<img src="../assets/fitller.svg" /> <img src="../assets/fitller.svg" />
<h2 class="section-title text-title-3-bold">核心相似度维度筛选</h2> <h2 class="section-title text-title-3-bold">核心相似度维度筛选</h2>
</div> </div>
<button class="btn-outline" @click="setAsCurrent">设置为当前提案</button>
</div> </div>
<div class="divider" /> <div class="divider" />
<div class="fields-grid"> <div class="fields-grid">
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
<div class="field-content"> <div class="field-content">
<el-select <el-select
v-model="localValues.oppositionProposer" v-model="localValues.oppositionProposer"
multiple
placeholder="请选择" placeholder="请选择"
style="width: 420px" style="width: 420px"
@change="handleChange" @change="handleChange"
...@@ -109,21 +110,21 @@ const props = defineProps<{ ...@@ -109,21 +110,21 @@ const props = defineProps<{
defaultFilters?: Record<string, string[]> defaultFilters?: Record<string, string[]>
}>() }>()
// 本地 v-model 值 // 本地 v-model 值(proposalTime 为单选,用 string)
const localValues = ref({ const localValues = ref({
policyArea: [] as string[], policyArea: [] as string[],
governmentType: [] as string[], governmentType: [] as string[],
oppositionProposer: '' as string, oppositionProposer: [] as string[],
proposalTime: '' as string, proposalTime: '' as string,
}) })
// 根据 proposalInfo 计算初始筛选值(即"设置为当前提案"的目标状态) // 根据 proposalInfo 计算初始筛选值(即"设置为当前提案"的目标状态)
function buildInitialValues(info?: ProposalInfo | null): Record<string, string[] | string> { function buildInitialValues(info?: ProposalInfo | null) {
if (!info) return { policyArea: [], governmentType: [], oppositionProposer: '', proposalTime: '' } if (!info) return { policyArea: [], governmentType: [], oppositionProposer: [], proposalTime: '' }
return { return {
policyArea: info.defaultDomains?.length ? [...info.defaultDomains] : [...(info.areas || [])], policyArea: info.defaultDomains?.length ? [...info.defaultDomains] : [...(info.areas || [])],
governmentType: info.patternType ? [info.patternType] : [], governmentType: info.patternType ? [info.patternType] : [],
oppositionProposer: '', oppositionProposer: [],
proposalTime: '', proposalTime: '',
} }
} }
...@@ -142,7 +143,7 @@ function reset() { ...@@ -142,7 +143,7 @@ function reset() {
localValues.value = { localValues.value = {
policyArea: [], policyArea: [],
governmentType: [], governmentType: [],
oppositionProposer: '', oppositionProposer: [],
proposalTime: '', proposalTime: '',
} }
} }
...@@ -152,14 +153,39 @@ function setAsCurrent() { ...@@ -152,14 +153,39 @@ function setAsCurrent() {
Object.assign(localValues.value, buildInitialValues(props.proposalInfo)) Object.assign(localValues.value, buildInitialValues(props.proposalInfo))
} }
defineExpose({ reset, setAsCurrent, getValues: () => localValues.value }) defineExpose({
reset,
setAsCurrent,
getValues: () => ({
...localValues.value,
// proposalTime 单选,包装为数组保持传值一致
proposalTime: localValues.value.proposalTime ? [localValues.value.proposalTime] : []
})
})
// 固定的政策领域选项(15个)
const policyAreaOptions = [
{ value: '人工智能', label: '人工智能' },
{ value: '生物科技', label: '生物科技' },
{ value: '新一代通信网络', label: '新一代通信网络' },
{ value: '量子科技', label: '量子科技' },
{ value: '新能源', label: '新能源' },
{ value: '集成电路', label: '集成电路' },
{ value: '海洋', label: '海洋' },
{ value: '先进制造', label: '先进制造' },
{ value: '新材料', label: '新材料' },
{ value: '航空航天', label: '航空航天' },
{ value: '太空', label: '太空' },
{ value: '深海', label: '深海' },
{ value: '极地', label: '极地' },
{ value: '核', label: '核' },
{ value: '其他', label: '其他' }
]
// 固定的字段配置,options 由 proposalInfo 动态注入 // 固定的字段配置
const fields = computed(() => { const fields = computed(() => {
const billDomain = props.proposalInfo?.billDomain
const domainOptions = Array.isArray(billDomain) ? billDomain.map(d => ({ value: d, label: d })) : []
return { return {
policyArea: { options: domainOptions }, policyArea: { options: policyAreaOptions },
governmentType: { governmentType: {
options: [ options: [
{ value: '统一政府', label: '统一政府' }, { value: '统一政府', label: '统一政府' },
...@@ -177,9 +203,9 @@ const fields = computed(() => { ...@@ -177,9 +203,9 @@ const fields = computed(() => {
}, },
proposalTime: { proposalTime: {
options: [ options: [
{ value: '近三年', label: '近三年' },
{ value: '近五年', label: '近五年' }, { value: '近五年', label: '近五年' },
{ value: '近十年', label: '近十年' }, { value: '近十年', label: '近十年' }
{ value: '全部', label: '全部' }
] ]
} }
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<div class="header-content"> <div class="header-content">
<div class="header-left"> <div class="header-left">
<div class="text-title-2-bold">科技法案立法进展预测</div> <div class="text-title-2-bold">科技法案立法进展预测</div>
<div class="text-tip-2 text-primary-65-clor">H.R.1-大而美法案(2025年5月20日)</div> <div class="text-tip-2 text-primary-65-clor" v-if="props.proposalInfo">{{ props.proposalInfo.title+"("+ props.proposalInfo.date+")" }}</div>
</div> </div>
<div class="header-actions"> <div class="header-actions">
<button class="action-btn"> <button class="action-btn">
...@@ -30,6 +30,11 @@ ...@@ -30,6 +30,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { ProposalInfo } from '../api'
const props = defineProps<{
proposalInfo?: ProposalInfo | null
defaultFilters?: Record<string, string[]>
}>()
</script> </script>
<style scoped> <style scoped>
...@@ -45,6 +50,7 @@ ...@@ -45,6 +50,7 @@
background: #ffffff; background: #ffffff;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
margin-bottom: 16px; margin-bottom: 16px;
margin-left: 0px;
} }
.header-content { .header-content {
......
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
/> />
</div> </div>
<ActionButtons <ActionButtons
show-set-as-current
@reset="handleReset" @reset="handleReset"
@set-as-current="handleSetAsCurrent"
@next="handleNext" @next="handleNext"
/> />
</template> </template>
...@@ -65,6 +67,11 @@ function handleReset() { ...@@ -65,6 +67,11 @@ function handleReset() {
filterSectionRef.value?.reset() filterSectionRef.value?.reset()
} }
// 设置为当前提案:恢复初始状态
function handleSetAsCurrent() {
filterSectionRef.value?.setAsCurrent()
}
// 下一步:获取已选的筛选条件并传给父组件 // 下一步:获取已选的筛选条件并传给父组件
function handleNext() { function handleNext() {
const selectedFilters = filterSectionRef.value?.getValues() || {} const selectedFilters = filterSectionRef.value?.getValues() || {}
......
...@@ -122,26 +122,27 @@ const selectedCount = computed(() => { ...@@ -122,26 +122,27 @@ const selectedCount = computed(() => {
async function loadData() { async function loadData() {
loading.value = true loading.value = true
try { try {
// 使用真实 API,传入 billIds、domains、patternType、proposalType // 标准 API 参数格式
const params = { const params = {
billIds: filterParams?.value.billIds, billIds: filterParams?.value.billIds,
domains: filterParams?.value.domains || [], domains: (filterParams?.value.domains || []).join(','),
patternType: filterParams?.value.patternType || '统一政府', patternType: filterParams?.value.patternType || '统一政府',
proposalType: filterParams?.value.proposalType || '两党共同提案' proposalType: filterParams?.value.proposalType || '两党共同提案',
timeFrame: filterParams?.value.timeFrame?.[0] || '',
maxNum: 50
} }
const response = await getSimiBills(params) const response = await getSimiBills(params)
if (response && response.data) { if (response && response.data) {
// 保存原始数据(新 API 返回结构中 simi_bills 是法案数组) // 保存原始数据
rawBillsData.value = response.data.simi_bills || [] rawBillsData.value = response.data
const { stats: apiStats, bills: apiBills } = transformSimiBillsData(response) const { stats: apiStats, bills: apiBills } = transformSimiBillsData(response)
stats.value = apiStats stats.value = apiStats
bills.value = apiBills bills.value = apiBills
} else { } else {
stats.value = null stats.value = null
bills.value = [] bills.value = []
rawBillsData.value = []
} }
} catch (error) { } catch (error) {
console.error('获取相似法案失败:', error) console.error('获取相似法案失败:', error)
...@@ -187,8 +188,9 @@ function handleBack() { ...@@ -187,8 +188,9 @@ function handleBack() {
function handleStartAnalysis() { function handleStartAnalysis() {
// 获取用户勾选的法案ID列表 // 获取用户勾选的法案ID列表
const selectedIds = bills.value.filter(b => b.selected).map(b => b.id) const selectedIds = bills.value.filter(b => b.selected).map(b => b.id)
// 从原始数据中筛选出用户勾选的法案 // 从原始数据中筛选出用户勾选的法案(确保 rawBillsData 是数组)
const selectedBills = rawBillsData.value.filter(b => selectedIds.includes(b.bill_id)) const rawData = Array.isArray(rawBillsData.value) ? rawBillsData.value : []
const selectedBills = rawData.filter(b => selectedIds.includes(b.bill_id))
emit('next', selectedBills) emit('next', selectedBills)
} }
</script> </script>
...@@ -210,12 +212,16 @@ function handleStartAnalysis() { ...@@ -210,12 +212,16 @@ function handleStartAnalysis() {
.content-wrapper { .content-wrapper {
flex: 1; flex: 1;
overflow: auto; overflow-y: auto;
display: flex;
flex-direction: column;
min-height: 0;
} }
.stats-section { .stats-section {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%;
} }
.stats-header { .stats-header {
...@@ -333,6 +339,10 @@ function handleStartAnalysis() { ...@@ -333,6 +339,10 @@ function handleStartAnalysis() {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
flex: 1;
overflow-y: auto;
min-height: 0;
padding-bottom: 16px;
} }
.action-footer { .action-footer {
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
<div class="highlight-wave text-regular"></div> <div class="highlight-wave text-regular"></div>
<div class="highlight-content text-regular"> <div class="highlight-content text-regular">
<p class="highlight-title text-regular">该法案的通过概率为 {{ predictionData?.overallProbability || '—' }}</p> <p class="highlight-title text-regular">该法案的通过概率为 {{ predictionData?.overallProbability || '—' }}</p>
<!-- {{ predictionData.factorAnalysis }} -->
<p class="highlight-text text-regular" v-for="value in predictionData.factorAnalysis" :key="value">{{ '*'+value }}</p>
<p class="highlight-text text-regular">{{ predictionData?.highlightText }}</p> <p class="highlight-text text-regular">{{ predictionData?.highlightText }}</p>
</div> </div>
</div> </div>
......
...@@ -22,6 +22,12 @@ ...@@ -22,6 +22,12 @@
<span class="meta-value sponsor-name" :title="allSponsorNames"> <span class="meta-value sponsor-name" :title="allSponsorNames">
{{ firstSponsorName }} {{ firstSponsorName }}
</span> </span>
</div>
<div class="meta-row">
<span class="meta-label">委员会:</span>
<span class="meta-value sponsor-name" :title="allSponsorNames">
{{ firstSponsorName }}
</span>
</div> </div>
<div class="meta-row"> <div class="meta-row">
<span class="meta-label">相关领域:</span> <span class="meta-label">相关领域:</span>
...@@ -114,6 +120,7 @@ const currentStageIndex = computed(() => { ...@@ -114,6 +120,7 @@ const currentStageIndex = computed(() => {
gap: 13px; gap: 13px;
align-items: center; align-items: center;
height: 100%; height: 100%;
margin:15px 1px
} }
.bill-card-preview { .bill-card-preview {
......
...@@ -23,9 +23,10 @@ ...@@ -23,9 +23,10 @@
<template v-else> <template v-else>
<BillCard <BillCard
v-for="bill in bills" v-for="bill in bills"
:key="bill.id" :key="bill.billId"
:bill="bill" :bill="bill"
:progress-stages="progressStages" :progress-stages="progressStages"
@click="handleBillMoreClick(bill.billId)"
/> />
<div v-if="total > 0" class="bill-pagination"> <div v-if="total > 0" class="bill-pagination">
...@@ -46,7 +47,10 @@ ...@@ -46,7 +47,10 @@
<script setup> <script setup>
import BillCard from './BillCard.vue' import BillCard from './BillCard.vue'
import { useRouter } from "vue-router";
const router = useRouter();
import { useRoute } from "vue-router";
const route = useRoute();
defineProps({ defineProps({
bills: { type: Array, required: true }, bills: { type: Array, required: true },
loading: { type: Boolean, default: false }, loading: { type: Boolean, default: false },
...@@ -56,27 +60,45 @@ defineProps({ ...@@ -56,27 +60,45 @@ defineProps({
progressStages: { type: Array, default: () => ['提出', '众议院通过', '参议院通过', '分歧协调', '提交总统', '法案通过'] }, progressStages: { type: Array, default: () => ['提出', '众议院通过', '参议院通过', '分歧协调', '提交总统', '法案通过'] },
}) })
defineEmits(['page-change']) defineEmits(['page-change'])
/** 政策建议关联法案:新标签页打开法案介绍页,billId 随接口 id 变化 */
const handleBillMoreClick = (bill) => {
const billId = bill;
// debugger
if (!billId) {
return;
}
const route = router.resolve({
path: "/billLayout/bill/introduction",
query: { billId: String(billId) }
});
window.open(route.href, "_blank");
};
</script> </script>
<style scoped> <style scoped>
/* Bill List */
.bill-list { .bill-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
} }
.bill-list-loading { .bill-list-loading {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
} }
.bill-list-skeleton { .bill-list-skeleton {
display: flex; display: flex;
gap: 24px; gap: 24px;
background: #fff; background: var(--bg-white-100);
border: 1px solid #ebedf0; border-radius: 10px;
border-radius: 8px; box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
padding: 24px; padding: 24px;
} }
.skeleton-left { .skeleton-left {
width: 120px; width: 120px;
height: 190px; height: 190px;
...@@ -84,30 +106,35 @@ defineEmits(['page-change']) ...@@ -84,30 +106,35 @@ defineEmits(['page-change'])
border-radius: 4px; border-radius: 4px;
animation: pulse 1.5s ease-in-out infinite; animation: pulse 1.5s ease-in-out infinite;
} }
.skeleton-right { .skeleton-right {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
} }
.skeleton-line { .skeleton-line {
height: 16px; height: 16px;
background: #f0f0f0; background: #f0f0f0;
border-radius: 4px; border-radius: 4px;
animation: pulse 1.5s ease-in-out infinite; animation: pulse 1.5s ease-in-out infinite;
} }
.skeleton-line.w30 { width: 30%; } .skeleton-line.w30 { width: 30%; }
.skeleton-line.w40 { width: 40%; } .skeleton-line.w40 { width: 40%; }
.skeleton-line.w50 { width: 50%; } .skeleton-line.w50 { width: 50%; }
.skeleton-line.w60 { width: 60%; } .skeleton-line.w60 { width: 60%; }
.skeleton-divider { .skeleton-divider {
height: 1px; height: 1px;
background: #ebedf0; background: #eaeced;
} }
.bill-list-empty { .bill-list-empty {
background: #fff; background: var(--bg-white-100);
border: 1px solid #ebedf0; border-radius: 10px;
border-radius: 8px; box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
padding: 48px; padding: 48px;
text-align: center; text-align: center;
color: #bfbfbf; color: #bfbfbf;
...@@ -117,6 +144,7 @@ defineEmits(['page-change']) ...@@ -117,6 +144,7 @@ defineEmits(['page-change'])
align-items: center; align-items: center;
gap: 12px; gap: 12px;
} }
@keyframes pulse { @keyframes pulse {
0%, 100% { opacity: 1; } 0%, 100% { opacity: 1; }
50% { opacity: 0.5; } 50% { opacity: 0.5; }
...@@ -129,6 +157,7 @@ defineEmits(['page-change']) ...@@ -129,6 +157,7 @@ defineEmits(['page-change'])
justify-content: space-between; justify-content: space-between;
padding: 16px 0 0; padding: 16px 0 0;
} }
.bill-pagination-total { .bill-pagination-total {
font-size: 14px; font-size: 14px;
font-family: 'Microsoft YaHei', sans-serif; font-family: 'Microsoft YaHei', sans-serif;
...@@ -139,10 +168,11 @@ defineEmits(['page-change']) ...@@ -139,10 +168,11 @@ defineEmits(['page-change'])
/* Override el-pagination to match design */ /* Override el-pagination to match design */
.bill-pagination :deep(.el-pagination) { .bill-pagination :deep(.el-pagination) {
--el-pagination-bg-color: #fff; --el-pagination-bg-color: var(--bg-white-100);
--el-pagination-hover-color: rgba(5, 95, 194, 1); --el-pagination-hover-color: rgba(5, 95, 194, 1);
padding: 0; padding: 0;
} }
.bill-pagination :deep(.el-pagination.is-background .btn-prev), .bill-pagination :deep(.el-pagination.is-background .btn-prev),
.bill-pagination :deep(.el-pagination.is-background .btn-next), .bill-pagination :deep(.el-pagination.is-background .btn-next),
.bill-pagination :deep(.el-pagination.is-background .el-pager li) { .bill-pagination :deep(.el-pagination.is-background .el-pager li) {
...@@ -151,20 +181,23 @@ defineEmits(['page-change']) ...@@ -151,20 +181,23 @@ defineEmits(['page-change'])
line-height: 32px; line-height: 32px;
border-radius: 4px; border-radius: 4px;
border: 1px solid rgba(234, 236, 238, 1); border: 1px solid rgba(234, 236, 238, 1);
background: #fff; background: var(--bg-white-100);
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-size: 14px; font-size: 14px;
font-family: 'Microsoft YaHei', sans-serif; font-family: 'Microsoft YaHei', sans-serif;
margin: 0 3px; margin: 0 3px;
} }
.bill-pagination :deep(.el-pagination.is-background .el-pager li:not(.is-disabled).is-active) { .bill-pagination :deep(.el-pagination.is-background .el-pager li:not(.is-disabled).is-active) {
background: #fff; background: var(--bg-white-100);
color: rgba(5, 95, 194, 1); color: rgba(5, 95, 194, 1);
border-color: rgba(5, 95, 194, 1); border-color: rgba(5, 95, 194, 1);
} }
.bill-pagination :deep(.el-pagination.is-background .el-pager li:not(.is-disabled):hover) { .bill-pagination :deep(.el-pagination.is-background .el-pager li:not(.is-disabled):hover) {
color: rgba(5, 95, 194, 1); color: rgba(5, 95, 194, 1);
} }
.bill-pagination :deep(.el-pagination.is-background .btn-prev:hover), .bill-pagination :deep(.el-pagination.is-background .btn-prev:hover),
.bill-pagination :deep(.el-pagination.is-background .btn-next:hover) { .bill-pagination :deep(.el-pagination.is-background .btn-next:hover) {
color: rgba(5, 95, 194, 1); color: rgba(5, 95, 194, 1);
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
</div> </div>
<div class="doc-info"> <div class="doc-info">
<div class="doc-number">{{ billNumber }}</div> <div class="doc-number">{{ billNumber }}</div>
<div class="doc-serial">{{ billSerial }}</div> <div class="doc-serial" :title="billSerial">{{ billSerial }}</div>
</div> </div>
</div> </div>
</template> </template>
...@@ -147,5 +147,13 @@ defineProps({ ...@@ -147,5 +147,13 @@ defineProps({
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
line-height: 24px; line-height: 24px;
text-align: center; text-align: center;
width:15em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 6px 10px;
font-size: 14px;
cursor: pointer;
} }
</style> </style>
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
</div> </div>
</AnalysisBox> </AnalysisBox>
<AnalysisBox title=" 金钱来源" width="1064px" height="512px" :show-all-btn="false" class="left-center"> <AnalysisBox title=" 资金来源" width="1064px" height="512px" :show-all-btn="false" class="left-center">
<template #header-btn> <template #header-btn>
<div class="input"> <div class="input">
<el-select v-model="selectedOption" placeholder="请选择" class="select" :teleported="true"> <el-select v-model="selectedOption" placeholder="请选择" class="select" :teleported="true">
...@@ -80,12 +80,12 @@ ...@@ -80,12 +80,12 @@
background @current-change="handleFundPageChange" /> background @current-change="handleFundPageChange" />
</div> </div>
</div> </div>
<div class="bottom"> <!-- <div class="bottom">
<img src="./assets/ai.png" alt="" class="icon"> <img src="./assets/ai.png" alt="" class="icon">
<div class="text1"> <div class="text1">
</div> </div>
<img src="./assets/right.png" alt="" class="icon1"> <img src="./assets/right.png" alt="" class="icon1">
</div> </div> -->
</AnalysisBox> </AnalysisBox>
<AnalysisBox title="最新动态" width="1064px" height="1330px" :show-all-btn="false" class="left-bottom"> <AnalysisBox title="最新动态" width="1064px" height="1330px" :show-all-btn="false" class="left-bottom">
<template #header-btn> <template #header-btn>
...@@ -375,6 +375,19 @@ import img5 from "./assets/img5.png"; ...@@ -375,6 +375,19 @@ import img5 from "./assets/img5.png";
import DefaultIcon1 from '@/assets/icons/default-icon1.png' import DefaultIcon1 from '@/assets/icons/default-icon1.png'
import DefaultIcon2 from '@/assets/icons/default-icon2.png' import DefaultIcon2 from '@/assets/icons/default-icon2.png'
/** 政策建议关联法案:新标签页打开法案介绍页,billId 随接口 id 变化 */
const handleBillMoreClick = (bill) => {
const billId = bill?.id;
if (!billId) {
return;
}
const route = router.resolve({
path: "/billLayout/bill/introduction",
query: { billId: String(billId) }
});
window.open(route.href, "_blank");
};
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
const route = useRoute(); const route = useRoute();
const personId = ref(route.query.personId || "Y000064"); const personId = ref(route.query.personId || "Y000064");
...@@ -1120,22 +1133,27 @@ const handleClickTag = async (tag) => { ...@@ -1120,22 +1133,27 @@ const handleClickTag = async (tag) => {
.left-bottom { .left-bottom {
width: 100%; width: 100%;
height: 1330px; height: 100%;
background-color: rgba(255, 255, 255, 1); background-color: rgba(255, 255, 255, 1);
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 0px 20px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px rgba(25, 69, 130, 0.1);
display: flex;
flex-direction: column;
overflow: hidden;
:deep(.wrapper-header) { :deep(.wrapper-header) {
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
height: 56px; height: 56px;
/* 根据设计图调整 */
padding: 0 24px; padding: 0 24px;
flex-shrink: 0;
} }
:deep(.header-btn){
:deep(.header-btn) {
top: 16px; top: 16px;
} }
.title { .title {
width: 100%; width: 100%;
height: 85px; height: 85px;
...@@ -1143,6 +1161,7 @@ const handleClickTag = async (tag) => { ...@@ -1143,6 +1161,7 @@ const handleClickTag = async (tag) => {
align-items: center; align-items: center;
padding: 14px 12px 45px 0; padding: 14px 12px 45px 0;
position: relative; position: relative;
flex-shrink: 0;
.box { .box {
width: 8px; width: 8px;
...@@ -1182,7 +1201,6 @@ const handleClickTag = async (tag) => { ...@@ -1182,7 +1201,6 @@ const handleClickTag = async (tag) => {
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
right: 120px; right: 120px;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
...@@ -1196,7 +1214,6 @@ const handleClickTag = async (tag) => { ...@@ -1196,7 +1214,6 @@ const handleClickTag = async (tag) => {
width: 16px; width: 16px;
height: 16px; height: 16px;
accent-color: #1890ff; accent-color: #1890ff;
cursor: pointer; cursor: pointer;
margin: 0; margin: 0;
} }
...@@ -1209,21 +1226,26 @@ const handleClickTag = async (tag) => { ...@@ -1209,21 +1226,26 @@ const handleClickTag = async (tag) => {
.main { .main {
width: 1064px; width: 1064px;
height: 1133px;
box-sizing: border-box; box-sizing: border-box;
padding-right: 50px; padding: 0 50px 0 0;
position: relative; position: relative;
z-index: 110; z-index: 1;
height: calc(100% - 5px - 76px);
min-height: 0;
overflow-y: auto;
overflow-x: hidden;
flex: 0 0 auto;
.main-item { .main-item {
width: 1014px; width: 1014px;
margin-bottom: 40px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: flex-start; align-items: flex-start;
margin-bottom: 20px; margin-bottom: 20px;
padding-bottom: 20px;
position: relative; position: relative;
.time { .time {
width: 77px; width: 77px;
box-sizing: border-box; box-sizing: border-box;
...@@ -1231,6 +1253,7 @@ const handleClickTag = async (tag) => { ...@@ -1231,6 +1253,7 @@ const handleClickTag = async (tag) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-end; align-items: flex-end;
flex-shrink: 0;
.year { .year {
font-size: 16px; font-size: 16px;
...@@ -1251,6 +1274,7 @@ const handleClickTag = async (tag) => { ...@@ -1251,6 +1274,7 @@ const handleClickTag = async (tag) => {
.image { .image {
margin-right: 20px; margin-right: 20px;
flex-shrink: 0;
img { img {
width: 24px; width: 24px;
...@@ -1260,6 +1284,7 @@ const handleClickTag = async (tag) => { ...@@ -1260,6 +1284,7 @@ const handleClickTag = async (tag) => {
.content { .content {
width: 873px; width: 873px;
min-width: 0;
.content-type1 { .content-type1 {
background-color: rgba(246, 250, 255, 1); background-color: rgba(246, 250, 255, 1);
...@@ -1320,6 +1345,7 @@ const handleClickTag = async (tag) => { ...@@ -1320,6 +1345,7 @@ const handleClickTag = async (tag) => {
width: 873px; width: 873px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
gap: 12px;
.tag { .tag {
font-size: 14px; font-size: 14px;
...@@ -1364,49 +1390,45 @@ const handleClickTag = async (tag) => { ...@@ -1364,49 +1390,45 @@ const handleClickTag = async (tag) => {
line-height: 22px; line-height: 22px;
color: rgb(132, 136, 142); color: rgb(132, 136, 142);
cursor: pointer; cursor: pointer;
white-space: nowrap;
} }
} }
} }
} }
.main-item::after {
content: ''; .main-item::after {
content: "";
position: absolute; position: absolute;
left: 109px; /* 与圆点对齐 */ left: 109px;
top: 24px; /* 从圆点下方开始 */ top: 24px;
bottom: -20px; /* 延伸到下一个 item */ height: calc(100% - 24px);
width: 1px; width: 1px;
background-color: rgb(230, 231, 232); background-color: rgb(230, 231, 232);
z-index: -1; z-index: 0;
}
.line-test {
position: absolute;
top: 10px;
left: 109px;
border: 1px solid rgb(230, 231, 232);
z-index: -1;
position: absolute;
bottom: 10px;
} }
.main-item:last-child::after {
display: none;
} }
.line { .line-test {
width: 100%; display: none;
height: 1px; }
background-color: rgb(234, 236, 238);
margin-top: 30px;
border: none;
} }
.pagination { .pagination {
width: 100%; width: 100%;
height: 76px; height: 76px;
margin: 20px auto; margin: 0;
display: flex; display: flex;
padding: 0 31px 0 36px; padding: 0 31px 0 36px;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
border-top: 1px solid rgb(234, 236, 238); border-top: 1px solid rgb(234, 236, 238);
position: relative;
z-index: 3;
background: #fff;
flex-shrink: 0;
.total { .total {
font-size: 16px; font-size: 16px;
...@@ -1468,7 +1490,7 @@ const handleClickTag = async (tag) => { ...@@ -1468,7 +1490,7 @@ const handleClickTag = async (tag) => {
background-color: #fff; background-color: #fff;
} }
} }
} }
} }
.right { .right {
...@@ -1734,7 +1756,7 @@ const handleClickTag = async (tag) => { ...@@ -1734,7 +1756,7 @@ const handleClickTag = async (tag) => {
.content-item { .content-item {
width: 454px; width: 454px;
margin-bottom: 60px; // margin-bottom: 60px;
margin-left: 26px; margin-left: 26px;
position: relative; position: relative;
...@@ -2080,4 +2102,32 @@ const handleClickTag = async (tag) => { ...@@ -2080,4 +2102,32 @@ const handleClickTag = async (tag) => {
color: rgba(170, 173, 177, 1); color: rgba(170, 173, 177, 1);
font-size: 14px; font-size: 14px;
} }
.baseInfo-item {
display: flex;
align-items: flex-start;
}
.baseInfo-item-title {
flex: 0 0 88px; /* 固定左侧宽度 */
font-size: 16px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
white-space: nowrap; /* 左侧不换行 */
}
.baseInfo-item-content {
flex: 1;
min-width: 0;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
display: flex;
flex-wrap: wrap; /* 右侧满了再换行 */
gap: 8px 12px; /* 行列间距可调 */
}
.education-item {
white-space: nowrap; /* 每个学校+专业作为一个整体不拆行 */
}
</style> </style>
...@@ -109,10 +109,17 @@ ...@@ -109,10 +109,17 @@
<div class="baseInfo-item-content">{{ characterBasicInfo.country }}</div> <div class="baseInfo-item-content">{{ characterBasicInfo.country }}</div>
</div> </div>
<div class="baseInfo-item"> <div class="baseInfo-item">
<div class="baseInfo-item">
<div class="baseInfo-item-title">教育背景:</div> <div class="baseInfo-item-title">教育背景:</div>
<div class="baseInfo-item-content" v-for="value in characterBasicInfo.educationList" <div class="baseInfo-item-content">
:key="value.school"> <span
class="education-item"
v-for="value in characterBasicInfo.educationList"
:key="value.school"
>
{{ value.school + "(" + value.major + ")" }} {{ value.school + "(" + value.major + ")" }}
</span>
</div>
</div> </div>
</div> </div>
<div class="baseInfo-item"> <div class="baseInfo-item">
...@@ -832,33 +839,120 @@ onMounted(() => { ...@@ -832,33 +839,120 @@ onMounted(() => {
} }
.left-bottom { .left-bottom {
.check-input { width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px rgba(25, 69, 130, 0.1);
display: flex;
flex-direction: column;
overflow: hidden;
:deep(.wrapper-header) {
position: relative;
display: flex;
align-items: center;
height: 56px;
padding: 0 24px;
flex-shrink: 0;
}
:deep(.header-btn) {
top: 16px;
}
.title {
width: 100%;
height: 85px;
display: flex;
align-items: center;
padding: 14px 12px 45px 0;
position: relative;
flex-shrink: 0;
.box {
width: 8px;
height: 20px;
background-color: rgb(5, 95, 194);
border-bottom-right-radius: 4px;
border-top-right-radius: 4px;
margin-right: 14px;
}
.text {
font-size: 20px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 26px;
color: rgb(5, 95, 194);
}
.btn {
width: 60px;
height: 28px;
margin-left: auto;
img {
width: 28px;
height: 28px;
cursor: pointer;
}
img:first-child {
margin-right: 4px;
}
}
.input {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 120px;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
line-height: 24px; line-height: 24px;
color: rgb(132, 136, 142); color: rgb(132, 136, 142);
display: flex;
align-items: center;
gap: 8px;
input { input[type="checkbox"] {
margin-right: 8px; width: 16px;
height: 16px;
accent-color: #1890ff;
cursor: pointer;
margin: 0;
}
span {
margin-left: 0 !important;
}
} }
} }
.main { .main {
width: 1064px; width: 1064px;
height: 1357px;
box-sizing: border-box; box-sizing: border-box;
padding-right: 50px; padding: 0 50px 0 0;
position: relative; position: relative;
z-index: 110; z-index: 1;
margin-top: 10px;
height: calc(100% - 5px - 76px);
min-height: 0;
overflow-y: auto;
overflow-x: hidden;
flex: 0 0 auto;
.main-item { .main-item {
width: 1014px; width: 1014px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: flex-start; align-items: flex-start;
margin-bottom: 20px; margin-bottom: 20px;
padding-bottom: 20px;
position: relative; position: relative;
.time { .time {
width: 77px; width: 77px;
box-sizing: border-box; box-sizing: border-box;
...@@ -866,8 +960,16 @@ onMounted(() => { ...@@ -866,8 +960,16 @@ onMounted(() => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-end; align-items: flex-end;
flex-shrink: 0;
.year {
font-size: 16px;
font-weight: 700;
font-family: "Microsoft YaHei";
color: rgb(5, 95, 194);
line-height: 24px;
}
.year,
.date { .date {
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
...@@ -879,6 +981,7 @@ onMounted(() => { ...@@ -879,6 +981,7 @@ onMounted(() => {
.image { .image {
margin-right: 20px; margin-right: 20px;
flex-shrink: 0;
img { img {
width: 24px; width: 24px;
...@@ -888,6 +991,7 @@ onMounted(() => { ...@@ -888,6 +991,7 @@ onMounted(() => {
.content { .content {
width: 873px; width: 873px;
min-width: 0;
.content-type1 { .content-type1 {
background-color: rgba(246, 250, 255, 1); background-color: rgba(246, 250, 255, 1);
...@@ -948,7 +1052,7 @@ onMounted(() => { ...@@ -948,7 +1052,7 @@ onMounted(() => {
width: 873px; width: 873px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-top: 10px; gap: 12px;
.tag { .tag {
font-size: 14px; font-size: 14px;
...@@ -993,39 +1097,45 @@ onMounted(() => { ...@@ -993,39 +1097,45 @@ onMounted(() => {
line-height: 22px; line-height: 22px;
color: rgb(132, 136, 142); color: rgb(132, 136, 142);
cursor: pointer; cursor: pointer;
white-space: nowrap;
} }
} }
} }
} }
.main-item::after { .main-item::after {
content: ''; content: "";
position: absolute; position: absolute;
left: 109px; left: 109px;
top: 24px; top: 24px;
bottom: -20px; height: calc(100% - 24px);
width: 1px; width: 1px;
background-color: rgb(230, 231, 232); background-color: rgb(230, 231, 232);
z-index: -1; z-index: 0;
}
.main-item:last-child::after {
display: none;
} }
.line-test { .line-test {
position: absolute; display: none;
top: 10px;
left: 109px;
height: 1300px;
border: 1px solid rgb(230, 231, 232);
z-index: -1;
} }
} }
.pagination { .pagination {
width: 100%; width: 100%;
height: 76px; height: 76px;
margin: 20px auto; margin: 0;
display: flex; display: flex;
padding: 0 31px 0 36px; padding: 0 31px 0 36px;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
border-top: 1px solid rgb(234, 236, 238); border-top: 1px solid rgb(234, 236, 238);
position: relative;
z-index: 3;
background: #fff;
flex-shrink: 0;
.total { .total {
font-size: 16px; font-size: 16px;
...@@ -1087,7 +1197,7 @@ onMounted(() => { ...@@ -1087,7 +1197,7 @@ onMounted(() => {
background-color: #fff; background-color: #fff;
} }
} }
} }
} }
.right { .right {
...@@ -1468,4 +1578,32 @@ onMounted(() => { ...@@ -1468,4 +1578,32 @@ onMounted(() => {
.tab-select { .tab-select {
width: 120px; width: 120px;
} }
.baseInfo-item {
display: flex;
align-items: flex-start;
}
.baseInfo-item-title {
flex: 0 0 88px; /* 固定左侧宽度 */
font-size: 16px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
white-space: nowrap; /* 左侧不换行 */
}
.baseInfo-item-content {
flex: 1;
min-width: 0;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
display: flex;
flex-wrap: wrap; /* 右侧满了再换行 */
gap: 8px 12px; /* 行列间距可调 */
}
.education-item {
white-space: nowrap; /* 每个学校+专业作为一个整体不拆行 */
}
</style> </style>
<template> <template>
<div class="news-pagination-bar"> <div class="news-pagination-bar" v-if="total>1">
<span class="news-pagination-total">{{ total }}篇新闻报告</span> <span class="news-pagination-total">{{ total }}篇新闻报告</span>
<div class="news-pagination"> <div class="news-pagination">
<button class="pg-btn" :disabled="currentPage <= 1" @click="$emit('update:currentPage', currentPage - 1)"> <button class="pg-btn" :disabled="currentPage <= 1" @click="$emit('update:currentPage', currentPage - 1)">
......
...@@ -20,11 +20,11 @@ ...@@ -20,11 +20,11 @@
<button <button
:class="['news-tab', { active: activeTab === 'local' }]" :class="['news-tab', { active: activeTab === 'local' }]"
@click="$emit('update:activeTab', 'local')" @click="$emit('update:activeTab', 'local')"
>智库报告</button> > 报告</button>
<button <button
:class="['news-tab', { active: activeTab === 'capital' }]" :class="['news-tab', { active: activeTab === 'capital' }]"
@click="$emit('update:activeTab', 'capital')" @click="$emit('update:activeTab', 'capital')"
>调查项目</button> > 项目</button>
</div> </div>
<div class="news-sort" ref="sortDropdownRef"> <div class="news-sort" ref="sortDropdownRef">
...@@ -172,9 +172,10 @@ onUnmounted(() => document.removeEventListener('click', handleClickOutside)) ...@@ -172,9 +172,10 @@ onUnmounted(() => document.removeEventListener('click', handleClickOutside))
margin-left: auto; margin-left: auto;
position: relative; position: relative;
flex-shrink: 0; flex-shrink: 0;
margin-right: 10px;
} }
.news-sort-btn { .news-sort-btn {
width: 120px; width: 150px;
height: 32px; height: 32px;
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -185,6 +186,7 @@ onUnmounted(() => document.removeEventListener('click', handleClickOutside)) ...@@ -185,6 +186,7 @@ onUnmounted(() => document.removeEventListener('click', handleClickOutside))
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
cursor: pointer; cursor: pointer;
box-sizing: border-box; box-sizing: border-box;
margin-top: 15px;
} }
.news-sort-btn:hover { .news-sort-btn:hover {
border-color: rgba(5, 95, 194, 0.4); border-color: rgba(5, 95, 194, 0.4);
......
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
<div class="news-main"> <div class="news-main">
<div class="news-grid"> <div class="news-grid">
<NewsCard <NewsCard
v-for="item in newsList" v-for="item in (activeTab === 'local' ? newsList : projectList)"
:key="item.reportId" :key="item.reportId"
:item="item" :item="item"
/> />
</div> </div>
<NewsPagination <NewsPagination
:total="totalNews" :total="activeTab === 'local' ? totalNews : totalProjects"
v-model:current-page="currentPage" v-model:current-page="currentPage"
:page-size="pageSize" :page-size="pageSize"
/> />
...@@ -41,7 +41,7 @@ import NewsSidebar from './NewsSidebar.vue' ...@@ -41,7 +41,7 @@ import NewsSidebar from './NewsSidebar.vue'
import NewsCard from './NewsCard.vue' import NewsCard from './NewsCard.vue'
import NewsPagination from './NewsPagination.vue' import NewsPagination from './NewsPagination.vue'
import { getIndustryKeyList } from '@/api/bill/billHome.js' import { getIndustryKeyList } from '@/api/bill/billHome.js'
import { getFindingsReport } from '@/api/characterPage/characterPage.js' import { getFindingsReport, getInvestigationProject } from '@/api/characterPage/characterPage.js'
const route = useRoute() const route = useRoute()
const personId = computed(() => route.params.personId || route.query.personId || '') const personId = computed(() => route.params.personId || route.query.personId || '')
...@@ -51,7 +51,9 @@ const activeTab = ref('local') ...@@ -51,7 +51,9 @@ const activeTab = ref('local')
const currentPage = ref(1) const currentPage = ref(1)
const pageSize = 12 const pageSize = 12
const totalNews = ref(0) const totalNews = ref(0)
const totalProjects = ref(0)
const newsList = ref([]) const newsList = ref([])
const projectList = ref([])
const loading = ref(false) const loading = ref(false)
const sortBy = ref('publishTimeDesc') const sortBy = ref('publishTimeDesc')
...@@ -79,17 +81,16 @@ async function loadFilterOptions() { ...@@ -79,17 +81,16 @@ async function loadFilterOptions() {
] ]
} }
function buildParams() { function buildParams({ includeSearchText = false } = {}) {
const params = { const params = {
currentPage: currentPage.value - 1, currentPage: currentPage.value - 1,
pageSize, pageSize,
sortFun: sortBy.value === 'publishTimeAsc', sortFun: sortBy.value === 'publishTimeAsc',
industryIds: selectedDomains.value.includes('all') ? '' : JSON.stringify(selectedDomains.value),
years: selectedTimes.value.includes('all') ? '' : JSON.stringify(selectedTimes.value),
} }
if (!selectedDomains.value.includes('all')) { if (includeSearchText) {
params.industryIds = selectedDomains.value params.searchText = searchText.value
}
if (!selectedTimes.value.includes('all')) {
params.years = selectedTimes.value
} }
return params return params
} }
...@@ -97,14 +98,18 @@ function buildParams() { ...@@ -97,14 +98,18 @@ function buildParams() {
function updateSort(value) { function updateSort(value) {
sortBy.value = value sortBy.value = value
currentPage.value = 1 currentPage.value = 1
if (activeTab.value === 'local') {
loadNews() loadNews()
} else {
loadProjects()
}
} }
async function loadNews() { async function loadNews() {
if (!personId.value) return if (!personId.value) return
loading.value = true loading.value = true
try { try {
const params = buildParams() const params = buildParams({ includeSearchText: true })
const res = await getFindingsReport(personId.value, params) const res = await getFindingsReport(personId.value, params)
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
newsList.value = res.data.content || [] newsList.value = res.data.content || []
...@@ -118,6 +123,32 @@ async function loadNews() { ...@@ -118,6 +123,32 @@ async function loadNews() {
} }
} }
async function loadProjects() {
if (!personId.value) return
loading.value = true
try {
const params = buildParams()
const res = await getInvestigationProject(personId.value, params)
if (res.code === 200 && res.data) {
projectList.value = (res.data.content || []).map(item => ({
reportId: item.projectId,
title: item.name,
content: item.description,
imageUrl: item.imageUrl,
time: item.time,
sourceName: item.sourceName,
industryList: item.industryList,
}))
totalProjects.value = res.data.totalElements || 0
} else {
projectList.value = []
totalProjects.value = 0
}
} finally {
loading.value = false
}
}
function toggleDomain(id) { function toggleDomain(id) {
if (id === 'all') { if (id === 'all') {
selectedDomains.value = ['all'] selectedDomains.value = ['all']
...@@ -142,17 +173,43 @@ function toggleTime(id) { ...@@ -142,17 +173,43 @@ function toggleTime(id) {
} }
} }
watch(searchText, () => {
currentPage.value = 1
if (activeTab.value === 'local') {
loadNews()
} else {
loadProjects()
}
})
watch(activeTab, (val) => {
currentPage.value = 1
if (val === 'local') {
loadNews()
} else {
loadProjects()
}
})
watch( watch(
() => [selectedDomains.value, selectedTimes.value], () => [selectedDomains.value, selectedTimes.value],
() => { () => {
currentPage.value = 1 currentPage.value = 1
if (activeTab.value === 'local') {
loadNews() loadNews()
} else {
loadProjects()
}
}, },
{ deep: true } { deep: true }
) )
watch(currentPage, () => { watch(currentPage, () => {
if (activeTab.value === 'local') {
loadNews() loadNews()
} else {
loadProjects()
}
}) })
onMounted(async () => { onMounted(async () => {
......
...@@ -103,11 +103,18 @@ ...@@ -103,11 +103,18 @@
<div class="baseInfo-item-title">国籍:</div> <div class="baseInfo-item-title">国籍:</div>
<div class="baseInfo-item-content">{{ characterBasicInfo.country }}</div> <div class="baseInfo-item-content">{{ characterBasicInfo.country }}</div>
</div> </div>
<div class="baseInfo-item">
<div class="baseInfo-item"> <div class="baseInfo-item">
<div class="baseInfo-item-title">教育背景:</div> <div class="baseInfo-item-title">教育背景:</div>
<div class="baseInfo-item-content long" <div class="baseInfo-item-content">
v-for="item in characterBasicInfo.educationList"> <span
{{ item.school + '--' + item.major }}<br> class="education-item"
v-for="value in characterBasicInfo.educationList"
:key="value.school"
>
{{ value.school + "(" + value.major + ")" }}
</span>
</div>
</div> </div>
</div> </div>
<div class="baseInfo-item"> <div class="baseInfo-item">
...@@ -1220,4 +1227,32 @@ const companyList = ref([ ...@@ -1220,4 +1227,32 @@ const companyList = ref([
color: rgba(170, 173, 177, 1); color: rgba(170, 173, 177, 1);
font-size: 14px; font-size: 14px;
} }
.baseInfo-item {
display: flex;
align-items: flex-start;
}
.baseInfo-item-title {
flex: 0 0 88px; /* 固定左侧宽度 */
font-size: 16px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
white-space: nowrap; /* 左侧不换行 */
}
.baseInfo-item-content {
flex: 1;
min-width: 0;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
display: flex;
flex-wrap: wrap; /* 右侧满了再换行 */
gap: 8px 12px; /* 行列间距可调 */
}
.education-item {
white-space: nowrap; /* 每个学校+专业作为一个整体不拆行 */
}
</style> </style>
\ No newline at end of file
...@@ -39,6 +39,7 @@ const getCharacterGlobalInfoFn = async () => { ...@@ -39,6 +39,7 @@ const getCharacterGlobalInfoFn = async () => {
const res = await getCharacterGlobalInfo(params); const res = await getCharacterGlobalInfo(params);
if (res.code === 200) { if (res.code === 200) {
console.log("人物全局信息111", res); console.log("人物全局信息111", res);
document.title=res.data.name
if (res.data) { if (res.data) {
characterInfo.value = res.data; characterInfo.value = res.data;
const personType = characterInfo.value.personType; const personType = characterInfo.value.personType;
......
差异被折叠。
const generateDate = () => {
const date = new Date()
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}${month}${day}日`
}
const generateMonthDay = () => {
const date = new Date()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${month}-${day}`
}
const sources = ['华盛顿邮报', '福克斯新闻网', '纽约时报', 'CNN', 'BBC']
const getRandomSource = () => sources[Math.floor(Math.random() * sources.length)]
export const getNewsDetail = (id) => {
return {
id: id || '1',
title: '新闻介绍',
subTitle: 'news',
tags: ['新闻介绍', '推荐新闻'],
coverImage: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjkwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iOTAiIGZpbGw9IiM0YTdiZjciLz48L3N2Zz4=',
time: generateDate(),
background: '住建部联合多部门发布新政,全国 27 个试点城市全面启动老旧小区加装电梯工作,政府补贴比例提至 60%,简化审批流程至 15 个工作日。预计年内完成超 5000 部加装,解决高层老人出行难题。同步完善无障碍配套,提升民居住幸福感。',
countries: [
{ name: '美国', flag: '🇺🇸' },
{ name: '日本', flag: '🇯🇵' },
{ name: '韩国', flag: '🇰🇷' },
{ name: '中国台湾', flag: '🇨🇳' }
]
}
}
export const getNewsList = (page = 1, pageSize = 10) => {
const total = 153
const list = []
for (let i = 0; i < pageSize; i++) {
const id = (page - 1) * pageSize + i + 1
list.push({
id: id,
title: `多地启动老旧小区电梯加装 - 第${id}条`,
content: '住建部联合多部门发布新政,全国 27 个试点城市全面启动老旧小区加装电梯工作,政府补贴比例提至 60%,简化审批流程至 15 个工作日。预计年内完成超 5000 部加装,解决高层老人出行难题,同步完善无障碍配套,提升居民居住幸福感。',
date: generateMonthDay(),
source: getRandomSource(),
image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjkwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iOTAiIGZpbGw9IiM0YTdiZjciLz48L3N2Zz4='
})
}
return {
list,
total,
page,
pageSize,
totalPages: Math.ceil(total / pageSize)
}
}
export const getNewsById = (id) => {
return {
id: id,
title: `多地启动老旧小区电梯加装`,
content: '住建部联合多部门发布新政,全国 27 个试点城市全面启动老旧小区加装电梯工作,政府补贴比例提至 60%,简化审批流程至 15 个工作日。预计年内完成超 5000 部加装,解决高层老人出行难题,同步完善无障碍配套,提升居民居住幸福感。',
date: generateDate(),
source: getRandomSource(),
image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjkwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iOTAiIGZpbGw9IiM0YTdiZjciLz48L3N2Zz4=',
background: '住建部联合多部门发布新政,全国 27 个试点城市全面启动老旧小区加装电梯工作,政府补贴比例提至 60%,简化审批流程至 15 个工作日。预计年内完成超 5000 部加装,解决高层老人出行难题。同步完善无障碍配套,提升民居住幸福感。',
countries: [
{ name: '美国', flag: '🇺🇸' },
{ name: '日本', flag: '🇯🇵' },
{ name: '韩国', flag: '🇰🇷' },
{ name: '中国台湾', flag: '🇨🇳' }
]
}
}
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
</div> </div>
<div class="right-main"> <div class="right-main">
<div class="main-content"> <div class="main-content">
<div v-for="item in mainDataList" :key="item.id" class="main-item"> <div v-for="item in mainDataList" :key="item.id" class="main-item" @click="handleClick(item)">
<div class="date">{{ getDate(item) }}</div> <div class="date">{{ getDate(item) }}</div>
<img :src="item.ORGPICTURE" alt class="img" /> <img :src="item.ORGPICTURE" alt class="img" />
<div class="box"> <div class="box">
...@@ -117,7 +117,8 @@ ...@@ -117,7 +117,8 @@
</div> </div>
<div class="right-unshow"> <div class="right-unshow">
<div class="top"> <div class="top">
<div v-for="item in unionDataList" :key="item.id" class="top-item"> <div v-for="item in unionDataList" :key="item.id" class="top-item" @click="handleAllianceClick(item)">
<div class="title"> <div class="title">
<div class="img-list"> <div class="img-list">
<img class="img-style" :src="ele.COUNTRYIMAGE" v-for="ele in item.countries" alt /> <img class="img-style" :src="ele.COUNTRYIMAGE" v-for="ele in item.countries" alt />
...@@ -186,6 +187,15 @@ const handleClick = item => { ...@@ -186,6 +187,15 @@ const handleClick = item => {
}); });
}; };
const handleAllianceClick = item => {
router.push({
path: "/ruleRestrictions/alliance",
query: {
id: item.ACTAID
}
});
};
const isShow = ref(true); const isShow = ref(true);
const navList = ref(["规则限制政令", "排华科技联盟"]); const navList = ref(["规则限制政令", "排华科技联盟"]);
const activeItem = ref("规则限制政令"); const activeItem = ref("规则限制政令");
...@@ -632,12 +642,14 @@ const handlePageChangeACTA = p => { ...@@ -632,12 +642,14 @@ const handlePageChangeACTA = p => {
display: flex; display: flex;
.left { .left {
width: 300px; width: 300px;
height: 429px; height: 480px;
margin-right: 16px; margin-right: 16px;
border-radius: 10px; border-radius: 10px;
background-color: #fff; background-color: #fff;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
position: relative; position: relative;
padding: 16px 0 24px 0;
box-sizing: border-box;
.left-ti1 { .left-ti1 {
width: 8px; width: 8px;
height: 16px; height: 16px;
...@@ -669,60 +681,67 @@ const handlePageChangeACTA = p => { ...@@ -669,60 +681,67 @@ const handlePageChangeACTA = p => {
} }
.left-content { .left-content {
width: 253px; width: 253px;
// height: 132px;
height: auto; height: auto;
margin-left: 25px; margin-left: 25px;
margin-top: 13px; margin-top: 13px;
display: flex; display: flex;
flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px 4px;
align-content: flex-start;
.el-checkbox { :deep(.el-checkbox) {
width: 50%; width: calc(50% - 2px);
margin-right: 0; margin-right: 0;
margin-bottom: 4px; margin-bottom: 0;
font-size: 16px; display: flex;
font-weight: 400; align-items: center;
font-family: "Microsoft YaHei"; gap: 8px;
line-height: 24px; flex-shrink: 0;
color: rgb(95, 101, 108); height: auto;
} .el-checkbox__input {
.left-item { .el-checkbox__inner {
width: 120px;
height: 30px;
margin-bottom: 4px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(95, 101, 108);
input[type="checkbox"] {
-webkit-appearance: none;
appearance: none;
width: 14px; width: 14px;
height: 14px; height: 14px;
margin-right: 8px; border: 1px solid rgba(230, 231, 232, 1);
border: 1px solid rgb(200, 204, 210);
border-radius: 4px; border-radius: 4px;
background-color: #fff; background: #fff;
vertical-align: middle; box-sizing: border-box;
&::after {
display: none;
} }
input[type="checkbox"]:checked {
background-color: rgb(5, 95, 194);
border-color: rgb(5, 95, 194);
} }
input[type="checkbox"]:checked::after { &.is-checked .el-checkbox__inner {
content: ""; background-color: #055FC2;
border-color: #055FC2;
&::after {
display: block; display: block;
content: "";
width: 4px; width: 4px;
height: 8px; height: 8px;
margin: 1px auto 0; left: 4px;
border: 2px solid #fff; top: 1px;
border: 1.5px solid #fff;
border-top: none; border-top: none;
border-left: none; border-left: none;
transform: rotate(45deg); transform: rotate(45deg);
} }
} }
} }
.el-checkbox__label {
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgba(95, 101, 108, 1);
white-space: nowrap;
padding-left: 0;
}
&.is-checked .el-checkbox__label {
color: rgba(95, 101, 108, 1);
}
}
}
.cl1 { .cl1 {
margin-top: 21px; margin-top: 21px;
} }
...@@ -936,12 +955,14 @@ const handlePageChangeACTA = p => { ...@@ -936,12 +955,14 @@ const handlePageChangeACTA = p => {
} }
.left-unshow { .left-unshow {
width: 300px; width: 300px;
height: 654px; height: 750px;
margin-right: 16px; margin-right: 16px;
border-radius: 10px; border-radius: 10px;
background-color: #fff; background-color: #fff;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
position: relative; position: relative;
padding: 16px 0 24px 0;
box-sizing: border-box;
.left-ti1 { .left-ti1 {
width: 8px; width: 8px;
height: 16px; height: 16px;
...@@ -983,48 +1004,66 @@ const handlePageChangeACTA = p => { ...@@ -983,48 +1004,66 @@ const handlePageChangeACTA = p => {
} }
.left-content { .left-content {
width: 253px; width: 253px;
// height: 132px;
margin-left: 25px; margin-left: 25px;
margin-top: 13px; margin-top: 13px;
display: flex; display: flex;
flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
.left-item { gap: 8px 4px;
width: 120px; align-content: flex-start;
height: 30px;
margin-bottom: 4px; :deep(.el-checkbox) {
font-size: 16px; width: calc(50% - 2px);
font-weight: 400; margin-right: 0;
font-family: "Microsoft YaHei"; margin-bottom: 0;
line-height: 24px; display: flex;
color: rgb(95, 101, 108); align-items: center;
input[type="checkbox"] { gap: 8px;
-webkit-appearance: none; flex-shrink: 0;
appearance: none; height: auto;
.el-checkbox__input {
.el-checkbox__inner {
width: 14px; width: 14px;
height: 14px; height: 14px;
margin-right: 8px; border: 1px solid rgba(230, 231, 232, 1);
border: 1px solid rgb(200, 204, 210);
border-radius: 4px; border-radius: 4px;
background-color: #fff; background: #fff;
vertical-align: middle; box-sizing: border-box;
&::after {
display: none;
} }
input[type="checkbox"]:checked {
background-color: rgb(5, 95, 194);
border-color: rgb(5, 95, 194);
} }
input[type="checkbox"]:checked::after { &.is-checked .el-checkbox__inner {
content: ""; background-color: #055FC2;
border-color: #055FC2;
&::after {
display: block; display: block;
content: "";
width: 4px; width: 4px;
height: 8px; height: 8px;
margin: 1px auto 0; left: 4px;
border: 2px solid #fff; top: 1px;
border: 1.5px solid #fff;
border-top: none; border-top: none;
border-left: none; border-left: none;
transform: rotate(45deg); transform: rotate(45deg);
} }
} }
} }
.el-checkbox__label {
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgba(95, 101, 108, 1);
white-space: nowrap;
padding-left: 0;
}
&.is-checked .el-checkbox__label {
color: rgba(95, 101, 108, 1);
}
}
}
.cl1 { .cl1 {
margin-top: 21px; margin-top: 21px;
} }
...@@ -1050,6 +1089,7 @@ const handlePageChangeACTA = p => { ...@@ -1050,6 +1089,7 @@ const handlePageChangeACTA = p => {
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
padding: 18px 33px 18px 26px; padding: 18px 33px 18px 26px;
cursor: pointer;
.title { .title {
width: 574px; width: 574px;
height: 72px; height: 72px;
......
...@@ -12,28 +12,18 @@ ...@@ -12,28 +12,18 @@
<img :src="item.avatar" alt="" class="source-library-avatar" /> <img :src="item.avatar" alt="" class="source-library-avatar" />
</div> </div>
<div class="source-library-text-content"> <div class="source-library-text-content">
<div style="width: 240px; height: 120px; display: flex; flex-direction: column"> <div class="card-main" :class="{ 'no-title': !item.title }">
<h3 class="source-library-name">{{ item.name }}</h3> <h3 class="source-library-name">{{ item.name }}</h3>
<p class="source-library-title">{{ item.title }}</p> <p class="source-library-title" v-if="item.title">{{ item.title }}</p>
<div class="taglist"> <div class="taglist">
<p <AreaTag
class="source-library-tag"
v-for="(value, index) in item.tag" v-for="(value, index) in item.tag"
:key="index" :key="index"
:class="{ :tagName="value.typeName"
tag1: value.typeId === '001', />
tag2: value.typeId === '002',
tag3: value.typeId === '003',
tag4: value.typeId === '004',
tag5: value.typeId === '005',
tag6: value.typeId === '006'
}"
>
{{ value.typeName }}
</p>
</div>
</div> </div>
</div> </div>
</div>
</div> </div>
</div> </div>
<div class="page"> <div class="page">
...@@ -57,7 +47,7 @@ import { ref, onMounted, watch } from "vue"; ...@@ -57,7 +47,7 @@ import { ref, onMounted, watch } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import DefaultIcon1 from "@/assets/icons/default-icon1.png"; import DefaultIcon1 from "@/assets/icons/default-icon1.png";
import DefaultIcon2 from "@/assets/icons/default-icon2.png"; import DefaultIcon2 from "@/assets/icons/default-icon2.png";
import AreaTag from '@/components/base/AreaTag/index.vue'
import { getPersonResource, getPersonSummaryInfo } from "@/api/technologyFigures/technologyFigures"; import { getPersonResource, getPersonSummaryInfo } from "@/api/technologyFigures/technologyFigures";
const props = defineProps({ const props = defineProps({
...@@ -298,6 +288,7 @@ const handlePageChange = p => { ...@@ -298,6 +288,7 @@ const handlePageChange = p => {
gap: 10px; gap: 10px;
margin-top: auto; margin-top: auto;
margin-bottom: 0px; margin-bottom: 0px;
flex-wrap: wrap;
} }
.source-library-tag { .source-library-tag {
...@@ -424,4 +415,27 @@ const handlePageChange = p => { ...@@ -424,4 +415,27 @@ const handlePageChange = p => {
border-color: rgb(235, 238, 242); border-color: rgb(235, 238, 242);
background-color: #fff; background-color: #fff;
} }
.card-main {
width: 240px;
min-height: 120px; /* 原来固定 height 改为 min-height */
display: flex;
flex-direction: column;
}
.source-library-title {
margin: 11px 0 0 0;
}
.taglist {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin-top: auto;
margin-bottom: 0;
}
/* title 为空时,让标签更靠上 */
.card-main.no-title .taglist {
margin-top: 10px; /* 不再 auto 顶到底部 */
}
</style> </style>
\ No newline at end of file
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="box5-main" ><WordCloudChart v-if="WordLoading" :data="CharacterOpinionWordCloud" /></div> <div class="box5-main" ><WordCloudChart width="790px" v-if="WordLoading" :data="CharacterOpinionWordCloud" /></div>
</div> </div>
<div class="box6"> <div class="box6">
<div class="box6-header" style="width: 790px"> <div class="box6-header" style="width: 790px">
...@@ -1817,7 +1817,7 @@ onMounted(async () => { ...@@ -1817,7 +1817,7 @@ onMounted(async () => {
background: rgba(20, 89, 187, 0); background: rgba(20, 89, 187, 0);
margin-right: 20px; margin-right: 20px;
cursor: pointer; cursor: pointer;
white-space: nowrap;
&:hover { &:hover {
background: rgba(20, 89, 187, 0.1); background: rgba(20, 89, 187, 0.1);
} }
......
...@@ -12,7 +12,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3, dataY4, dataY5, dataY6 ...@@ -12,7 +12,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3, dataY4, dataY5, dataY6
} }
}, },
grid: { grid: {
top: "15px", top: "50px",
right: "50px", right: "50px",
bottom: "0px", bottom: "0px",
left: "40px", left: "40px",
...@@ -21,6 +21,8 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3, dataY4, dataY5, dataY6 ...@@ -21,6 +21,8 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3, dataY4, dataY5, dataY6
legend: { legend: {
data: ["人工智能", "集成电路", "量子科技", "生物科技", "通信网络", "能源"], data: ["人工智能", "集成电路", "量子科技", "生物科技", "通信网络", "能源"],
show: true, show: true,
top: "0px",
left: "center",
textStyle: { textStyle: {
color: "rgba(95, 101, 108, 1)", color: "rgba(95, 101, 108, 1)",
fontFamily: "Microsoft YaHei", fontFamily: "Microsoft YaHei",
......
<template> <template>
<!-- 调查项目:与智库报告相同的「全部」互斥逻辑 -->
<div class="home-main-footer-main"> <div class="home-main-footer-main">
<div class="left"> <div class="left">
<div class="select-box"> <div class="select-box">
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论