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

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

Yp dev 查看合并请求 !341
流水线 #469 已通过 于阶段
in 6 分 4 秒
......@@ -189,7 +189,8 @@ export function getDeepMiningSelect(data) {
export function getDeepMiningIndustry(params) {
return request({
method: "GET",
url: `/api/chain/getChainInfo`,
// url: `/api/chain/getChainInfo`,
url: `/api/chain/getAllChain`,
params
});
}
......@@ -204,7 +205,7 @@ export function getDeepMiningIndustry(params) {
export function getDeepMiningIndustryFishbone(params) {
return request({
method: "GET",
url: `/api/chain/getChainFishbone`,
url: `/api/chain/getChainNodes`,
params
});
}
......
差异被折叠。
......@@ -18,7 +18,12 @@ import RelationChart from '@/components/base/RelationChart/index.vue'
</el-radio-group>
</div>
<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>
</el-col>
</el-row>
......@@ -149,7 +154,15 @@ const graphData = ref({
{ id: "e2-9", text: "e2-9" }
],
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: "b1", to: "b1-1" },
{ from: "b1", to: "b1-2" },
......@@ -254,18 +267,15 @@ const graphData = ref({
]
});
const handleClickNode = (value) => {
console.log('value', value);
alert('我点击了node-'+ value.text)
}
const handleClickLine = (value) => {
console.log('value', value);
alert('我点击了line-'+ value.text)
}
const handleClickNode = value => {
console.log("value", value);
alert("我点击了node-" + value.text);
};
const handleClickLine = value => {
console.log("value", value);
alert("我点击了line-" + value.text);
};
</script>
<style lang="scss" scoped>
......@@ -278,4 +288,4 @@ const handleClickLine = (value) => {
width: 1600px;
height: 500px;
}
</style>
\ No newline at end of file
</style>
......@@ -670,7 +670,9 @@
</el-col>
</template>
<template v-if="activeResourceTab === 'commerce'">
<listPage />
<div class="commerce-wrapper" :style="{ minHeight: '500px' }">
<listPage />
</div>
</template>
</el-row>
</div>
......@@ -1974,7 +1976,7 @@ const handleMediaClick = item => {
position: absolute;
width: 240px;
height: 89px;
top: 30px;
top: 12px;
right: -24px;
display: flex;
flex-direction: column;
......
......@@ -390,6 +390,9 @@ onMounted(async () => {
background-color: #fff;
border-radius: 4px;
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) {
......@@ -462,6 +465,11 @@ onMounted(async () => {
height: 24px;
color: rgb(95, 101, 108);
}
:deep(.el-checkbox__label) {
font-size: 16px;
color: #666666;
font-weight: 400;
}
.custom-date-picker {
width: 100%;
......
......@@ -4,7 +4,7 @@
<div class="left-top">
<AnalysisBox title="基本信息" :showAllBtn="false">
<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="content-item">
<span class="label">法律依据:</span>
......
......@@ -5,81 +5,80 @@
* @LastEditTime: 2026-01-07 09:58:04
-->
<template>
<div class="sanctions-overview">
<div class="side-nav">
<div 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>
</div>
</div>
<div class="content-box">
<introductionPage v-if="activeIndex === 0"></introductionPage>
<listPage v-if="activeIndex === 1"></listPage>
</div>
</div>
<div class="sanctions-overview">
<div class="side-nav">
<div
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>
</div>
</div>
<div class="content-box">
<introductionPage v-if="activeIndex === 0"></introductionPage>
<listPage v-if="activeIndex === 1"></listPage>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import introductionPage from "./components/introductionPage/index.vue"
import listPage from "./components/listPage/index.vue"
const activeTab = ref(["CCL清单简介", "CCL清单列表"])
const activeIndex = ref(0)
import { ref } from "vue";
import introductionPage from "./components/introductionPage/index.vue";
import listPage from "./components/listPage/index.vue";
const activeTab = ref(["CMC清单简介", "CMC清单列表"]);
const activeIndex = ref(0);
</script>
<style scoped lang="scss">
*{
margin: 0;
padding: 0;
}
.sanctions-overview{
width: 1601px;
margin: 0 auto;
position: relative;
// min-height: 800px;
.side-nav {
position: absolute;
top: 27px;
right: 100%;
margin-right: 12px;
display: flex;
flex-direction: column;
gap: 16px;
.tab-item {
cursor: pointer;
padding: 4px 20px;
border-radius: 22px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(95, 101, 108);
white-space: nowrap;
display: flex;
align-items: center;
&.active {
background-color: rgb(5, 95, 194);
color: #fff;
.arrow {
display: inline-block;
width: 0;
height: 0;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 6px solid #fff;
margin-left: 8px;
}
}
}
}
.content-box {
width: 100%;
}
.sanctions-overview {
width: 1601px;
margin: 0 auto;
position: relative;
// min-height: 800px;
.side-nav {
position: absolute;
top: 27px;
right: 100%;
margin-right: 12px;
display: flex;
flex-direction: column;
gap: 16px;
.tab-item {
cursor: pointer;
padding: 4px 20px;
border-radius: 22px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(95, 101, 108);
white-space: nowrap;
display: flex;
align-items: center;
&.active {
background-color: rgb(5, 95, 194);
color: #fff;
.arrow {
display: inline-block;
width: 0;
height: 0;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 6px solid #fff;
margin-left: 8px;
}
}
}
}
.content-box {
width: 100%;
}
}
</style>
......@@ -55,21 +55,42 @@ import icon2Active from "../assets/icons/icon2_active.png";
import icon3 from "../assets/icons/icon3.png";
import icon3Active from "../assets/icons/icon3_active.png";
import { getCCLInfo } from "@/api/exportControlV2.0.js";
const route = useRoute();
const sanTypeId = ref("");
onMounted(() => {
// 获取路由参数sanTypeId
sanTypeId.value = route.query.sanTypeId;
console.log("CommercialControlList 页面接收到的 sanTypeId:", sanTypeId.value);
getCCLInfoFn();
});
const headerTitle = ref({
img: title,
title: "商业管制清单(CCL)",
titleEn: "Commercial Control List",
department: "美国商务部工业与安全局"
img: "",
title: "",
titleEn: "",
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 headerNavList = ref([
......
......@@ -110,7 +110,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入实体清单的中国实体数量变化趋势,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入SDN清单的中国实体数量变化趋势,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -169,7 +171,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入实体清单的中国实体领域分布情况,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -208,7 +212,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入实体清单的中国实体领域分布情况,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -240,7 +246,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入实体清单的中国实体类型分布情况,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入SDN清单的中国实体类型分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......
......@@ -45,7 +45,7 @@
<div class="right">
<AnalysisBox title="投融资限制举措关系图">
<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">
<template #description>
<div class="empty">请在左侧勾选多次投融资限制制裁后点击“开始分析”查看结果</div>
......@@ -139,7 +139,24 @@
<div class="icon2"></div>
</div>
</div>
<RelationChart :is-vertical-chart="true" :graph-data="graphData" />
<!-- <div class="relation-content">
<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>
</el-dialog>
</div>
......@@ -383,13 +400,16 @@ const fetchRecordRelation = async () => {
recordRelation.value = { noRelationVertices: [], relationVoList: [] };
}
};
const emptyOfRelation = computed(
() => recordRelation.value.noRelationVertices.length == 0 || recordRelation.value.relationVoList.length == 0
);
const vertexInfo = ref({});
const curNode = ref({});
const curLink = ref({});
const nodeVisible = ref(false);
const relationVisible = ref(false);
const tipsInfo = ref("");
const graphData = ref({});
const graphDataList = ref([]);
const getTipsInfo = (relationType, reason) => {
switch (relationType) {
case "继承":
......@@ -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},属于相似关系。`;
}
};
// 在 constrainedAssociation.vue 的 script setup 中
const handleClickNode = node => {
console.log("节点点击", node);
if (node.dataType == "node") {
......@@ -418,25 +440,126 @@ const handleClickNode = node => {
relationVisible.value = true;
curLink.value = node;
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) {
// recordRelation.value = res;
console.log("制裁之间的关系 =>", res);
let reason = "";
if (relationType == "相似") {
reason = res[0].edgeReasonList[0].reason;
// 获取边详情数据
getEdgeInfo(node.data.edgeInfo.key)
.then(res => {
if (!!res && Array.isArray(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 = "";
if (relationType == "相似" && res[0]?.edgeReasonList?.[0]?.reason) {
reason = res[0].edgeReasonList[0].reason;
}
tipsInfo.value = getTipsInfo(relationType, reason);
} else {
graphDataList.value = [];
}
tipsInfo.value = getTipsInfo(relationType, reason);
} else {
// recordRelation.value = { noRelationVertices: [], relationVoList: [] };
}
});
})
.catch(err => {
console.error("获取边信息失败", err);
graphDataList.value = [];
});
}
};
......@@ -481,10 +604,6 @@ const formatChangeSummary = (addList, delList) => {
return `${item.value}${unit}${noun}`;
});
// 拼接:移除 + item1 + , + item2 ...
// 注意:题目要求“删除”,但之前代码用的是“移除”,这里统一使用“移除”或“删除”。
// 根据题目描述“展示样本为:新增12个实体,3名个人,移除1个实体”,这里使用“移除”更贴切上下文,
// 如果必须用“删除”,请将下面的 '移除' 改为 '删除'。
parts.push(`移除${delItems.join(",")}`);
}
......@@ -708,6 +827,57 @@ onMounted(() => {
flex-direction: column;
gap: 16px;
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 {
display: flex;
align-items: center;
......@@ -753,6 +923,10 @@ onMounted(() => {
}
}
}
.relation-content {
height: 400px;
width: 100%;
}
.info-btn {
position: absolute;
top: 20px;
......
......@@ -155,15 +155,8 @@ const getTagStyle = tag => {
// 跳转公司详情页
const handleCompClick = item => {
console.log("item", item);
window.sessionStorage.setItem("curTabName", item.entityNameZh || item.entityName);
window.sessionStorage.setItem("curTabName", item.name || item.orgName);
gotoCompanyPages(item.id);
// const route = router.resolve({
// name: "companyPages",
// params: {
// id: item.id
// }
// });
// window.open(route.href, "_blank");
};
</script>
......
......@@ -253,7 +253,7 @@ const handleCompClick = item => {
// }
// });
// window.open(route.href, "_blank");
gotoCompanyPages(item.entityId);
gotoCompanyPages(item.id);
};
const searchKeyword = ref("");
......
......@@ -175,7 +175,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">美国商务部发布实体清单的频次,数据来源:美国商务部官网</div>
<div class="data-origin-text">
美国商务部发布实体清单的频次,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -210,7 +212,7 @@
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">
美国商务部发布商业管制清单的频次,数据来源:美国商务部官网
美国商务部发布商业管制清单的频次,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
......@@ -260,7 +262,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入实体清单的中国实体领域分布情况,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -285,7 +289,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入实体清单的中国实体数量变化趋势,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入SDN清单的中国实体数量变化趋势,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -306,7 +312,7 @@
</div>
</div>
<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">
<template #default>
<div class="box4">
......@@ -341,7 +347,7 @@
</template>
</custom-container>
</el-col>
<el-col :span="16" style="padding: 0">
<el-col :span="16" style="padding-right: 0">
<custom-container title="制裁实体清单" :titleIcon="entityIcon" height="845px">
<template #header-right>
<div class="box5-header-right">{{ total }}家实体</div>
......@@ -1706,15 +1712,6 @@ const handleMediaClick = item => {
</script>
<style lang="scss" scoped>
// * {
// margin: 0;
// padding: 0;
// }
:deep(.el-input__wrapper) {
// box-shadow: none;
}
.home-header {
height: 64px;
background: url("@/assets/images/nav-bg.png");
......@@ -1783,7 +1780,7 @@ const handleMediaClick = item => {
position: absolute;
width: 240px;
height: 89px;
top: 30px;
top: 12px;
right: -24px;
display: flex;
flex-direction: column;
......@@ -3095,7 +3092,7 @@ const handleMediaClick = item => {
align-items: center;
margin-top: 6px;
margin-bottom: 36px;
padding-left: 10px;
// padding-left: 10px;
.resource-tab-item {
margin-right: 12px;
......@@ -3164,7 +3161,7 @@ const handleMediaClick = item => {
}
.text {
font-size: 20px;
font-size: 16px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 26px;
......
......@@ -59,7 +59,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入本次实体清单的中国实体领域分布情况,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入本次SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -109,7 +111,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入本次实体清单的中国实体类型分布情况,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入本次SDN清单的中国实体类型分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -150,7 +154,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入本次实体清单的实体国家地区分布情况,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入本次SDN清单的实体国家地区分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -194,7 +200,9 @@
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入本次实体清单的中国实体各省分布情况,数据来源:美国商务部官网</div>
<div class="data-origin-text">
进入本次SDN清单的中国实体各省分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -845,11 +853,6 @@ onMounted(() => {
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.data-statistics {
width: 1601px;
margin: 0 auto;
......
......@@ -540,11 +540,6 @@ onMounted(async () => {
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.deepMiningChartmode {
height: calc(100vh - 220px) !important;
// overflow: hidden;
......
......@@ -990,11 +990,6 @@ onMounted(async () => {
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.industrial-impact {
width: 100%;
padding-top: 16px;
......
......@@ -1118,11 +1118,6 @@ onBeforeUnmount(() => {
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.industrial-impact {
width: 100%;
padding-top: 16px;
......
......@@ -29,10 +29,6 @@ const activeIndex = ref(0);
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
}
.impact-analysis {
width: 1601px;
margin: 0 auto;
......
......@@ -95,7 +95,7 @@
</div>
</div>
<div class="right" v-loading="isLoading">
<AnalysisBox title="制裁清单" :showAllBtn="false">
<AnalysisBox title="制裁清单" :showAllBtn="false" style="height: auto">
<div class="right-title">
<div class="filter-row">
<div class="filter-left">
......@@ -234,7 +234,31 @@
</div>
</AnalysisBox>
<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>
<!-- 50%规则子企业弹框 -->
......@@ -252,7 +276,6 @@ import { ref, defineProps, computed, onMounted, watch } from "vue";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import AreaTag from "@/components/base/AreaTag/index.vue";
import { DArrowRight, Search } from "@element-plus/icons-vue";
import { debounce } from "lodash";
import title from "../../assets/title.png";
import defaultTitle from "../../assets/default-icon1.png";
......@@ -265,6 +288,7 @@ import {
} from "@/api/exportControlV2.0";
import { getRelateNews } from "@/api/finance";
import RuleSubsidiaryDialog from "../../../entityList/components/sanctionsOverview/components/listPage/RuleSubsidiaryDialog.vue";
import { getReasonAndSan } from "@/api/finance";
import { useRoute } from "vue-router";
import { useGotoCompanyPages } from "@/router/modules/company";
......@@ -365,7 +389,7 @@ const getSanctionOverviewList = async () => {
// 单次制裁-制裁概况-制裁背景
const timelinePage = ref(1);
const timelinePageSize = ref(3);
const timelinePageSize = ref(5);
const hasMore = ref(true);
const getSanctionBackground = async (isLoadMore = false) => {
......@@ -594,6 +618,18 @@ const entityDistribution = ref([
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("");
onMounted(() => {
// 获取路由参数中的sanTypeId
......@@ -609,6 +645,8 @@ onMounted(() => {
getSanctionBackground();
// 单次制裁-制裁概况-制裁清单
getSanctionOverviewList();
// 单次制裁-制裁概况-制裁原因及相关历史制裁
getReasonHistoryList();
});
</script>
......@@ -828,7 +866,7 @@ onMounted(() => {
.left-bottom-content {
padding: 20px 25px 0 25px;
height: calc(100% - 45px); // 减去标题高度
height: calc(100% - 20px); // 减去标题高度
display: flex;
flex-direction: column;
......@@ -836,7 +874,7 @@ onMounted(() => {
display: flex;
flex-direction: column;
gap: 24px;
margin-bottom: 24px;
margin-bottom: 5px;
overflow-y: auto; // 允许垂直滚动
flex: 1; // 占据剩余空间
padding-right: 10px; // 防止滚动条遮挡内容
......@@ -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";
// 处理点击实体清单原文按钮
const handleClickOriginalText = () => {
// 打开新标签页
window.open(`/exportControl/origin?id=${sanRecordId.value}`, "_blank");
window.open(`/finance/origin?id=${sanRecordId.value}`, "_blank");
};
// 获取URL参数
......@@ -241,7 +241,6 @@ const handlePageChange = async newPage => {
await fetchSanctionData();
};
// ========== 选择某项 ==========
const selectSanction = async item => {
selectedSanctionId.value = item.id;
router.replace({
......@@ -254,6 +253,7 @@ const selectSanction = async item => {
sanctionModalVisible.value = false;
console.log("跳转URL:", window.location.href);
// 根据最新URL参数刷新当前页面
window.sessionStorage.setItem("curTabName", item.postDate + " 《实体清单新增条目》");
window.open(`${window.location.pathname}?id=${item.id}&sanTypeId=${item.sanTypeId}`, "_self");
};
......
......@@ -15,26 +15,21 @@
<div class="header-right">
<!-- 中英文切换开关 -->
<div class="toggle-group">
<span :class="{ active: !showChinese }">英文</span>
<el-switch
v-model="showChinese"
active-text="中"
inactive-text="英"
:inline-prompt="true"
@change="handleToggleChange"
/>
<span :class="{ active: showChinese }">中文</span>
<!-- <span :class="{ active: !showChinese }">英文</span> -->
<el-switch v-model="showChinese" @change="handleToggleChange" />
<img :src="transIcon" alt="" />
<span :class="{ active: showChinese }">显示原文</span>
</div>
<!-- 下载按钮 -->
<el-button type="primary" :icon="Download" @click="handleDownload"> 下载 </el-button>
<el-button plain :icon="Download" @click="handleDownload"> 下载 </el-button>
</div>
</div>
<!-- 外层滚动容器,统一控制两侧滚动 -->
<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" />
</div>
<div class="pdf-pane-wrap" v-if="showChinese">
<div class="pdf-pane-wrap">
<pdf ref="rightPdfRef" :pdfUrl="headerTitle.transUrl" class="pdf-pane-inner" />
</div>
</div>
......@@ -47,6 +42,7 @@ import { ref, onMounted, watch, computed } from "vue";
import { Download } from "@element-plus/icons-vue";
import { getSingleSanctionOverview } from "@/api/exportControlV2.0.js";
import title from "../assets/title.png";
import transIcon from "../assets/icon-translation.png";
import pdf from "./pdf.vue";
const leftPdfRef = ref(null);
......@@ -299,15 +295,15 @@ onMounted(() => {
}
}
:deep(.el-button) {
--el-button-bg-color: #055fc2;
--el-button-border-color: #055fc2;
--el-button-hover-bg-color: #044c9b;
--el-button-hover-border-color: #044c9b;
// :deep(.el-button) {
// --el-button-bg-color: #055fc2;
// --el-button-border-color: #055fc2;
// --el-button-hover-bg-color: #044c9b;
// --el-button-hover-border-color: #044c9b;
font-size: 14px;
padding: 10px 20px;
}
// font-size: 14px;
// padding: 10px 20px;
// }
}
}
......@@ -318,6 +314,8 @@ onMounted(() => {
display: flex;
overflow-y: auto;
overflow-x: hidden;
// ✅ 添加居中对齐
justify-content: center;
}
.pdf-pane-wrap {
......@@ -330,6 +328,8 @@ onMounted(() => {
&.center-mode {
flex: 0 0 100%;
max-width: 100%;
// ✅ 添加居中样式
width: 728px; // 约一半宽度,保持单栏时美观
margin: 0 auto;
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论