Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
57a3db48
提交
57a3db48
authored
4月 02, 2026
作者:
coderBryanFu
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'pre' of
http://8.140.26.4:10003/caijian/risk-monitor
into fk-dev
上级
3ca78c85
a517e8f6
流水线
#294
已通过 于阶段
in 1 分 26 秒
变更
47
流水线
1
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
47 个修改的文件
包含
1171 行增加
和
193 行删除
+1171
-193
index.js
src/api/aiAnalysis/index.js
+2
-1
bill.js
src/api/bill.js
+2
-1
exportControlV2.0.js
src/api/exportControlV2.0.js
+2
-2
index.js
src/api/finance/index.js
+2
-0
overview.js
src/api/thinkTank/overview.js
+114
-2
index.vue
src/components/base/GraphChart/index.vue
+51
-43
exportControl.js
src/router/modules/exportControl.js
+1
-1
thinktank.js
src/router/modules/thinktank.js
+15
-1
index.vue
src/views/bill/background/index.vue
+21
-3
index.vue
src/views/bill/deepDig/processOverview/index.vue
+120
-40
index.vue
src/views/bill/introdoction/index.vue
+1
-0
index.vue
src/views/bill/template/index.vue
+2
-2
index.vue
src/views/coopRestriction/components/dataSub/index.vue
+6
-0
index.vue
src/views/dataLibrary/index.vue
+0
-0
index.vue
src/views/exportControl/index.vue
+0
-0
charts.js
src/views/exportControl/utils/charts.js
+17
-1
index.vue
...omponents/sanctionsOverview/components/listPage/index.vue
+0
-0
index.vue
...ontrol/v2.0EntityList/components/dataStatistics/index.vue
+43
-17
index.vue
...ortControl/v2.0EntityList/components/deepMining/index.vue
+82
-33
index.vue
...s/sanctionsOverview/components/introductionPage/index.vue
+2
-2
index.vue
...omponents/sanctionsOverview/components/listPage/index.vue
+19
-3
index.vue
...ol/v2.0SingleSanction/components/dataStatistics/index.vue
+19
-15
RelationGraph.vue
...nction/components/deepMining/components/RelationGraph.vue
+175
-14
index.vue
...ontrol/v2.0SingleSanction/components/deepMining/index.vue
+170
-0
index.vue
...ents/impactAnalysis/components/industrialImpact/index.vue
+1
-1
index.vue
...onents/impactAnalysis/components/researchImpact/index.vue
+1
-1
index.vue
...v2.0SingleSanction/components/sanctionsOverview/index.vue
+19
-7
index.vue
src/views/exportControl/v2.0SingleSanction/index.vue
+13
-3
index-back.vue
...xportControl/v2.0SingleSanction/originPage/index-back.vue
+271
-0
index.vue
...ews/exportControl/v2.0SingleSanction/originPage/index.vue
+0
-0
pdf.vue
...views/exportControl/v2.0SingleSanction/originPage/pdf.vue
+0
-0
index.vue
src/views/finance/index.vue
+0
-0
index.vue
src/views/thinkTank/CongressHearingView/index.vue
+0
-0
index.vue
src/views/thinkTank/SurveyProjectView/index.vue
+0
-0
index.vue
src/views/thinkTank/ThinkTankDetail/PolicyTracking/index.vue
+0
-0
piechart.js
...hinkTank/ThinkTankDetail/PolicyTracking/utils/piechart.js
+0
-0
index.vue
...k/ThinkTankDetail/thinkDynamics/CongressHearing/index.vue
+0
-0
index.vue
...nkTank/ThinkTankDetail/thinkDynamics/SurveyForm/index.vue
+0
-0
index.vue
...k/ThinkTankDetail/thinkDynamics/ThinkTankReport/index.vue
+0
-0
index.vue
src/views/thinkTank/ThinkTankDetail/thinkDynamics/index.vue
+0
-0
HomeMainFooterMain.vue
src/views/thinkTank/components/HomeMainFooterMain.vue
+0
-0
HomeMainFooterSurvey.vue
src/views/thinkTank/components/HomeMainFooterSurvey.vue
+0
-0
ThinkTankCongressHearingOverview.vue
...thinkTank/components/ThinkTankCongressHearingOverview.vue
+0
-0
ThinkTankPolicyAdviceOverview.vue
...ws/thinkTank/components/ThinkTankPolicyAdviceOverview.vue
+0
-0
index.vue
src/views/thinkTank/index.vue
+0
-0
index.vue
src/views/thinkTank/reportOriginal/index.vue
+0
-0
piechart.js
src/views/thinkTank/utils/piechart.js
+0
-0
没有找到文件。
src/api/aiAnalysis/index.js
浏览文件 @
57a3db48
...
...
@@ -196,7 +196,8 @@ export function getChartAnalysis(data, options = {}) {
},
body: JSON.stringify(data),
signal: abortController.signal,
openWhenHidden: true,
openWhenHidden: false,
retryDelay: 1000,
maxRetries: 2,
onopen: response => {
...
...
src/api/bill.js
浏览文件 @
57a3db48
...
...
@@ -56,11 +56,12 @@ export function getBillDyqk(params) {
* @param {id,cRelated,currentPage,pageSize}
* @header token
*/
export
function
getBillBackground
(
params
)
{
export
function
getBillBackground
(
params
,
config
=
{}
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/billInfoBean/background/
${
params
.
id
}
`
,
params
,
signal
:
config
.
signal
})
}
// 相关事件-根据法案ID获取相关事件信息
...
...
src/api/exportControlV2.0.js
浏览文件 @
57a3db48
...
...
@@ -292,10 +292,10 @@ export function getSingleSanctionOverviewList(data) {
* @param {string} params.sanRecordId - 制裁记录ID
* @header token
*/
export
function
getSingleSanctionTotalCount
(
i
d
)
{
export
function
getSingleSanctionTotalCount
(
sanTypeId
,
recordI
d
)
{
return
request
({
method
:
"GET"
,
url
:
`/api/sanctionList/statistics/total?sanTypeId=
${
i
d
}
`
,
url
:
`/api/sanctionList/statistics/total?sanTypeId=
${
sanTypeId
}
&sanRecordId=
${
recordI
d
}
`
,
});
}
...
...
src/api/finance/index.js
0 → 100644
浏览文件 @
57a3db48
import
request
from
"@/api/request.js"
;
\ No newline at end of file
src/api/thinkTank/overview.js
浏览文件 @
57a3db48
...
...
@@ -91,7 +91,7 @@ export function getHylyList() {
/**
* 智库概览/智库动态-智库报告
、调查项目
* 智库概览/智库动态-智库报告
* GET /api/thinkTankOverview/report
* 常用 query:pageNum, pageSize, sortFun, domainIds, startDate, endDate, category(调查项目), thinkTankId(详情页), keyword(动态搜索)
*/
...
...
@@ -103,6 +103,81 @@ export function getThinkTankReport(params) {
})
}
//智库概览调查项目
export
function
getThinkTankProjects
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/projects`
,
params
})
}
//智库概览页国会听证会
export
function
getThinkTankTestimonies
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/testimonies`
,
params
})
}
//智库调查项目详情主页
export
function
getThinkTankProjectsInfo
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/projects/
${
params
.
id
}
`
,
})
}
//智库国会听证会详情主页
export
function
getThinkTankHearingInfo
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/testimonies/
${
params
.
id
}
`
,
})
}
// 智库详情-调查项目(按智库 id)
export
function
getThinkTankProjectsByThinkTankId
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/
${
params
.
thinkTankId
}
/projects`
,
params
:
{
pageNum
:
params
.
pageNum
,
pageSize
:
params
.
pageSize
,
sortFun
:
params
.
sortFun
,
sortField
:
params
.
sortField
,
sortOrder
:
params
.
sortOrder
,
domainIds
:
params
.
domainIds
,
startDate
:
params
.
startDate
,
endDate
:
params
.
endDate
,
projectName
:
params
.
projectName
,
}
})
}
// 智库动态-国会听证会(按智库 id)
export
function
getThinkTankTestimoniesByThinkTankId
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/
${
params
.
thinkTankId
}
/testimonies`
,
params
:
{
pageNum
:
params
.
pageNum
,
pageSize
:
params
.
pageSize
,
domainIds
:
params
.
domainIds
,
startDate
:
params
.
startDate
,
endDate
:
params
.
endDate
,
title
:
params
.
title
,
}
})
}
//智库调查项目详情作者
export
function
getThinkTankProjectsAuthors
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/projects/
${
params
.
id
}
/team`
,
})
}
// 智库概览:政策建议(资源库-政策建议)
export
function
getThinkTankOverviewPolicy
(
params
)
{
return
request
({
...
...
@@ -378,6 +453,15 @@ export const getThinkTankReportRelated = (params) => {
}
);
}
//调查项目:获取项目报告
export
const
getThinkTankProjectRelated
=
(
params
)
=>
{
return
request
(
{
method
:
'GET'
,
url
:
`/api/think-tank/projects/
${
params
}
/reports`
,
}
);
}
//获取报告原文
export
const
getThinkTankReportcontentUrl
=
(
params
)
=>
{
...
...
@@ -424,7 +508,21 @@ export function getThinkTankReportViewpoint(params) {
}
})
}
// 获取报告核心论点(支持关键字搜索)
export
function
getThinkTankHearingViewpoint
(
params
)
{
const
{
testimonyId
,
pageSize
,
keyword
=
''
,
pageNum
}
=
params
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/testimonies/qa`
,
params
:
{
pageSize
,
keyword
,
pageNum
,
testimonyId
}
})
}
//获取涉及科技领域
export
function
getThinkTankReportIndustry
(
params
)
{
return
request
({
...
...
@@ -440,6 +538,20 @@ export function getThinkTankReportIndustryCloud(params) {
url
:
`/api/thinkTankReport/keyword/
${
params
.
id
}
`
,
})
}
//获取调查项目词云
export
function
getThinkTankProjectCloud
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/projects/
${
params
.
id
}
/word-cloud`
,
})
}
//获取国会听证会词云
export
function
getThinkTankHearingCloud
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/think-tank/testimonies/
${
params
.
id
}
/wordcloud`
,
})
}
//获取政策建议落实情况
export
function
getThinkTankReportPolicy
(
params
)
{
...
...
src/components/base/GraphChart/index.vue
浏览文件 @
57a3db48
<
template
>
<div
class=
"graph-chart-wrapper"
id=
"graph"
>
</div>
<div
class=
"graph-chart-wrapper"
id=
"graph"
></div>
</
template
>
<
script
setup
>
import
{
onMounted
,
onBeforeUnmount
}
from
'vue'
;
import
setChart
from
'@/utils/setChart'
;
import
getGraphChart
from
'./graphChart'
;
import
{
onMounted
,
onBeforeUnmount
,
watch
}
from
"vue"
;
import
setChart
from
"@/utils/setChart"
;
import
getGraphChart
from
"./graphChart"
;
const
emits
=
defineEmits
([
"handleClickNode"
])
const
emits
=
defineEmits
([
"handleClickNode"
])
;
const
props
=
defineProps
({
nodes
:
{
type
:
Array
,
default
:
[]
},
links
:
{
type
:
Array
,
default
:
[]
},
layoutType
:
{
type
:
String
,
default
:
'force'
},
width
:
{
type
:
String
,
default
:
'force'
},
height
:
{
type
:
String
,
default
:
'force'
}
})
nodes
:
{
type
:
Array
,
default
:
[]
},
links
:
{
type
:
Array
,
default
:
[]
},
layoutType
:
{
type
:
String
,
default
:
"force"
},
width
:
{
type
:
String
,
default
:
"force"
},
height
:
{
type
:
String
,
default
:
"force"
}
})
;
let
chart
=
null
let
chart
=
null
;
onMounted
(()
=>
{
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
)
chart
=
setChart
(
graph
,
'graph'
)
chart
.
on
(
"click"
,
(
event
)
=>
{
emits
(
"handleClickNode"
,
event
)
})
})
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
);
chart
=
setChart
(
graph
,
"graph"
);
chart
.
on
(
"click"
,
event
=>
{
emits
(
"handleClickNode"
,
event
);
});
});
onBeforeUnmount
(()
=>
{
chart
.
off
(
"click"
)
chart
.
dispose
()
})
chart
.
off
(
"click"
);
chart
.
dispose
();
})
;
watch
(
()
=>
[
props
.
nodes
,
props
.
links
],
()
=>
{
if
(
chart
)
{
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
);
chart
.
setOption
(
graph
,
true
);
}
},
{
deep
:
true
}
);
</
script
>
<
style
lang=
"scss"
scoped
>
.graph-chart-wrapper
{
width
:
100%
;
height
:
100%
;
// width: 800px;
// height: 500px;
width
:
100%
;
height
:
100%
;
// width: 800px;
// height: 500px;
}
</
style
>
\ No newline at end of file
</
style
>
src/router/modules/exportControl.js
浏览文件 @
57a3db48
...
...
@@ -121,7 +121,7 @@ const exportControlRoutes = [
name
:
"commercialControlList"
,
component
:
()
=>
import
(
"@/views/exportControl/v2.0CommercialControlList/index.vue"
),
meta
:
{
title
:
"商业管制清单"
title
:
"商业管制清单
概览
"
}
}
]
...
...
src/router/modules/thinktank.js
浏览文件 @
57a3db48
...
...
@@ -41,17 +41,31 @@ const thinktankRoutes = [
path
:
"/thinkTank/reportOriginal/:id"
,
name
:
"ReportOriginal"
,
component
:
ReportOriginal
,
meta
:
{
title
:
"报告原文"
,
dynamicTitle
:
true
,
titleStorageKey
:
"reportOriginalTabName"
}
},
{
path
:
"/thinkTank/SurveyProjectView/:id"
,
name
:
"SurveyProjectView"
,
component
:
SurveyProjectView
,
meta
:
{
title
:
"调查项目"
,
dynamicTitle
:
true
,
titleStorageKey
:
"surveyProjectTabName"
}
},
{
path
:
"/thinkTank/CongressHearingView/:id"
,
name
:
"CongressHearingView"
,
component
:
CongressHearingView
,
meta
:
{
title
:
"国会听证会"
,
dynamicTitle
:
true
,
titleStorageKey
:
"congressHearingTabName"
}
},
{
path
:
"/thinkTank/allThinkTank"
,
...
...
src/views/bill/background/index.vue
浏览文件 @
57a3db48
...
...
@@ -8,7 +8,7 @@
<el-button
:type=
"box1Btn2Type"
plain
@
click=
"handleClickBox1Btn(2)"
>
全部背景
</el-button>
</div>
</
template
>
<div
class=
"box1-main"
>
<div
class=
"box1-main"
v-loading=
"backgroundLoading"
>
<div
class=
"box1-main-center"
>
<div
class=
"box1-main-item"
v-for=
"item in backgroundDisplayList"
:key=
"item.id"
>
<div
class=
"id"
>
{{ item.displayIndex }}
</div>
...
...
@@ -198,6 +198,8 @@ const handleClickBox2Btn = index => {
const
aboutUserList
=
ref
([]);
const
backgroundList
=
ref
([]);
const
backgroundLoading
=
ref
(
false
);
let
backgroundAbortController
=
null
;
const
eventList
=
ref
([]);
...
...
@@ -244,6 +246,12 @@ const nextIconColor = computed(() => (currentIndex.value < personList.value.leng
// 获取立法背景内容
const
handleGetBillBackground
=
async
()
=>
{
if
(
backgroundAbortController
)
{
backgroundAbortController
.
abort
();
}
const
controller
=
new
AbortController
();
backgroundAbortController
=
controller
;
const
cRelated
=
box1BtnActive
.
value
===
1
?
"Y"
:
"N"
;
const
params
=
{
cRelated
:
cRelated
,
...
...
@@ -251,11 +259,21 @@ const handleGetBillBackground = async () => {
currentPage
:
currentPage
.
value
-
1
,
pageSize
:
10
};
backgroundLoading
.
value
=
true
;
try
{
const
res
=
await
getBillBackground
(
params
);
const
res
=
await
getBillBackground
(
params
,
{
signal
:
controller
.
signal
}
);
backgroundList
.
value
=
res
.
data
.
content
;
total
.
value
=
res
.
data
.
totalElements
;
// 假设API返回totalElements
}
catch
(
error
)
{
}
}
catch
(
error
)
{
if
(
error
?.
name
!==
"AbortError"
&&
error
?.
code
!==
"ERR_CANCELED"
)
{
console
.
error
(
error
);
}
}
finally
{
if
(
backgroundAbortController
===
controller
)
{
backgroundLoading
.
value
=
false
;
backgroundAbortController
=
null
;
}
}
};
// 获取相关事件
...
...
src/views/bill/deepDig/processOverview/index.vue
浏览文件 @
57a3db48
...
...
@@ -153,7 +153,7 @@
class=
"item-box"
v-for=
"item in sharedEvents"
:key=
"`shared-$
{item.id}`"
style="width: 280px; flex-shrink: 0;
"
:style="{ width: TIMELINE_ITEM_WIDTH_PX + 'px', flexShrink: 0 }
"
>
<div
class=
"item-time"
>
{{
item
.
actionDate
}}
</div>
<div
class=
"item-box-dot"
></div>
...
...
@@ -211,7 +211,15 @@ const dialogPos = ref({ left: "0px", top: "0px" });
const
ORG_SENATE
=
"参议院"
;
const
ORG_HOUSE
=
"众议院"
;
const
PRESIDENT_KEYWORD
=
"呈递给总统"
;
/** 卡片宽度;同一条时间线上相邻圆点间距 ≥ 此值,避免同轨卡片横向重叠 */
const
TIMELINE_ITEM_WIDTH_PX
=
280
;
/** 时间线锚点为圆点;与样式 .item-box-dot { left: 10px } 一致 */
const
DOT_LEFT_IN_ITEM_BOX_PX
=
10
;
/** 与 scoped 样式中 .top/.bottom .content-box 的 margin-left 一致,用于跨轨圆点与「两密点中点」对齐 */
const
SENATE_CONTENT_BOX_MARGIN_LEFT_PX
=
134
;
const
HOUSE_CONTENT_BOX_MARGIN_LEFT_PX
=
30
;
/** 双轨主线在最后一个圆点/卡片之后保留的空白(原先用整卡宽 W 导致尾部过长) */
const
TIMELINE_LINE_TAIL_PADDING_PX
=
48
;
const
ARROW_SEGMENT_TOTAL_PX
=
16
;
const
DIAGONAL_LINE_WIDTH_PX
=
127
;
...
...
@@ -281,50 +289,98 @@ const dualLaneTimeline = computed(() => {
.
filter
((
item
)
=>
!
isDualEvent
(
item
));
});
const
senateEventsPositioned
=
computed
(()
=>
{
const
list
=
[];
let
slotIndex
=
0
;
dualLaneTimeline
.
value
.
forEach
((
item
)
=>
{
if
(
!
isSenateEvent
(
item
))
return
;
list
.
push
({
key
:
item
.
id
,
/**
* 双轨事件已按时间排好(dualLaneTimeline)。依次放置:与前一条同轨则绝对 x + W,
* 异轨则以前一条圆点绝对位置为锚 + 0.5W(方案 C)。单轨(灰线)仍用 sharedEvents 顺序定宽。
*/
const
dualLaneLayout
=
computed
(()
=>
{
const
U
=
dualLaneTimeline
.
value
;
const
W
=
TIMELINE_ITEM_WIDTH_PX
;
const
chamberRowSenate
=
(
item
)
=>
{
const
s
=
isSenateEvent
(
item
);
const
h
=
isHouseEvent
(
item
);
if
(
s
&&
!
h
)
return
true
;
if
(
h
&&
!
s
)
return
false
;
return
Boolean
(
s
);
};
const
idxInU
=
(
item
)
=>
U
.
indexOf
(
item
);
const
toSlots
=
(
list
,
posByItem
)
=>
list
.
map
((
item
)
=>
({
key
:
`
${
idxInU
(
item
)}
-
${
item
.
id
??
"e"
}
`,
item,
left
:
slotIndex
*
TIMELINE_ITEM_WIDTH_PX
});
slotIndex
+=
1
;
});
return
list
;
});
left: (posByItem.get(item) ?? 0) - DOT_LEFT_IN_ITEM_BOX_PX
}));
const
houseEventsPositioned
=
computed
(()
=>
{
const
list
=
[];
let
slotIndex
=
0
;
dualLaneTimeline
.
value
.
forEach
((
item
)
=>
{
if
(
!
isHouseEvent
(
item
))
return
;
list
.
push
({
key
:
item
.
id
,
item
,
left
:
slotIndex
*
TIMELINE_ITEM_WIDTH_PX
});
slotIndex
+=
1
;
});
return
list
;
if (!U.length) {
return { senateSlots: [], houseSlots: [], maxDualLaneRightPx: 0 };
}
const posByItem = new Map();
let prevAbs = null;
let prevSenate = null;
for (const item of U) {
const sen = chamberRowSenate(item);
const margin = sen ? SENATE_CONTENT_BOX_MARGIN_LEFT_PX : HOUSE_CONTENT_BOX_MARGIN_LEFT_PX;
const absDot =
prevAbs === null ? margin : prevAbs + (sen === prevSenate ? W : W / 2);
posByItem.set(item, absDot - margin);
prevAbs = absDot;
prevSenate = sen;
}
/** 相对 content-box 左缘:卡片右边界 = layoutDotX - DOT_LEFT + W */
let maxDualLaneRightPx = 0;
for (const item of U) {
const layoutDotX = posByItem.get(item) ?? 0;
const rightPx = layoutDotX - DOT_LEFT_IN_ITEM_BOX_PX + W;
maxDualLaneRightPx = Math.max(maxDualLaneRightPx, rightPx);
}
return {
senateSlots: toSlots(
U.filter((item) => isSenateEvent(item)),
posByItem
),
houseSlots: toSlots(
U.filter((item) => isHouseEvent(item)),
posByItem
),
maxDualLaneRightPx
};
});
const senateEventsPositioned = computed(() => dualLaneLayout.value.senateSlots);
const houseEventsPositioned = computed(() => dualLaneLayout.value.houseSlots);
const sharedEvents = computed(() => {
return sortedTimeline.value.filter((item, idx) => {
return isDualEvent(item) || idx >= mergeIndexExclusive.value;
});
});
const
dualLaneCount
=
computed
(()
=>
{
return
Math
.
max
(
senateEventsPositioned
.
value
.
length
,
houseEventsPositioned
.
value
.
length
);
/** 双轨 content-box 内所需宽度:最后卡片右缘 + 尾部留白(与 maxLineWidth 中的 extent 一致) */
const dualLaneContentExtentPx = computed(() => {
if (!dualLaneTimeline.value.length) return 0;
return (
dualLaneLayout.value.maxDualLaneRightPx + TIMELINE_LINE_TAIL_PADDING_PX
);
});
/**
* 双轨横线(top-line / bottom-line 共用)宽度:起点 left:110,需画到与卡片区右缘对齐。
* 右缘 x = 120 + 参院 margin + extent = 254 + extent,故宽度 = 254 + extent - 110 = 144 + extent。
* 旧式 254+extent 多 110px,导致上下线都偏长。
*/
const maxLineWidth = computed(() => {
const
senateWidth
=
254
+
dualLaneCount
.
value
*
TIMELINE_ITEM_WIDTH_PX
;
const
houseWidth
=
150
+
dualLaneCount
.
value
*
TIMELINE_ITEM_WIDTH_PX
;
return
Math
.
max
(
senateWidth
,
houseWidth
);
if (!dualLaneTimeline.value.length) {
return Math.max(254, 150);
}
const extent = dualLaneContentExtentPx.value;
return 120 + SENATE_CONTENT_BOX_MARGIN_LEFT_PX + extent - 110;
});
const lineWidth = computed(() => `
$
{
maxLineWidth
.
value
}
px
`);
...
...
@@ -350,22 +406,41 @@ const rightArrowCount = computed(() => {
return Math.max(1, Math.ceil(sharedLineWidth.value / ARROW_SEGMENT_TOTAL_PX));
});
/** 参院 content 起点更靠右(margin 134 vs 30),众院 box 需多 104px 才能与参院右缘对齐 */
const CONTENT_BOX_WIDTH_DELTA_SENATE_HOUSE_PX =
SENATE_CONTENT_BOX_MARGIN_LEFT_PX - HOUSE_CONTENT_BOX_MARGIN_LEFT_PX;
const senateBoxStyle = computed(() => ({
width
:
`
${
maxLineWidth
.
value
+
110
-
254
}
px`
,
width: `
$
{
dualLaneTimeline
.
value
.
length
?
dualLaneContentExtentPx
.
value
:
110
}
px
`,
justifyContent: "flex-start"
}));
const houseBoxStyle = computed(() => ({
width
:
`
${
maxLineWidth
.
value
+
110
-
150
}
px`
,
width: `
$
{
dualLaneTimeline
.
value
.
length
?
dualLaneContentExtentPx
.
value
+
CONTENT_BOX_WIDTH_DELTA_SENATE_HOUSE_PX
:
214
}
px
`,
justifyContent: "flex-start"
}));
const rightPos = computed(() => `
$
{
maxLineWidth
.
value
+
90
}
px
`);
const
sharedBoxStyle
=
computed
(()
=>
({
left
:
`
${
maxLineWidth
.
value
+
219
}
px`
,
width
:
`
${
Math
.
max
(
sharedLineWidth
.
value
,
sharedEvents
.
value
.
length
*
TIMELINE_ITEM_WIDTH_PX
)}
px`
}));
const sharedBoxStyle = computed(() => {
const rightTopPx = Number.parseFloat(String(rightTop.value)) || 0;
const rightCenterY = rightTopPx + 12;
return {
left: `
$
{
maxLineWidth
.
value
+
230
}
px
`,
top: `
$
{
rightCenterY
}
px
`,
transform: "translateY(-100%)",
width: `
$
{
Math
.
max
(
sharedLineWidth
.
value
,
sharedEvents
.
value
.
length
*
TIMELINE_ITEM_WIDTH_PX
)}
px
`
};
});
const topLineEndRef = ref(null);
const bottomLineEndRef = ref(null);
...
...
@@ -547,13 +622,18 @@ const updateRightTop = () => {
}
}
/* .top 高 260px,时间线 top:242px;卡片下缘应对齐线顶:距容器底 18px */
.content-box
{
position
:
relative
;
margin-left
:
134px
;
margin-bottom
:
19px
;
margin-bottom
:
0
;
align-self
:
stretch
;
min-height
:
0
;
.item-box
{
position
:
absolute
;
top
:
auto
;
bottom
:
18px
;
}
}
}
...
...
@@ -808,7 +888,7 @@ const updateRightTop = () => {
.shared-content-box
{
position
:
absolute
;
top
:
170
px
;
top
:
254
px
;
display
:
flex
;
.item-box
{
...
...
src/views/bill/introdoction/index.vue
浏览文件 @
57a3db48
...
...
@@ -834,6 +834,7 @@ onMounted(() => {
flex
-
shrink
:
1
;
max
-
width
:
170
px
;
text
-
align
:
center
;
margin
-
bottom
:
10
px
;
}
.
nameItemActive
{
...
...
src/views/bill/template/index.vue
浏览文件 @
57a3db48
...
...
@@ -46,7 +46,7 @@
<div
class=
"chart-ai-wrap"
>
<div
:class=
"['right-box2-main', { 'right-box-main--full': !domainFooterText }]"
id=
"chart2"
></div>
<div
class=
"overview-tip-row"
>
<TipTab
class=
"overview-tip"
/>
<TipTab
class=
"overview-tip"
:text=
"'涉华科技法案数量及通过率变化趋势,数据来源:美国国会官网'"
/>
<AiButton
class=
"overview-tip-action"
@
mouseenter=
"handleShowAiPane('domain')"
/>
</div>
<div
v-if=
"aiPaneVisible.domain"
class=
"overview-ai-pane"
...
...
@@ -72,7 +72,7 @@
<div
class=
"chart-ai-wrap"
>
<div
:class=
"['right-box1-main', { 'right-box-main--full': !limitFooterText }]"
id=
"chart1"
></div>
<div
class=
"overview-tip-row"
>
<TipTab
class=
"overview-tip"
/>
<TipTab
class=
"overview-tip"
:text=
"'涉华科技法案数量及通过率变化趋势,数据来源:美国国会官网'"
/>
<AiButton
class=
"overview-tip-action"
@
mouseenter=
"handleShowAiPane('limit')"
/>
</div>
<div
v-if=
"aiPaneVisible.limit"
class=
"overview-ai-pane"
...
...
src/views/coopRestriction/components/dataSub/index.vue
浏览文件 @
57a3db48
...
...
@@ -849,6 +849,9 @@ onBeforeUnmount(() => {
position
:
absolute
;
right
:
0
;
bottom
:
18px
;
width
:
74px
;
height
:
28px
;
z-index
:
2
;
.btn-box
{
width
:
74px
;
...
...
@@ -953,6 +956,9 @@ onBeforeUnmount(() => {
position
:
absolute
;
right
:
0
;
bottom
:
18px
;
width
:
74px
;
height
:
28px
;
z-index
:
2
;
.btn-box
{
width
:
74px
;
...
...
src/views/dataLibrary/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/exportControl/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/exportControl/utils/charts.js
浏览文件 @
57a3db48
import
*
as
echarts
from
"echarts"
;
import
chinaJson
from
"./China.json"
;
import
_
from
"lodash"
;
import
{
name
}
from
"dayjs/locale/zh-cn"
;
//饼图
export
function
getPieOption
(
data
,
title
)
{
let
option
=
{
...
...
@@ -1006,7 +1007,7 @@ export const getMultipleBarChart_m = object => {
margin
:
20
},
axisLabel
:
{
formatter
:
"{value}
年
"
,
formatter
:
"{value}"
,
color
:
"rgba(95, 101, 108, 1)"
,
margin
:
20
},
...
...
@@ -1022,6 +1023,21 @@ export const getMultipleBarChart_m = object => {
},
yAxis
:
{
type
:
"value"
,
name
:
"数量"
,
nameLocation
:
"end"
,
nameGap
:
20
,
nameRotate
:
0
,
nameTextStyle
:
{
color
:
"#666"
,
fontFamily
:
"Microsoft YaHei"
,
fontWeight
:
400
,
fontSize
:
14
,
lineHeight
:
14
,
letterSpacing
:
0
,
align
:
"right"
,
verticalAlign
:
"bottom"
,
padding
:
[
0
,
8
,
0
,
0
]
},
splitNumber
:
5
,
alignTicks
:
false
,
axisLabel
:
{
...
...
src/views/exportControl/v2.0CommercialControlList/components/sanctionsOverview/components/listPage/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/exportControl/v2.0EntityList/components/dataStatistics/index.vue
浏览文件 @
57a3db48
...
...
@@ -105,7 +105,7 @@
</div>
</
template
>
<!-- <div class="echarts" ref="sanctionCountChartRef"></div> -->
<EChart
:option=
"sanctionCountChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"sanctionCountChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<div class="ai">
<div class="left">
...
...
@@ -121,7 +121,7 @@
<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
/>
...
...
@@ -130,7 +130,7 @@
</AnalysisBox>
</div>
<div
class=
"main-item"
>
<AnalysisBox
title=
"制裁实体
地域
分布情况"
>
<AnalysisBox
title=
"制裁实体
各省
分布情况"
>
<
template
#
header-btn
>
<el-select
v-model=
"regionTime"
class=
"time-select"
placeholder=
"请选择"
@
change=
"getRegionCountData"
>
<el-option
v-for=
"item in timeOptions"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
...
...
@@ -170,7 +170,7 @@
<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
/>
...
...
@@ -186,7 +186,7 @@
</el-select>
</
template
>
<!-- <div class="echarts" ref="domainChartRef"></div> -->
<EChart
:option=
"domainChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"domainChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<div class="ai">
<div class="left">
...
...
@@ -202,7 +202,7 @@
<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
/>
...
...
@@ -218,7 +218,7 @@
</el-select>
</
template
>
<!-- <div class="echarts" ref="typeChartRef"></div> -->
<EChart
:option=
"typeChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"typeChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<div class="ai">
<div class="left">
...
...
@@ -234,7 +234,7 @@
<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
/>
...
...
@@ -357,7 +357,7 @@ const getRegionCountData = async () => {
}));
// Sort by value descending
rankData
.
value
.
sort
((
a
,
b
)
=>
b
.
value
-
a
.
value
);
rankChart
.
interpret
({
type
:
"柱状图"
,
name
:
"制裁实体
地域
分布情况"
,
data
:
data
});
rankChart
.
interpret
({
type
:
"柱状图"
,
name
:
"制裁实体
各省
分布情况"
,
data
:
data
});
updateMapChart
();
}
}
catch
(
error
)
{
...
...
@@ -691,7 +691,7 @@ const domainChartOption = ref({
},
rich
:
{
name
:
{
fontSize
:
1
8
,
fontSize
:
1
6
,
fontWeight
:
700
,
color
:
"rgb(59, 65, 75)"
,
padding
:
[
0
,
0
,
5
,
0
],
...
...
@@ -717,8 +717,21 @@ const domainChartOption = ref({
width
:
1.1
}
},
labelLayout
:
{
hideOverlap
:
true
labelLayout
:
function
(
params
)
{
// hideOverlap: true
const
points
=
params
.
labelLinePoints
;
const
isLeft
=
params
.
labelRect
.
x
<
params
.
rect
.
x
+
params
.
rect
.
width
/
2
;
// 调整指示线终点到 label 垂直中心
const
labelCenterY
=
params
.
labelRect
.
y
+
params
.
labelRect
.
height
/
2
;
points
[
2
][
1
]
=
labelCenterY
;
// 调整指示线终点到 label 水平边缘
points
[
2
][
0
]
=
isLeft
?
params
.
labelRect
.
x
:
params
.
labelRect
.
x
+
params
.
labelRect
.
width
;
return
{
labelLinePoints
:
points
};
},
itemStyle
:
{
borderWidth
:
0
...
...
@@ -899,7 +912,7 @@ const typeChartOption = ref({
},
rich
:
{
name
:
{
fontSize
:
1
8
,
fontSize
:
1
6
,
fontWeight
:
700
,
color
:
"rgb(59, 65, 75)"
,
padding
:
[
0
,
0
,
5
,
0
],
...
...
@@ -926,10 +939,23 @@ const typeChartOption = ref({
}
},
labelLayout
:
function
(
params
)
{
const
isLeft
=
params
.
labelRect
.
x
<
chart
.
getWidth
()
/
2
;
// const isLeft = params.labelRect.x
<
chart
.
getWidth
()
/
2
;
// const points = params.labelLinePoints;
// points[2][0] = isLeft ? params.labelRect.x : params.labelRect.x + params.labelRect.width;
// return {
// labelLinePoints: points
// };
const
points
=
params
.
labelLinePoints
;
// Update the end point.
const
isLeft
=
params
.
labelRect
.
x
<
params
.
rect
.
x
+
params
.
rect
.
width
/
2
;
// 调整指示线终点到 label 垂直中心
const
labelCenterY
=
params
.
labelRect
.
y
+
params
.
labelRect
.
height
/
2
;
points
[
2
][
1
]
=
labelCenterY
;
// 调整指示线终点到 label 水平边缘
points
[
2
][
0
]
=
isLeft
?
params
.
labelRect
.
x
:
params
.
labelRect
.
x
+
params
.
labelRect
.
width
;
return
{
labelLinePoints
:
points
};
...
...
@@ -1508,8 +1534,8 @@ onMounted(() => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
padding
:
22px
0
;
justify-content
:
flex-start
;
padding
:
22px
;
.data-origin-icon
{
width
:
16px
;
height
:
16px
;
...
...
src/views/exportControl/v2.0EntityList/components/deepMining/index.vue
浏览文件 @
57a3db48
...
...
@@ -32,14 +32,14 @@
<div
class=
"list-header"
>
<div
class=
"count"
>
共
{{
sanctionList
.
length
}}
次制裁
</div>
<!-- 暂时隐藏,说这里可能是轮播图的效果 -->
<!--
<div
class=
"pagination"
>
<div
class=
"page-btn prev"
>
<el-icon><ArrowLeft
/></el-icon>
</div>
<div
class=
"page-btn next"
>
<el-icon><ArrowRight
/></el-icon>
<div
class=
"pagination"
>
<div
class=
"page-btn prev"
@
click=
"handlePrevClick"
>
<el-icon><ArrowLeft
/></el-icon>
</div>
<div
class=
"page-btn next"
@
click=
"handleNextClick"
>
<el-icon><ArrowRight
/></el-icon>
</div>
</div>
</div>
-->
</div>
<div
class=
"list-content"
v-loading=
"loading"
>
<div
...
...
@@ -243,7 +243,7 @@
</template>
<
script
setup
>
import
{
ref
,
onMounted
,
nextTick
}
from
"vue"
;
import
{
ref
,
onMounted
,
nextTick
,
onUnmounted
}
from
"vue"
;
import
{
ArrowLeft
,
ArrowRight
}
from
"@element-plus/icons-vue"
;
import
defaultTitle
from
"../../assets/default-icon2.png"
;
import
{
...
...
@@ -365,15 +365,17 @@ const getDeepMiningSelectData = async () => {
try
{
const
res
=
await
getDeepMiningSelect
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
&&
res
.
data
.
content
)
{
sanctionList
.
value
=
res
.
data
.
content
.
map
(
item
=>
({
id
:
item
.
id
,
date
:
item
.
postDate
,
title
:
item
.
name
,
count
:
item
.
cnEntityCount
,
unit
:
"家中国实体"
,
// 接口未返回单位,暂时固定
summary
:
item
.
summary
,
// 保留额外信息备用
techDomainList
:
item
.
techDomainList
// 保留额外信息备用
}));
sanctionList
.
value
=
res
.
data
.
content
.
map
(
item
=>
({
id
:
item
.
id
,
date
:
item
.
postDate
,
title
:
item
.
name
,
count
:
item
.
cnEntityCount
,
unit
:
"家中国实体"
,
// 接口未返回单位,暂时固定
summary
:
item
.
summary
,
// 保留额外信息备用
techDomainList
:
item
.
techDomainList
// 保留额外信息备用
}))
.
reverse
();
// 默认选中第一条
if
(
sanctionList
.
value
.
length
>
0
)
{
...
...
@@ -396,35 +398,74 @@ const handleDateChange = () => {
currentPage
.
value
=
1
;
getDeepMiningSelectData
();
};
// ✅ 自动轮播定时器
const
autoPlayTimer
=
ref
(
null
);
// ✅ 启动自动轮播
const
startAutoPlay
=
()
=>
{
stopAutoPlay
();
if
(
sanctionList
.
value
.
length
>
1
)
{
autoPlayTimer
.
value
=
setInterval
(()
=>
{
handleNextClickAuto
();
},
10000
);
}
};
// 翻页
const
handlePageChange
=
page
=>
{
if
(
page
<
1
||
page
>
totalPage
.
value
)
return
;
currentPage
.
value
=
page
;
getDeepMiningSelectData
();
// ✅ 停止自动轮播
const
stopAutoPlay
=
()
=>
{
if
(
autoPlayTimer
.
value
)
{
clearInterval
(
autoPlayTimer
.
value
);
autoPlayTimer
.
value
=
null
;
}
};
// ✅ 自动下一个(支持循环)
const
handleNextClickAuto
=
()
=>
{
const
currentIndex
=
sanctionList
.
value
.
findIndex
(
item
=>
item
.
id
===
currentSanctionId
.
value
);
let
nextItem
;
if
(
currentIndex
<
sanctionList
.
value
.
length
-
1
)
{
nextItem
=
sanctionList
.
value
[
currentIndex
+
1
];
}
else
{
nextItem
=
sanctionList
.
value
[
0
];
// 循环到第一个
}
if
(
nextItem
)
{
handleSanctionSelect
(
nextItem
.
id
);
}
};
// ✅ 修改现有函数,添加重置定时器
const
handlePrevClick
=
()
=>
{
const
currentIndex
=
sanctionList
.
value
.
findIndex
(
item
=>
item
.
id
===
currentSanctionId
.
value
);
if
(
currentIndex
>
0
)
{
const
prevItem
=
sanctionList
.
value
[
currentIndex
-
1
];
handleSanctionSelect
(
prevItem
.
id
);
startAutoPlay
();
}
};
const
handleNextClick
=
()
=>
{
const
currentIndex
=
sanctionList
.
value
.
findIndex
(
item
=>
item
.
id
===
currentSanctionId
.
value
);
if
(
currentIndex
<
sanctionList
.
value
.
length
-
1
)
{
const
nextItem
=
sanctionList
.
value
[
currentIndex
+
1
];
handleSanctionSelect
(
nextItem
.
id
);
startAutoPlay
();
}
};
// 列表项点击事件
const
handleSanctionSelect
=
id
=>
{
currentSanctionId
.
value
=
id
;
getFishboneData
();
getCnEntityOnChainData
();
startAutoPlay
();
};
const
activeTab
=
ref
([
"制裁时序分析"
]);
const
activeIndex
=
ref
(
0
);
const
dateRange
=
ref
([
"2025-01-01"
,
"2025-12-31"
]);
const
sanctionList
=
ref
([
{
id
:
1
,
date
:
"2025年2月8日"
,
title
:
"实体清单更新"
,
count
:
2
,
unit
:
"家中国实体"
},
{
id
:
2
,
date
:
"2025年4月10日"
,
title
:
"实体清单更新"
,
count
:
5
,
unit
:
"家中国实体"
},
{
id
:
3
,
date
:
"2025年6月29日"
,
title
:
"实体清单更新"
,
count
:
6
,
unit
:
"家中国实体"
},
{
id
:
4
,
date
:
"2025年8月12日"
,
title
:
"实体清单更新"
,
count
:
24
,
unit
:
"家中国实体"
},
{
id
:
5
,
date
:
"2025年8月19日"
,
title
:
"实体清单更新"
,
count
:
11
,
unit
:
"家中国实体"
},
{
id
:
6
,
date
:
"2025年9月12日"
,
title
:
"实体清单更新"
,
count
:
3
,
unit
:
"家中国实体"
},
{
id
:
7
,
date
:
"2025年9月26日"
,
title
:
"实体清单更新"
,
count
:
6
,
unit
:
"家中国实体"
},
{
id
:
8
,
date
:
"2025年10月12日"
,
title
:
"实体清单更新"
,
count
:
18
,
unit
:
"家中国实体"
}
]);
const
sanctionList
=
ref
([]);
const
currentSanctionId
=
ref
(
5
);
const
cnEntityOnChainData
=
ref
({});
...
...
@@ -479,6 +520,14 @@ onMounted(() => {
getDeepMiningSelectData
();
// 获取产业链信息
getIndustryList
();
nextTick
(()
=>
{
startAutoPlay
();
});
});
// 组件卸载时停止自动轮播
onUnmounted
(()
=>
{
stopAutoPlay
();
});
</
script
>
...
...
src/views/exportControl/v2.0EntityList/components/sanctionsOverview/components/introductionPage/index.vue
浏览文件 @
57a3db48
...
...
@@ -241,11 +241,11 @@ const handleClick = item => {
const
route
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
query
:
{
id
:
item
.
id
id
:
item
.
id
,
sanTypeId
:
item
.
sanTypeId
||
1
}
}
);
window
.
open
(
route
.
href
,
"_blank"
);
}
;
const
selectedDomain
=
ref
(
0
);
...
...
src/views/exportControl/v2.0EntityList/components/sanctionsOverview/components/listPage/index.vue
浏览文件 @
57a3db48
...
...
@@ -173,6 +173,13 @@
</div>
</
template
>
</el-table-column>
<el-table-column
prop=
"listingLocation"
label=
"上市地点"
width=
"140"
show-overflow-tooltip
align=
"center"
/>
<el-table-column
prop=
"startTime"
label=
"制裁时间"
...
...
@@ -557,6 +564,10 @@ watch(customDateRange, () => {
width
:
160px
;
height
:
32px
;
}
:deep
(
.el-checkbox__label
)
{
font-size
:
16px
;
color
:
rgb
(
95
,
101
,
108
);
}
}
}
...
...
@@ -575,9 +586,14 @@ watch(customDateRange, () => {
background-color
:
#fff
;
.checkbox-group
{
display
:
flex
;
flex-wrap
:
wrap
;
padding
:
0
0
0
24px
;
// display: flex;
// flex-wrap: wrap;
// padding: 0 0 0 24px;
display
:
grid
;
grid-template-columns
:
repeat
(
2
,
160px
);
gap
:
8px
4px
;
padding-left
:
20px
;
.el-checkbox
{
width
:
50%
;
...
...
src/views/exportControl/v2.0SingleSanction/components/dataStatistics/index.vue
浏览文件 @
57a3db48
...
...
@@ -54,12 +54,12 @@
</div>
</div>
</div>
-->
<EChart
:option=
"domainChartOption"
autoresize
:style=
"
{ height: '300px' }" />
<EChart
:option=
"domainChartOption"
autoresize
:style=
"
{ height: '300px'
, padding: '0 20px'
}" />
<div
class=
"data-origin-box"
>
<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
/>
...
...
@@ -104,12 +104,12 @@
</div>
</div>
</div>
-->
<EChart
:option=
"typeChartOption"
autoresize
:style=
"
{ height: '300px' }" />
<EChart
:option=
"typeChartOption"
autoresize
:style=
"
{ height: '300px'
, padding: '0 20px'
}" />
<div
class=
"data-origin-box"
>
<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
/>
...
...
@@ -118,7 +118,7 @@
</AnalysisBox>
</div>
<div
class=
"main-item"
>
<AnalysisBox
title=
"制裁实体国家分布情况"
>
<AnalysisBox
title=
"制裁实体国家
地区
分布情况"
>
<div
class=
"country-list"
>
<div
class=
"list-item"
v-for=
"(item, index) in countryDistribution"
:key=
"index"
>
<img
:src=
"flag"
alt=
""
class=
"flag"
/>
...
...
@@ -150,7 +150,7 @@
<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
/>
...
...
@@ -159,7 +159,7 @@
</AnalysisBox>
</div>
<div
class=
"main-item"
>
<AnalysisBox
title=
"制裁实体
地域
分布情况"
>
<AnalysisBox
title=
"制裁实体
各省
分布情况"
>
<div
class=
"map-wrapper"
>
<div
class=
"map-chart"
ref=
"mapChartRef"
></div>
<div
class=
"rank-list"
>
...
...
@@ -194,7 +194,7 @@
<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
/>
...
...
@@ -251,7 +251,7 @@ const getRegionData = async () => {
regionDistribution
.
value
=
res
.
data
||
[];
maxRegionCount
.
value
=
Math
.
max
(...
regionDistribution
.
value
.
map
(
item
=>
item
.
count
),
0
);
initMapChart
();
regionDistributionChart
.
interpret
({
type
:
"柱状图"
,
name
:
"
制裁实体地域
分布情况"
,
data
:
res
.
data
});
regionDistributionChart
.
interpret
({
type
:
"柱状图"
,
name
:
"
进入本次实体清单的中国实体各省
分布情况"
,
data
:
res
.
data
});
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -291,7 +291,11 @@ const getCountryCount = async () => {
gradient
};
});
countryDistributionChart
.
interpret
({
type
:
"柱状图"
,
name
:
"制裁实体国家分布情况"
,
data
:
res
.
data
});
countryDistributionChart
.
interpret
({
type
:
"柱状图"
,
name
:
"进入本次实体清单的实体国家地区分布情况"
,
data
:
res
.
data
});
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -312,7 +316,7 @@ const getEntityTypeCount = async () => {
const
res
=
await
getSingleSanctionEntityTypeCount
(
params
);
if
(
res
.
code
===
200
)
{
entityTypeCount
.
value
=
res
.
data
||
[];
typeChart
.
interpret
({
type
:
"饼图"
,
name
:
"
制裁
实体类型分布情况"
,
data
:
entityTypeCount
.
value
});
typeChart
.
interpret
({
type
:
"饼图"
,
name
:
"
进入本次实体清单的中国
实体类型分布情况"
,
data
:
entityTypeCount
.
value
});
initTypeChart
();
}
}
catch
(
error
)
{
...
...
@@ -335,7 +339,7 @@ const getDomainCount = async () => {
if
(
res
.
code
===
200
)
{
domainCount
.
value
=
res
.
data
||
[];
initDomainChart
();
domainChart
.
interpret
({
type
:
"饼图"
,
name
:
"
制裁
实体领域分布情况"
,
data
:
domainCount
.
value
});
domainChart
.
interpret
({
type
:
"饼图"
,
name
:
"
进入本次实体清单的中国
实体领域分布情况"
,
data
:
domainCount
.
value
});
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -348,7 +352,7 @@ const totalCount = ref({});
const
getTotalCount
=
async
()
=>
{
if
(
!
sanRecordId
.
value
)
return
;
try
{
const
res
=
await
getSingleSanctionTotalCount
(
route
.
query
.
sanTypeId
);
const
res
=
await
getSingleSanctionTotalCount
(
route
.
query
.
sanTypeId
,
sanRecordId
.
value
);
if
(
res
.
code
===
200
)
{
totalCount
.
value
=
res
.
data
||
{};
}
...
...
@@ -1264,8 +1268,8 @@ onMounted(() => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
padding
:
22px
0
;
justify-content
:
flex-start
;
padding
:
22px
;
.data-origin-icon
{
width
:
16px
;
height
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/components/deepMining/components/RelationGraph.vue
浏览文件 @
57a3db48
...
...
@@ -107,22 +107,185 @@ const initGraph = (layoutType = 1) => {
});
};
// const initNormalGraph = (layoutType, width, height) => {
// const data = processGraphData(props.graphData);
// console.log("初始数据", props.graphData);
// if (!data.nodes || data.nodes.length === 0) return;
// const layout = {
// type: "none",
// center: [width / 2, height / 2],
// preventOverlap: true,
// nodeSpacing: 80,
// linkDistance: 250,
// nodeStrength: -800,
// edgeStrength: 0.1,
// collideStrength: 0.8,
// alphaDecay: 0.01,
// alphaMin: 0.001
// };
// graphInstance.value = new G6.Graph({
// container: containerRef.value,
// width,
// height,
// fitView: true,
// fitViewPadding: 100,
// fitCenter: true,
// animate: true,
// animateCfg: {
// duration: 300,
// easing: "easeLinear"
// },
// minZoom: 0.1,
// maxZoom: 10,
// modes: {
// default: [
// "drag-canvas",
// "zoom-canvas",
// "drag-node",
// {
// type: "activate-relations",
// trigger: "mouseenter",
// resetSelected: true
// }
// ]
// },
// layout,
// defaultNode: {
// type: "image",
// size: 40,
// clipCfg: {
// show: true,
// type: "circle",
// r: 20
// },
// labelCfg: {
// position: "bottom",
// offset: 10,
// style: {
// fill: "#333",
// fontSize: 11,
// fontFamily: "Microsoft YaHei",
// textAlign: "center",
// background: {
// fill: "rgba(255, 255, 255, 0.95)",
// padding: [4, 6, 4, 6],
// radius: 4
// }
// }
// }
// // 注意:节点边框样式在 processGraphData 中单独设置,不在这里设置
// },
// defaultEdge: {
// type: "quadratic",
// style: {
// stroke: "red",
// lineWidth: 3,
// opacity: 0.9,
// shadowColor: "rgba(231, 243, 255, 1)",
// shadowBlur: 4,
// endArrow: {
// path: "M 0,0 L 12,6 L 12,-6 Z",
// fill: "#5B8FF9"
// }
// },
// labelCfg: {
// autoRotate: true,
// style: {
// fill: "rgba(137, 193, 255, 1)",
// fontSize: 10,
// fontFamily: "Microsoft YaHei",
// background: {
// fill: "rgba(231, 243, 255, 1)",
// padding: [2, 4, 2, 4],
// radius: 5
// }
// }
// }
// },
// nodeStateStyles: {
// active: {
// shadowColor: "#1459BB",
// shadowBlur: 15,
// stroke: "#1459BB",
// lineWidth: 3
// },
// inactive: {
// opacity: 0.3
// }
// },
// edgeStateStyles: {
// active: {
// stroke: "#1459BB",
// lineWidth: 4
// },
// inactive: {
// opacity: 0.15
// }
// }
// });
// graphInstance.value.data(data);
// graphInstance.value.render();
// bindGraphEvents();
// };
const
initNormalGraph
=
(
layoutType
,
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
);
console
.
log
(
"初始数据"
,
props
.
graphData
);
if
(
!
data
.
nodes
||
data
.
nodes
.
length
===
0
)
return
;
// 中心节点坐标
const
centerX
=
width
/
2
;
const
centerY
=
height
/
2
;
const
upperY
=
centerY
-
240
;
// 上方节点 Y 坐标
const
lowerY
=
centerY
+
240
;
// 下方节点 Y 坐标
const
nodeSpacing
=
100
;
// 节点水平间距
// 分离中心节点和其他节点
const
centerNode
=
data
.
nodes
.
find
(
n
=>
n
.
isCenter
);
const
otherNodes
=
data
.
nodes
.
filter
(
n
=>
!
n
.
isCenter
);
const
totalNodes
=
otherNodes
.
length
;
const
upperCount
=
Math
.
ceil
(
totalNodes
/
2
);
// 向上取整,上方多一个
const
lowerCount
=
totalNodes
-
upperCount
;
// 为上方节点分配坐标
const
upperNodes
=
otherNodes
.
slice
(
0
,
upperCount
);
upperNodes
.
forEach
((
node
,
index
)
=>
{
const
totalWidth
=
(
upperCount
-
1
)
*
nodeSpacing
;
const
startX
=
centerX
-
totalWidth
/
2
;
node
.
x
=
startX
+
index
*
nodeSpacing
;
node
.
y
=
upperY
;
// 固定位置,防止力导向布局移动
node
.
fx
=
node
.
x
;
node
.
fy
=
node
.
y
;
});
// 为下方节点分配坐标
const
lowerNodes
=
otherNodes
.
slice
(
upperCount
);
lowerNodes
.
forEach
((
node
,
index
)
=>
{
const
totalWidth
=
(
lowerCount
-
1
)
*
nodeSpacing
;
const
startX
=
centerX
-
totalWidth
/
2
;
node
.
x
=
startX
+
index
*
nodeSpacing
;
node
.
y
=
lowerY
;
// 固定位置,防止力导向布局移动
node
.
fx
=
node
.
x
;
node
.
fy
=
node
.
y
;
});
// 设置中心节点坐标
if
(
centerNode
)
{
centerNode
.
x
=
centerX
;
centerNode
.
y
=
centerY
;
// 固定中心节点位置
centerNode
.
fx
=
centerX
;
centerNode
.
fy
=
centerY
;
}
const
layout
=
{
type
:
"force"
,
center
:
[
width
/
2
,
height
/
2
],
preventOverlap
:
true
,
nodeSpacing
:
80
,
linkDistance
:
250
,
nodeStrength
:
-
800
,
edgeStrength
:
0.1
,
collideStrength
:
0.8
,
alphaDecay
:
0.01
,
alphaMin
:
0.001
type
:
"none"
,
// 使用预设坐标,不进行力导向布局
center
:
[
centerX
,
centerY
]
};
graphInstance
.
value
=
new
G6
.
Graph
({
...
...
@@ -175,10 +338,9 @@ const initNormalGraph = (layoutType, width, height) => {
}
}
}
// 注意:节点边框样式在 processGraphData 中单独设置,不在这里设置
},
defaultEdge
:
{
type
:
"
quadratic
"
,
type
:
"
line
"
,
style
:
{
stroke
:
"red"
,
lineWidth
:
3
,
...
...
@@ -230,7 +392,6 @@ const initNormalGraph = (layoutType, width, height) => {
graphInstance
.
value
.
render
();
bindGraphEvents
();
};
const
initCircularGraph
=
(
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
);
...
...
@@ -307,7 +468,7 @@ const initCircularGraph = (width, height) => {
}
},
defaultEdge
:
{
type
:
"
quadratic
"
,
type
:
"
line
"
,
style
:
{
stroke
:
"#5B8FF9"
,
lineWidth
:
3
,
...
...
src/views/exportControl/v2.0SingleSanction/components/deepMining/index.vue
浏览文件 @
57a3db48
...
...
@@ -110,6 +110,7 @@
@
node-click=
"handleNodeClick"
@
layout-change=
"handleLayoutChange"
/>
<!-- <GraphChart :nodes="nodes" :links="links" layoutType="none" /> -->
</div>
</div>
</div>
...
...
@@ -134,6 +135,7 @@ import {
}
from
"@/api/exportControlV2.0"
;
import
RelationGraph
from
"./components/RelationGraph.vue"
;
import
AnalysisBox
from
"@/components/base/boxBackground/analysisBox.vue"
;
import
GraphChart
from
"@/components/base/GraphChart/index.vue"
;
const
sanRecordId
=
ref
(
""
);
const
activeTab
=
ref
([
"实体穿透分析"
]);
...
...
@@ -157,6 +159,9 @@ const graphData = ref({ nodes: [], links: [] });
const
treeData
=
ref
(
null
);
const
selectedNode
=
ref
(
null
);
const
nodes
=
ref
([]);
const
links
=
ref
([]);
const
singleSanctionEntityEquityData
=
ref
(
null
);
const
singleSanctionEntitySupplyChainData
=
ref
(
null
);
const
singleSanctionEntityList
=
ref
([]);
...
...
@@ -204,6 +209,7 @@ const updateGraphData = () => {
const
data
=
rightActiveTab
.
value
===
"supplyChain"
?
singleSanctionEntitySupplyChainData
.
value
:
singleSanctionEntityEquityData
.
value
;
console
.
log
(
"图谱数据 =>"
,
data
);
if
(
!
data
)
return
;
const
nodes
=
[];
...
...
@@ -252,8 +258,172 @@ const updateGraphData = () => {
});
graphData
.
value
=
{
nodes
,
links
};
// nodes.value = nodes;
// links.value = links;
};
const
links1
=
[
{
source
:
1
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
2
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
3
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
4
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"从属"
}
},
{
source
:
5
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
6
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
0
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
8
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
9
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"从属"
}
},
{
source
:
10
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
11
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
12
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
13
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
14
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
15
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
,
color
:
"red"
,
borderColor
:
"red"
}
}
];
// const updateGraphData = () => {
// const data =
// rightActiveTab.value === "supplyChain" ? singleSanctionEntitySupplyChainData.value : singleSanctionEntityEquityData.value;
// console.log("图谱数据 =>", data);
// if (!data) return;
// const newNodes = [];
// const newLinks = [];
// // 容器尺寸(根据 .right-echarts 的高度 calc(100% - 56px) ≈ 772px)
// const containerWidth = 1000;
// const containerHeight = 700;
// // 中心节点坐标(居中)
// const centerX = containerWidth / 2;
// const centerY = containerHeight / 2;
// // 上下节点分布参数
// const upperY = centerY - 200; // 上方节点 Y 坐标
// const lowerY = centerY + 200; // 下方节点 Y 坐标
// const nodeSpacing = 100; // 节点水平间距
// // 合并所有节点列表(上游 + 下游)
// const allItems = [];
// const parentList = data.parentOrgList || [];
// const childList = data.childrenOrgList || [];
// // 添加上游节点
// parentList.forEach((item, index) => {
// allItems.push({
// ...item,
// linkType: rightActiveTab.value === "supplyChain" ? "供应商" : item.type || "持股",
// direction: "source" // 链接方向:指向中心节点
// });
// });
// // 添加下游节点
// childList.forEach((item, index) => {
// allItems.push({
// ...item,
// linkType: rightActiveTab.value === "supplyChain" ? "客户" : item.description || "投资",
// direction: "target" // 链接方向:从中心节点指出
// });
// });
// // 中心节点
// newNodes.push({
// id: 0,
// name: data.orgName || "中心节点",
// symbol: `image://${companyActive}`,
// symbolSize: 60,
// value: 10,
// isSanctioned: true,
// x: centerX,
// y: centerY
// });
// // 计算上下分配
// const totalNodes = allItems.length;
// const upperCount = Math.ceil(totalNodes / 2); // 向上取整,上方多一个
// const lowerCount = totalNodes - upperCount;
// // 上方节点(前一半)
// const upperItems = allItems.slice(0, upperCount);
// upperItems.forEach((item, index) => {
// const totalWidth = (upperCount - 1) * nodeSpacing;
// const startX = centerX - totalWidth / 2;
// const x = startX + index * nodeSpacing;
// const y = upperY;
// const nodeId = `n-${index}`;
// newNodes.push({
// id: nodeId,
// name: item.name || `节点${index}`,
// symbol: `image://${item.isSanctioned ? companyActive : company}`,
// symbolSize: 40,
// value: 5,
// isSanctioned: item.isSanctioned,
// x,
// y
// });
// // 根据 direction 决定链接方向
// if (item.direction === "source") {
// newLinks.push({
// source: nodeId,
// target: 0,
// name: item.linkType,
// label: { show: true, formatter: item.description }
// });
// } else {
// newLinks.push({
// source: 0,
// target: nodeId,
// name: item.linkType,
// label: { show: true, formatter: item.description }
// });
// }
// });
// // 下方节点(后一半)
// const lowerItems = allItems.slice(upperCount);
// lowerItems.forEach((item, index) => {
// const totalWidth = (lowerCount - 1) * nodeSpacing;
// const startX = centerX - totalWidth / 2;
// const x = startX + index * nodeSpacing;
// const y = lowerY;
// const nodeId = `n-${upperCount + index}`;
// newNodes.push({
// id: nodeId,
// name: item.name || `节点${upperCount + index}`,
// symbol: `image://${item.isSanctioned ? companyActive : company}`,
// symbolSize: 40,
// value: 5,
// isSanctioned: item.isSanctioned,
// x,
// y
// });
// // 根据 direction 决定链接方向
// if (item.direction === "source") {
// newLinks.push({
// source: nodeId,
// target: 0,
// name: item.linkType,
// label: { show: true, formatter: "{c}" }
// });
// } else {
// newLinks.push({
// source: 0,
// target: nodeId,
// name: item.linkType,
// label: { show: true, formatter: "{c}" }
// });
// }
// });
// console.log("最终节点数:", newNodes, "最终链接数:", newLinks, "上方节点:", upperCount, "下方节点:", lowerCount);
// // 更新响应式数据
// nodes.value = newNodes;
// links.value = newLinks;
// };
const
updateTreeData
=
data
=>
{
if
(
!
data
)
return
;
...
...
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/industrialImpact/index.vue
浏览文件 @
57a3db48
...
...
@@ -1317,7 +1317,7 @@ onMounted(async () => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
30px
0
;
.data-origin-icon
{
width
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/researchImpact/index.vue
浏览文件 @
57a3db48
...
...
@@ -1543,7 +1543,7 @@ onBeforeUnmount(() => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
35px
0
;
.data-origin-icon
{
width
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/components/sanctionsOverview/index.vue
浏览文件 @
57a3db48
...
...
@@ -168,14 +168,21 @@
</el-table-column>
<el-table-column
label=
"涉及领域"
width=
"180"
align=
"center"
>
<
template
#
default=
"scope"
>
<span
<
!--
<
span
v-for=
"(item, index) in scope.row.fields"
:key=
"index"
class=
"tag"
:style=
"getTagStyle(item)"
style=
"margin: 0 2px"
>
{{
item
}}
</span
>
>
-->
<div
class=
"domain-box"
>
<AreaTag
v-for=
"(domain, index) in scope.row.fields"
:key=
"index"
:tagName=
"domain"
/>
</div>
</
template
>
</el-table-column>
<el-table-column
prop=
"location"
label=
"上市地点"
width=
"90"
align=
"center"
/>
...
...
@@ -563,10 +570,10 @@ onMounted(() => {
</
script
>
<
style
scoped
lang=
"scss"
>
*
{
margin
:
0
;
padding
:
0
;
}
//
* {
//
margin: 0;
//
padding: 0;
//
}
.sanctions-overview
{
width
:
1601px
;
...
...
@@ -669,7 +676,7 @@ onMounted(() => {
.left-top-content
{
width
:
100%
;
height
:
234px
;
//
height: 234px;
padding
:
19px
29px
22px
27px
;
overflow
:
auto
;
...
...
@@ -1001,6 +1008,11 @@ onMounted(() => {
border-radius
:
8px
;
overflow
:
hidden
;
.domain-box
{
display
:
flex
;
gap
:
8px
;
}
:deep
(
.el-table__header-wrapper
)
{
th
{
background-color
:
var
(
--
color-primary-100
)
!
important
;
...
...
src/views/exportControl/v2.0SingleSanction/index.vue
浏览文件 @
57a3db48
...
...
@@ -52,7 +52,7 @@
:close-on-click-modal=
"false"
@
close=
"resetModal"
>
<div
class=
"sanction-list"
>
<div
class=
"sanction-list"
:loading=
"loading"
>
<div
v-for=
"item in sanctionList"
:key=
"item.id"
...
...
@@ -61,6 +61,7 @@
@click="selectSanction(item)"
>
{{
item
.
name
}}
<div
class=
"sanction-type"
>
{{
item
.
postDate
}}
</div>
</div>
</div>
...
...
@@ -193,6 +194,7 @@ const handleAnalysisClick = () => {
};
// ========== 新增响应式状态 ==========
const
loading
=
ref
(
false
);
const
sanctionModalVisible
=
ref
(
false
);
const
sanctionList
=
ref
([]);
const
selectedSanctionId
=
ref
(
null
);
...
...
@@ -204,6 +206,7 @@ const totalElements = ref(0);
const
openSanctionModal
=
async
()
=>
{
sanctionModalVisible
.
value
=
true
;
console
.
log
(
"制裁事件列表11:"
,
sanctionList
.
value
);
loading
.
value
=
true
;
await
fetchSanctionData
();
};
...
...
@@ -211,6 +214,7 @@ const openSanctionModal = async () => {
const
fetchSanctionData
=
async
()
=>
{
try
{
const
res
=
await
getSanctionProcess
([
1
],
currentPage
.
value
,
10
);
loading
.
value
=
false
;
if
(
res
&&
!!
res
.
content
)
{
sanctionList
.
value
=
res
.
content
||
[];
totalElements
.
value
=
res
.
totalElements
||
0
;
...
...
@@ -225,6 +229,7 @@ const fetchSanctionData = async () => {
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁事件失败:"
,
error
);
loading
.
value
=
false
;
sanctionList
.
value
=
[];
totalElements
.
value
=
0
;
}
...
...
@@ -237,7 +242,7 @@ const handlePageChange = async newPage => {
};
// ========== 选择某项 ==========
const
selectSanction
=
item
=>
{
const
selectSanction
=
async
item
=>
{
selectedSanctionId
.
value
=
item
.
id
;
router
.
replace
({
path
:
window
.
location
.
pathname
,
...
...
@@ -247,7 +252,10 @@ const selectSanction = item => {
}
});
sanctionModalVisible
.
value
=
false
;
window
.
location
.
reload
();
console
.
log
(
"跳转URL:"
,
window
.
location
.
href
);
// 根据最新URL参数刷新当前页面
window
.
open
(
`
${
window
.
location
.
pathname
}
?id=
${
item
.
id
}
&sanTypeId=
${
item
.
sanTypeId
}
`
,
"_self"
);
};
// ========== 关闭弹窗时重置 ==========
...
...
@@ -467,6 +475,8 @@ onMounted(() => {
font-size
:
14px
;
color
:
#333
;
transition
:
background-color
0
.2s
;
display
:
flex
;
justify-content
:
space-between
;
}
.sanction-item
:hover
{
...
...
src/views/exportControl/v2.0SingleSanction/originPage/index-back.vue
0 → 100644
浏览文件 @
57a3db48
<
template
>
<div
class=
"entity-list"
>
<div
class=
"header"
>
<div
class=
"header-title"
>
<img
:src=
"headerTitle.img"
alt=
""
/>
<div>
<div
class=
"title"
>
{{
headerTitle
.
title
}}
<!--
<span>
{{
headerTitle
.
titleEn
}}
</span>
-->
</div>
<div
class=
"department"
>
{{
headerTitle
.
department
}}
</div>
</div>
<!--
<div
class=
"btn"
>
<img
:src=
"icon01"
alt=
""
>
切换
</div>
-->
</div>
</div>
<div
class=
"main"
>
<div
class=
"pdf-container"
>
<iframe
v-if=
"headerTitle.srcUrl"
:src=
"headerTitle.srcUrl"
width=
"100%"
height=
"100%"
frameborder=
"0"
></iframe>
<div
v-else
class=
"no-pdf"
>
暂无原文
</div>
</div>
<div
class=
"pdf-container"
>
<iframe
v-if=
"headerTitle.transUrl"
:src=
"headerTitle.transUrl"
width=
"100%"
height=
"100%"
frameborder=
"0"
></iframe>
<div
v-else
class=
"no-pdf"
>
暂无译文
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
}
from
"vue"
;
import
{
getSingleSanctionOverview
}
from
"@/api/exportControlV2.0.js"
;
import
title
from
"../assets/title.png"
;
import
icon01
from
"../assets/icon01.png"
;
// 单次制裁-制裁概况-基本信息
const
singleSanctionOverview
=
ref
({});
const
getSingleSanctionOverviewData
=
async
()
=>
{
if
(
!
sanRecordId
.
value
)
return
;
try
{
const
res
=
await
getSingleSanctionOverview
({
sanRecordId
:
sanRecordId
.
value
});
if
(
res
.
code
===
200
)
{
singleSanctionOverview
.
value
=
res
.
data
||
{};
// 格式化日期
let
dateStr
=
""
;
if
(
singleSanctionOverview
.
value
.
postDate
)
{
const
date
=
new
Date
(
singleSanctionOverview
.
value
.
postDate
);
if
(
!
isNaN
(
date
.
getTime
()))
{
dateStr
=
`
${
date
.
getFullYear
()}
年
${
date
.
getMonth
()
+
1
}
月
${
date
.
getDate
()}
日`
;
}
else
{
dateStr
=
singleSanctionOverview
.
value
.
postDate
;
}
}
// 更新头部信息
headerTitle
.
value
=
{
...
headerTitle
.
value
,
title
:
`
${
dateStr
}
《
${
singleSanctionOverview
.
value
.
sanTitleZh
||
singleSanctionOverview
.
value
.
sanTitle
}
》`
,
titleEn
:
singleSanctionOverview
.
value
.
sanTitle
||
""
,
department
:
singleSanctionOverview
.
value
.
fileCode
||
""
,
srcUrl
:
singleSanctionOverview
.
value
.
srcUrl
||
""
,
transUrl
:
singleSanctionOverview
.
value
.
transUrl
||
""
};
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁概况失败:"
,
error
);
}
};
const
headerTitle
=
ref
({
img
:
title
});
// 获取URL参数
const
sanRecordId
=
ref
(
""
);
const
getUrlParams
=
()
=>
{
const
urlParams
=
new
URLSearchParams
(
window
.
location
.
search
);
sanRecordId
.
value
=
urlParams
.
get
(
"id"
)
||
""
;
};
onMounted
(()
=>
{
getUrlParams
();
getSingleSanctionOverviewData
();
});
</
script
>
<
style
scoped
lang=
"scss"
>
*
{
margin
:
0
;
padding
:
0
;
}
.entity-list
{
width
:
100%
;
height
:
100%
;
.header
{
width
:
100%
;
height
:
148px
;
background-color
:
#fff
;
padding-top
:
16px
;
.header-title
{
width
:
1601px
;
height
:
72px
;
background-color
:
rgba
(
246
,
250
,
255
,
1
);
margin
:
0
auto
;
border-radius
:
10px
;
border
:
2px
solid
rgba
(
174
,
214
,
255
,
1
);
display
:
flex
;
align-items
:
center
;
margin-bottom
:
12px
;
position
:
relative
;
img
{
width
:
54px
;
height
:
54px
;
margin-left
:
15px
;
margin-right
:
11px
;
}
.title
{
font-size
:
20px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
26px
;
color
:
rgb
(
59
,
65
,
75
);
span
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
95
,
101
,
108
);
margin-left
:
11px
;
}
}
.department
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
95
,
101
,
108
);
}
.btn
{
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
position
:
absolute
;
right
:
16px
;
top
:
25px
;
font-size
:
18px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
5
,
95
,
194
);
img
{
width
:
20px
;
height
:
20px
;
margin-right
:
7px
;
}
}
}
.header-nav
{
width
:
1601px
;
margin
:
0
auto
;
height
:
48px
;
display
:
flex
;
align-items
:
center
;
.nav-item
{
display
:
flex
;
align-items
:
center
;
height
:
100%
;
margin-right
:
32px
;
cursor
:
pointer
;
position
:
relative
;
font-size
:
18px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
59
,
65
,
75
);
&
:last-child
{
margin-right
:
0
;
}
img
{
width
:
16px
;
height
:
16px
;
margin-right
:
4px
;
}
&
.active
{
color
:
rgb
(
5
,
95
,
194
);
font-weight
:
700
;
}
.active-line
{
position
:
absolute
;
bottom
:
0
;
left
:
0
;
width
:
100%
;
height
:
3px
;
background-color
:
#055fc2
;
border-radius
:
1
.5px
;
}
}
.original-text-btn
{
margin-left
:
auto
;
width
:
152px
;
height
:
36px
;
background
:
#ffffff
;
border-radius
:
4px
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
img
{
width
:
16px
;
height
:
16px
;
margin-right
:
8px
;
}
span
{
font-size
:
16px
;
font-weight
:
400
;
color
:
rgb
(
95
,
101
,
108
);
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
}
}
}
}
.main
{
width
:
1601px
;
height
:
calc
(
100%
-
148px
);
background-color
:
#f7f8f9
;
margin
:
0
auto
;
display
:
flex
;
justify-content
:
space-between
;
padding-top
:
20px
;
box-sizing
:
border-box
;
.pdf-container
{
width
:
790px
;
height
:
calc
(
100%
-
20px
);
background-color
:
#fff
;
// border: 1px solid rgba(174, 214, 255, 1);
border-radius
:
4px
;
overflow
:
hidden
;
.no-pdf
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
height
:
100%
;
color
:
#909399
;
font-size
:
16px
;
background-color
:
#fff
;
}
}
}
}
</
style
>
src/views/exportControl/v2.0SingleSanction/originPage/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/exportControl/v2.0SingleSanction/originPage/pdf.vue
0 → 100644
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/finance/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/CongressHearingView/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/SurveyProjectView/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/ThinkTankDetail/PolicyTracking/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/ThinkTankDetail/PolicyTracking/utils/piechart.js
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/ThinkTankDetail/thinkDynamics/CongressHearing/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/ThinkTankDetail/thinkDynamics/SurveyForm/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/ThinkTankDetail/thinkDynamics/ThinkTankReport/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/ThinkTankDetail/thinkDynamics/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/components/HomeMainFooterMain.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/components/HomeMainFooterSurvey.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/components/ThinkTankCongressHearingOverview.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/components/ThinkTankPolicyAdviceOverview.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/reportOriginal/index.vue
浏览文件 @
57a3db48
差异被折叠。
点击展开。
src/views/thinkTank/utils/piechart.js
浏览文件 @
57a3db48
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论