提交 e2656fcf authored 作者: 朱政's avatar 朱政

feat:完善智库主页部分样式,增加报告分析部分分页功能以及点击打开详情图片跳转报告原文功能

上级 2759ede8
...@@ -222,9 +222,14 @@ export function getThinkTankReportAbstract(params) { ...@@ -222,9 +222,14 @@ export function getThinkTankReportAbstract(params) {
//获取报告主要观点 //获取报告主要观点
export function getThinkTankReportContent(params) { export function getThinkTankReportContent(params) {
const { id, currentPage, pageSize } = params
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/thinkTankReport/content/${params}`, url: `/api/thinkTankReport/content/${id}`,
params: {
currentPage,
pageSize,
}
}) })
} }
......
...@@ -67,7 +67,7 @@ const handleCollect = () => { ...@@ -67,7 +67,7 @@ const handleCollect = () => {
} }
const emit = defineEmits(['save','download','collect']) const emit = defineEmits(['save', 'download', 'collect'])
</script> </script>
......
...@@ -95,6 +95,7 @@ const handleGetThinkTankReportSummary = async () => { ...@@ -95,6 +95,7 @@ const handleGetThinkTankReportSummary = async () => {
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
reportUrl.value = res.data.reportUrl; reportUrl.value = res.data.reportUrl;
thinkInfo.value = res.data; thinkInfo.value = res.data;
console.log(reportUrl.value, 'reportUrl.value')
} }
} catch (error) { } catch (error) {
console.error("获取报告全局信息error", error); console.error("获取报告全局信息error", error);
......
...@@ -57,43 +57,35 @@ ...@@ -57,43 +57,35 @@
</div> </div>
<div class="center"> <div class="center">
<div class="title">{{ item.content }}</div> <div class="title">{{ item.content }}</div>
<div>
<img src="../images/image-open.png" alt="" class="center-image"
@click="handleOpenReportOriginal(item)">
</div>
<!-- <div class="desc">{{ item.econtent }}</div> --> <!-- <div class="desc">{{ item.econtent }}</div> -->
</div> </div>
<div class="right"> <!-- <div class="right"> -->
<!-- <div class="tag" v-for="(val, idx) in item.hylyList" :key="idx"> <!-- <div class="tag" v-for="(val, idx) in item.hylyList" :key="idx">
{{ val }} {{ val }}
</div> </div>
<div class="tag" v-for="(val, idx) in item.serialNum" :key="idx"> <div class="tag" v-for="(val, idx) in item.serialNum" :key="idx">
{{ val }} {{ val }}
</div> --> </div> -->
<AreaTag v-for="(val, idx) in item.hylyList" :key="idx" :tagName="val"></AreaTag> <!-- <AreaTag v-for="(val, idx) in item.hylyList" :key="idx" :tagName="val"></AreaTag>
</div> </div> -->
<!-- <div class="more"> <!-- <div class="more">
<img src="@/assets/icons/open.png" alt="" /> <img src="@/assets/icons/open.png" alt="" />
</div> --> </div> -->
</div> </div>
</div> </div>
<div class="box3-main-footer"> <div class="box3-main-footer">
<div class="info"> {{ total }}</div> <div class="info">{{ total }}条核心论点</div>
<div class="page-box"> <div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total" <el-pagination :page-size="10" background layout="prev, pager, next" :total="total"
@current-change="handleCurrentChange" :current-page="currentPage" /> @current-change="handleCurrentChange" :current-page="currentPage" />
</div> </div>
</div> </div>
</div> </div>
<div class="box3-footer">
<div class="footer-left">
<img src="@/assets/icons/box-footer-left-icon.png" alt="" />
</div>
<div class="footer-center">
{{
`中美经济深度交织,全面脱钩成本高昂且不现实。其核心揭示了三大纽带:生产网络相互依存使强行分离代价巨大;人才双向流动推动创新却成政策博弈焦点;能源领域合作与竞争并存,关乎全球气候治理与经济博弈。报告主张理性竞合,在竞争中找到合作路径。`
}}
</div>
<div class="footer-right">
<img src="@/assets/icons/box-footer-right-icon.png" alt="" />
</div>
</div>
</AnalysisBox> </AnalysisBox>
</div> </div>
</div> </div>
...@@ -240,22 +232,49 @@ const majorOpinions = ref([ ...@@ -240,22 +232,49 @@ const majorOpinions = ref([
] ]
} }
]); ]);
//处理点击详情页事件
const handleOpenReportOriginal = item => {
const route = router.resolve({
name: "ReportOriginal",
params: {
id: router.currentRoute._value.params.id
},
query: {
currentPage: currentPage.value,
pageSize: pageSize.value,
opinionId: item?.id ?? "",
opinionContent: item?.content ?? ""
}
});
window.open(route.href, "_blank");
};
const tabActiveName = ref("报告分析");
const switchTab = name => {
tabActiveName.value = name;
}
// 处理页码改变事件 // 处理页码改变事件
const currentPage = ref(1); const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0) const total = ref(0)
const handleCurrentChange = page => { const handleCurrentChange = page => {
currentPage.value = page; currentPage.value = page;
handleGetThinkDynamicsReport(); handleGetThinkTankReportContent();
}; };
//获取报告主要观点 //获取报告主要观点
const handleGetThinkTankReportContent = async () => { const handleGetThinkTankReportContent = async () => {
try { try {
const res = await getThinkTankReportContent(router.currentRoute._value.params.id); const params = {
id: router.currentRoute._value.params.id,
currentPage: currentPage.value - 1,
pageSize: pageSize.value,
};
const res = await getThinkTankReportContent(params);
console.log("主要观点", res.data); console.log("主要观点", res.data);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
majorOpinions.value = res.data.content; majorOpinions.value = res.data.content || [];
handleGetBox3AnalysisContent(majorOpinions.value) handleGetBox3AnalysisContent(majorOpinions.value)
total.value = res.data.totalElements total.value = res.data.totalElements || 0
} }
} catch (error) { } catch (error) {
console.error("获取主要观点error", error); console.error("获取主要观点error", error);
...@@ -489,7 +508,7 @@ onMounted(() => { ...@@ -489,7 +508,7 @@ onMounted(() => {
.box3 { .box3 {
width: 1103px; width: 1103px;
height: 946px; height: 965px;
// border: 1px solid rgba(234, 236, 238, 1); // border: 1px solid rgba(234, 236, 238, 1);
// 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);
...@@ -498,11 +517,11 @@ onMounted(() => { ...@@ -498,11 +517,11 @@ onMounted(() => {
.box3-main { .box3-main {
width: 1057px; width: 1057px;
height: 800px;
margin: 0 auto; margin: 0 auto;
.box3-main-main { .box3-main-main {
height: 720px; height: 767px;
overflow: hidden; overflow: hidden;
.box3-item { .box3-item {
...@@ -541,6 +560,7 @@ onMounted(() => { ...@@ -541,6 +560,7 @@ onMounted(() => {
.title { .title {
margin-top: 12px; margin-top: 12px;
width: 918px;
// height: 55px; // height: 55px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -556,6 +576,16 @@ onMounted(() => { ...@@ -556,6 +576,16 @@ onMounted(() => {
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
}
.center-image {
width: 16px;
height: 24px;
margin-top: 12px;
margin-left: 18px;
} }
.desc { .desc {
......
...@@ -168,7 +168,12 @@ ...@@ -168,7 +168,12 @@
<div class="item-right"> <div class="item-right">
<div> <div>
<div class="title">{{ item.content }}</div> <div class="title">{{ item.content }}</div>
<div class="info">{{ item.times }} · {{ item.name }}</div> <div class="info">
{{ item.times }} · {{ item.name }}
<div class="more" @click="toDetail(item)">
<img src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image open.png" alt="" />
</div>
</div>
<div class="tag-box"> <div class="tag-box">
<AreaTag v-for="(tag, idx) in item.tagList" :key="idx" :tagName="tag"></AreaTag> <AreaTag v-for="(tag, idx) in item.tagList" :key="idx" :tagName="tag"></AreaTag>
</div> </div>
...@@ -190,15 +195,13 @@ ...@@ -190,15 +195,13 @@
</div> </div>
</div> </div>
<div> <div>
<div class="more" @click="toDetail(item)">
<img src="@/assets/icons/open.png" alt="" />
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="right-footer"> <div class="right-footer">
<div class="info"> {{ total }} 项</div> <div class="info">{{ total }}条政策建议</div>
<div class="page-box"> <div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total" <el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="handleCurrentChange" :current-page="currentPage" /> @current-change="handleCurrentChange" :current-page="currentPage" />
...@@ -269,7 +272,8 @@ const box1Data = ref([ ...@@ -269,7 +272,8 @@ const box1Data = ref([
// color: "#D6E4FF" // color: "#D6E4FF"
// } // }
]); ]);
const relationBillsList = ref([{ billName: "2025《人工智能安全与评估法案》" }])
const relationAdList = ref([{ adName: "2025《人工智能安全与评估法案》" }])
const box1SelectYear = ref("2025"); const box1SelectYear = ref("2025");
const box1YearList = ref([ const box1YearList = ref([
{ {
...@@ -627,7 +631,12 @@ const handleGetThinkPolicy = async () => { ...@@ -627,7 +631,12 @@ const handleGetThinkPolicy = async () => {
const res = await getThinkPolicy(parmas); const res = await getThinkPolicy(parmas);
console.log("智库政策", res); console.log("智库政策", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
policyList.value = res.data.content; policyList.value = res.data.content.map(item => ({
...item,
relationBillsList: relationBillsList.value,
relationAdList: relationAdList.value
}));
total.value = res.data.totalElements; total.value = res.data.totalElements;
} }
} catch (error) { } catch (error) {
...@@ -663,6 +672,7 @@ onMounted(() => { ...@@ -663,6 +672,7 @@ onMounted(() => {
margin: 16px 0; margin: 16px 0;
display: flex; display: flex;
gap: 16px; gap: 16px;
.box { .box {
width: 520px; width: 520px;
height: 420px; height: 420px;
...@@ -1170,21 +1180,30 @@ onMounted(() => { ...@@ -1170,21 +1180,30 @@ onMounted(() => {
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
.right-main { .right-main {
margin: 17px auto; margin-top: 17px;
width: 1209px; margin-left: 0;
width: 100%;
box-sizing: border-box;
padding-left: 37px;
padding-right: 0;
max-height: 1540px; max-height: 1540px;
.right-main-item { .right-main-item {
// height: 154px; // height: 154px;
box-sizing: border-box; box-sizing: border-box;
padding-top: 8px; padding-top: 16px;
padding-bottom: 16px;
margin-left: -37px;
padding-left: 37px;
padding-right: 36px;
width: calc(100% + 37px - 36px);
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
display: flex; display: flex;
.item-left { .item-left {
width: 57px; width: 57px;
height: 77px; height: 77px;
margin-top: 3px;
img { img {
width: 100%; width: 100%;
...@@ -1201,7 +1220,7 @@ onMounted(() => { ...@@ -1201,7 +1220,7 @@ onMounted(() => {
.title { .title {
// height: 24px; // height: 24px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 18px; font-size: 18px;
font-weight: 700; font-weight: 700;
line-height: 24px; line-height: 24px;
...@@ -1213,12 +1232,25 @@ onMounted(() => { ...@@ -1213,12 +1232,25 @@ onMounted(() => {
margin-top: 7px; margin-top: 7px;
height: 22px; height: 22px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 22px; line-height: 22px;
letter-spacing: 0px; letter-spacing: 0px;
text-align: left; text-align: left;
display: flex;
.more {
width: 16px;
height: 16px;
margin-top: 3px;
margin-left: 9px;
img {
width: 100%;
height: 100%;
}
}
} }
.tag-box { .tag-box {
...@@ -1248,30 +1280,30 @@ onMounted(() => { ...@@ -1248,30 +1280,30 @@ onMounted(() => {
.file { .file {
height: 32px; height: 32px;
padding: 0 8px; padding: 4px 8px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 8px; gap: 12px;
border-radius: 4px; border-radius: 4px;
background: rgba(246, 250, 255, 1); background: rgba(246, 250, 255, 1);
.type { .type {
height: 22px; height: 22px;
margin-top: 1px;
padding: 0 4px; padding: 0 4px;
border-radius: 4px; border-radius: 4px;
background: rgba(231, 243, 255, 1); background: rgba(231, 243, 255, 1);
color: rgba(5, 95, 194, 1); color: rgba(5, 95, 194, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 22px; line-height: 22px;
} }
.title { .title {
height: 24px;
color: rgba(5, 95, 194, 1); color: rgba(5, 95, 194, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
...@@ -1280,12 +1312,16 @@ onMounted(() => { ...@@ -1280,12 +1312,16 @@ onMounted(() => {
.more { .more {
width: 20px; width: 20px;
height: 20px; height: 20px;
display: flex;
margin-top: 2px;
img { .img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
} }
} }
} }
...@@ -1293,21 +1329,32 @@ onMounted(() => { ...@@ -1293,21 +1329,32 @@ onMounted(() => {
} }
.right-footer { .right-footer {
margin: 0 auto;
width: 1209px; height: 86px;
height: 96px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-top: 17px;
.info { .info {
margin-top: 29px;
margin-left: 39px;
color: rgba(132, 136, 142, 1); color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 14px; font-size: 14px;
height: 19px;
font-weight: 400; font-weight: 400;
line-height: 18px; line-height: 18px;
letter-spacing: 0px; letter-spacing: 0px;
text-align: left; text-align: left;
} }
.page-box {
margin-top: 23px;
margin-right: 36px;
height: 32px;
}
} }
} }
} }
...@@ -1319,4 +1366,22 @@ onMounted(() => { ...@@ -1319,4 +1366,22 @@ onMounted(() => {
height: 8px !important; height: 8px !important;
margin-right: 4px; margin-right: 4px;
} }
/* PolicyTracking 分页按钮样式:1px 描边 + 白底 + 6px 圆角 */
:deep(.right-footer .el-pagination.is-background .btn-prev),
:deep(.right-footer .el-pagination.is-background .btn-next),
:deep(.right-footer .el-pagination.is-background .el-pager li) {
border: 1px solid rgba(0, 0, 0, 0.15) !important;
background-color: rgba(255, 255, 255, 1) !important;
border-radius: 6px !important;
box-sizing: border-box;
}
// 选中状态的页码样式(描边+文字颜色改为指定蓝色)
:deep(.right-footer .el-pagination.is-background .el-pager li.is-active) {
border-color: rgba(22, 119, 255, 1) !important; // 选中后描边颜色
color: rgba(22, 119, 255, 1) !important; // 选中后页码文字颜色
background-color: rgba(255, 255, 255, 1) !important; // 保持白色背景
font-weight: 400;
}
</style> </style>
\ No newline at end of file
...@@ -22,9 +22,12 @@ ...@@ -22,9 +22,12 @@
</div> </div>
<div class="select-main"> <div class="select-main">
<div class="checkbox-group"> <div class="checkbox-group">
<el-checkbox label="全部领域"></el-checkbox> <el-checkbox class="filter-checkbox" :model-value="isGroupAllSelected(researchTypeIds)"
<el-checkbox v-for="type in researchTypeList" :key="type.id" v-model="selectedResearchTypeList" @change="val => handleToggleAll(val, researchTypeIds)">
:label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()"> 全部领域
</el-checkbox>
<el-checkbox v-for="type in researchTypeList" :key="type.id" v-model="selectedResearchIds" :label="type.id"
class="filter-checkbox" @change="handleGetThinkDynamicsReport()">
{{ type.name }} {{ type.name }}
</el-checkbox> </el-checkbox>
</div> </div>
...@@ -37,8 +40,11 @@ ...@@ -37,8 +40,11 @@
</div> </div>
<div class="select-main"> <div class="select-main">
<div class="checkbox-group"> <div class="checkbox-group">
<el-checkbox label="全部时间"></el-checkbox> <el-checkbox class="filter-checkbox" :model-value="isGroupAllSelected(researchTimeIds)"
<el-checkbox v-for="type in researchTimeList" :key="type.id" v-model="selectedResearchTypeList" @change="val => handleToggleAll(val, researchTimeIds)">
全部时间
</el-checkbox>
<el-checkbox v-for="type in researchTimeList" :key="type.id" v-model="selectedResearchTimeIds"
:label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()"> :label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()">
{{ type.name }} {{ type.name }}
</el-checkbox> </el-checkbox>
...@@ -55,8 +61,11 @@ ...@@ -55,8 +61,11 @@
</div> </div>
<div class="select-main"> <div class="select-main">
<div class="checkbox-group"> <div class="checkbox-group">
<el-checkbox label="全部部门"></el-checkbox> <el-checkbox class="filter-checkbox" :model-value="isGroupAllSelected(researchHearingIds)"
<el-checkbox v-for="type in researchHearingList" :key="type.id" v-model="selectedResearchTypeList" @change="val => handleToggleAll(val, researchHearingIds)">
全部部门
</el-checkbox>
<el-checkbox v-for="type in researchHearingList" :key="type.id" v-model="selectedResearchHearingIds"
:label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()"> :label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()">
{{ type.name }} {{ type.name }}
</el-checkbox> </el-checkbox>
...@@ -92,10 +101,10 @@ ...@@ -92,10 +101,10 @@
</div> </div>
<div class="right-footer"> <div class="right-footer">
<div class="info"> <div class="info">
{{ hearingData.length }} {{ filteredHearingData.length }} 篇智库报告
</div> </div>
<div class="page-box"> <div class="page-box">
<el-pagination :page-size="10" background layout="prev, pager, next" :total="hearingData.length" <el-pagination :page-size="10" background layout="prev, pager, next" :total="filteredHearingData.length"
@current-change="handleCurrentChange" :current-page="currentPage" /> @current-change="handleCurrentChange" :current-page="currentPage" />
</div> </div>
</div> </div>
...@@ -122,9 +131,17 @@ const props = defineProps({ ...@@ -122,9 +131,17 @@ const props = defineProps({
type: Array, type: Array,
default: () => [] default: () => []
}, },
selectedResearchTypeList: { selectedFilters: {
type: Array, type: Object,
default: () => [] default: () => ({
researchTypeIds: [],
researchTimeIds: [],
researchHearingIds: []
})
},
selectedYear: {
type: Number,
default: 1
}, },
curFooterList: { curFooterList: {
type: Array, type: Array,
...@@ -141,48 +158,108 @@ const props = defineProps({ ...@@ -141,48 +158,108 @@ const props = defineProps({
}); });
const emit = defineEmits([ const emit = defineEmits([
"update:selectedResearchTypeList", "update:selectedFilters",
"filter-change", "filter-change",
"page-change", "page-change",
"report-click" "report-click"
]); ]);
// 解构 props,保持模板里变量名不变 // 解构 props,保持模板里变量名不变
const { researchTypeList, researchTimeList, curFooterList, total, currentPage, researchHearingList, hearingData } = toRefs(props); const { researchTypeList, researchTimeList, curFooterList, total, currentPage, researchHearingList, hearingData, selectedYear } = toRefs(props);
const pageSize = 10; const pageSize = 10;
// 只展示当前页的 12 条,否则会一页显示全部 20 条 function getDateYearsAgo(years) {
const displayList = computed(() => { const currentDate = new Date();
const list = hearingData.value || []; return new Date(currentDate.getFullYear() - years, currentDate.getMonth(), currentDate.getDate());
const start = (currentPage.value - 1) * pageSize; }
return list.slice(start, start + pageSize);
}); function parseChineseDate(dateStr) {
if (!dateStr) return null;
const match = String(dateStr).match(/(\d{4})(\d{1,2})(\d{1,2})日/);
if (!match) return null;
return new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
}
// 用本地 ref 替代 computed,el-checkbox 会直接修改数组,需要可变的 ref const selectedResearchIds = ref([]);
const selectedResearchTypeList = ref([...(props.selectedResearchTypeList || [])]); const selectedResearchTimeIds = ref([]);
const selectedResearchHearingIds = ref([]);
// 父组件更新时同步到子组件
watch( watch(
() => props.selectedResearchTypeList, () => props.selectedFilters,
val => { val => {
selectedResearchTypeList.value = val ? [...val] : []; selectedResearchIds.value = val?.researchTypeIds ? [...val.researchTypeIds] : [];
selectedResearchTimeIds.value = val?.researchTimeIds ? [...val.researchTimeIds] : [];
selectedResearchHearingIds.value = val?.researchHearingIds ? [...val.researchHearingIds] : [];
}, },
{ immediate: true, deep: true } { immediate: true, deep: true }
); );
// 子组件勾选变化时通知父组件,flush: 'sync' 确保在 @change 触发前父组件已更新,否则 filter-change 时父组件拿到的还是旧值 const buildSelectedFiltersPayload = () => ({
watch( researchTypeIds: [...selectedResearchIds.value],
selectedResearchTypeList, researchTimeIds: [...selectedResearchTimeIds.value],
val => { researchHearingIds: [...selectedResearchHearingIds.value]
emit("update:selectedResearchTypeList", val); });
},
{ deep: true, flush: "sync" } const researchTypeIds = computed(() => (researchTypeList.value || []).map(item => item.id));
); const researchTimeIds = computed(() => (researchTimeList.value || []).map(item => item.id));
const researchHearingIds = computed(() => (researchHearingList.value || []).map(item => item.id));
const getTargetSelection = ids => {
if (ids === researchTypeIds.value) return selectedResearchIds;
if (ids === researchTimeIds.value) return selectedResearchTimeIds;
return selectedResearchHearingIds;
};
const isGroupAllSelected = ids =>
ids.length > 0 && ids.every(id => getTargetSelection(ids).value.includes(id));
const handleToggleAll = (checked, ids) => {
if (!ids.length) return;
const targetSelection = getTargetSelection(ids);
const nextSelected = new Set(targetSelection.value);
if (checked) {
ids.forEach(id => nextSelected.add(id));
} else {
ids.forEach(id => nextSelected.delete(id));
}
targetSelection.value = [...nextSelected];
handleGetThinkDynamicsReport();
};
const filteredHearingData = computed(() => {
const rangeStart = getDateYearsAgo(selectedYear.value || 1);
return (hearingData.value || []).filter(item => {
const itemDate = parseChineseDate(item.time);
const matchTopRange = itemDate ? itemDate >= rangeStart : true;
const matchYear =
selectedResearchTimeIds.value.length === 0 ||
selectedResearchTimeIds.value.some(year => String(item.time || "").startsWith(year));
const matchDepartment =
selectedResearchHearingIds.value.length === 0 ||
selectedResearchHearingIds.value.some(department =>
String(item.content || "").includes(department) || String(item.title || "").includes(department)
);
const matchType =
selectedResearchIds.value.length === 0 ||
selectedResearchIds.value.some(typeId =>
String(item.category || "").includes(typeId) || String(item.title || "").includes(typeId)
);
return matchTopRange && matchYear && matchDepartment && matchType;
});
});
// 只展示当前页的数据
const displayList = computed(() => {
const list = filteredHearingData.value || [];
const start = (currentPage.value - 1) * pageSize;
return list.slice(start, start + pageSize);
});
// 保持模板里的方法名不变,但改成通知父组件,直接传入当前选中值避免时序问题 // 保持模板里的方法名不变,但改成通知父组件,直接传入当前选中值避免时序问题
const handleGetThinkDynamicsReport = () => { const handleGetThinkDynamicsReport = () => {
emit("update:selectedResearchTypeList", [...selectedResearchTypeList.value]); const payload = buildSelectedFiltersPayload();
emit("filter-change", [...selectedResearchTypeList.value]); emit("update:selectedFilters", payload);
emit("filter-change", payload);
}; };
const handleCurrentChange = page => { const handleCurrentChange = page => {
...@@ -214,7 +291,7 @@ const handleToReportDetail = item => { ...@@ -214,7 +291,7 @@ const handleToReportDetail = item => {
.select-research-box { .select-research-box {
width: 360px; width: 360px;
height: 284px; height: 284px;
margin-top: 21px; margin-top: 19px;
.select-box-header { .select-box-header {
display: flex; display: flex;
...@@ -243,31 +320,30 @@ const handleToReportDetail = item => { ...@@ -243,31 +320,30 @@ const handleToReportDetail = item => {
.select-main { .select-main {
margin-left: 25px; margin-left: 24px;
.checkbox-group { .checkbox-group {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 8px 4px;
.filter-checkbox {
width: 160px;
height: 24px;
} }
} }
.select-main1 {
width: 100px;
} }
.input-main {
margin: 10px auto;
width: 250px;
height: 34px;
border-radius: 10px;
border: 1px solid rgba(230, 231, 232, 1);
}
} }
.select-time-box { .select-time-box {
margin-top: 21px; margin-top: 44px;
width: 360px; width: 360px;
height: 156px; height: 156px;
...@@ -298,11 +374,18 @@ const handleToReportDetail = item => { ...@@ -298,11 +374,18 @@ const handleToReportDetail = item => {
.select-main { .select-main {
margin-left: 25px; margin-left: 24px;
.checkbox-group { .checkbox-group {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 8px 4px;
.filter-checkbox {
width: 160px;
height: 24px;
}
} }
...@@ -322,12 +405,13 @@ const handleToReportDetail = item => { ...@@ -322,12 +405,13 @@ const handleToReportDetail = item => {
} }
.select-hearing-box { .select-hearing-box {
margin-top: 21px; margin-top: 36px;
width: 360px; width: 360px;
.select-box-header { .select-box-header {
display: flex; display: flex;
gap: 17px; gap: 17px;
margin-bottom: 12px;
.icon { .icon {
margin-top: 4px; margin-top: 4px;
...@@ -350,13 +434,16 @@ const handleToReportDetail = item => { ...@@ -350,13 +434,16 @@ const handleToReportDetail = item => {
} }
.select-main { .select-main {
margin-left: 24px;
margin-left: 25px;
.checkbox-group { .checkbox-group {
display: grid; display: grid;
width: 259px;
gap: 4px;
.filter-checkbox {
height: 24px;
}
} }
...@@ -509,4 +596,13 @@ const handleToReportDetail = item => { ...@@ -509,4 +596,13 @@ const handleToReportDetail = item => {
} }
} }
} }
:deep(.el-checkbox) {
margin-right: 0 !important;
}
:deep(.el-checkbox__inner) {
border-radius: 4px !important;
}
</style> </style>
\ No newline at end of file
<template>
<div class="main-content">
<div class="left">
<!-- <div class="select-box">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">{{ "报告类型" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-for="type in reportTypeList" :key="type.id" v-model="selectedReportTypeList"
:label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()">
{{ type.typeName }}
</el-checkbox>
</div>
</div>
</div> -->
<div class="select-research-box">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">{{ "研究类型" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox class="filter-checkbox" :model-value="isGroupAllSelected(researchTypeIds)"
@change="val => handleToggleAll(val, researchTypeIds)">
全部领域
</el-checkbox>
<el-checkbox v-for="type in researchTypeList" :key="type.id" v-model="selectedResearchIds" :label="type.id"
class="filter-checkbox" @change="handleGetThinkDynamicsReport()">
{{ type.name }}
</el-checkbox>
</div>
</div>
</div>
<div class="select-time-box">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">{{ "发布时间" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox class="filter-checkbox" :model-value="isGroupAllSelected(researchTimeIds)"
@change="val => handleToggleAll(val, researchTimeIds)">
全部时间
</el-checkbox>
<el-checkbox v-for="type in researchTimeList" :key="type.id" v-model="selectedResearchTimeIds"
:label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()">
{{ type.name }}
</el-checkbox>
</div>
</div>
<!-- <div class="input-main">
<el-input placeholder="输入作者名字" v-model="author" @input="handleGetThinkDynamicsReport()" />
</div> -->
</div>
</div>
<div class="right">
<div class="card-box">
<div class="footer-card" v-for="(item, index) in curFooterList" :key="index"
@click="handleToReportDetail(item)">
<div class="footer-card-top">
<img :src="item.imageUrl" alt="" />
</div>
<div class="footer-card-title">
{{ item.name }}
</div>
<div class="footer-card-footer">
<div class="time">{{ item.times }}</div>
<div class="from">{{ item.thinkTankName }}</div>
</div>
</div>
</div>
<div class="right-footer">
<div class="info">
{{ total }} 篇智库报告
</div>
<div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="handleCurrentChange" :current-page="currentPage" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed, ref, toRefs, watch } from "vue";
const props = defineProps({
researchTypeList: {
type: Array,
default: () => []
},
researchTimeList: {
type: Array,
default: () => []
},
selectedFilters: {
type: Object,
default: () => ({
researchTypeIds: [],
researchTimeIds: [],
researchHearingIds: []
})
},
curFooterList: {
type: Array,
default: () => []
},
total: {
type: Number,
default: 0
},
currentPage: {
type: Number,
default: 1
}
});
const emit = defineEmits([
"update:selectedFilters",
"filter-change",
"page-change",
"report-click"
]);
// 解构 props,保持模板里变量名不变
const { researchTypeList, researchTimeList, curFooterList, total, currentPage } = toRefs(props);
const selectedResearchIds = ref([]);
const selectedResearchTimeIds = ref([]);
// 父组件更新时同步到子组件
watch(
() => props.selectedFilters,
val => {
selectedResearchIds.value = val?.researchTypeIds ? [...val.researchTypeIds] : [];
selectedResearchTimeIds.value = val?.researchTimeIds ? [...val.researchTimeIds] : [];
},
{ immediate: true, deep: true }
);
const buildSelectedFiltersPayload = () => ({
researchTypeIds: [...selectedResearchIds.value],
researchTimeIds: [...selectedResearchTimeIds.value],
researchHearingIds: []
});
const researchTypeIds = computed(() => (researchTypeList.value || []).map(item => item.id));
const researchTimeIds = computed(() => (researchTimeList.value || []).map(item => item.id));
const getTargetSelection = ids => (ids === researchTypeIds.value ? selectedResearchIds : selectedResearchTimeIds);
const isGroupAllSelected = ids =>
ids.length > 0 && ids.every(id => getTargetSelection(ids).value.includes(id));
const handleToggleAll = (checked, ids) => {
if (!ids.length) return;
const targetSelection = getTargetSelection(ids);
const nextSelected = new Set(targetSelection.value);
if (checked) {
ids.forEach(id => nextSelected.add(id));
} else {
ids.forEach(id => nextSelected.delete(id));
}
targetSelection.value = [...nextSelected];
handleGetThinkDynamicsReport();
};
// 保持模板里的方法名不变,但改成通知父组件,直接传入当前选中值避免时序问题
const handleGetThinkDynamicsReport = () => {
const payload = buildSelectedFiltersPayload();
emit("update:selectedFilters", payload);
emit("filter-change", payload);
};
const handleCurrentChange = page => {
emit("page-change", page);
};
const handleToReportDetail = item => {
emit("report-click", item);
};
</script>
<style lang="scss" scoped>
.main-content {
display: flex;
gap: 16px;
.left {
width: 360px;
height: 541px;
padding-bottom: 36px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(94, 95, 95, 0.1);
background: rgba(255, 255, 255, 1);
position: relative;
.select-research-box {
width: 360px;
height: 284px;
margin-top: 19px;
.select-box-header {
display: flex;
gap: 17px;
margin-bottom: 12px;
.icon {
margin-top: 4px;
width: 8px;
height: 16px;
background: var(--color-main-active);
border-radius: 0 4px 4px 0;
}
.title {
height: 26px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 20px;
font-weight: 700;
line-height: 26px;
letter-spacing: 1px;
text-align: left;
}
}
.select-main {
margin-left: 24px;
.checkbox-group {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px 4px;
.filter-checkbox {
width: 160px;
height: 24px;
}
}
}
.select-main1 {
width: 100px;
}
.input-main {
margin: 10px auto;
width: 250px;
height: 34px;
border-radius: 10px;
border: 1px solid rgba(230, 231, 232, 1);
}
}
.select-time-box {
margin-top: 44px;
width: 360px;
height: 156px;
.select-box-header {
display: flex;
gap: 17px;
margin-bottom: 12px;
.icon {
margin-top: 4px;
width: 8px;
height: 16px;
background: var(--color-main-active);
border-radius: 0 4px 4px 0;
}
.title {
height: 26px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 20px;
font-weight: 700;
line-height: 26px;
letter-spacing: 1px;
text-align: left;
}
}
.select-main {
margin-left: 24px;
.checkbox-group {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px 4px;
.filter-checkbox {
width: 160px;
height: 24px;
}
}
}
.select-main1 {
width: 100px;
}
.input-main {
margin: 10px auto;
width: 250px;
height: 34px;
border-radius: 10px;
border: 1px solid rgba(230, 231, 232, 1);
}
}
}
.right {
width: 1284px;
height: 1377px;
.card-box {
width: 1226px;
height: 1248px;
display: flex;
flex-wrap: wrap;
gap: 13px;
.footer-card {
width: 398px;
height: 300px;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
position: relative;
&:hover {
transform: translateY(-3px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
cursor: pointer;
.footer-card-top {
width: 364px;
height: 180px;
margin: 0 auto;
margin-top: 15px;
position: relative;
img {
width: 100%;
height: 100%;
}
}
.footer-card-title {
margin: 0 auto;
margin-top: 12px;
width: 360px;
color: rgb(59, 65, 75);
font-family: "Source Han Sans CN";
font-size: 18px;
font-weight: 700;
line-height: 24px;
// 多行省略 + 自动换行(兼容写法)
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box; // webkit 私有:开启弹性盒模型
display: box; // 标准写法(兜底)
-webkit-line-clamp: 2; // webkit 私有:限制行数
line-clamp: 2; // 标准属性:解决兼容性提示
-webkit-box-orient: vertical; // webkit 私有:垂直排列
box-orient: vertical; // 标准写法(兜底)
// 基础换行属性(确保文字能换行)
word-wrap: break-word;
word-break: break-all;
white-space: normal;
}
.footer-card-footer {
position: absolute;
left: 50%;
bottom: 15px;
transform: translateX(-50%);
margin: 0;
width: 360px;
height: 22px;
display: flex;
justify-content: space-between;
color: rgb(95, 101, 108);
font-family: "Source Han Sans CN";
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
}
}
.right-footer {
margin-top: 35px;
display: flex;
justify-content: space-between;
.info {
height: 19px;
color: rgb(132, 136, 142);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0px;
text-align: left;
}
}
}
}
:deep(.el-checkbox) {
margin-right: 0 !important;
}
/* PolicyTracking 分页按钮样式:1px 描边 + 白底 + 6px 圆角 */
:deep(.right-footer .el-pagination.is-background .btn-prev),
:deep(.right-footer .el-pagination.is-background .btn-next),
:deep(.right-footer .el-pagination.is-background .el-pager li) {
border: 1px solid rgba(0, 0, 0, 0.15) !important;
background-color: rgba(255, 255, 255, 1) !important;
border-radius: 6px !important;
box-sizing: border-box;
}
// 选中状态的页码样式(描边+文字颜色改为指定蓝色)
:deep(.right-footer .el-pagination.is-background .el-pager li.is-active) {
border-color: rgba(22, 119, 255, 1) !important; // 选中后描边颜色
color: rgba(22, 119, 255, 1) !important; // 选中后页码文字颜色
background-color: rgba(255, 255, 255, 1) !important; // 保持白色背景
font-weight: 400;
}
:deep(.el-checkbox__inner) {
border-radius: 4px !important;
}
</style>
\ No newline at end of file
...@@ -22,9 +22,12 @@ ...@@ -22,9 +22,12 @@
</div> </div>
<div class="select-main"> <div class="select-main">
<div class="checkbox-group"> <div class="checkbox-group">
<el-checkbox label="全部领域" class="filter-checkbox"></el-checkbox> <el-checkbox class="filter-checkbox" :model-value="isGroupAllSelected(researchTypeIds)"
<el-checkbox v-for="type in researchTypeList" :key="type.id" v-model="selectedResearchTypeList" @change="val => handleToggleAll(val, researchTypeIds)">
:label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()"> 全部领域
</el-checkbox>
<el-checkbox v-for="type in researchTypeList" :key="type.id" v-model="selectedResearchIds" :label="type.id"
class="filter-checkbox" @change="handleGetThinkDynamicsReport()">
{{ type.name }} {{ type.name }}
</el-checkbox> </el-checkbox>
</div> </div>
...@@ -37,8 +40,11 @@ ...@@ -37,8 +40,11 @@
</div> </div>
<div class="select-main"> <div class="select-main">
<div class="checkbox-group"> <div class="checkbox-group">
<el-checkbox label="全部时间"></el-checkbox> <el-checkbox class="filter-checkbox" :model-value="isGroupAllSelected(researchTimeIds)"
<el-checkbox v-for="type in researchTimeList" :key="type.id" v-model="selectedResearchTypeList" @change="val => handleToggleAll(val, researchTimeIds)">
全部时间
</el-checkbox>
<el-checkbox v-for="type in researchTimeList" :key="type.id" v-model="selectedResearchTimeIds"
:label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()"> :label="type.id" class="filter-checkbox" @change="handleGetThinkDynamicsReport()">
{{ type.name }} {{ type.name }}
</el-checkbox> </el-checkbox>
...@@ -78,7 +84,7 @@ ...@@ -78,7 +84,7 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, toRefs, watch } from "vue"; import { computed, ref, toRefs, watch } from "vue";
const props = defineProps({ const props = defineProps({
researchTypeList: { researchTypeList: {
...@@ -89,9 +95,13 @@ const props = defineProps({ ...@@ -89,9 +95,13 @@ const props = defineProps({
type: Array, type: Array,
default: () => [] default: () => []
}, },
selectedResearchTypeList: { selectedFilters: {
type: Array, type: Object,
default: () => [] default: () => ({
researchTypeIds: [],
researchTimeIds: [],
researchHearingIds: []
})
}, },
curFooterList: { curFooterList: {
type: Array, type: Array,
...@@ -108,7 +118,7 @@ const props = defineProps({ ...@@ -108,7 +118,7 @@ const props = defineProps({
}); });
const emit = defineEmits([ const emit = defineEmits([
"update:selectedResearchTypeList", "update:selectedFilters",
"filter-change", "filter-change",
"page-change", "page-change",
"report-click" "report-click"
...@@ -117,31 +127,51 @@ const emit = defineEmits([ ...@@ -117,31 +127,51 @@ const emit = defineEmits([
// 解构 props,保持模板里变量名不变 // 解构 props,保持模板里变量名不变
const { researchTypeList, researchTimeList, curFooterList, total, currentPage } = toRefs(props); const { researchTypeList, researchTimeList, curFooterList, total, currentPage } = toRefs(props);
// 用本地 ref 替代 computed,el-checkbox 会直接修改数组,需要可变的 ref const selectedResearchIds = ref([]);
const selectedResearchTypeList = ref([...(props.selectedResearchTypeList || [])]); const selectedResearchTimeIds = ref([]);
// 父组件更新时同步到子组件 // 父组件更新时同步到子组件
watch( watch(
() => props.selectedResearchTypeList, () => props.selectedFilters,
val => { val => {
selectedResearchTypeList.value = val ? [...val] : []; selectedResearchIds.value = val?.researchTypeIds ? [...val.researchTypeIds] : [];
selectedResearchTimeIds.value = val?.researchTimeIds ? [...val.researchTimeIds] : [];
}, },
{ immediate: true, deep: true } { immediate: true, deep: true }
); );
// 子组件勾选变化时通知父组件,flush: 'sync' 确保在 @change 触发前父组件已更新,否则 filter-change 时父组件拿到的还是旧值 const buildSelectedFiltersPayload = () => ({
watch( researchTypeIds: [...selectedResearchIds.value],
selectedResearchTypeList, researchTimeIds: [...selectedResearchTimeIds.value],
val => { researchHearingIds: []
emit("update:selectedResearchTypeList", val); });
},
{ deep: true, flush: "sync" } const researchTypeIds = computed(() => (researchTypeList.value || []).map(item => item.id));
); const researchTimeIds = computed(() => (researchTimeList.value || []).map(item => item.id));
const getTargetSelection = ids => (ids === researchTypeIds.value ? selectedResearchIds : selectedResearchTimeIds);
const isGroupAllSelected = ids =>
ids.length > 0 && ids.every(id => getTargetSelection(ids).value.includes(id));
const handleToggleAll = (checked, ids) => {
if (!ids.length) return;
const targetSelection = getTargetSelection(ids);
const nextSelected = new Set(targetSelection.value);
if (checked) {
ids.forEach(id => nextSelected.add(id));
} else {
ids.forEach(id => nextSelected.delete(id));
}
targetSelection.value = [...nextSelected];
handleGetThinkDynamicsReport();
};
// 保持模板里的方法名不变,但改成通知父组件,直接传入当前选中值避免时序问题 // 保持模板里的方法名不变,但改成通知父组件,直接传入当前选中值避免时序问题
const handleGetThinkDynamicsReport = () => { const handleGetThinkDynamicsReport = () => {
emit("update:selectedResearchTypeList", [...selectedResearchTypeList.value]); const payload = buildSelectedFiltersPayload();
emit("filter-change", [...selectedResearchTypeList.value]); emit("update:selectedFilters", payload);
emit("filter-change", payload);
}; };
const handleCurrentChange = page => { const handleCurrentChange = page => {
...@@ -171,7 +201,7 @@ const handleToReportDetail = item => { ...@@ -171,7 +201,7 @@ const handleToReportDetail = item => {
.select-research-box { .select-research-box {
width: 360px; width: 360px;
height: 284px; height: 284px;
margin-top: 21px; margin-top: 19px;
.select-box-header { .select-box-header {
display: flex; display: flex;
...@@ -200,7 +230,7 @@ const handleToReportDetail = item => { ...@@ -200,7 +230,7 @@ const handleToReportDetail = item => {
.select-main { .select-main {
margin-left: 25px; margin-left: 24px;
.checkbox-group { .checkbox-group {
display: grid; display: grid;
...@@ -230,13 +260,14 @@ const handleToReportDetail = item => { ...@@ -230,13 +260,14 @@ const handleToReportDetail = item => {
} }
.select-time-box { .select-time-box {
margin-top: 21px; margin-top: 44px;
width: 360px; width: 360px;
height: 156px; height: 156px;
.select-box-header { .select-box-header {
display: flex; display: flex;
gap: 17px; gap: 17px;
margin-bottom: 12px;
.icon { .icon {
margin-top: 4px; margin-top: 4px;
...@@ -260,11 +291,17 @@ const handleToReportDetail = item => { ...@@ -260,11 +291,17 @@ const handleToReportDetail = item => {
.select-main { .select-main {
margin-left: 25px; margin-left: 24px;
.checkbox-group { .checkbox-group {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 8px 4px;
.filter-checkbox {
width: 160px;
height: 24px;
}
} }
...@@ -394,4 +431,26 @@ const handleToReportDetail = item => { ...@@ -394,4 +431,26 @@ const handleToReportDetail = item => {
margin-right: 0 !important; margin-right: 0 !important;
} }
/* PolicyTracking 分页按钮样式:1px 描边 + 白底 + 6px 圆角 */
:deep(.right-footer .el-pagination.is-background .btn-prev),
:deep(.right-footer .el-pagination.is-background .btn-next),
:deep(.right-footer .el-pagination.is-background .el-pager li) {
border: 1px solid rgba(0, 0, 0, 0.15) !important;
background-color: rgba(255, 255, 255, 1) !important;
border-radius: 6px !important;
box-sizing: border-box;
}
// 选中状态的页码样式(描边+文字颜色改为指定蓝色)
:deep(.right-footer .el-pagination.is-background .el-pager li.is-active) {
border-color: rgba(22, 119, 255, 1) !important; // 选中后描边颜色
color: rgba(22, 119, 255, 1) !important; // 选中后页码文字颜色
background-color: rgba(255, 255, 255, 1) !important; // 保持白色背景
font-weight: 400;
}
:deep(.el-checkbox__inner) {
border-radius: 4px !important;
}
</style> </style>
\ No newline at end of file
...@@ -69,18 +69,28 @@ ...@@ -69,18 +69,28 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="pageChange"> <div v-if="isThinkTankReport">
<ThinkTankReport :research-type-list="researchTypeList" :research-time-list="researchTimeList" <ThinkTankReport :research-type-list="researchTypeList" :research-time-list="researchTimeList"
:selected-research-type-list="selectedResearchTypeList" :cur-footer-list="curFooterList" :total="total" :key="`智库报告-${tabResetKey}`" :selected-filters="selectedFilters" :cur-footer-list="curFooterList" :total="total"
:current-page="currentPage" @update:selected-research-type-list="val => (selectedResearchTypeList.value = val)" :current-page="currentPage"
@update:selected-filters="handleSelectedFiltersUpdate"
@filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange" @filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange"
@report-click="handleToReportDetail" /> @report-click="handleToReportDetail" />
</div> </div>
<div v-if="!pageChange"> <div v-if="isCongressHearing">
<CongressHearing :research-type-list="researchTypeList" :research-time-list="researchTimeList" <CongressHearing :research-type-list="researchTypeList" :research-time-list="researchTimeList"
:research-hearing-list="researchHearingList" :selected-research-type-list="selectedResearchTypeList" :key="`国会听证会-${tabResetKey}`" :research-hearing-list="researchHearingList"
:cur-footer-list="curFooterList" :total="total" :current-page="currentPage" :hearing-data="hearingData" :selected-filters="selectedFilters" :selected-year="selectedYear" :cur-footer-list="curFooterList" :total="total"
@update:selected-research-type-list="val => (selectedResearchTypeList.value = val)" :current-page="currentPage" :hearing-data="hearingData"
@update:selected-filters="handleSelectedFiltersUpdate"
@filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange"
@report-click="handleToReportDetail" />
</div>
<div>
<SurveyForm v-if="isSurveyForm" :research-type-list="researchTypeList" :research-time-list="researchTimeList"
:key="`调查项目-${tabResetKey}`" :selected-filters="selectedFilters" :cur-footer-list="curFooterList" :total="total"
:current-page="currentPage"
@update:selected-filters="handleSelectedFiltersUpdate"
@filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange" @filter-change="(payload) => handleGetThinkDynamicsReport(payload)" @page-change="handleCurrentChange"
@report-click="handleToReportDetail" /> @report-click="handleToReportDetail" />
</div> </div>
...@@ -89,6 +99,7 @@ ...@@ -89,6 +99,7 @@
<script setup> <script setup>
import { ref, reactive, onMounted } from "vue"; import { ref, reactive, onMounted } from "vue";
import SurveyForm from "./SurveyForm/index.vue"
// import Img1 from "./images/img1.png"; // import Img1 from "./images/img1.png";
// import Img2 from "./images/img2.png"; // import Img2 from "./images/img2.png";
// import Img3 from "./images/img3.png"; // import Img3 from "./images/img3.png";
...@@ -111,7 +122,9 @@ import { useRouter } from "vue-router"; ...@@ -111,7 +122,9 @@ import { useRouter } from "vue-router";
import ThinkTankReport from "./ThinkTankReport/index.vue"; import ThinkTankReport from "./ThinkTankReport/index.vue";
import CongressHearing from "./CongressHearing/index.vue"; import CongressHearing from "./CongressHearing/index.vue";
const router = useRouter(); const router = useRouter();
const pageChange = ref(true) const isThinkTankReport = ref(true);
const isSurveyForm = ref(false);
const isCongressHearing = ref(false);
const searchReport = ref('') const searchReport = ref('')
const handleToReportDetail = (item) => { const handleToReportDetail = (item) => {
...@@ -302,15 +315,46 @@ const choseTypeList = ref([ ...@@ -302,15 +315,46 @@ const choseTypeList = ref([
]) ])
const activeTypeId = ref(choseTypeList.value[0]?.id || null) const activeTypeId = ref(choseTypeList.value[0]?.id || null)
const tabResetKey = ref(0)
const createDefaultSelectedFilters = () => ({
researchTypeIds: [],
researchTimeIds: [],
researchHearingIds: []
})
const resetThinkDynamicsState = () => {
searchReport.value = ''
selectedYear.value = 1
sort.value = false
author.value = ''
currentPage.value = 1
selectedFilters.value = createDefaultSelectedFilters()
curFooterList.value = []
total.value = 0
tabResetKey.value += 1
}
const handleChooseType = (type) => { const handleChooseType = (type) => {
if (activeTypeId.value === type.id) {
return
}
activeTypeId.value = type.id activeTypeId.value = type.id
if (type.id === '国会听证会') { if (type.id === '国会听证会') {
pageChange.value = false isThinkTankReport.value = false
isCongressHearing.value = true
isSurveyForm.value = false
} else if (type.id === "智库报告") {
isThinkTankReport.value = true
isCongressHearing.value = false
isSurveyForm.value = false
} else { } else {
pageChange.value = true isThinkTankReport.value = false
isCongressHearing.value = false
isSurveyForm.value = true
} }
resetThinkDynamicsState()
handleGetThinkDynamicsReport()
} }
const researchTimeList = ref([ const researchTimeList = ref([
{ {
...@@ -368,7 +412,11 @@ const researchHearingList = ref([ ...@@ -368,7 +412,11 @@ const researchHearingList = ref([
name: '新材料', name: '新材料',
} }
]) ])
const selectedResearchTypeList = ref([]) const selectedFilters = ref(createDefaultSelectedFilters())
const handleSelectedFiltersUpdate = val => {
selectedFilters.value = val
}
const author = ref('') // 作者 const author = ref('') // 作者
...@@ -524,11 +572,26 @@ function arrayToString(arr) { ...@@ -524,11 +572,26 @@ function arrayToString(arr) {
}, ""); }, "");
} }
function buildThinkDynamicsYears(selectedYears) {
const allYearIds = researchTimeList.value.map(item => item.id)
if (!selectedYears?.length || selectedYears.length === allYearIds.length) {
return null
}
return arrayToString(selectedYears)
}
// 获取智库动态报告,payload 为子组件筛选变更时传入的当前选中值,避免时序导致拿到旧值 // 获取智库动态报告,payload 为子组件筛选变更时传入的当前选中值,避免时序导致拿到旧值
const handleGetThinkDynamicsReport = async (payload) => { const handleGetThinkDynamicsReport = async (payload) => {
const selectedIds = Array.isArray(payload) ? payload : selectedResearchTypeList.value; const nextFilters = payload && typeof payload === 'object'
if (Array.isArray(payload)) { ? {
selectedResearchTypeList.value = payload; researchTypeIds: payload.researchTypeIds ? [...payload.researchTypeIds] : [],
researchTimeIds: payload.researchTimeIds ? [...payload.researchTimeIds] : [],
researchHearingIds: payload.researchHearingIds ? [...payload.researchHearingIds] : []
}
: selectedFilters.value;
if (payload && typeof payload === 'object') {
selectedFilters.value = nextFilters;
currentPage.value = 1;
} }
try { try {
const parmas = { const parmas = {
...@@ -540,7 +603,8 @@ const handleGetThinkDynamicsReport = async (payload) => { ...@@ -540,7 +603,8 @@ const handleGetThinkDynamicsReport = async (payload) => {
sortFun: sort.value ?? true, sortFun: sort.value ?? true,
currentPage: currentPage.value - 1, currentPage: currentPage.value - 1,
pageSize: 12, pageSize: 12,
researchTypeIds: arrayToString(selectedIds) === '' ? null : arrayToString(selectedIds) researchTypeIds: arrayToString(nextFilters.researchTypeIds) === '' ? null : arrayToString(nextFilters.researchTypeIds),
years: buildThinkDynamicsYears(nextFilters.researchTimeIds)
} }
} }
......
...@@ -202,7 +202,7 @@ ...@@ -202,7 +202,7 @@
<div class="info"> <div class="info">
<div class="info-header"> <div class="info-header">
<div class="name">{{ item.name }}</div> <div class="name">{{ item.name }}</div>
<div class="position">{{ item.positionTitle }}</div> <div class="position">{{ item.positionTitle ?? '全球研究人才' }}</div>
</div> </div>
<div class="info-footer">{{ item.describe }}</div> <div class="info-footer">{{ item.describe }}</div>
</div> </div>
...@@ -220,7 +220,7 @@ ...@@ -220,7 +220,7 @@
<div class="info"> <div class="info">
<div class="info-header"> <div class="info-header">
<div class="name">{{ item.name }}</div> <div class="name">{{ item.name }}</div>
<div class="position">{{ item.positionTitle }}</div> <div class="position">{{ item.positionTitle ?? '全球研究人才' }}</div>
</div> </div>
<div class="info-footer">{{ item.describe }}</div> <div class="info-footer">{{ item.describe }}</div>
</div> </div>
...@@ -401,6 +401,97 @@ const handleGetThinkTankFundsSource = async () => { ...@@ -401,6 +401,97 @@ const handleGetThinkTankFundsSource = async () => {
}) })
box1ChartData.value = data box1ChartData.value = data
const box1Chart = getPieChart(box1ChartData.value); const box1Chart = getPieChart(box1ChartData.value);
// 图表整体宽度 830px,中间圆形 194*194(半径 97)
const CHART_WIDTH = 830
const PIE_OUTER_RADIUS = 97
const PIE_INNER_RADIUS = Math.round((80 / 110) * PIE_OUTER_RADIUS)
box1Chart.series[0].radius = [PIE_INNER_RADIUS, PIE_OUTER_RADIUS]
// 仅覆盖 label:左侧标注 部门左+经费比例右,右侧标注 经费比例左+部门右
const LABEL_BOX_HEIGHT = 21.41
const LABEL_OFFSET_UP = 3 + LABEL_BOX_HEIGHT / 2
const dataList = box1ChartData.value
const total = dataList.reduce((s, d) => s + (d.value || 0), 0) || 1
box1Chart.series[0].label = {
...box1Chart.series[0].label,
alignTo: 'edge',
offset: [0, -LABEL_OFFSET_UP],
formatter(params) {
const valueYi = (params.data.value || 0) / 1000000
const percent = Math.round(params.percent || 0)
const valueStr = `${Math.round(valueYi)}亿 ${percent}%`
let cumulative = 0
for (let i = 0; i < params.dataIndex; i++) cumulative += dataList[i].value || 0
const centerAngle = 90 + ((cumulative + (params.data.value || 0) / 2) / total) * 360
const angleNorm = ((centerAngle % 360) + 360) % 360
// 左侧仅 270–360° 及跨圈:部门左、经费右;其余(含 180–270° 右下两条):经费左、部门右
const isLeftLabel = (angleNorm >= 270 && angleNorm < 360) || centerAngle >= 360
if (isLeftLabel) {
return `{nameL|${params.data.name}}{valueR|${valueStr}}`
}
return `{valueL|${valueStr}}{nameR|${params.data.name}}`
},
lineHeight: LABEL_BOX_HEIGHT,
rich: {
nameL: {
fontFamily: 'Source Han Sans CN',
fontSize: 16,
fontWeight: 700,
lineHeight: 24,
color: 'rgba(59, 65, 75, 1)',
width: 180,
align: 'left',
overflow: 'truncate',
ellipsis: '...',
letterSpacing: 1
},
nameR: {
fontFamily: 'Source Han Sans CN',
fontSize: 16,
fontWeight: 700,
lineHeight: 24,
color: 'rgba(59, 65, 75, 1)',
width: 180,
align: 'right',
overflow: 'truncate',
ellipsis: '...',
letterSpacing: 1
},
valueL: {
fontFamily: 'Microsoft YaHei',
fontSize: 14,
fontWeight: 400,
lineHeight: 22,
color: 'rgba(59, 65, 75, 1)',
align: 'left',
width: 88,
padding: [0, 8, 0, 0]
},
valueR: {
fontFamily: 'Microsoft YaHei',
fontSize: 14,
fontWeight: 400,
lineHeight: 22,
color: 'rgba(59, 65, 75, 1)',
align: 'left',
width: 88,
padding: [0, 0, 0, 8]
}
}
}
// 标线末端 x 对齐(左右贴齐),图表宽度 830
box1Chart.series[0].labelLayout = function (params) {
const isLeft = params.labelRect.x < CHART_WIDTH / 2
const points = params.labelLinePoints
points[2][0] = isLeft
? params.labelRect.x
: params.labelRect.x + params.labelRect.width
return {
labelLinePoints: points
}
}
setChart(box1Chart, "box1Chart"); setChart(box1Chart, "box1Chart");
} }
} catch (error) { } catch (error) {
...@@ -445,8 +536,14 @@ const handleGetThinkTankResearchAreae = async () => { ...@@ -445,8 +536,14 @@ const handleGetThinkTankResearchAreae = async () => {
}; };
// 核心研究人员 // 核心研究人员
const handleBox3Chart = () => { const handleBox3Chart = () => {
// 将分类数据转换为树状图格式 // 四大区域:顺序与比例 9:6:6:6 → 左侧3×3、中间3×2、右侧3×2、底4–9列一行
const treemapData = []; const REGION_ORDER = ['政府部门及国家实验室', '领先科技企业', '顶尖大学与研究机构', '国际人才'];
const REGION_COLORS = {
政府部门及国家实验室: 'rgb(80,112,221)',
领先科技企业: 'rgb(182,214,52)',
顶尖大学与研究机构: 'rgb(80,83,114)',
国际人才: 'rgb(255,153,77)'
};
const mockRandResearcherCategories = { const mockRandResearcherCategories = {
政府部门及国家实验室: { 政府部门及国家实验室: {
商务部: 12, 商务部: 12,
...@@ -478,19 +575,45 @@ const handleBox3Chart = () => { ...@@ -478,19 +575,45 @@ const handleBox3Chart = () => {
其他: 6 其他: 6
} }
}; };
Object.keys(mockRandResearcherCategories).forEach(category => { // 政府部门占整块左侧;领先科技企业、顶尖大学各加长 0.5 行,国际人才缩小 0.5 行(右三区比例约 50:50:35)
const children = Object.keys(mockRandResearcherCategories[category]).map(item => ({ const REGION_VALUES = { 政府部门及国家实验室: 135, 领先科技企业: 50, 顶尖大学与研究机构: 50, 国际人才: 35 };
const treemapData = REGION_ORDER.map(name => {
const children = Object.keys(mockRandResearcherCategories[name]).map(item => ({
name: item, name: item,
value: mockRandResearcherCategories[category][item] value: mockRandResearcherCategories[name][item]
})); }));
treemapData.push({ return {
name: category, name,
value: children.reduce((sum, item) => sum + item.value, 0), value: REGION_VALUES[name],
children: children itemStyle: { color: REGION_COLORS[name] },
}); children
};
}); });
const box3Chart = getTreeMapChart(treemapData); const box3Chart = getTreeMapChart(treemapData);
delete box3Chart.series[0].itemStyle;
box3Chart.series[0].sort = false;
// 图表充满 box3-main-left,左右各留 12px
box3Chart.series[0].left = 12;
box3Chart.series[0].right = 12;
box3Chart.series[0].top = 0;
box3Chart.series[0].bottom = 0;
// 方块内文字与区域标题统一为黑色,方块内文字加 1px 白色描边(等效 CSS text-stroke: 1px #fff)
box3Chart.series[0].label = {
...box3Chart.series[0].label,
color: 'rgb(51,51,51)',
textBorderColor: '#fff',
textBorderWidth: 0.7,
// 可选:白色阴影兜底
textShadowColor: '#fff',
textShadowBlur: 0,
textShadowOffsetX: 0,
textShadowOffsetY: 0
};
box3Chart.series[0].upperLabel = {
...box3Chart.series[0].upperLabel,
color: 'rgb(51,51,51)'
};
setChart(box3Chart, "box3Chart"); setChart(box3Chart, "box3Chart");
}; };
...@@ -591,12 +714,13 @@ onMounted(() => { ...@@ -591,12 +714,13 @@ onMounted(() => {
height: 16px; height: 16px;
border-radius: 0 4px 4px 0; border-radius: 0 4px 4px 0;
background: var(--color-main-active); background: var(--color-main-active);
} }
.title { .title {
margin-left: 14px; margin-left: 14px;
color: var(--color-main-active); color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 20px; font-size: 20px;
font-weight: 700; font-weight: 700;
line-height: 26px; line-height: 26px;
...@@ -656,7 +780,7 @@ onMounted(() => { ...@@ -656,7 +780,7 @@ onMounted(() => {
} }
.left-bottom { .left-bottom {
padding-bottom: 16px; margin-bottom: 69px;
.left-bottom-main { .left-bottom-main {
margin-top: 4px; margin-top: 4px;
...@@ -770,13 +894,15 @@ onMounted(() => { ...@@ -770,13 +894,15 @@ onMounted(() => {
height: 72px; height: 72px;
border-radius: 4px; border-radius: 4px;
background: linear-gradient(180deg, rgba(230, 244, 255, 1), rgba(230, 244, 255, 0) 100%); background: linear-gradient(180deg, rgba(230, 244, 255, 1), rgba(230, 244, 255, 0) 100%);
display: flex;
flex-direction: column;
.card-title { .card-title {
height: 24px; height: 24px;
margin-top: 8px; margin-top: 8px;
margin-left: 19px; margin-left: 19px;
color: var(--color-main-active); color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
...@@ -804,13 +930,15 @@ onMounted(() => { ...@@ -804,13 +930,15 @@ onMounted(() => {
height: 72px; height: 72px;
border-radius: 4px; border-radius: 4px;
background: linear-gradient(180deg, rgba(255, 241, 240, 1), rgba(255, 241, 240, 0) 100%); background: linear-gradient(180deg, rgba(255, 241, 240, 1), rgba(255, 241, 240, 0) 100%);
display: flex;
flex-direction: column;
.card-title { .card-title {
height: 24px; height: 24px;
margin-top: 8px; margin-top: 8px;
margin-left: 19px; margin-left: 19px;
color: rgba(206, 79, 81, 1); color: rgba(206, 79, 81, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
...@@ -838,13 +966,15 @@ onMounted(() => { ...@@ -838,13 +966,15 @@ onMounted(() => {
height: 72px; height: 72px;
border-radius: 4px; border-radius: 4px;
background: linear-gradient(180deg, rgba(230, 255, 251, 1), rgba(230, 255, 251, 0) 100%); background: linear-gradient(180deg, rgba(230, 255, 251, 1), rgba(230, 255, 251, 0) 100%);
display: flex;
flex-direction: column;
.card-title { .card-title {
height: 24px; height: 24px;
margin-top: 8px; margin-top: 8px;
margin-left: 19px; margin-left: 19px;
color: rgba(19, 168, 168, 1); color: rgba(19, 168, 168, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
...@@ -870,7 +1000,7 @@ onMounted(() => { ...@@ -870,7 +1000,7 @@ onMounted(() => {
.box1-main-right { .box1-main-right {
margin-left: 38px; margin-left: 38px;
margin-top: 6px; margin-top: 6px;
width: 800px; width: 830px;
height: 300px; height: 300px;
} }
} }
...@@ -879,7 +1009,8 @@ onMounted(() => { ...@@ -879,7 +1009,8 @@ onMounted(() => {
height: 320px; height: 320px;
display: flex; display: flex;
position: relative; position: relative;
padding-left: 150px; padding-left: 111px;
margin-top: 4px;
.box2-arrow-left { .box2-arrow-left {
width: 24px; width: 24px;
...@@ -919,13 +1050,13 @@ onMounted(() => { ...@@ -919,13 +1050,13 @@ onMounted(() => {
} }
.box2-item { .box2-item {
margin-top: 4px; margin-top: 19px;
width: 300px; width: 221px;
height: 150px; height: 134px;
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
padding-left: 13px; padding-left: 13px;
margin-left: -100px; margin-left: 0;
border-left: 1px solid #0a57a6; border-left: 1px solid #0a57a6;
.box2-item-header { .box2-item-header {
...@@ -935,7 +1066,7 @@ onMounted(() => { ...@@ -935,7 +1066,7 @@ onMounted(() => {
.title { .title {
color: var(--color-main-active); color: var(--color-main-active);
height: 26px; height: 26px;
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
} }
...@@ -946,7 +1077,7 @@ onMounted(() => { ...@@ -946,7 +1077,7 @@ onMounted(() => {
min-height: 48px; min-height: 48px;
max-height: 96px; max-height: 96px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
...@@ -1008,13 +1139,17 @@ onMounted(() => { ...@@ -1008,13 +1139,17 @@ onMounted(() => {
.box3-main { .box3-main {
display: flex; display: flex;
.box3-main-left { .box3-main-left {
width: 536px; width: 536px;
height: 345px; height: 326px;
margin-left: 9px;
} }
.box3-main-right { .box3-main-right {
margin-left: 10px; margin-left: 28px;
margin-top: 12px;
width: 536px; width: 536px;
height: 326px; height: 326px;
...@@ -1027,8 +1162,10 @@ onMounted(() => { ...@@ -1027,8 +1162,10 @@ onMounted(() => {
.icon { .icon {
width: 48px; width: 48px;
height: 48px; height: 48px;
margin-left: 8px; border-radius: 50% !important;
cursor: pointer; cursor: pointer;
overflow: hidden;
flex-shrink: 0;
img { img {
width: 100%; width: 100%;
...@@ -1047,7 +1184,7 @@ onMounted(() => { ...@@ -1047,7 +1184,7 @@ onMounted(() => {
.name { .name {
height: 24px; height: 24px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
line-height: 24px; line-height: 24px;
...@@ -1057,7 +1194,7 @@ onMounted(() => { ...@@ -1057,7 +1194,7 @@ onMounted(() => {
.position { .position {
height: 22px; height: 22px;
color: var(--color-main-active); color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 22px; line-height: 22px;
...@@ -1069,7 +1206,7 @@ onMounted(() => { ...@@ -1069,7 +1206,7 @@ onMounted(() => {
.info-footer { .info-footer {
height: 22px; height: 22px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: "Source Han Sans CN";
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 22px; line-height: 22px;
......
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
</div> </div>
<div class="report-box"> <div class="report-box">
<iframe :src="reportUrl" width="50%" height="100%"> <iframe :src="reportUrlWithPage" width="50%" height="100%">
</iframe> </iframe>
<iframe :src="reportUrlEn" width="50%" height="100%"> <iframe :src="reportUrlEnWithPage" width="50%" height="100%">
</iframe> </iframe>
<!-- <pdf :pdfUrl="reportUrl" style="width: 48%;" /> <!-- <pdf :pdfUrl="reportUrl" style="width: 48%;" />
...@@ -49,21 +49,35 @@ ...@@ -49,21 +49,35 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { computed, ref, onMounted } from "vue";
import pdf from "./pdf.vue"; import pdf from "./pdf.vue";
import { import {
getThinkTankReportSummary, getThinkTankReportSummary,
getThinkTankReportcontentUrl getThinkTankReportcontentUrl
} from "@/api/thinkTank/overview"; } from "@/api/thinkTank/overview";
import { useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
const router = useRouter(); const router = useRouter();
const route = useRoute();
const reportUrl = ref('') const reportUrl = ref('')
const reportUrlEn = ref('') const reportUrlEn = ref('')
const thinkInfo = ref({}) const thinkInfo = ref({})
const defaultPdfPage = ref(1)
const sourceCurrentPage = ref(Number(route.query.currentPage) || 1)
const sourcePageSize = ref(Number(route.query.pageSize) || 12)
const opinionId = ref(route.query.opinionId || "")
const opinionContent = ref(route.query.opinionContent || "")
const buildPdfPageUrl = url => {
if (!url) return ''
return `${url}#page=${defaultPdfPage.value}`
}
const reportUrlWithPage = computed(() => buildPdfPageUrl(reportUrl.value))
const reportUrlEnWithPage = computed(() => buildPdfPageUrl(reportUrlEn.value))
// 获取报告全局信息 // 获取报告全局信息
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论