提交 c8dfe65c authored 作者: 闫鹏's avatar 闫鹏

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

Yp dev 查看合并请求 !341
流水线 #469 已通过 于阶段
in 6 分 4 秒
...@@ -189,7 +189,8 @@ export function getDeepMiningSelect(data) { ...@@ -189,7 +189,8 @@ export function getDeepMiningSelect(data) {
export function getDeepMiningIndustry(params) { export function getDeepMiningIndustry(params) {
return request({ return request({
method: "GET", method: "GET",
url: `/api/chain/getChainInfo`, // url: `/api/chain/getChainInfo`,
url: `/api/chain/getAllChain`,
params params
}); });
} }
...@@ -204,7 +205,7 @@ export function getDeepMiningIndustry(params) { ...@@ -204,7 +205,7 @@ export function getDeepMiningIndustry(params) {
export function getDeepMiningIndustryFishbone(params) { export function getDeepMiningIndustryFishbone(params) {
return request({ return request({
method: "GET", method: "GET",
url: `/api/chain/getChainFishbone`, url: `/api/chain/getChainNodes`,
params params
}); });
} }
......
差异被折叠。
...@@ -18,7 +18,12 @@ import RelationChart from '@/components/base/RelationChart/index.vue' ...@@ -18,7 +18,12 @@ import RelationChart from '@/components/base/RelationChart/index.vue'
</el-radio-group> </el-radio-group>
</div> </div>
<div class="chart-box"> <div class="chart-box">
<RelationChart @line-click="handleClickLine" @node-click="handleClickNode" :is-vertical-chart="isVerticalChart" :graph-data="graphData" /> <RelationChart
@line-click="handleClickLine"
@node-click="handleClickNode"
:is-vertical-chart="isVerticalChart"
:graph-data="graphData"
/>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
...@@ -149,7 +154,15 @@ const graphData = ref({ ...@@ -149,7 +154,15 @@ const graphData = ref({
{ id: "e2-9", text: "e2-9" } { id: "e2-9", text: "e2-9" }
], ],
lines: [ lines: [
{ from: "a", to: "b", text: '从属', fontColor: 'var(--color-orange-100)', color: 'orange', textOffset_x: -20, lineWidth: 5}, {
from: "a",
to: "b",
text: "从属",
fontColor: "var(--color-orange-100)",
color: "orange",
textOffset_x: -20,
lineWidth: 5
},
{ from: "b", to: "b1" }, { from: "b", to: "b1" },
{ from: "b1", to: "b1-1" }, { from: "b1", to: "b1-1" },
{ from: "b1", to: "b1-2" }, { from: "b1", to: "b1-2" },
...@@ -254,18 +267,15 @@ const graphData = ref({ ...@@ -254,18 +267,15 @@ const graphData = ref({
] ]
}); });
const handleClickNode = (value) => { const handleClickNode = value => {
console.log('value', value); console.log("value", value);
alert('我点击了node-'+ value.text) alert("我点击了node-" + value.text);
} };
const handleClickLine = (value) => {
console.log('value', value);
alert('我点击了line-'+ value.text)
}
const handleClickLine = value => {
console.log("value", value);
alert("我点击了line-" + value.text);
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -670,7 +670,9 @@ ...@@ -670,7 +670,9 @@
</el-col> </el-col>
</template> </template>
<template v-if="activeResourceTab === 'commerce'"> <template v-if="activeResourceTab === 'commerce'">
<div class="commerce-wrapper" :style="{ minHeight: '500px' }">
<listPage /> <listPage />
</div>
</template> </template>
</el-row> </el-row>
</div> </div>
...@@ -1974,7 +1976,7 @@ const handleMediaClick = item => { ...@@ -1974,7 +1976,7 @@ const handleMediaClick = item => {
position: absolute; position: absolute;
width: 240px; width: 240px;
height: 89px; height: 89px;
top: 30px; top: 12px;
right: -24px; right: -24px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
......
...@@ -390,6 +390,9 @@ onMounted(async () => { ...@@ -390,6 +390,9 @@ onMounted(async () => {
background-color: #fff; background-color: #fff;
border-radius: 4px; border-radius: 4px;
box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset; box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset;
&:hover {
box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset !important;
}
} }
:deep(.el-input__inner) { :deep(.el-input__inner) {
...@@ -462,6 +465,11 @@ onMounted(async () => { ...@@ -462,6 +465,11 @@ onMounted(async () => {
height: 24px; height: 24px;
color: rgb(95, 101, 108); color: rgb(95, 101, 108);
} }
:deep(.el-checkbox__label) {
font-size: 16px;
color: #666666;
font-weight: 400;
}
.custom-date-picker { .custom-date-picker {
width: 100%; width: 100%;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<div class="left-top"> <div class="left-top">
<AnalysisBox title="基本信息" :showAllBtn="false"> <AnalysisBox title="基本信息" :showAllBtn="false">
<div class="left-top-main"> <div class="left-top-main">
<div class="left-top-main-title">{{ CCLInfo.description }}</div> <div class="left-top-main-title">{{ CCLInfo.name + CCLInfo.description }}</div>
<div class="left-top-main-content"> <div class="left-top-main-content">
<div class="content-item"> <div class="content-item">
<span class="label">法律依据:</span> <span class="label">法律依据:</span>
......
...@@ -7,8 +7,14 @@ ...@@ -7,8 +7,14 @@
<template> <template>
<div class="sanctions-overview"> <div class="sanctions-overview">
<div class="side-nav"> <div class="side-nav">
<div v-for="(item, index) in activeTab" :key="index" class="tab-item" :class="{'active': index === activeIndex}" @click="activeIndex = index"> <div
{{item}} v-for="(item, index) in activeTab"
:key="index"
class="tab-item"
:class="{ active: index === activeIndex }"
@click="activeIndex = index"
>
{{ item }}
<span v-if="index === activeIndex" class="arrow"></span> <span v-if="index === activeIndex" class="arrow"></span>
</div> </div>
</div> </div>
...@@ -20,23 +26,16 @@ ...@@ -20,23 +26,16 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref } from "vue";
import introductionPage from "./components/introductionPage/index.vue" import introductionPage from "./components/introductionPage/index.vue";
import listPage from "./components/listPage/index.vue" import listPage from "./components/listPage/index.vue";
const activeTab = ref(["CCL清单简介", "CCL清单列表"])
const activeIndex = ref(0)
const activeTab = ref(["CMC清单简介", "CMC清单列表"]);
const activeIndex = ref(0);
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
*{ .sanctions-overview {
margin: 0;
padding: 0;
}
.sanctions-overview{
width: 1601px; width: 1601px;
margin: 0 auto; margin: 0 auto;
position: relative; position: relative;
......
...@@ -55,21 +55,42 @@ import icon2Active from "../assets/icons/icon2_active.png"; ...@@ -55,21 +55,42 @@ import icon2Active from "../assets/icons/icon2_active.png";
import icon3 from "../assets/icons/icon3.png"; import icon3 from "../assets/icons/icon3.png";
import icon3Active from "../assets/icons/icon3_active.png"; import icon3Active from "../assets/icons/icon3_active.png";
import { getCCLInfo } from "@/api/exportControlV2.0.js";
const route = useRoute(); const route = useRoute();
const sanTypeId = ref(""); const sanTypeId = ref("");
onMounted(() => { onMounted(() => {
// 获取路由参数sanTypeId // 获取路由参数sanTypeId
sanTypeId.value = route.query.sanTypeId; sanTypeId.value = route.query.sanTypeId;
console.log("CommercialControlList 页面接收到的 sanTypeId:", sanTypeId.value); console.log("CommercialControlList 页面接收到的 sanTypeId:", sanTypeId.value);
getCCLInfoFn();
}); });
const headerTitle = ref({ const headerTitle = ref({
img: title, img: "",
title: "商业管制清单(CCL)", title: "",
titleEn: "Commercial Control List", titleEn: "",
department: "美国商务部工业与安全局" department: ""
}); });
const getCCLInfoFn = async () => {
try {
const res = await getCCLInfo(route.query.sanTypeId || 13);
if (res && res.code === 200) {
const info = res.data;
headerTitle.value = {
img: info.orgLogoUrl,
title: `${info.name}${info.shortName})`,
titleEn: info.originalName,
department: info.orgName
};
console.log("getCCLInfoFn", info);
}
} catch (error) {
console.error("获取商业管制清单基本信息失败:", error);
}
};
const activeIndex = ref(0); const activeIndex = ref(0);
const headerNavList = ref([ const headerNavList = ref([
......
...@@ -110,7 +110,9 @@ ...@@ -110,7 +110,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入实体清单的中国实体数量变化趋势,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入SDN清单的中国实体数量变化趋势,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -169,7 +171,9 @@ ...@@ -169,7 +171,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入实体清单的中国实体领域分布情况,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -208,7 +212,9 @@ ...@@ -208,7 +212,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入实体清单的中国实体领域分布情况,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -240,7 +246,9 @@ ...@@ -240,7 +246,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入实体清单的中国实体类型分布情况,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入SDN清单的中国实体类型分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
<div class="right"> <div class="right">
<AnalysisBox title="投融资限制举措关系图"> <AnalysisBox title="投融资限制举措关系图">
<div class="right-main"> <div class="right-main">
<div class="relation-empty" v-if="selectedSanctionIds.length == 0"> <div class="relation-empty" v-if="emptyOfRelation">
<el-empty :image="emptyImg" :image-size="200"> <el-empty :image="emptyImg" :image-size="200">
<template #description> <template #description>
<div class="empty">请在左侧勾选多次投融资限制制裁后点击“开始分析”查看结果</div> <div class="empty">请在左侧勾选多次投融资限制制裁后点击“开始分析”查看结果</div>
...@@ -139,7 +139,24 @@ ...@@ -139,7 +139,24 @@
<div class="icon2"></div> <div class="icon2"></div>
</div> </div>
</div> </div>
<!-- <div class="relation-content">
<RelationChart :is-vertical-chart="true" :graph-data="graphData" /> <RelationChart :is-vertical-chart="true" :graph-data="graphData" />
</div> -->
<div class="relation-charts-container">
<div v-for="(graphData, index) in graphDataList" :key="index" class="single-relation-chart-wrapper">
<!-- 可选:显示当前小图的标题,例如制裁名称 -->
<!-- <div class="chart-title" v-if="graphData.originalItem?.vertex?.name">
{{ graphData.originalItem.vertex.name }}
</div> -->
<div class="relation-content-item">
<RelationChart :is-vertical-chart="true" :graph-data="graphData" />
</div>
</div>
<!-- 空状态提示 -->
<div v-if="graphDataList.length === 0" class="empty-chart-tip">暂无关联详情数据</div>
</div>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
...@@ -383,13 +400,16 @@ const fetchRecordRelation = async () => { ...@@ -383,13 +400,16 @@ const fetchRecordRelation = async () => {
recordRelation.value = { noRelationVertices: [], relationVoList: [] }; recordRelation.value = { noRelationVertices: [], relationVoList: [] };
} }
}; };
const emptyOfRelation = computed(
() => recordRelation.value.noRelationVertices.length == 0 || recordRelation.value.relationVoList.length == 0
);
const vertexInfo = ref({}); const vertexInfo = ref({});
const curNode = ref({}); const curNode = ref({});
const curLink = ref({}); const curLink = ref({});
const nodeVisible = ref(false); const nodeVisible = ref(false);
const relationVisible = ref(false); const relationVisible = ref(false);
const tipsInfo = ref(""); const tipsInfo = ref("");
const graphData = ref({}); const graphDataList = ref([]);
const getTipsInfo = (relationType, reason) => { const getTipsInfo = (relationType, reason) => {
switch (relationType) { switch (relationType) {
case "继承": case "继承":
...@@ -400,6 +420,8 @@ const getTipsInfo = (relationType, reason) => { ...@@ -400,6 +420,8 @@ const getTipsInfo = (relationType, reason) => {
return `${dayjs(curLink.value.data.originInfo.fromVertex.date).format("YYYY年MM月DD日")}-SDN清单更新与${dayjs(curLink.value.data.originInfo.toVertex.date).format("YYYY年MM月DD日")}-SDN清单更新存在相同${reason},属于相似关系。`; return `${dayjs(curLink.value.data.originInfo.fromVertex.date).format("YYYY年MM月DD日")}-SDN清单更新与${dayjs(curLink.value.data.originInfo.toVertex.date).format("YYYY年MM月DD日")}-SDN清单更新存在相同${reason},属于相似关系。`;
} }
}; };
// 在 constrainedAssociation.vue 的 script setup 中
const handleClickNode = node => { const handleClickNode = node => {
console.log("节点点击", node); console.log("节点点击", node);
if (node.dataType == "node") { if (node.dataType == "node") {
...@@ -418,24 +440,125 @@ const handleClickNode = node => { ...@@ -418,24 +440,125 @@ const handleClickNode = node => {
relationVisible.value = true; relationVisible.value = true;
curLink.value = node; curLink.value = node;
const relationType = node.data.relationType; const relationType = node.data.relationType;
// 继承 - 2025年10月1日-SDN清单更新依托于2024年2月08日-SDN清单更新,两次制裁存在继承关系。
// 冲突 - 2025年2月19日-SDN清单更新中制裁的实体在2024年2月08日-SDN清单更新中被移除,属于冲突关系。
// 相似 - 2025年2月19日-SDN清单更新与2024年2月08日-SDN清单更新存在相同制裁原因,属于相似关系。
// 相似 - 2025年2月19日-SDN清单更新与2024年2月08日-SDN清单更新存在同领域制裁实体,属于相似关系。
// 相似 - 2025年2月19日-SDN清单更新与2024年2月08日-SDN清单更新存在相同依托文件,属于相似关系。
getEdgeInfo(node.data.edgeInfo.key).then(res => { // 获取边详情数据
if (!!res) { getEdgeInfo(node.data.edgeInfo.key)
// recordRelation.value = res; .then(res => {
if (!!res && Array.isArray(res)) {
console.log("制裁之间的关系 =>", res); console.log("制裁之间的关系 =>", res);
// 【核心修改】遍历 res,为每一项生成独立的图表数据
const list = [];
res.forEach((item, index) => {
const vertex = item.vertex;
if (!vertex || !vertex.id) return;
const nodes = [];
const lines = [];
const nodeMap = new Map();
// 辅助函数:添加节点
const addNode = (id, text, type = "vertex") => {
if (nodeMap.has(id)) return;
const newNode = {
id: id,
text: text,
// 样式:顶点用主题色,细节用白色
color: type === "vertex" ? "var(--color-primary-50)" : "#ffffff",
fontColor: type === "vertex" ? "var(--text-primary-90-color)" : "#333333",
customFontSize: type === "vertex" ? "14px" : "12px"
};
nodes.push(newNode);
nodeMap.set(id, newNode);
};
// 辅助函数:添加连线
const addLine = (fromId, toId, relationText) => {
lines.push({
from: fromId,
to: toId,
text: relationText,
color: "var(--color-primary-50)",
fontColor: "#666"
});
};
// 1. 添加出发点 (Vertex)
// addNode(vertex.id, vertex.name, "vertex");
// 1. 添加出发点 (Vertex)
// 【修改点】:根据 originInfo 中的 fromVertex 或 toVertex 动态生成名称
let vertexName = vertex.name; // 默认 fallback
// 尝试从 curLink (即 node) 中获取 originInfo
const originInfo = node.data?.originInfo;
if (originInfo) {
// 判断当前 vertex.id 是 from 还是 to,从而决定取哪个日期
// 通常 item.vertex 对应的是边的起点或终点之一,这里假设 item.vertex 就是我们要展示的核心节点
// 如果业务逻辑中 item.vertex 始终对应 fromVertex 或 toVertex 中的一个,我们可以这样判断:
let sourceDate = null;
if (originInfo.fromVertex && originInfo.fromVertex.id === vertex.id) {
sourceDate = originInfo.fromVertex.date;
} else if (originInfo.toVertex && originInfo.toVertex.id === vertex.id) {
sourceDate = originInfo.toVertex.date;
}
// 如果找到了对应的日期,则格式化;否则保持原名或使用默认逻辑
if (sourceDate) {
vertexName = dayjs(sourceDate).format("YYYY年MM月DD日") + " SDN清单更新";
}
}
addNode(vertex.id, vertexName, "vertex");
// 2. 处理 edgeReasonList -> reasonDetail
if (item.edgeReasonList && item.edgeReasonList.length > 0) {
item.edgeReasonList.forEach(reasonItem => {
const relationName = reasonItem.reason; // 例如: "依托文件"
if (reasonItem.reasonDetail && reasonItem.reasonDetail.length > 0) {
reasonItem.reasonDetail.forEach(detailItem => {
// 使用 detailItem.name 作为唯一 ID
// 注意:在这个独立的小图中,ID 只要不重复即可。
// 如果不同项之间有相同的 detailItem.name,它们在不同图中是隔离的,所以没问题。
const detailId = detailItem.name;
addNode(detailId, detailItem.name, "detail");
addLine(vertex.id, detailId, relationName);
});
}
});
}
// 只有当有连线时才加入列表,或者即使只有顶点也加入(视需求而定)
if (nodes.length > 0) {
list.push({
rootId: vertex.id,
nodes: nodes,
lines: lines,
// 可以保留原始数据用于调试或额外展示
originalItem: item
});
}
});
graphDataList.value = list;
// 处理提示文案 (取第一个或根据业务逻辑组合)
let reason = ""; let reason = "";
if (relationType == "相似") { if (relationType == "相似" && res[0]?.edgeReasonList?.[0]?.reason) {
reason = res[0].edgeReasonList[0].reason; reason = res[0].edgeReasonList[0].reason;
} }
tipsInfo.value = getTipsInfo(relationType, reason); tipsInfo.value = getTipsInfo(relationType, reason);
} else { } else {
// recordRelation.value = { noRelationVertices: [], relationVoList: [] }; graphDataList.value = [];
} }
})
.catch(err => {
console.error("获取边信息失败", err);
graphDataList.value = [];
}); });
} }
}; };
...@@ -481,10 +604,6 @@ const formatChangeSummary = (addList, delList) => { ...@@ -481,10 +604,6 @@ const formatChangeSummary = (addList, delList) => {
return `${item.value}${unit}${noun}`; return `${item.value}${unit}${noun}`;
}); });
// 拼接:移除 + item1 + , + item2 ...
// 注意:题目要求“删除”,但之前代码用的是“移除”,这里统一使用“移除”或“删除”。
// 根据题目描述“展示样本为:新增12个实体,3名个人,移除1个实体”,这里使用“移除”更贴切上下文,
// 如果必须用“删除”,请将下面的 '移除' 改为 '删除'。
parts.push(`移除${delItems.join(",")}`); parts.push(`移除${delItems.join(",")}`);
} }
...@@ -708,6 +827,57 @@ onMounted(() => { ...@@ -708,6 +827,57 @@ onMounted(() => {
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
border-top: 1px solid rgb(238, 238, 238); border-top: 1px solid rgb(238, 238, 238);
// 【新增】关系图容器样式
.relation-charts-container {
display: flex;
flex-direction: column;
gap: 20px;
height: 400px;
overflow-y: auto;
padding-right: 10px; // 给滚动条留空间
// 自定义滚动条样式
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 3px;
}
}
.single-relation-chart-wrapper {
border: 1px solid #eee;
border-radius: 8px;
padding: 10px;
background-color: #fafafa;
height: 400px;
.chart-title {
font-size: 14px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
padding-left: 5px;
border-left: 3px solid var(--color-primary-50);
}
.relation-content-item {
height: 400px; // 每个小图的高度,可根据需要调整
// width: 100%;
// 确保 RelationChart 内部能正确填充
:deep(.relation-graph) {
width: 100%;
height: 100%;
}
}
}
.empty-chart-tip {
text-align: center;
color: #999;
padding: 20px;
}
.hintWrap { .hintWrap {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -753,6 +923,10 @@ onMounted(() => { ...@@ -753,6 +923,10 @@ onMounted(() => {
} }
} }
} }
.relation-content {
height: 400px;
width: 100%;
}
.info-btn { .info-btn {
position: absolute; position: absolute;
top: 20px; top: 20px;
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
<div class="right"> <div class="right">
<AnalysisBox title="投融资限制举措关系图"> <AnalysisBox title="投融资限制举措关系图">
<div class="right-main"> <div class="right-main">
<div class="relation-empty" v-if="selectedSanctionIds.length == 0"> <div class="relation-empty" v-if="emptyOfRelation">
<el-empty :image="emptyImg" :image-size="200"> <el-empty :image="emptyImg" :image-size="200">
<template #description> <template #description>
<div class="empty">请在左侧勾选多次投融资限制制裁后点击“开始分析”查看结果</div> <div class="empty">请在左侧勾选多次投融资限制制裁后点击“开始分析”查看结果</div>
...@@ -145,12 +145,16 @@ ...@@ -145,12 +145,16 @@
<div class="relation-charts-container"> <div class="relation-charts-container">
<div v-for="(graphData, index) in graphDataList" :key="index" class="single-relation-chart-wrapper"> <div v-for="(graphData, index) in graphDataList" :key="index" class="single-relation-chart-wrapper">
<!-- 可选:显示当前小图的标题,例如制裁名称 --> <!-- 可选:显示当前小图的标题,例如制裁名称 -->
<div class="chart-title" v-if="graphData.originalItem?.vertex?.name"> <!-- <div class="chart-title" v-if="graphData.originalItem?.vertex?.name">
{{ graphData.originalItem.vertex.name }} {{ graphData.originalItem.vertex.name }}
</div> </div> -->
<div class="relation-content-item"> <div class="relation-content-item">
<RelationChart :is-vertical-chart="true" :graph-data="graphData" /> <RelationChart
:is-vertical-chart="true"
:graph-data="graphData"
:is-reversed="graphData.isReversed"
/>
</div> </div>
</div> </div>
...@@ -400,6 +404,9 @@ const fetchRecordRelation = async () => { ...@@ -400,6 +404,9 @@ const fetchRecordRelation = async () => {
recordRelation.value = { noRelationVertices: [], relationVoList: [] }; recordRelation.value = { noRelationVertices: [], relationVoList: [] };
} }
}; };
const emptyOfRelation = computed(
() => recordRelation.value.noRelationVertices.length == 0 || recordRelation.value.relationVoList.length == 0
);
const vertexInfo = ref({}); const vertexInfo = ref({});
const curNode = ref({}); const curNode = ref({});
const curLink = ref({}); const curLink = ref({});
...@@ -434,6 +441,11 @@ const handleClickNode = node => { ...@@ -434,6 +441,11 @@ const handleClickNode = node => {
} }
}); });
} else { } else {
handleLink(node);
}
};
const handleLink = node => {
relationVisible.value = true; relationVisible.value = true;
curLink.value = node; curLink.value = node;
const relationType = node.data.relationType; const relationType = node.data.relationType;
...@@ -456,15 +468,86 @@ const handleClickNode = node => { ...@@ -456,15 +468,86 @@ const handleClickNode = node => {
const nodeMap = new Map(); const nodeMap = new Map();
// 辅助函数:添加节点 // 辅助函数:添加节点
const addNode = (id, text, type = "vertex") => { const addNode = (id, text, type = "vertex", highlight = false) => {
if (nodeMap.has(id)) return; if (nodeMap.has(id)) return;
// 【修改】根据 type 定义不同的样式
let nodeStyle = {};
if (type === "vertex") {
nodeStyle = {
color: "rgb(185, 220, 255)", // 背景色
fontColor: "rgb(5, 95, 194)", // 文字颜色
customFontSize: "16px", // 文字大小
fontWeight: 700, // 加粗
// width: "120px", // 固定宽度,防止长文本换行难看
// height: "40px", // 固定高度
borderRadius: "20px", // 圆角
borderColor: "rgb(185, 220, 255)"
// border: "1px solid rgb(185, 220, 255)"
};
} else {
// 细节节点样式
// nodeStyle = {
// color: "#ffffff",
// fontColor: "#333333",
// customFontSize: "12px",
// // width: "100px",
// // height: "30px",
// borderRadius: "15px",
// borderColor: "rgb(230, 231, 232)"
// };
// 细节节点样式
if (highlight) {
// 【核心逻辑】根据 relationType 设置高亮样式
if (relationType === "冲突") {
nodeStyle = {
color: "rgba(255, 241, 240, 1)", // 背景
borderColor: "rgb(206, 79, 81)", // 边框
fontColor: "rgb(206, 79, 81)", // 字体
fontWeight: 700, // 加粗
customFontSize: "12px",
borderRadius: "15px"
};
} else if (relationType === "相似" || relationType === "继承") {
// 相似和继承使用相同的蓝色系高亮
nodeStyle = {
color: "rgb(185, 220, 255)", // 背景
borderColor: "rgb(5, 95, 194)", // 边框
fontColor: "rgb(5, 95, 194)", // 字体
fontWeight: 700, // 加粗
customFontSize: "12px",
borderRadius: "15px"
};
} else {
// 默认高亮样式(以防万一)
nodeStyle = {
color: "#e6f7ff",
borderColor: "#1890ff",
fontColor: "#1890ff",
fontWeight: 700,
customFontSize: "12px",
borderRadius: "15px"
};
}
} else {
// 非高亮细节节点默认样式
nodeStyle = {
color: "#ffffff",
borderColor: "rgb(230, 231, 232)",
fontColor: "#333333",
customFontSize: "12px",
borderRadius: "15px",
fontWeight: 400
};
}
}
const newNode = { const newNode = {
id: id, id: id,
text: text, text: text,
// 样式:顶点用主题色,细节用白色 // color: type === "vertex" ? "var(--color-primary-50)" : "#ffffff",
color: type === "vertex" ? "var(--color-primary-50)" : "#ffffff", // fontColor: type === "vertex" ? "var(--text-primary-90-color)" : "#333333",
fontColor: type === "vertex" ? "var(--text-primary-90-color)" : "#333333", // customFontSize: type === "vertex" ? "14px" : "12px",
customFontSize: type === "vertex" ? "14px" : "12px" ...nodeStyle
}; };
nodes.push(newNode); nodes.push(newNode);
nodeMap.set(id, newNode); nodeMap.set(id, newNode);
...@@ -482,7 +565,33 @@ const handleClickNode = node => { ...@@ -482,7 +565,33 @@ const handleClickNode = node => {
}; };
// 1. 添加出发点 (Vertex) // 1. 添加出发点 (Vertex)
addNode(vertex.id, vertex.name, "vertex"); // addNode(vertex.id, vertex.name, "vertex");
// 1. 添加出发点 (Vertex)
// 【修改点】:根据 originInfo 中的 fromVertex 或 toVertex 动态生成名称
let vertexName = vertex.name; // 默认 fallback
// 尝试从 curLink (即 node) 中获取 originInfo
const originInfo = node.data?.originInfo;
if (originInfo) {
// 判断当前 vertex.id 是 from 还是 to,从而决定取哪个日期
// 通常 item.vertex 对应的是边的起点或终点之一,这里假设 item.vertex 就是我们要展示的核心节点
// 如果业务逻辑中 item.vertex 始终对应 fromVertex 或 toVertex 中的一个,我们可以这样判断:
let sourceDate = null;
if (originInfo.fromVertex && originInfo.fromVertex.id === vertex.id) {
sourceDate = originInfo.fromVertex.date;
} else if (originInfo.toVertex && originInfo.toVertex.id === vertex.id) {
sourceDate = originInfo.toVertex.date;
}
// 如果找到了对应的日期,则格式化;否则保持原名或使用默认逻辑
if (sourceDate) {
vertexName = dayjs(sourceDate).format("YYYY年MM月DD日") + " SDN清单更新";
}
}
addNode(vertex.id, vertexName, "vertex");
// 2. 处理 edgeReasonList -> reasonDetail // 2. 处理 edgeReasonList -> reasonDetail
if (item.edgeReasonList && item.edgeReasonList.length > 0) { if (item.edgeReasonList && item.edgeReasonList.length > 0) {
...@@ -496,7 +605,12 @@ const handleClickNode = node => { ...@@ -496,7 +605,12 @@ const handleClickNode = node => {
// 如果不同项之间有相同的 detailItem.name,它们在不同图中是隔离的,所以没问题。 // 如果不同项之间有相同的 detailItem.name,它们在不同图中是隔离的,所以没问题。
const detailId = detailItem.name; const detailId = detailItem.name;
addNode(detailId, detailItem.name, "detail"); addNode(
detailId,
detailItem.name,
"detail",
addNode(detailId, detailItem.name, "detail", !!detailItem.highlight)
);
addLine(vertex.id, detailId, relationName); addLine(vertex.id, detailId, relationName);
}); });
} }
...@@ -510,7 +624,8 @@ const handleClickNode = node => { ...@@ -510,7 +624,8 @@ const handleClickNode = node => {
nodes: nodes, nodes: nodes,
lines: lines, lines: lines,
// 可以保留原始数据用于调试或额外展示 // 可以保留原始数据用于调试或额外展示
originalItem: item originalItem: item,
isReversed: index % 2 !== 0
}); });
} }
}); });
...@@ -531,7 +646,6 @@ const handleClickNode = node => { ...@@ -531,7 +646,6 @@ const handleClickNode = node => {
console.error("获取边信息失败", err); console.error("获取边信息失败", err);
graphDataList.value = []; graphDataList.value = [];
}); });
}
}; };
// 【新增/修改】格式化变动 summary 的函数 // 【新增/修改】格式化变动 summary 的函数
...@@ -575,10 +689,6 @@ const formatChangeSummary = (addList, delList) => { ...@@ -575,10 +689,6 @@ const formatChangeSummary = (addList, delList) => {
return `${item.value}${unit}${noun}`; return `${item.value}${unit}${noun}`;
}); });
// 拼接:移除 + item1 + , + item2 ...
// 注意:题目要求“删除”,但之前代码用的是“移除”,这里统一使用“移除”或“删除”。
// 根据题目描述“展示样本为:新增12个实体,3名个人,移除1个实体”,这里使用“移除”更贴切上下文,
// 如果必须用“删除”,请将下面的 '移除' 改为 '删除'。
parts.push(`移除${delItems.join(",")}`); parts.push(`移除${delItems.join(",")}`);
} }
...@@ -805,10 +915,10 @@ onMounted(() => { ...@@ -805,10 +915,10 @@ onMounted(() => {
// 【新增】关系图容器样式 // 【新增】关系图容器样式
.relation-charts-container { .relation-charts-container {
display: flex; display: flex;
flex-direction: column; flex-direction: row;
gap: 20px; gap: 20px;
max-height: 60vh; // 限制最大高度,超出滚动 height: 400px;
overflow-y: auto; overflow-x: auto;
padding-right: 10px; // 给滚动条留空间 padding-right: 10px; // 给滚动条留空间
// 自定义滚动条样式 // 自定义滚动条样式
...@@ -822,11 +932,14 @@ onMounted(() => { ...@@ -822,11 +932,14 @@ onMounted(() => {
} }
.single-relation-chart-wrapper { .single-relation-chart-wrapper {
border: 1px solid #eee; flex: 1;
border-radius: 8px; min-width: 400px; /* 保证每个图表有最小宽度 */
// border: 1px solid #eee;
// border-radius: 8px;
padding: 10px; padding: 10px;
background-color: #fafafa; // background-color: #fafafa;
display: flex;
flex-direction: column;
.chart-title { .chart-title {
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
...@@ -837,8 +950,10 @@ onMounted(() => { ...@@ -837,8 +950,10 @@ onMounted(() => {
} }
.relation-content-item { .relation-content-item {
height: 200px; // 每个小图的高度,可根据需要调整 flex: 1;
position: relative;
width: 100%; width: 100%;
height: 100%;
// 确保 RelationChart 内部能正确填充 // 确保 RelationChart 内部能正确填充
:deep(.relation-graph) { :deep(.relation-graph) {
......
...@@ -155,15 +155,8 @@ const getTagStyle = tag => { ...@@ -155,15 +155,8 @@ const getTagStyle = tag => {
// 跳转公司详情页 // 跳转公司详情页
const handleCompClick = item => { const handleCompClick = item => {
console.log("item", item); console.log("item", item);
window.sessionStorage.setItem("curTabName", item.entityNameZh || item.entityName); window.sessionStorage.setItem("curTabName", item.name || item.orgName);
gotoCompanyPages(item.id); gotoCompanyPages(item.id);
// const route = router.resolve({
// name: "companyPages",
// params: {
// id: item.id
// }
// });
// window.open(route.href, "_blank");
}; };
</script> </script>
......
...@@ -253,7 +253,7 @@ const handleCompClick = item => { ...@@ -253,7 +253,7 @@ const handleCompClick = item => {
// } // }
// }); // });
// window.open(route.href, "_blank"); // window.open(route.href, "_blank");
gotoCompanyPages(item.entityId); gotoCompanyPages(item.id);
}; };
const searchKeyword = ref(""); const searchKeyword = ref("");
......
...@@ -175,7 +175,9 @@ ...@@ -175,7 +175,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">美国商务部发布实体清单的频次,数据来源:美国商务部官网</div> <div class="data-origin-text">
美国商务部发布实体清单的频次,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -210,7 +212,7 @@ ...@@ -210,7 +212,7 @@
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text"> <div class="data-origin-text">
美国商务部发布商业管制清单的频次,数据来源:美国商务部官网 美国商务部发布商业管制清单的频次,数据来源:美国财政部海外资产管理办公室官网
</div> </div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
...@@ -260,7 +262,9 @@ ...@@ -260,7 +262,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入实体清单的中国实体领域分布情况,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -285,7 +289,9 @@ ...@@ -285,7 +289,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入实体清单的中国实体数量变化趋势,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入SDN清单的中国实体数量变化趋势,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -306,7 +312,7 @@ ...@@ -306,7 +312,7 @@
</div> </div>
</div> </div>
<template v-if="activeResourceTab === 'entity'"> <template v-if="activeResourceTab === 'entity'">
<el-col :span="8" style="padding: 0"> <el-col :span="8" style="padding-left: 0">
<custom-container title="历次制裁过程" :titleIcon="listIcon" height="845px"> <custom-container title="历次制裁过程" :titleIcon="listIcon" height="845px">
<template #default> <template #default>
<div class="box4"> <div class="box4">
...@@ -341,7 +347,7 @@ ...@@ -341,7 +347,7 @@
</template> </template>
</custom-container> </custom-container>
</el-col> </el-col>
<el-col :span="16" style="padding: 0"> <el-col :span="16" style="padding-right: 0">
<custom-container title="制裁实体清单" :titleIcon="entityIcon" height="845px"> <custom-container title="制裁实体清单" :titleIcon="entityIcon" height="845px">
<template #header-right> <template #header-right>
<div class="box5-header-right">{{ total }}家实体</div> <div class="box5-header-right">{{ total }}家实体</div>
...@@ -1706,15 +1712,6 @@ const handleMediaClick = item => { ...@@ -1706,15 +1712,6 @@ const handleMediaClick = item => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
// * {
// margin: 0;
// padding: 0;
// }
:deep(.el-input__wrapper) {
// box-shadow: none;
}
.home-header { .home-header {
height: 64px; height: 64px;
background: url("@/assets/images/nav-bg.png"); background: url("@/assets/images/nav-bg.png");
...@@ -1783,7 +1780,7 @@ const handleMediaClick = item => { ...@@ -1783,7 +1780,7 @@ const handleMediaClick = item => {
position: absolute; position: absolute;
width: 240px; width: 240px;
height: 89px; height: 89px;
top: 30px; top: 12px;
right: -24px; right: -24px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -3095,7 +3092,7 @@ const handleMediaClick = item => { ...@@ -3095,7 +3092,7 @@ const handleMediaClick = item => {
align-items: center; align-items: center;
margin-top: 6px; margin-top: 6px;
margin-bottom: 36px; margin-bottom: 36px;
padding-left: 10px; // padding-left: 10px;
.resource-tab-item { .resource-tab-item {
margin-right: 12px; margin-right: 12px;
...@@ -3164,7 +3161,7 @@ const handleMediaClick = item => { ...@@ -3164,7 +3161,7 @@ const handleMediaClick = item => {
} }
.text { .text {
font-size: 20px; font-size: 16px;
font-weight: 700; font-weight: 700;
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
line-height: 26px; line-height: 26px;
......
...@@ -59,7 +59,9 @@ ...@@ -59,7 +59,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入本次实体清单的中国实体领域分布情况,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入本次SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -109,7 +111,9 @@ ...@@ -109,7 +111,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入本次实体清单的中国实体类型分布情况,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入本次SDN清单的中国实体类型分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -150,7 +154,9 @@ ...@@ -150,7 +154,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入本次实体清单的实体国家地区分布情况,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入本次SDN清单的实体国家地区分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -194,7 +200,9 @@ ...@@ -194,7 +200,9 @@
<div class="data-origin-icon"> <div class="data-origin-icon">
<img :src="tipsIcon" alt="" /> <img :src="tipsIcon" alt="" />
</div> </div>
<div class="data-origin-text">进入本次实体清单的中国实体各省分布情况,数据来源:美国商务部官网</div> <div class="data-origin-text">
进入本次SDN清单的中国实体各省分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -845,11 +853,6 @@ onMounted(() => { ...@@ -845,11 +853,6 @@ onMounted(() => {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.data-statistics { .data-statistics {
width: 1601px; width: 1601px;
margin: 0 auto; margin: 0 auto;
......
...@@ -540,11 +540,6 @@ onMounted(async () => { ...@@ -540,11 +540,6 @@ onMounted(async () => {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.deepMiningChartmode { .deepMiningChartmode {
height: calc(100vh - 220px) !important; height: calc(100vh - 220px) !important;
// overflow: hidden; // overflow: hidden;
......
...@@ -990,11 +990,6 @@ onMounted(async () => { ...@@ -990,11 +990,6 @@ onMounted(async () => {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.industrial-impact { .industrial-impact {
width: 100%; width: 100%;
padding-top: 16px; padding-top: 16px;
......
...@@ -1118,11 +1118,6 @@ onBeforeUnmount(() => { ...@@ -1118,11 +1118,6 @@ onBeforeUnmount(() => {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.industrial-impact { .industrial-impact {
width: 100%; width: 100%;
padding-top: 16px; padding-top: 16px;
......
...@@ -29,10 +29,6 @@ const activeIndex = ref(0); ...@@ -29,10 +29,6 @@ const activeIndex = ref(0);
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.impact-analysis { .impact-analysis {
width: 1601px; width: 1601px;
margin: 0 auto; margin: 0 auto;
......
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
</div> </div>
</div> </div>
<div class="right" v-loading="isLoading"> <div class="right" v-loading="isLoading">
<AnalysisBox title="制裁清单" :showAllBtn="false"> <AnalysisBox title="制裁清单" :showAllBtn="false" style="height: auto">
<div class="right-title"> <div class="right-title">
<div class="filter-row"> <div class="filter-row">
<div class="filter-left"> <div class="filter-left">
...@@ -234,7 +234,31 @@ ...@@ -234,7 +234,31 @@
</div> </div>
</AnalysisBox> </AnalysisBox>
<div :style="{ height: '20px' }"></div> <div :style="{ height: '20px' }"></div>
<AnalysisBox title="制裁原因及相关历史制裁" :showAllBtn="false"></AnalysisBox> <AnalysisBox title="制裁原因及相关历史制裁" :showAllBtn="false" style="height: auto">
<div class="reason-history">
<div class="reason-history-item" v-for="(item, index) in reasonHistoryList" :key="item.id">
<div class="item-header">
<div class="item-header-title">
<div class="item-header-title-idx">{{ index + 1 }}</div>
<div class="item-header-title-text">{{ item.sanReason }}</div>
</div>
<div class="item-header-domain">
<AreaTag v-for="(domain, index) in item.techDomains" :key="index" :tagName="domain" />
</div>
</div>
<div class="item-content" v-for="(record, index) in item.relateSanRecords" :key="index">
<div class="item-content-record">
<div class="item-content-record-header">
{{ record.postDate + " " + record.title }}
</div>
<div class="item-content-record-content">
{{ record.content }}
</div>
</div>
</div>
</div>
</div>
</AnalysisBox>
</div> </div>
</div> </div>
<!-- 50%规则子企业弹框 --> <!-- 50%规则子企业弹框 -->
...@@ -252,7 +276,6 @@ import { ref, defineProps, computed, onMounted, watch } from "vue"; ...@@ -252,7 +276,6 @@ import { ref, defineProps, computed, onMounted, watch } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import AreaTag from "@/components/base/AreaTag/index.vue"; import AreaTag from "@/components/base/AreaTag/index.vue";
import { DArrowRight, Search } from "@element-plus/icons-vue";
import { debounce } from "lodash"; import { debounce } from "lodash";
import title from "../../assets/title.png"; import title from "../../assets/title.png";
import defaultTitle from "../../assets/default-icon1.png"; import defaultTitle from "../../assets/default-icon1.png";
...@@ -265,6 +288,7 @@ import { ...@@ -265,6 +288,7 @@ import {
} from "@/api/exportControlV2.0"; } from "@/api/exportControlV2.0";
import { getRelateNews } from "@/api/finance"; import { getRelateNews } from "@/api/finance";
import RuleSubsidiaryDialog from "../../../entityList/components/sanctionsOverview/components/listPage/RuleSubsidiaryDialog.vue"; import RuleSubsidiaryDialog from "../../../entityList/components/sanctionsOverview/components/listPage/RuleSubsidiaryDialog.vue";
import { getReasonAndSan } from "@/api/finance";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useGotoCompanyPages } from "@/router/modules/company"; import { useGotoCompanyPages } from "@/router/modules/company";
...@@ -365,7 +389,7 @@ const getSanctionOverviewList = async () => { ...@@ -365,7 +389,7 @@ const getSanctionOverviewList = async () => {
// 单次制裁-制裁概况-制裁背景 // 单次制裁-制裁概况-制裁背景
const timelinePage = ref(1); const timelinePage = ref(1);
const timelinePageSize = ref(3); const timelinePageSize = ref(5);
const hasMore = ref(true); const hasMore = ref(true);
const getSanctionBackground = async (isLoadMore = false) => { const getSanctionBackground = async (isLoadMore = false) => {
...@@ -594,6 +618,18 @@ const entityDistribution = ref([ ...@@ -594,6 +618,18 @@ const entityDistribution = ref([
gradient: "linear-gradient(270deg, rgba(5,95,194,1) 0%, rgba(255,255,255,0) 100%)" gradient: "linear-gradient(270deg, rgba(5,95,194,1) 0%, rgba(255,255,255,0) 100%)"
} }
]); ]);
const reasonHistoryList = ref([]);
const getReasonHistoryList = async () => {
try {
const res = await getReasonAndSan(sanRecordId.value);
console.log("制裁原因及相关历史制裁", res);
reasonHistoryList.value = res;
} catch (error) {
console.log(error);
}
};
const sanTypeId = ref(""); const sanTypeId = ref("");
onMounted(() => { onMounted(() => {
// 获取路由参数中的sanTypeId // 获取路由参数中的sanTypeId
...@@ -609,6 +645,8 @@ onMounted(() => { ...@@ -609,6 +645,8 @@ onMounted(() => {
getSanctionBackground(); getSanctionBackground();
// 单次制裁-制裁概况-制裁清单 // 单次制裁-制裁概况-制裁清单
getSanctionOverviewList(); getSanctionOverviewList();
// 单次制裁-制裁概况-制裁原因及相关历史制裁
getReasonHistoryList();
}); });
</script> </script>
...@@ -828,7 +866,7 @@ onMounted(() => { ...@@ -828,7 +866,7 @@ onMounted(() => {
.left-bottom-content { .left-bottom-content {
padding: 20px 25px 0 25px; padding: 20px 25px 0 25px;
height: calc(100% - 45px); // 减去标题高度 height: calc(100% - 20px); // 减去标题高度
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -836,7 +874,7 @@ onMounted(() => { ...@@ -836,7 +874,7 @@ onMounted(() => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 24px; gap: 24px;
margin-bottom: 24px; margin-bottom: 5px;
overflow-y: auto; // 允许垂直滚动 overflow-y: auto; // 允许垂直滚动
flex: 1; // 占据剩余空间 flex: 1; // 占据剩余空间
padding-right: 10px; // 防止滚动条遮挡内容 padding-right: 10px; // 防止滚动条遮挡内容
...@@ -1183,6 +1221,95 @@ onMounted(() => { ...@@ -1183,6 +1221,95 @@ onMounted(() => {
} }
} }
} }
.reason-history {
display: flex;
flex-direction: column;
gap: 16px;
padding: 5px 24px;
min-height: 500px;
max-height: 1000px;
margin-bottom: 15px;
.reason-history-item {
.item-header {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
.item-header-title {
display: flex;
align-items: center;
width: 85%;
.item-header-title-idx {
width: 24px;
height: 24px;
border-radius: 50%;
background-color: rgb(231, 243, 255);
font-size: 12px;
line-height: 24px;
text-align: center;
}
.item-header-title-text {
margin-left: 13px;
font-size: 16px;
font-weight: 700;
line-height: 28px;
font-family: "Source Han Sans CN";
color: rgb(59, 65, 75);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.item-header-domain {
// min-width: 100px;
}
}
.item-content {
padding: 10px 20px;
border-radius: 4px;
.item-content-record {
position: relative;
margin-top: 20px;
// border-left: 3px solid rgb(5, 95, 194);
background-color: rgb(247, 248, 249);
padding: 10px 0;
border-radius: 4px;
&::before {
content: "";
position: absolute;
left: 0;
top: 10px;
bottom: 10px;
width: 4px;
background-color: rgb(5, 95, 194);
}
.item-content-record-header {
padding: 0px 15px;
font-size: 16px;
font-weight: 700;
height: 30px;
line-height: 30px;
color: rgb(5, 95, 194);
font-family: "Source Han Sans CN";
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.item-content-record-content {
padding: 5px 15px;
font-size: 16px;
font-family: "Source Han Sans CN";
color: rgb(59, 65, 75);
line-height: 30px;
}
}
}
}
}
} }
} }
} }
......
...@@ -108,7 +108,7 @@ import router from "@/router"; ...@@ -108,7 +108,7 @@ import router from "@/router";
// 处理点击实体清单原文按钮 // 处理点击实体清单原文按钮
const handleClickOriginalText = () => { const handleClickOriginalText = () => {
// 打开新标签页 // 打开新标签页
window.open(`/exportControl/origin?id=${sanRecordId.value}`, "_blank"); window.open(`/finance/origin?id=${sanRecordId.value}`, "_blank");
}; };
// 获取URL参数 // 获取URL参数
...@@ -241,7 +241,6 @@ const handlePageChange = async newPage => { ...@@ -241,7 +241,6 @@ const handlePageChange = async newPage => {
await fetchSanctionData(); await fetchSanctionData();
}; };
// ========== 选择某项 ==========
const selectSanction = async item => { const selectSanction = async item => {
selectedSanctionId.value = item.id; selectedSanctionId.value = item.id;
router.replace({ router.replace({
...@@ -254,6 +253,7 @@ const selectSanction = async item => { ...@@ -254,6 +253,7 @@ const selectSanction = async item => {
sanctionModalVisible.value = false; sanctionModalVisible.value = false;
console.log("跳转URL:", window.location.href); console.log("跳转URL:", window.location.href);
// 根据最新URL参数刷新当前页面 // 根据最新URL参数刷新当前页面
window.sessionStorage.setItem("curTabName", item.postDate + " 《实体清单新增条目》");
window.open(`${window.location.pathname}?id=${item.id}&sanTypeId=${item.sanTypeId}`, "_self"); window.open(`${window.location.pathname}?id=${item.id}&sanTypeId=${item.sanTypeId}`, "_self");
}; };
......
...@@ -15,26 +15,21 @@ ...@@ -15,26 +15,21 @@
<div class="header-right"> <div class="header-right">
<!-- 中英文切换开关 --> <!-- 中英文切换开关 -->
<div class="toggle-group"> <div class="toggle-group">
<span :class="{ active: !showChinese }">英文</span> <!-- <span :class="{ active: !showChinese }">英文</span> -->
<el-switch <el-switch v-model="showChinese" @change="handleToggleChange" />
v-model="showChinese" <img :src="transIcon" alt="" />
active-text="中" <span :class="{ active: showChinese }">显示原文</span>
inactive-text="英"
:inline-prompt="true"
@change="handleToggleChange"
/>
<span :class="{ active: showChinese }">中文</span>
</div> </div>
<!-- 下载按钮 --> <!-- 下载按钮 -->
<el-button type="primary" :icon="Download" @click="handleDownload"> 下载 </el-button> <el-button plain :icon="Download" @click="handleDownload"> 下载 </el-button>
</div> </div>
</div> </div>
<!-- 外层滚动容器,统一控制两侧滚动 --> <!-- 外层滚动容器,统一控制两侧滚动 -->
<div class="report-box" ref="reportBoxRef"> <div class="report-box" ref="reportBoxRef">
<div class="pdf-pane-wrap" :class="{ 'center-mode': !showChinese }"> <div class="pdf-pane-wrap" v-if="showChinese" :class="{ 'center-mode': !showChinese }">
<pdf ref="leftPdfRef" :pdfUrl="headerTitle.srcUrl" class="pdf-pane-inner" /> <pdf ref="leftPdfRef" :pdfUrl="headerTitle.srcUrl" class="pdf-pane-inner" />
</div> </div>
<div class="pdf-pane-wrap" v-if="showChinese"> <div class="pdf-pane-wrap">
<pdf ref="rightPdfRef" :pdfUrl="headerTitle.transUrl" class="pdf-pane-inner" /> <pdf ref="rightPdfRef" :pdfUrl="headerTitle.transUrl" class="pdf-pane-inner" />
</div> </div>
</div> </div>
...@@ -47,6 +42,7 @@ import { ref, onMounted, watch, computed } from "vue"; ...@@ -47,6 +42,7 @@ import { ref, onMounted, watch, computed } from "vue";
import { Download } from "@element-plus/icons-vue"; import { Download } from "@element-plus/icons-vue";
import { getSingleSanctionOverview } from "@/api/exportControlV2.0.js"; import { getSingleSanctionOverview } from "@/api/exportControlV2.0.js";
import title from "../assets/title.png"; import title from "../assets/title.png";
import transIcon from "../assets/icon-translation.png";
import pdf from "./pdf.vue"; import pdf from "./pdf.vue";
const leftPdfRef = ref(null); const leftPdfRef = ref(null);
...@@ -299,15 +295,15 @@ onMounted(() => { ...@@ -299,15 +295,15 @@ onMounted(() => {
} }
} }
:deep(.el-button) { // :deep(.el-button) {
--el-button-bg-color: #055fc2; // --el-button-bg-color: #055fc2;
--el-button-border-color: #055fc2; // --el-button-border-color: #055fc2;
--el-button-hover-bg-color: #044c9b; // --el-button-hover-bg-color: #044c9b;
--el-button-hover-border-color: #044c9b; // --el-button-hover-border-color: #044c9b;
font-size: 14px; // font-size: 14px;
padding: 10px 20px; // padding: 10px 20px;
} // }
} }
} }
...@@ -318,6 +314,8 @@ onMounted(() => { ...@@ -318,6 +314,8 @@ onMounted(() => {
display: flex; display: flex;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
// ✅ 添加居中对齐
justify-content: center;
} }
.pdf-pane-wrap { .pdf-pane-wrap {
...@@ -330,6 +328,8 @@ onMounted(() => { ...@@ -330,6 +328,8 @@ onMounted(() => {
&.center-mode { &.center-mode {
flex: 0 0 100%; flex: 0 0 100%;
max-width: 100%; max-width: 100%;
// ✅ 添加居中样式
width: 728px; // 约一半宽度,保持单栏时美观
margin: 0 auto; margin: 0 auto;
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论