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

合并分支 'zz-dev' 到 'pre'

feat:修改合作限制动态的样式,将合作限制后端更改的数据展示出来;修改合作限制图表样式及下拉框样式,完善相关实体点击跳转对应页面功能 查看合并请求 !283
流水线 #245 已取消 于阶段
...@@ -69,7 +69,8 @@ router.beforeEach((to, from, next) => { ...@@ -69,7 +69,8 @@ router.beforeEach((to, from, next) => {
if (to.meta.title) { if (to.meta.title) {
if (to.meta.dynamicTitle) { if (to.meta.dynamicTitle) {
console.log('to', to); console.log('to', to);
document.title = window.sessionStorage.getItem("curTabName") || to.meta.title; const storageKey = to.meta.titleStorageKey || "curTabName";
document.title = window.sessionStorage.getItem(storageKey) || to.meta.title;
} else { } else {
document.title = to.meta.title document.title = to.meta.title
......
...@@ -20,7 +20,8 @@ const cooperationRestrictionsRoutes = [ ...@@ -20,7 +20,8 @@ const cooperationRestrictionsRoutes = [
component: CooperationRestrictionsDetail, component: CooperationRestrictionsDetail,
meta: { meta: {
title: "合作限制详情", title: "合作限制详情",
dynamicTitle: true dynamicTitle: true,
titleStorageKey: "cooperationRestrictionsTabName"
} }
}, },
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<div class="left-top"> <div class="left-top">
<img src="./assets/icon01.png" alt="" /> <img src="./assets/icon01.png" alt="" />
<div class="left-top-title">合作限制动态</div> <div class="left-top-title">合作限制动态</div>
<div class="more" @click="handleClickToDetail">查看详情 ></div> <div class="more" @click="handleClickToDetail">{{ "查看详情 >" }}</div>
</div> </div>
<el-carousel ref="carouselRef" height="412px" direction="horizontal" :autoplay="true" :interval="5000" <el-carousel ref="carouselRef" height="412px" direction="horizontal" :autoplay="true" :interval="5000"
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
</div> </div>
</div> </div>
<div class="left-center-type" v-if="item.type">{{ item.type }}</div> <div class="left-center-type" v-if="item.limitMeans">{{ item.limitMeans }}</div>
<!-- <div class="left-center-title">{{ item.LIMITTYPE }}</div> --> <!-- <div class="left-center-title">{{ item.LIMITTYPE }}</div> -->
</div> </div>
<div class="left-bottom"> <div class="left-bottom">
...@@ -188,12 +188,12 @@ const riskSignals = ref([]); ...@@ -188,12 +188,12 @@ const riskSignals = ref([]);
// 点击查看详情 // 点击查看详情
const handleClickToDetail = item => { const handleClickToDetail = item => {
const activeItem = item && item.ID ? item : mainTrend.value; const activeItem = item && item.ID ? item : mainTrend.value;
const id = activeItem?.ID; const id = activeItem?.ID || activeItem?.id || activeItem?.limitId;
if (!id) return; if (!id) return;
window.sessionStorage.setItem("curTabName", activeItem?.LIMITNAME); window.sessionStorage.setItem("cooperationRestrictionsTabName", activeItem?.LIMITNAME || "");
const curRoute = router.resolve({ const curRoute = router.resolve({
path: "/cooperationRestrictions/detail", name: "CooperationRestrictionsDetail",
query: { id: id } query: { id: id }
}); });
window.open(curRoute.href, "_blank"); window.open(curRoute.href, "_blank");
...@@ -201,9 +201,11 @@ const handleClickToDetail = item => { ...@@ -201,9 +201,11 @@ const handleClickToDetail = item => {
// 点击风险信号详情 // 点击风险信号详情
const handleToRiskDetail = (item) => { const handleToRiskDetail = (item) => {
const id = item?.cooperationId || item?.ID || item?.id || item?.limitId;
if (!id) return;
const curRoute = router.resolve({ const curRoute = router.resolve({
path: "/cooperationRestrictions/detail", name: "CooperationRestrictionsDetail",
query: { id: item.cooperationId }, query: { id },
}); });
window.open(curRoute.href, "_blank"); window.open(curRoute.href, "_blank");
}; };
...@@ -318,7 +320,7 @@ onMounted(() => { ...@@ -318,7 +320,7 @@ onMounted(() => {
width: 967px; width: 967px;
height: 208px; height: 208px;
margin-top: 33px; margin-top: 33px;
margin-left: 62px; margin-left: 57px;
border-bottom: 1px solid rgb(234, 236, 238); border-bottom: 1px solid rgb(234, 236, 238);
position: relative; position: relative;
...@@ -326,6 +328,7 @@ onMounted(() => { ...@@ -326,6 +328,7 @@ onMounted(() => {
width: 148px; width: 148px;
height: 148px; height: 148px;
margin-right: 21px; margin-right: 21px;
margin-left: 5px;
} }
display: flex; display: flex;
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
<div class="left-title"> <div class="left-title">
<img src="./assets/icon01.png" alt="" /> <img src="./assets/icon01.png" alt="" />
<div class="tit">各类型合作限制政策对比</div> <div class="tit">各类型合作限制政策对比</div>
<el-select v-model="value" placeholder="Select" class="select" @change="getCoopRestrictionCompareData"> <el-select v-model="value" placeholder="Select" class="select" popper-class="coop-select-dropdown"
@change="getCoopRestrictionCompareData">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
...@@ -34,7 +35,8 @@ ...@@ -34,7 +35,8 @@
<div class="right-title"> <div class="right-title">
<img src="./assets/icon02.png" alt="" /> <img src="./assets/icon02.png" alt="" />
<div class="tit">各领域规则分布情况</div> <div class="tit">各领域规则分布情况</div>
<el-select v-model="value1" placeholder="Select" class="select" @change="getCoopRestrictionDomainData"> <el-select v-model="value1" placeholder="Select" class="select" popper-class="coop-select-dropdown"
@change="getCoopRestrictionDomainData">
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
...@@ -75,6 +77,22 @@ import AiPane from "@/components/base/Ai/AiPane/index.vue"; ...@@ -75,6 +77,22 @@ import AiPane from "@/components/base/Ai/AiPane/index.vue";
const COOP_LEFT_TIP_TEXT = "各类型合作限制政策对比,数据来源:美对华科技合作限制信息平台"; const COOP_LEFT_TIP_TEXT = "各类型合作限制政策对比,数据来源:美对华科技合作限制信息平台";
const COOP_RIGHT_TIP_TEXT = "各领域规则分布情况,数据来源:美对华科技合作限制信息平台"; const COOP_RIGHT_TIP_TEXT = "各领域规则分布情况,数据来源:美对华科技合作限制信息平台";
// 临时展示 mock(不改样式):右侧“各领域规则分布情况”
// 用完把这个开关改回 false 即可恢复走接口
const USE_DOMAIN_MOCK = false;
const MOCK_COOP_RESTRICTION_DOMAIN = [
{ COOPERTYPE: "科研合作", COOPERTYPECOUNT: 1, AREA: "人工智能" },
{ COOPERTYPE: "科研合作", COOPERTYPECOUNT: 1, AREA: "生物科技" },
{ COOPERTYPE: "技术合作", COOPERTYPECOUNT: 2, AREA: "大数据" },
{ COOPERTYPE: "产学研合作", COOPERTYPECOUNT: 3, AREA: "新能源" },
{ COOPERTYPE: "项目合作", COOPERTYPECOUNT: 1, AREA: "智能制造" },
{ COOPERTYPE: "人才合作", COOPERTYPECOUNT: 2, AREA: "集成电路" },
{ COOPERTYPE: "科研合作", COOPERTYPECOUNT: 2, AREA: "大数据" },
{ COOPERTYPE: "科研合作", COOPERTYPECOUNT: 3, AREA: "新能源" },
{ COOPERTYPE: "科研合作", COOPERTYPECOUNT: 1, AREA: "智能制造" },
{ COOPERTYPE: "科研合作", COOPERTYPECOUNT: 2, AREA: "集成电路" }
];
const value = ref(10); const value = ref(10);
const value1 = ref("2025"); const value1 = ref("2025");
const options = [ const options = [
...@@ -109,6 +127,10 @@ const options1 = [ ...@@ -109,6 +127,10 @@ const options1 = [
const coopRestrictionDomain = ref([]); const coopRestrictionDomain = ref([]);
const getCoopRestrictionDomainData = async () => { const getCoopRestrictionDomainData = async () => {
if (USE_DOMAIN_MOCK) {
coopRestrictionDomain.value = MOCK_COOP_RESTRICTION_DOMAIN;
return;
}
try { try {
const res = await getCoopRestrictionDomain({ const res = await getCoopRestrictionDomain({
year: value1.value year: value1.value
...@@ -449,10 +471,18 @@ const initLeftChart = () => { ...@@ -449,10 +471,18 @@ const initLeftChart = () => {
const option = { const option = {
color: colorMap.map((c) => c.line), color: colorMap.map((c) => c.line),
grid: { left: 40, right: 24, top: 46, bottom: 36 }, // 与智库概览「数量变化趋势」一致:预留图例空间,并用 containLabel 让轴文字不挤压绘图区
grid: {
top: "34%",
right: "3%",
bottom: "5%",
left: "2%",
containLabel: true
},
tooltip: { trigger: "axis", axisPointer: { type: "line" } }, tooltip: { trigger: "axis", axisPointer: { type: "line" } },
legend: { legend: {
top: 8, top: 8,
left: "center",
icon: "circle", icon: "circle",
itemWidth: 12, itemWidth: 12,
itemHeight: 12, itemHeight: 12,
...@@ -572,6 +602,10 @@ const initRightChart = () => { ...@@ -572,6 +602,10 @@ const initRightChart = () => {
const domains = Array.from(domainsSet); const domains = Array.from(domainsSet);
const types = Array.from(typesSet); const types = Array.from(typesSet);
const legendSplitAt = Math.ceil(types.length / 2);
const legendFirstLine = types.slice(0, legendSplitAt);
const legendSecondLine = types.slice(legendSplitAt);
const indicators = domains.map((domain) => { const indicators = domains.map((domain) => {
const domainData = rawData.filter((item) => item.AREA === domain); const domainData = rawData.filter((item) => item.AREA === domain);
const maxVal = Math.max(...domainData.map((d) => d.COOPERTYPECOUNT), 5); const maxVal = Math.max(...domainData.map((d) => d.COOPERTYPECOUNT), 5);
...@@ -589,31 +623,56 @@ const initRightChart = () => { ...@@ -589,31 +623,56 @@ const initRightChart = () => {
name: type, name: type,
value: dataValues, value: dataValues,
itemStyle: { color: colorMap[index % colorMap.length] }, itemStyle: { color: colorMap[index % colorMap.length] },
// 不要填充多边形:让雷达图“圆里面是空的” // 雷达图围成区域填充:对应颜色 0.1 透明度
// areaStyle 不设置(或设为 0)可避免穿透同心圆的填充效果 areaStyle: { color: colorMap[index % colorMap.length], opacity: 0.1 }
}; };
}); });
const option = { const option = {
color: colorMap, color: colorMap,
legend: { // 避免自动换行导致“第二行不居中”:拆成两行 legend,每行各自居中
top: 8, legend: [
icon: "circle", {
itemWidth: 12, show: true,
itemHeight: 12, type: "plain",
itemGap: 24, data: legendFirstLine,
textStyle: { top: 8,
color: "rgb(95, 101, 108)", left: "center",
fontSize: 16, icon: "circle",
fontFamily: "Microsoft YaHei", itemWidth: 12,
fontWeight: 400, itemHeight: 12,
lineHeight: 24 itemGap: 24,
textStyle: {
color: "rgb(95, 101, 108)",
fontSize: 16,
fontFamily: "Microsoft YaHei",
fontWeight: 400,
lineHeight: 24
}
}, },
data: types {
}, show: legendSecondLine.length > 0,
type: "plain",
data: legendSecondLine,
top: 32,
left: "center",
icon: "circle",
itemWidth: 12,
itemHeight: 12,
itemGap: 24,
textStyle: {
color: "rgb(95, 101, 108)",
fontSize: 16,
fontFamily: "Microsoft YaHei",
fontWeight: 400,
lineHeight: 24
}
}
],
radar: { radar: {
center: ["50%", "55%"], // 对齐左侧折线图(grid top=34%)的“图例到图形”间距:下移雷达中心并略缩半径
radius: "65%", center: ["50%", "62%"],
radius: "60%",
indicator: indicators, indicator: indicators,
axisName: { axisName: {
color: "rgba(132, 136, 142, 1)", color: "rgba(132, 136, 142, 1)",
...@@ -688,6 +747,11 @@ onBeforeUnmount(() => { ...@@ -688,6 +747,11 @@ onBeforeUnmount(() => {
padding: 0; padding: 0;
} }
/* 合作限制:下拉项内边距(teleport 到 body,用 :global 生效) */
:global(.coop-select-dropdown .el-select-dropdown__item) {
padding: 0 20px !important;
}
.datasub { .datasub {
width: 1600px; width: 1600px;
height: 460px; height: 460px;
...@@ -742,7 +806,7 @@ onBeforeUnmount(() => { ...@@ -742,7 +806,7 @@ onBeforeUnmount(() => {
height: 412px; height: 412px;
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;
padding: 24px 24px 65px 24px; padding: 0px 24px 64px 24px;
&.left-main--empty { &.left-main--empty {
display: flex; display: flex;
...@@ -770,7 +834,7 @@ onBeforeUnmount(() => { ...@@ -770,7 +834,7 @@ onBeforeUnmount(() => {
.left-main-echarts { .left-main-echarts {
width: 1015px; width: 1015px;
height: 323px; height: 348px;
} }
.source { .source {
...@@ -847,7 +911,7 @@ onBeforeUnmount(() => { ...@@ -847,7 +911,7 @@ onBeforeUnmount(() => {
width: 521px; width: 521px;
height: 412px; height: 412px;
box-sizing: border-box; box-sizing: border-box;
padding: 24px 24px 64px 24px; padding: 0px 24px 64px 24px;
position: relative; position: relative;
&.right-main--empty { &.right-main--empty {
...@@ -874,7 +938,7 @@ onBeforeUnmount(() => { ...@@ -874,7 +938,7 @@ onBeforeUnmount(() => {
.right-main-echarts { .right-main-echarts {
width: 473px; width: 473px;
height: 324px; height: 348px;
} }
.source { .source {
......
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
{{ item.name }} {{ item.name }}
</div> </div>
</div> </div>
<el-select v-model="sortModel" placeholder="发布时间" class="select" :teleported="true" placement="bottom-start" <el-select v-model="sortModel" placeholder="发布时间" class="select" popper-class="coop-select-dropdown"
:teleported="true" placement="bottom-start"
:popper-options="sortPopperOptions" @change="handleSortChange"> :popper-options="sortPopperOptions" @change="handleSortChange">
<template #prefix> <template #prefix>
<img v-if="sortModel !== true" src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image down.png" <img v-if="sortModel !== true" src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image down.png"
...@@ -120,8 +121,8 @@ const getMainDataList = async () => { ...@@ -120,8 +121,8 @@ const getMainDataList = async () => {
date: item.limitDate, date: item.limitDate,
domain: item.limitArea || [], domain: item.limitArea || [],
type: item.limitMeans, type: item.limitMeans,
// 使用默认图片 // 优先使用接口返回的机构 logo(limitOrgLogo),空则回退默认图
img: defaultImg img: item.limitOrgLogo || defaultImg
})); }));
total.value = res.data.totalElements || 0; total.value = res.data.totalElements || 0;
} else { } else {
...@@ -138,10 +139,16 @@ const getMainDataList = async () => { ...@@ -138,10 +139,16 @@ const getMainDataList = async () => {
const router = useRouter(); const router = useRouter();
const handleClick = item => { const handleClick = item => {
const id = item?.id || item?.limitId || item?.ID;
if (!id) return;
window.sessionStorage.setItem(
"cooperationRestrictionsTabName",
item?.limitName || item?.title || item?.name || ""
);
const routeData = router.resolve({ const routeData = router.resolve({
path: "/cooperationRestrictions/detail", name: "CooperationRestrictionsDetail",
query: { query: {
id: item.id id
} }
}); });
window.open(routeData.href, "_blank"); window.open(routeData.href, "_blank");
...@@ -355,6 +362,11 @@ watch(currentPage, () => { ...@@ -355,6 +362,11 @@ watch(currentPage, () => {
padding: 0; padding: 0;
} }
/* 合作限制:下拉项内边距(teleport 到 body,用 :global 生效) */
:global(.coop-select-dropdown .el-select-dropdown__item) {
padding: 0 20px !important;
}
.reslib-page { .reslib-page {
width: 1600px; width: 1600px;
......
...@@ -45,9 +45,9 @@ ...@@ -45,9 +45,9 @@
<AnalysisBox title="相关实体" :showAllBtn="true"> <AnalysisBox title="相关实体" :showAllBtn="true">
<div class="left-bottom-main"> <div class="left-bottom-main">
<div v-for="item in coopRelatedData" :key="item.id" class="main-box" @click="handleClickOnEntity(item)"> <div v-for="item in coopRelatedData" :key="item.id" class="main-box" @click="handleClickOnEntity(item)">
<img :src="item.img || defaultCom" alt="" /> <img :src="item.img || defaultCom" alt="" class="img-left-item" />
<div class="name">{{ item.ENTITYNAME }}</div> <div class="name">{{ item.ENTITYNAME }}</div>
<div class="type">{{ item.type }}</div> <div class="type">{{ item.position }}</div>
</div> </div>
</div> </div>
</AnalysisBox> </AnalysisBox>
...@@ -80,8 +80,15 @@ ...@@ -80,8 +80,15 @@
<span>{{ chineseNumbers[index] }}{{ item.TITLE }} </span> <span>{{ chineseNumbers[index] }}{{ item.TITLE }} </span>
<img src="./assets/打开按钮.png" alt=""> <img src="./assets/打开按钮.png" alt="">
</div> </div>
<div class="clause-item-content"> <!-- contentList:单条按原样式展示;多条则逐条展示并加 1.2.3. 前缀 -->
{{ item.CONTENT }} <div v-if="Array.isArray(item.contentList) && item.contentList.length > 1" class="clause-item-content-list">
<div v-for="(row, i) in item.contentList" :key="i" class="clause-item-content-row">
<span class="row-index">{{ i + 1 }}.</span>
<span class="row-text">{{ row.CONTENT }}</span>
</div>
</div>
<div v-else class="clause-item-content-row">
<span class="row-text">{{ item.contentList?.[0]?.CONTENT || "" }}</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -163,19 +170,34 @@ const getcoopRelatedData = async () => { ...@@ -163,19 +170,34 @@ const getcoopRelatedData = async () => {
limitId: route.query.id limitId: route.query.id
}); });
if (res && res.code === 200) { if (res && res.code === 200) {
coopRelatedData.value = res.data || {}; // 展示图片:优先后端返回的 imageUrl,其次用已有 img 字段,再兜底默认图
coopRelatedData.value = (Array.isArray(res.data) ? res.data : []).map((row) => ({
...row,
img: row?.imageUrl || row?.img || row?.IMAGEURL || row?.image || ""
}));
} else { } else {
coopRelatedData.value = {}; coopRelatedData.value = [];
} }
} catch (error) { } catch (error) {
console.error("获取合作限制相关实体数据失败:", error); console.error("获取合作限制相关实体数据失败:", error);
coopRelatedData.value = {}; coopRelatedData.value = [];
} }
}; };
// 点击跳转关联实体详情 // 点击跳转关联实体详情
const handleClickOnEntity = (item) => { const handleClickOnEntity = (item) => {
if (!item.ENTITYID) return; const entityType = item?.ENTITYTYPE;
const path = `/companyPages/${item.ENTITYID}`; // ENTITYTYPE: 'O' 机构/公司;'P' 人物
if (entityType === "P") {
const personId = item?.PERSONID || item?.ENTITYID || item?.id;
if (!personId) return;
const url = `http://localhost:3000/characterPage?type=2&personId=${encodeURIComponent(personId)}`;
window.open(url, "_blank");
return;
}
// 默认按公司/机构跳转(含 ENTITYTYPE === 'O' 或字段缺失)
const companyId = item?.ENTITYID || item?.id;
if (!companyId) return;
const path = `/companyPages/${companyId}`;
const { href } = router.resolve({ path }); const { href } = router.resolve({ path });
window.open(href, "_blank"); window.open(href, "_blank");
}; };
...@@ -260,11 +282,21 @@ const filteredBackgroundList = computed(() => { ...@@ -260,11 +282,21 @@ const filteredBackgroundList = computed(() => {
const active2 = ref("涉华条款"); const active2 = ref("涉华条款");
const chineseNumbers = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十"]; const chineseNumbers = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十"];
const filteredClauseList = computed(() => { const filteredClauseList = computed(() => {
const list = Array.isArray(limitClauseData.value) ? limitClauseData.value : [];
if (active2.value === "全部条款") { if (active2.value === "全部条款") {
return limitClauseData.value; // 展示全部条款及全部段落
} else { return list.map((item) => ({
return limitClauseData.value.filter(item => item.ISCN === "Y"); ...item,
contentList: Array.isArray(item?.contentList) ? item.contentList : []
}));
} }
// 涉华条款:仅展示 contentList 中 ISCN=Y 的段落;若过滤后为空则不展示该条款
return list
.map((item) => {
const contentList = (Array.isArray(item?.contentList) ? item.contentList : []).filter((row) => row?.ISCN === "Y");
return { ...item, contentList };
})
.filter((item) => Array.isArray(item?.contentList) && item.contentList.length > 0);
}); });
const dataList = ref([ const dataList = ref([
...@@ -660,6 +692,12 @@ const dataList3 = ref([ ...@@ -660,6 +692,12 @@ const dataList3 = ref([
img { img {
width: 24px; width: 24px;
height: 24px; height: 24px;
border-radius: 50%;
display: inline-block;
object-fit: cover;
object-position: center;
} }
.name { .name {
...@@ -923,7 +961,12 @@ const dataList3 = ref([ ...@@ -923,7 +961,12 @@ const dataList3 = ref([
} }
} }
.clause-item-content { .clause-item-content-list {
width: 1022px;
}
/* 每条段落的展示:padding / 描边 / 间距保持与旧版单条 CONTENT 一致 */
.clause-item-content-row {
width: 1022px; width: 1022px;
padding: 12px 24px 12px 54px; padding: 12px 24px 12px 54px;
font-size: 16px; font-size: 16px;
...@@ -933,6 +976,17 @@ const dataList3 = ref([ ...@@ -933,6 +976,17 @@ const dataList3 = ref([
color: rgb(59, 65, 75); color: rgb(59, 65, 75);
border-bottom: 1px solid rgb(234, 236, 238); border-bottom: 1px solid rgb(234, 236, 238);
white-space: pre-line; white-space: pre-line;
display: flex;
gap: 8px;
.row-index {
flex: 0 0 auto;
}
.row-text {
flex: 1;
min-width: 0;
}
} }
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论