Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
8e94a51d
提交
8e94a51d
authored
3月 31, 2026
作者:
yanpeng
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'pre' of
http://8.140.26.4:10003/caijian/risk-monitor
into yp-dev
上级
1fd134f1
466614be
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
58 个修改的文件
包含
1021 行增加
和
225 行删除
+1021
-225
index.js
src/api/aiAnalysis/index.js
+17
-0
bill.js
src/api/bill.js
+8
-4
billHome.js
src/api/bill/billHome.js
+8
-2
index.js
src/api/comprehensiveSearch/index.js
+8
-0
graphChart.js
src/components/base/GraphChart/graphChart.js
+1
-0
index.vue
src/components/base/TimeTabPane/index.vue
+12
-1
index.vue
src/components/base/moduleHeader/index.vue
+3
-0
index.js
src/router/index.js
+2
-1
cooperationRestrictions.js
src/router/modules/cooperationRestrictions.js
+2
-1
index.vue
src/styles/components/GraphChart/index.vue
+1
-1
getQuarterRange.js
src/utils/getQuarterRange.js
+5
-5
setChart.js
src/utils/setChart.js
+53
-48
index.vue
src/views/bill/billHome/index.vue
+0
-0
multiLineChart.js
src/views/bill/billHome/utils/multiLineChart.js
+14
-9
BillHeader.vue
src/views/bill/billLayout/components/BillHeader.vue
+19
-43
index.vue
src/views/bill/template/index.vue
+51
-7
index.vue
src/views/comprehensiveSearch/searchResults/index.vue
+2
-2
index.vue
src/views/coopRestriction/components/dataNew/index.vue
+11
-8
index.vue
src/views/coopRestriction/components/dataSub/index.vue
+89
-25
index.vue
src/views/coopRestriction/components/resLib/index.vue
+17
-5
index.vue
src/views/coopRestriction/detail/index.vue
+67
-13
index.vue
src/views/dataLibrary/bill/countryBill/index.vue
+11
-8
index.vue
src/views/dataLibrary/components/InputBox/index.vue
+66
-0
index.vue
src/views/dataLibrary/decree/index.vue
+12
-7
index.vue
src/views/dataLibrary/thinkTank/index.vue
+0
-0
index.vue
src/views/decree/allOrganization/index.vue
+2
-2
index.vue
src/views/decree/decreeHome/index.vue
+45
-31
index.vue
src/views/decree/decreeLayout/influence/index.vue
+4
-2
open.png
src/views/marketAccessRestrictions/assets/icons/open.png
+0
-0
AiTips.vue
src/views/marketAccessRestrictions/com/AiTips.vue
+62
-0
RelatedEvent.vue
src/views/marketAccessRestrictions/com/RelatedEvent.vue
+81
-0
SurveyConclusion.vue
src/views/marketAccessRestrictions/com/SurveyConclusion.vue
+108
-0
SurveyHistory.vue
src/views/marketAccessRestrictions/com/SurveyHistory.vue
+240
-0
icon_1599.png
...sRestrictions/marketAccessHome/assets/icons/icon_1599.png
+0
-0
index.vue
...views/marketAccessRestrictions/marketAccessHome/index.vue
+0
-0
index.vue
...tAccessRestrictions/marketAccessLayout/case/232/index.vue
+0
-0
index.vue
...tAccessRestrictions/marketAccessLayout/case/301/index.vue
+0
-0
index.vue
...tAccessRestrictions/marketAccessLayout/case/337/index.vue
+0
-0
index.vue
...arketAccessRestrictions/marketAccessLayout/case/index.vue
+0
-0
index.vue
...ews/marketAccessRestrictions/marketAccessLayout/index.vue
+0
-0
index.vue
...essRestrictions/marketAccessLayout/overview/232/index.vue
+0
-0
index.vue
...essRestrictions/marketAccessLayout/overview/301/index.vue
+0
-0
index.vue
...essRestrictions/marketAccessLayout/overview/337/index.vue
+0
-0
index.vue
...tAccessRestrictions/marketAccessLayout/overview/index.vue
+0
-0
232.png
...AccessRestrictions/singleCaseLayout/assets/images/232.png
+0
-0
301.png
...AccessRestrictions/singleCaseLayout/assets/images/301.png
+0
-0
337.png
...AccessRestrictions/singleCaseLayout/assets/images/337.png
+0
-0
icon_affiche.png
...trictions/singleCaseLayout/assets/images/icon_affiche.png
+0
-0
index.vue
...AccessRestrictions/singleCaseLayout/deepdig/232/index.vue
+0
-0
index.vue
...AccessRestrictions/singleCaseLayout/deepdig/337/index.vue
+0
-0
index.vue
...rketAccessRestrictions/singleCaseLayout/deepdig/index.vue
+0
-0
index.vue
...views/marketAccessRestrictions/singleCaseLayout/index.vue
+0
-0
index.vue
...ccessRestrictions/singleCaseLayout/overview/232/index.vue
+0
-0
index.vue
...ccessRestrictions/singleCaseLayout/overview/301/index.vue
+0
-0
index.vue
...ccessRestrictions/singleCaseLayout/overview/337/index.vue
+0
-0
index.vue
...ketAccessRestrictions/singleCaseLayout/overview/index.vue
+0
-0
index.vue
src/views/thinkTank/index.vue
+0
-0
multiLineChart.js
src/views/thinkTank/utils/multiLineChart.js
+0
-0
没有找到文件。
src/api/aiAnalysis/index.js
浏览文件 @
8e94a51d
...
...
@@ -143,6 +143,7 @@ export function getChartAnalysis(data, options = {}) {
: typeof options?.onInterpretationDelta === "function"
? options.onInterpretationDelta
: null;
const externalSignal = options?.signal;
return new Promise((resolve, reject) => {
let buffer = "";
let latestInterpretation = "";
...
...
@@ -150,16 +151,32 @@ export function getChartAnalysis(data, options = {}) {
let lastStreamedInterpretationLen = 0;
let settled = false;
const abortController = new AbortController();
const externalAbortHandler = () => {
abortController.abort();
};
if (externalSignal) {
if (externalSignal.aborted) {
abortController.abort();
} else {
externalSignal.addEventListener("abort", externalAbortHandler, { once: true });
}
}
const safeResolve = value => {
if (settled) return;
settled = true;
if (externalSignal) {
externalSignal.removeEventListener("abort", externalAbortHandler);
}
resolve(value);
};
const safeReject = err => {
if (settled) return;
settled = true;
if (externalSignal) {
externalSignal.removeEventListener("abort", externalAbortHandler);
}
reject(err);
};
...
...
src/api/bill.js
浏览文件 @
8e94a51d
...
...
@@ -107,11 +107,12 @@ export function getBillPersonAnalyzeDy(params) {
* @param {id}
* @header token
*/
export
function
getBillContentId
(
params
)
{
export
function
getBillContentId
(
params
,
config
=
{}
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/billInfoBean/contentId/
${
params
.
id
}
`
,
params
,
signal
:
config
.
signal
})
}
...
...
@@ -120,11 +121,12 @@ export function getBillContentId(params) {
* @param {billId,id,cRelated,currentPage,pageSize,domainNameList,measuresNameList,content}
* @header token
*/
export
function
getBillContentTk
(
params
)
{
export
function
getBillContentTk
(
params
,
config
=
{}
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/billInfoBean/content/tk/
${
params
.
billId
}
/
${
params
.
id
}
`
,
params
,
signal
:
config
.
signal
})
}
...
...
@@ -133,11 +135,12 @@ export function getBillContentTk(params) {
* @param {billId,versionId,cRelated}
* @header token
*/
export
function
getBillContentXzfs
(
params
)
{
export
function
getBillContentXzfs
(
params
,
config
=
{}
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/billInfoBean/content/xzfs/
${
params
.
billId
}
/
${
params
.
versionId
}
`
,
params
,
signal
:
config
.
signal
})
}
...
...
@@ -146,11 +149,12 @@ export function getBillContentXzfs(params) {
* @param {billId,versionId,cRelated}
* @header token
*/
export
function
getBillHyly
(
params
)
{
export
function
getBillHyly
(
params
,
config
=
{}
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/billInfoBean/content/hyly/
${
params
.
billId
}
/
${
params
.
versionId
}
`
,
params
,
signal
:
config
.
signal
})
}
...
...
src/api/bill/billHome.js
浏览文件 @
8e94a51d
...
...
@@ -3,8 +3,14 @@ import request from "@/api/request.js";
// 涉华法案领域分布
/**
* @param {Object} params
* @param {string} params.year - 年份
* @param {string} [params.status] - 状态:提出法案/通过法案
* @param {string} params.year - 年份(2022-2026)
* @param {string} [params.status] - 法案状态:
* - 提案
* - 众议院通过
* - 参议院通过
* - 分歧已解决
* - 呈交总统
* - 完成立法
*/
export
function
getBillIndustry
(
params
)
{
return
request
({
...
...
src/api/comprehensiveSearch/index.js
浏览文件 @
8e94a51d
...
...
@@ -10,4 +10,11 @@ export function search(data) {
url
:
`/temporarySearch/search-info/es/page`
,
data
:
data
})
}
export
function
getThinkTankList
()
{
return
request
({
method
:
'GET'
,
url
:
`/temporarySearch/search-info/all-organization-names`
,
})
}
\ No newline at end of file
src/components/base/GraphChart/graphChart.js
浏览文件 @
8e94a51d
...
...
@@ -82,6 +82,7 @@ const getGraphChart = (nodes, links, layoutType) => {
}
},
force
:
{
layoutAnimation
:
false
,
// 关闭初始化晃来晃去的动画
repulsion
:
300
,
gravity
:
0
,
edgeLength
:
300
...
...
src/components/base/TimeTabPane/index.vue
浏览文件 @
8e94a51d
...
...
@@ -17,7 +17,14 @@
</
template
>
<
script
setup
>
import
{
ref
}
from
'vue'
import
{
onMounted
,
ref
}
from
'vue'
const
props
=
defineProps
({
activeTime
:
{
typeof
:
String
,
default
:
'近一周'
}
})
const
timeList
=
ref
([
{
...
...
@@ -34,6 +41,10 @@ const timeList = ref([
},
])
onMounted
(()
=>
{
timeList
.
value
.
forEach
(
item
=>
{
item
.
active
=
item
.
time
===
props
.
activeTime
})
})
const
handleTimeClick
=
(
item
,
index
)
=>
{
timeList
.
value
.
forEach
(
time
=>
{
time
.
active
=
false
...
...
src/components/base/moduleHeader/index.vue
浏览文件 @
8e94a51d
...
...
@@ -246,6 +246,9 @@ const handleToModule = (item, index) => {
window
.
sessionStorage
.
setItem
(
'homeActiveTitleIndex'
,
index
)
if
(
index
===
1
)
{
homeActiveTitleIndex
.
value
=
index
menuList
.
value
.
forEach
(
val
=>
{
val
.
active
=
false
})
item
.
active
=
true
router
.
push
({
path
:
item
.
path
...
...
src/router/index.js
浏览文件 @
8e94a51d
...
...
@@ -69,7 +69,8 @@ router.beforeEach((to, from, next) => {
if
(
to
.
meta
.
title
)
{
if
(
to
.
meta
.
dynamicTitle
)
{
console
.
log
(
'to'
,
to
);
document
.
title
=
window
.
sessionStorage
.
getItem
(
"curTabName"
)
||
to
.
meta
.
title
;
const
storageKey
=
to
.
meta
.
titleStorageKey
||
"curTabName"
;
document
.
title
=
window
.
sessionStorage
.
getItem
(
storageKey
)
||
to
.
meta
.
title
;
}
else
{
document
.
title
=
to
.
meta
.
title
...
...
src/router/modules/cooperationRestrictions.js
浏览文件 @
8e94a51d
...
...
@@ -20,7 +20,8 @@ const cooperationRestrictionsRoutes = [
component
:
CooperationRestrictionsDetail
,
meta
:
{
title
:
"合作限制详情"
,
dynamicTitle
:
true
dynamicTitle
:
true
,
titleStorageKey
:
"cooperationRestrictionsTabName"
}
},
...
...
src/styles/components/GraphChart/index.vue
浏览文件 @
8e94a51d
...
...
@@ -11,7 +11,7 @@
`
}}
</pre>
<div
class=
"chart-box"
>
<GraphChart
:nodes=
"nodes"
:links=
"links"
layoutType=
"
forc
e"
>
<GraphChart
:nodes=
"nodes"
:links=
"links"
layoutType=
"
non
e"
>
</GraphChart>
</div>
</el-col>
...
...
src/utils/getQuarterRange.js
浏览文件 @
8e94a51d
const
getQuarterRange
=
(
quatarNum
)
=>
{
const
getQuarterRange
=
(
year
,
quatarNum
)
=>
{
const
quarters
=
{
1
:
[
'2025-01-01'
,
'2025
-03-31'
],
2
:
[
'2025-04-01'
,
'2025
-06-30'
],
3
:
[
'2025-07-01'
,
'2025
-09-30'
],
4
:
[
'2025-10-01'
,
'2025
-12-31'
]
1
:
[
year
+
'-01-01'
,
year
+
'
-03-31'
],
2
:
[
year
+
'-04-01'
,
year
+
'
-06-30'
],
3
:
[
year
+
'-07-01'
,
year
+
'
-09-30'
],
4
:
[
year
+
'-10-01'
,
year
+
'
-12-31'
]
};
return
quarters
[
quatarNum
];
...
...
src/utils/setChart.js
浏览文件 @
8e94a51d
...
...
@@ -16,67 +16,51 @@ const setChart = (option, chartId, allowClick, selectParam) => {
chart
.
on
(
'click'
,
function
(
params
)
{
switch
(
selectParam
.
moduleType
)
{
case
'国会法案'
:
// 判断点击的是否为饼图的数据项
if
(
params
.
componentType
===
'series'
&&
params
.
seriesType
===
'pie'
)
{
console
.
log
(
'点击的扇形名称:'
,
params
.
name
);
if
(
selectParam
.
key
===
'领域'
)
{
selectParam
.
domains
=
params
.
name
if
(
selectParam
.
key
===
1
)
{
// console.log('当前点击', selectParam, params.seriesName, params.name);
selectParam
.
selectedStatus
=
params
.
seriesName
selectParam
.
selectedDate
=
JSON
.
stringify
(
getMonthRange
(
params
.
name
))
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/countryBill"
,
query
:
selectParam
});
window
.
open
(
route
.
href
,
"_blank"
);
return
}
else
if
(
selectParam
.
key
===
2
)
{
selectParam
.
domains
=
params
.
name
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/countryBill"
,
query
:
selectParam
});
window
.
open
(
route
.
href
,
"_blank"
);
return
}
else
if
(
selectParam
.
key
===
3
)
{
if
(
params
.
name
===
'众议院'
||
params
.
name
===
'参议院'
)
{
selectParam
.
selectedCongress
=
params
.
name
selectParam
.
selectedOrg
=
'全部委员会'
if
(
selectParam
.
selectedDate
.
length
===
4
)
{
selectParam
.
selectedDate
=
JSON
.
stringify
([
selectParam
.
selectedDate
+
'-01-01'
,
selectParam
.
selectedDate
+
'-12-31'
])
}
}
else
if
(
selectParam
.
key
===
'议院委员会'
)
{
if
(
params
.
name
===
'众议院'
||
params
.
name
===
'参议院'
)
{
selectParam
.
selectedCongress
=
params
.
name
selectParam
.
selectedOrg
=
''
if
(
selectParam
.
selectedDate
.
length
===
4
)
{
selectParam
.
selectedDate
=
JSON
.
stringify
([
selectParam
.
selectedDate
+
'-01-01'
,
selectParam
.
selectedDate
+
'-12-31'
])
}
}
else
{
selectParam
.
selectedOrg
=
params
.
name
selectParam
.
selectedCongress
=
''
if
(
selectParam
.
selectedDate
.
length
===
4
)
{
selectParam
.
selectedDate
=
JSON
.
stringify
([
selectParam
.
selectedDate
+
'-01-01'
,
selectParam
.
selectedDate
+
'-12-31'
])
}
}
else
{
selectParam
.
selectedOrg
=
params
.
name
selectParam
.
selectedCongress
=
'全部议院'
if
(
selectParam
.
selectedDate
.
length
===
4
)
{
selectParam
.
selectedDate
=
JSON
.
stringify
([
selectParam
.
selectedDate
+
'-01-01'
,
selectParam
.
selectedDate
+
'-12-31'
])
}
}
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/countryBill"
,
query
:
selectParam
});
window
.
open
(
route
.
href
,
"_blank"
);
}
else
if
(
params
.
componentType
===
'series'
&&
params
.
seriesType
===
'bar'
)
{
if
(
params
.
name
===
'已立法'
)
{
selectParam
.
selectedStatus
=
1
}
else
{
selectParam
.
selectedStatus
=
0
}
if
(
selectParam
.
selectedDate
.
length
===
4
)
{
selectParam
.
selectedDate
=
JSON
.
stringify
([
selectParam
.
selectedDate
+
'-01-01'
,
selectParam
.
selectedDate
+
'-12-31'
])
}
return
}
else
{
selectParam
.
selectedStatus
=
params
.
name
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/countryBill"
,
query
:
selectParam
});
window
.
open
(
route
.
href
,
"_blank"
);
}
else
{
console
.
log
(
'当前点击'
,
selectParam
,
params
.
seriesName
,
params
.
name
);
if
(
params
.
seriesName
!==
'通过率'
)
{
selectParam
.
selectedDate
=
JSON
.
stringify
(
getMonthRange
(
params
.
name
))
if
(
params
.
seriesName
===
'通过法案'
)
{
selectParam
.
selectedStatus
=
1
}
else
{
selectParam
.
selectedStatus
=
null
}
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/countryBill"
,
query
:
selectParam
});
window
.
open
(
route
.
href
,
"_blank"
);
}
}
break
...
...
@@ -89,16 +73,37 @@ const setChart = (option, chartId, allowClick, selectParam) => {
});
window
.
open
(
route
.
href
,
"_blank"
);
}
else
if
(
params
.
componentType
===
'series'
&&
params
.
seriesType
===
'bar'
)
{
const
quatarNum
=
Number
(
params
.
name
[
params
.
name
.
length
-
1
])
selectParam
.
selectedDate
=
JSON
.
stringify
(
getQuarterRange
(
quatarNum
))
selectParam
.
selectedDate
=
JSON
.
stringify
(
getQuarterRange
(
selectParam
.
selectedDate
,
quatarNum
))
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/dataDecree"
,
query
:
selectParam
});
window
.
open
(
route
.
href
,
"_blank"
);
}
break
case
'科技智库报告'
:
if
(
selectParam
.
key
===
1
)
{
selectParam
.
domains
=
params
.
seriesName
const
year
=
params
.
name
.
slice
(
0
,
4
)
const
quatarNum
=
Number
(
params
.
name
[
params
.
name
.
length
-
1
])
selectParam
.
selectedDate
=
JSON
.
stringify
(
getQuarterRange
(
year
,
quatarNum
))
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/dataThinkTank"
,
query
:
selectParam
});
window
.
open
(
route
.
href
,
"_blank"
);
return
}
else
if
(
selectParam
.
key
===
2
)
{
selectParam
.
domains
=
params
.
name
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/dataThinkTank"
,
query
:
selectParam
});
window
.
open
(
route
.
href
,
"_blank"
);
return
}
}
});
...
...
src/views/bill/billHome/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/bill/billHome/utils/multiLineChart.js
浏览文件 @
8e94a51d
...
...
@@ -49,7 +49,8 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
containLabel
:
true
},
legend
:
{
data
:
[
'提出法案'
,
'通过法案'
,
'众议院通过'
,
'参议院通过'
,
'双院通过'
],
// 图例顺序:提出法案、众议院通过、参议院通过、解决分歧、完成立法
data
:
[
'提出法案'
,
'众议院通过'
,
'参议院通过'
,
'解决分歧'
,
'完成立法'
],
show
:
true
,
top
:
10
,
icon
:
'circle'
,
...
...
@@ -126,7 +127,8 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
data
:
proposedData
},
{
name
:
'通过法案'
,
// 众议院通过
name
:
'众议院通过'
,
type
:
'line'
,
smooth
:
true
,
symbol
:
'emptyCircle'
,
...
...
@@ -137,10 +139,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
itemStyle
:
{
color
:
lineColors
[
1
]
},
data
:
pass
Data
data
:
house
Data
},
{
name
:
'众议院通过'
,
// 参议院通过
name
:
'参议院通过'
,
type
:
'line'
,
smooth
:
true
,
symbol
:
'emptyCircle'
,
...
...
@@ -151,10 +154,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
itemStyle
:
{
color
:
lineColors
[
2
]
},
data
:
hous
eData
data
:
senat
eData
},
{
name
:
'参议院通过'
,
// 解决分歧
name
:
'解决分歧'
,
type
:
'line'
,
smooth
:
true
,
symbol
:
'emptyCircle'
,
...
...
@@ -165,10 +169,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
itemStyle
:
{
color
:
lineColors
[
3
]
},
data
:
senate
Data
data
:
hs
Data
},
{
name
:
'双院通过'
,
// 完成立法
name
:
'完成立法'
,
type
:
'line'
,
smooth
:
true
,
symbol
:
'emptyCircle'
,
...
...
@@ -179,7 +184,7 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
itemStyle
:
{
color
:
lineColors
[
4
]
},
data
:
h
sData
data
:
pas
sData
}
]
}
...
...
src/views/bill/billLayout/components/BillHeader.vue
浏览文件 @
8e94a51d
...
...
@@ -27,29 +27,17 @@
</div>
<div
class=
"left-box-bottom"
v-if=
"showTabs"
>
<
template
v-if=
"isLoading"
>
<div
class=
"left-box-bottom-item is-skeleton"
v-for=
"n in 4"
:key=
"n"
>
<div
class=
"icon"
>
<el-skeleton-item
class=
"skeleton-tab-icon"
variant=
"text"
/>
</div>
<div
class=
"name"
>
<el-skeleton-item
class=
"skeleton-tab-text"
variant=
"text"
/>
</div>
<div
class=
"left-box-bottom-item"
:class=
"{ leftBoxBottomItemActive: activeTitle === item.name }"
v-for=
"item in tabs"
:key=
"item.path"
@
click=
"emit('tab-click', item)"
>
<div
class=
"icon"
>
<img
v-if=
"activeTitle === item.name"
:src=
"item.activeIcon"
alt=
""
/>
<img
v-else
:src=
"item.icon"
alt=
""
/>
</div>
</
template
>
<
template
v-else
>
<div
class=
"left-box-bottom-item"
:class=
"
{ leftBoxBottomItemActive: activeTitle === item.name }" v-for="item in tabs"
:key="item.path" @click="emit('tab-click', item)">
<div
class=
"icon"
>
<img
v-if=
"activeTitle === item.name"
:src=
"item.activeIcon"
alt=
""
/>
<img
v-else
:src=
"item.icon"
alt=
""
/>
</div>
<div
class=
"name"
:class=
"
{ nameActive: activeTitle === item.name }">
{{
item
.
name
}}
</div>
<div
class=
"name"
:class=
"{ nameActive: activeTitle === item.name }"
>
{{ item.name }}
</div>
</
template
>
</
div
>
</div>
</div>
...
...
@@ -73,30 +61,18 @@
</div>
<div
class=
"right-box-bottom"
v-if=
"showActions"
>
<
template
v-if=
"isLoading"
>
<div
class=
"btn3 is-skeleton"
>
<div
class=
"icon"
>
<el-skeleton-item
class=
"skeleton-action-icon"
variant=
"text"
/>
</div>
<div
class=
"text"
>
<el-skeleton-item
class=
"skeleton-action-text"
variant=
"text"
/>
</div>
<div
class=
"btn2"
@
click=
"emit('open-analysis', 'forsee')"
>
<div
class=
"icon"
>
<img
:src=
"btnIconForsee"
alt=
""
/>
</div>
</
template
>
<
template
v-else
>
<div
class=
"btn2"
@
click=
"emit('open-analysis', 'forsee')"
>
<div
class=
"icon"
>
<img
:src=
"btnIconForsee"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
"进展预测"
}}
</div>
</div>
<div
class=
"btn3"
@
click=
"emit('open-analysis', 'analysis')"
>
<div
class=
"icon"
>
<img
:src=
"btnIconAnalysis"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
"分析报告"
}}
</div>
<div
class=
"text"
>
{{ "进展预测" }}
</div>
</div>
<div
class=
"btn3"
@
click=
"emit('open-analysis', 'analysis')"
>
<div
class=
"icon"
>
<img
:src=
"btnIconAnalysis"
alt=
""
/>
</div>
</
template
>
<div
class=
"text"
>
{{ "分析报告" }}
</div>
</div>
</div>
</div>
</div>
...
...
src/views/bill/template/index.vue
浏览文件 @
8e94a51d
...
...
@@ -150,8 +150,8 @@
</template>
<
script
setup
>
import
{
ref
,
onMounted
,
computed
,
watch
}
from
"vue"
;
import
{
useRoute
}
from
"vue-router"
;
import
{
ref
,
onMounted
,
onBeforeUnmount
,
computed
,
watch
}
from
"vue"
;
import
{
useRoute
,
onBeforeRouteLeave
}
from
"vue-router"
;
import
*
as
echarts
from
"echarts"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
getPieChart
from
"./utils/piechart"
;
...
...
@@ -165,6 +165,31 @@ import { extractTextEntity } from "@/api/intelligent/index";
const
route
=
useRoute
();
const
pageAbortController
=
new
AbortController
();
const
isRequestCanceled
=
error
=>
{
return
(
error
?.
code
===
"ERR_CANCELED"
||
error
?.
name
===
"CanceledError"
||
error
?.
name
===
"AbortError"
||
(
typeof
error
?.
message
===
"string"
&&
/canceled|aborted/i
.
test
(
error
.
message
))
);
};
const
getPageSignal
=
()
=>
pageAbortController
.
signal
;
const
stopCurrentPageRequests
=
()
=>
{
pageAbortController
.
abort
();
// 让旧请求回调全部失效,避免离开页面后回写状态
tkRequestToken
.
value
+=
1
;
xzfsRequestToken
.
value
+=
1
;
hylyRequestToken
.
value
+=
1
;
entityRequestToken
.
value
+=
1
;
termsLoading
.
value
=
false
;
limitLoading
.
value
=
false
;
domainLoading
.
value
=
false
;
aiPaneLoading
.
value
=
{
domain
:
false
,
limit
:
false
};
};
const
curBill
=
ref
(
""
);
const
curBillId
=
ref
(
null
);
...
...
@@ -294,7 +319,7 @@ const ensureEntitiesForTerms = async terms => {
try
{
const
results
=
await
Promise
.
all
(
tasks
.
map
(
async
item
=>
{
const
res
=
await
extractTextEntity
(
item
.
text
);
const
res
=
await
extractTextEntity
(
item
.
text
,
{
signal
:
getPageSignal
()
}
);
const
entities
=
normalizeEntities
(
res
?.
result
??
res
?.
data
?.
result
??
res
?.
data
??
res
);
return
{
key
:
item
.
key
,
entities
};
})
...
...
@@ -434,6 +459,7 @@ const requestAiPaneContent = async key => {
const
res
=
await
getChartAnalysis
(
{
text
:
JSON
.
stringify
(
payload
)
},
{
signal
:
getPageSignal
(),
onChunk
:
chunk
=>
{
const
current
=
overviewAiContent
.
value
[
key
];
const
base
=
current
===
"智能总结生成中..."
?
""
:
current
;
...
...
@@ -455,6 +481,7 @@ const requestAiPaneContent = async key => {
}
aiPaneFetched
.
value
=
{
...
aiPaneFetched
.
value
,
[
key
]:
true
};
}
catch
(
error
)
{
if
(
isRequestCanceled
(
error
))
return
;
console
.
error
(
"获取图表解读失败"
,
error
);
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成失败"
};
}
finally
{
...
...
@@ -518,7 +545,7 @@ const handleGetBillList = async () => {
id
:
route
.
query
.
billId
};
try
{
const
res
=
await
getBillContentId
(
params
);
const
res
=
await
getBillContentId
(
params
,
{
signal
:
getPageSignal
()
}
);
console
.
log
(
"法案id列表"
,
res
);
const
rawList
=
Array
.
isArray
(
res
?.
data
)
?
res
.
data
:
[];
const
seen
=
new
Set
();
...
...
@@ -579,7 +606,7 @@ const handleGetBillContentTk = async cRelated => {
params.content = searchKeyword.value.trim();
}
try {
const res = await getBillContentTk(params);
const res = await getBillContentTk(params
, { signal: getPageSignal() }
);
if (currentToken !== tkRequestToken.value) {
return;
}
...
...
@@ -627,6 +654,9 @@ const handleGetBillContentTk = async cRelated => {
total.value = 0;
}
} catch (error) {
if (isRequestCanceled(error)) {
return;
}
if (currentToken !== tkRequestToken.value) {
return;
}
...
...
@@ -652,7 +682,7 @@ const handleGetBillContentXzfs = async () => {
};
try {
const res = await getBillContentXzfs(params);
const res = await getBillContentXzfs(params
, { signal: getPageSignal() }
);
if (currentToken !== xzfsRequestToken.value) {
return;
}
...
...
@@ -679,6 +709,9 @@ const handleGetBillContentXzfs = async () => {
let chart1 = getPieChart(chart1Data.value, chart1ColorList.value);
setChart(chart1, "chart1");
} catch (error) {
if (isRequestCanceled(error)) {
return;
}
if (currentToken !== xzfsRequestToken.value) {
return;
}
...
...
@@ -701,7 +734,7 @@ const handleGetBillHyly = async () => {
};
try {
const res = await getBillHyly(params);
const res = await getBillHyly(params
, { signal: getPageSignal() }
);
if (currentToken !== hylyRequestToken.value) {
return;
}
...
...
@@ -729,6 +762,9 @@ const handleGetBillHyly = async () => {
let chart2 = getPieChart(chart2Data.value, chart2ColorList.value);
setChart(chart2, "chart2");
} catch (error) {
if (isRequestCanceled(error)) {
return;
}
if (currentToken !== hylyRequestToken.value) {
return;
}
...
...
@@ -745,6 +781,14 @@ onMounted(async () => {
await handleGetBillContentXzfs();
await handleGetBillHyly();
});
onBeforeRouteLeave(() => {
stopCurrentPageRequests();
});
onBeforeUnmount(() => {
stopCurrentPageRequests();
});
</
script
>
<
style
lang=
"scss"
scoped
>
...
...
src/views/comprehensiveSearch/searchResults/index.vue
浏览文件 @
8e94a51d
...
...
@@ -316,12 +316,12 @@ const handleSearch = async () => {
console
.
log
(
"综合搜索结果"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
if
(
!
selectedDomains
.
value
.
length
)
{
domains
.
value
=
Object
.
entries
(
res
.
data
.
aggregations
).
map
(([
name
,
id
])
=>
({
domains
.
value
=
Object
.
entries
(
res
.
data
.
aggregations
Domain
).
map
(([
name
,
id
])
=>
({
name
,
id
,
selected
:
false
}));
}
}
searchResults
.
value
=
res
.
data
.
records
;
searchResults
.
value
.
forEach
(
item
=>
{
item
.
originalTitle
=
highlightText
(
item
.
originalTitle
,
keyword
.
value
);
...
...
src/views/coopRestriction/components/dataNew/index.vue
浏览文件 @
8e94a51d
...
...
@@ -6,7 +6,7 @@
<div
class=
"left-top"
>
<img
src=
"./assets/icon01.png"
alt=
""
/>
<div
class=
"left-top-title"
>
合作限制动态
</div>
<div
class=
"more"
@
click=
"handleClickToDetail"
>
查看详情 >
</div>
<div
class=
"more"
@
click=
"handleClickToDetail"
>
{{
"查看详情 >"
}}
</div>
</div>
<el-carousel
ref=
"carouselRef"
height=
"412px"
direction=
"horizontal"
:autoplay=
"true"
:interval=
"5000"
...
...
@@ -46,7 +46,7 @@
</div>
</div>
<div
class=
"left-center-type"
v-if=
"item.
type"
>
{{
item
.
type
}}
</div>
<div
class=
"left-center-type"
v-if=
"item.
limitMeans"
>
{{
item
.
limitMeans
}}
</div>
<!--
<div
class=
"left-center-title"
>
{{
item
.
LIMITTYPE
}}
</div>
-->
</div>
<div
class=
"left-bottom"
>
...
...
@@ -188,12 +188,12 @@ const riskSignals = ref([]);
// 点击查看详情
const
handleClickToDetail
=
item
=>
{
const
activeItem
=
item
&&
item
.
ID
?
item
:
mainTrend
.
value
;
const
id
=
activeItem
?.
ID
;
const
id
=
activeItem
?.
ID
||
activeItem
?.
id
||
activeItem
?.
limitId
;
if
(
!
id
)
return
;
window
.
sessionStorage
.
setItem
(
"c
urTabName"
,
activeItem
?.
LIMITNAME
);
window
.
sessionStorage
.
setItem
(
"c
ooperationRestrictionsTabName"
,
activeItem
?.
LIMITNAME
||
""
);
const
curRoute
=
router
.
resolve
({
path
:
"/cooperationRestrictions/d
etail"
,
name
:
"CooperationRestrictionsD
etail"
,
query
:
{
id
:
id
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
...
...
@@ -201,9 +201,11 @@ const handleClickToDetail = item => {
// 点击风险信号详情
const
handleToRiskDetail
=
(
item
)
=>
{
const
id
=
item
?.
cooperationId
||
item
?.
ID
||
item
?.
id
||
item
?.
limitId
;
if
(
!
id
)
return
;
const
curRoute
=
router
.
resolve
({
path
:
"/cooperationRestrictions/d
etail"
,
query
:
{
id
:
item
.
cooperationId
},
name
:
"CooperationRestrictionsD
etail"
,
query
:
{
id
},
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
...
...
@@ -318,7 +320,7 @@ onMounted(() => {
width
:
967px
;
height
:
208px
;
margin-top
:
33px
;
margin-left
:
62
px
;
margin-left
:
57
px
;
border-bottom
:
1px
solid
rgb
(
234
,
236
,
238
);
position
:
relative
;
...
...
@@ -326,6 +328,7 @@ onMounted(() => {
width
:
148px
;
height
:
148px
;
margin-right
:
21px
;
margin-left
:
5px
;
}
display
:
flex
;
...
...
src/views/coopRestriction/components/dataSub/index.vue
浏览文件 @
8e94a51d
...
...
@@ -4,7 +4,8 @@
<div
class=
"left-title"
>
<img
src=
"./assets/icon01.png"
alt=
""
/>
<div
class=
"tit"
>
各类型合作限制政策对比
</div>
<el-select
v-model=
"value"
placeholder=
"Select"
class=
"select"
@
change=
"getCoopRestrictionCompareData"
>
<el-select
v-model=
"value"
placeholder=
"Select"
class=
"select"
popper-class=
"coop-select-dropdown"
@
change=
"getCoopRestrictionCompareData"
>
<el-option
v-for=
"item in options"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
...
...
@@ -34,7 +35,8 @@
<div
class=
"right-title"
>
<img
src=
"./assets/icon02.png"
alt=
""
/>
<div
class=
"tit"
>
各领域规则分布情况
</div>
<el-select
v-model=
"value1"
placeholder=
"Select"
class=
"select"
@
change=
"getCoopRestrictionDomainData"
>
<el-select
v-model=
"value1"
placeholder=
"Select"
class=
"select"
popper-class=
"coop-select-dropdown"
@
change=
"getCoopRestrictionDomainData"
>
<el-option
v-for=
"item in options1"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
...
...
@@ -75,6 +77,22 @@ import AiPane from "@/components/base/Ai/AiPane/index.vue";
const
COOP_LEFT_TIP_TEXT
=
"各类型合作限制政策对比,数据来源:美对华科技合作限制信息平台"
;
const
COOP_RIGHT_TIP_TEXT
=
"各领域规则分布情况,数据来源:美对华科技合作限制信息平台"
;
// 临时展示 mock(不改样式):右侧“各领域规则分布情况”
// 用完把这个开关改回 false 即可恢复走接口
const
USE_DOMAIN_MOCK
=
false
;
const
MOCK_COOP_RESTRICTION_DOMAIN
=
[
{
COOPERTYPE
:
"科研合作"
,
COOPERTYPECOUNT
:
1
,
AREA
:
"人工智能"
},
{
COOPERTYPE
:
"科研合作"
,
COOPERTYPECOUNT
:
1
,
AREA
:
"生物科技"
},
{
COOPERTYPE
:
"技术合作"
,
COOPERTYPECOUNT
:
2
,
AREA
:
"大数据"
},
{
COOPERTYPE
:
"产学研合作"
,
COOPERTYPECOUNT
:
3
,
AREA
:
"新能源"
},
{
COOPERTYPE
:
"项目合作"
,
COOPERTYPECOUNT
:
1
,
AREA
:
"智能制造"
},
{
COOPERTYPE
:
"人才合作"
,
COOPERTYPECOUNT
:
2
,
AREA
:
"集成电路"
},
{
COOPERTYPE
:
"科研合作"
,
COOPERTYPECOUNT
:
2
,
AREA
:
"大数据"
},
{
COOPERTYPE
:
"科研合作"
,
COOPERTYPECOUNT
:
3
,
AREA
:
"新能源"
},
{
COOPERTYPE
:
"科研合作"
,
COOPERTYPECOUNT
:
1
,
AREA
:
"智能制造"
},
{
COOPERTYPE
:
"科研合作"
,
COOPERTYPECOUNT
:
2
,
AREA
:
"集成电路"
}
];
const
value
=
ref
(
10
);
const
value1
=
ref
(
"2025"
);
const
options
=
[
...
...
@@ -109,6 +127,10 @@ const options1 = [
const
coopRestrictionDomain
=
ref
([]);
const
getCoopRestrictionDomainData
=
async
()
=>
{
if
(
USE_DOMAIN_MOCK
)
{
coopRestrictionDomain
.
value
=
MOCK_COOP_RESTRICTION_DOMAIN
;
return
;
}
try
{
const
res
=
await
getCoopRestrictionDomain
({
year
:
value1
.
value
...
...
@@ -449,10 +471,18 @@ const initLeftChart = () => {
const
option
=
{
color
:
colorMap
.
map
((
c
)
=>
c
.
line
),
grid
:
{
left
:
40
,
right
:
24
,
top
:
46
,
bottom
:
36
},
// 与智库概览「数量变化趋势」一致:预留图例空间,并用 containLabel 让轴文字不挤压绘图区
grid
:
{
top
:
"34%"
,
right
:
"3%"
,
bottom
:
"5%"
,
left
:
"2%"
,
containLabel
:
true
},
tooltip
:
{
trigger
:
"axis"
,
axisPointer
:
{
type
:
"line"
}
},
legend
:
{
top
:
8
,
left
:
"center"
,
icon
:
"circle"
,
itemWidth
:
12
,
itemHeight
:
12
,
...
...
@@ -572,6 +602,10 @@ const initRightChart = () => {
const
domains
=
Array
.
from
(
domainsSet
);
const
types
=
Array
.
from
(
typesSet
);
const
legendSplitAt
=
Math
.
ceil
(
types
.
length
/
2
);
const
legendFirstLine
=
types
.
slice
(
0
,
legendSplitAt
);
const
legendSecondLine
=
types
.
slice
(
legendSplitAt
);
const
indicators
=
domains
.
map
((
domain
)
=>
{
const
domainData
=
rawData
.
filter
((
item
)
=>
item
.
AREA
===
domain
);
const
maxVal
=
Math
.
max
(...
domainData
.
map
((
d
)
=>
d
.
COOPERTYPECOUNT
),
5
);
...
...
@@ -589,31 +623,56 @@ const initRightChart = () => {
name
:
type
,
value
:
dataValues
,
itemStyle
:
{
color
:
colorMap
[
index
%
colorMap
.
length
]
},
//
不要填充多边形:让雷达图“圆里面是空的”
// areaStyle 不设置(或设为 0)可避免穿透同心圆的填充效果
//
雷达图围成区域填充:对应颜色 0.1 透明度
areaStyle
:
{
color
:
colorMap
[
index
%
colorMap
.
length
],
opacity
:
0.1
}
};
});
const
option
=
{
color
:
colorMap
,
legend
:
{
top
:
8
,
icon
:
"circle"
,
itemWidth
:
12
,
itemHeight
:
12
,
itemGap
:
24
,
textStyle
:
{
color
:
"rgb(95, 101, 108)"
,
fontSize
:
16
,
fontFamily
:
"Microsoft YaHei"
,
fontWeight
:
400
,
lineHeight
:
24
// 避免自动换行导致“第二行不居中”:拆成两行 legend,每行各自居中
legend
:
[
{
show
:
true
,
type
:
"plain"
,
data
:
legendFirstLine
,
top
:
8
,
left
:
"center"
,
icon
:
"circle"
,
itemWidth
:
12
,
itemHeight
:
12
,
itemGap
:
24
,
textStyle
:
{
color
:
"rgb(95, 101, 108)"
,
fontSize
:
16
,
fontFamily
:
"Microsoft YaHei"
,
fontWeight
:
400
,
lineHeight
:
24
}
},
data
:
types
},
{
show
:
legendSecondLine
.
length
>
0
,
type
:
"plain"
,
data
:
legendSecondLine
,
top
:
32
,
left
:
"center"
,
icon
:
"circle"
,
itemWidth
:
12
,
itemHeight
:
12
,
itemGap
:
24
,
textStyle
:
{
color
:
"rgb(95, 101, 108)"
,
fontSize
:
16
,
fontFamily
:
"Microsoft YaHei"
,
fontWeight
:
400
,
lineHeight
:
24
}
}
],
radar
:
{
center
:
[
"50%"
,
"55%"
],
radius
:
"65%"
,
// 对齐左侧折线图(grid top=34%)的“图例到图形”间距:下移雷达中心并略缩半径
center
:
[
"50%"
,
"62%"
],
radius
:
"60%"
,
indicator
:
indicators
,
axisName
:
{
color
:
"rgba(132, 136, 142, 1)"
,
...
...
@@ -688,6 +747,11 @@ onBeforeUnmount(() => {
padding
:
0
;
}
/* 合作限制:下拉项内边距(teleport 到 body,用 :global 生效) */
:global
(
.coop-select-dropdown
.el-select-dropdown__item
)
{
padding
:
0
20px
!
important
;
}
.datasub
{
width
:
1600px
;
height
:
460px
;
...
...
@@ -742,7 +806,7 @@ onBeforeUnmount(() => {
height
:
412px
;
box-sizing
:
border-box
;
position
:
relative
;
padding
:
24px
24px
65
px
24px
;
padding
:
0px
24px
64
px
24px
;
&
.left-main--empty
{
display
:
flex
;
...
...
@@ -770,7 +834,7 @@ onBeforeUnmount(() => {
.left-main-echarts
{
width
:
1015px
;
height
:
3
23
px
;
height
:
3
48
px
;
}
.source
{
...
...
@@ -847,7 +911,7 @@ onBeforeUnmount(() => {
width
:
521px
;
height
:
412px
;
box-sizing
:
border-box
;
padding
:
24
px
24px
64px
24px
;
padding
:
0
px
24px
64px
24px
;
position
:
relative
;
&
.right-main--empty
{
...
...
@@ -874,7 +938,7 @@ onBeforeUnmount(() => {
.right-main-echarts
{
width
:
473px
;
height
:
3
24
px
;
height
:
3
48
px
;
}
.source
{
...
...
src/views/coopRestriction/components/resLib/index.vue
浏览文件 @
8e94a51d
...
...
@@ -6,7 +6,8 @@
{{
item
.
name
}}
</div>
</div>
<el-select
v-model=
"sortModel"
placeholder=
"发布时间"
class=
"select"
:teleported=
"true"
placement=
"bottom-start"
<el-select
v-model=
"sortModel"
placeholder=
"发布时间"
class=
"select"
popper-class=
"coop-select-dropdown"
:teleported=
"true"
placement=
"bottom-start"
:popper-options=
"sortPopperOptions"
@
change=
"handleSortChange"
>
<template
#
prefix
>
<img
v-if=
"sortModel !== true"
src=
"@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image down.png"
...
...
@@ -120,8 +121,8 @@ const getMainDataList = async () => {
date
:
item
.
limitDate
,
domain
:
item
.
limitArea
||
[],
type
:
item
.
limitMeans
,
//
使用默认图片
img
:
defaultImg
//
优先使用接口返回的机构 logo(limitOrgLogo),空则回退默认图
img
:
item
.
limitOrgLogo
||
defaultImg
}));
total
.
value
=
res
.
data
.
totalElements
||
0
;
}
else
{
...
...
@@ -138,10 +139,16 @@ const getMainDataList = async () => {
const
router
=
useRouter
();
const
handleClick
=
item
=>
{
const
id
=
item
?.
id
||
item
?.
limitId
||
item
?.
ID
;
if
(
!
id
)
return
;
window
.
sessionStorage
.
setItem
(
"cooperationRestrictionsTabName"
,
item
?.
limitName
||
item
?.
title
||
item
?.
name
||
""
);
const
routeData
=
router
.
resolve
({
path
:
"/cooperationRestrictions/d
etail"
,
name
:
"CooperationRestrictionsD
etail"
,
query
:
{
id
:
item
.
id
id
}
});
window
.
open
(
routeData
.
href
,
"_blank"
);
...
...
@@ -355,6 +362,11 @@ watch(currentPage, () => {
padding
:
0
;
}
/* 合作限制:下拉项内边距(teleport 到 body,用 :global 生效) */
:global
(
.coop-select-dropdown
.el-select-dropdown__item
)
{
padding
:
0
20px
!
important
;
}
.reslib-page
{
width
:
1600px
;
...
...
src/views/coopRestriction/detail/index.vue
浏览文件 @
8e94a51d
...
...
@@ -45,9 +45,9 @@
<AnalysisBox
title=
"相关实体"
:showAllBtn=
"true"
>
<div
class=
"left-bottom-main"
>
<div
v-for=
"item in coopRelatedData"
:key=
"item.id"
class=
"main-box"
@
click=
"handleClickOnEntity(item)"
>
<img
:src=
"item.img || defaultCom"
alt=
""
/>
<img
:src=
"item.img || defaultCom"
alt=
""
class=
"img-left-item"
/>
<div
class=
"name"
>
{{
item
.
ENTITYNAME
}}
</div>
<div
class=
"type"
>
{{
item
.
type
}}
</div>
<div
class=
"type"
>
{{
item
.
position
}}
</div>
</div>
</div>
</AnalysisBox>
...
...
@@ -80,8 +80,15 @@
<span>
(
{{
chineseNumbers
[
index
]
}}
)
{{
item
.
TITLE
}}
</span>
<img
src=
"./assets/打开按钮.png"
alt=
""
>
</div>
<div
class=
"clause-item-content"
>
{{
item
.
CONTENT
}}
<!-- contentList:单条按原样式展示;多条则逐条展示并加 1.2.3. 前缀 -->
<div
v-if=
"Array.isArray(item.contentList) && item.contentList.length > 1"
class=
"clause-item-content-list"
>
<div
v-for=
"(row, i) in item.contentList"
:key=
"i"
class=
"clause-item-content-row"
>
<span
class=
"row-index"
>
{{
i
+
1
}}
.
</span>
<span
class=
"row-text"
>
{{
row
.
CONTENT
}}
</span>
</div>
</div>
<div
v-else
class=
"clause-item-content-row"
>
<span
class=
"row-text"
>
{{
item
.
contentList
?.[
0
]?.
CONTENT
||
""
}}
</span>
</div>
</div>
</div>
...
...
@@ -163,19 +170,34 @@ const getcoopRelatedData = async () => {
limitId
:
route
.
query
.
id
});
if
(
res
&&
res
.
code
===
200
)
{
coopRelatedData
.
value
=
res
.
data
||
{};
// 展示图片:优先后端返回的 imageUrl,其次用已有 img 字段,再兜底默认图
coopRelatedData
.
value
=
(
Array
.
isArray
(
res
.
data
)
?
res
.
data
:
[]).
map
((
row
)
=>
({
...
row
,
img
:
row
?.
imageUrl
||
row
?.
img
||
row
?.
IMAGEURL
||
row
?.
image
||
""
}));
}
else
{
coopRelatedData
.
value
=
{}
;
coopRelatedData
.
value
=
[]
;
}
}
catch
(
error
)
{
console
.
error
(
"获取合作限制相关实体数据失败:"
,
error
);
coopRelatedData
.
value
=
{}
;
coopRelatedData
.
value
=
[]
;
}
};
// 点击跳转关联实体详情
const
handleClickOnEntity
=
(
item
)
=>
{
if
(
!
item
.
ENTITYID
)
return
;
const
path
=
`/companyPages/
${
item
.
ENTITYID
}
`
;
const
entityType
=
item
?.
ENTITYTYPE
;
// ENTITYTYPE: 'O' 机构/公司;'P' 人物
if
(
entityType
===
"P"
)
{
const
personId
=
item
?.
PERSONID
||
item
?.
ENTITYID
||
item
?.
id
;
if
(
!
personId
)
return
;
const
url
=
`http://localhost:3000/characterPage?type=2&personId=
${
encodeURIComponent
(
personId
)}
`
;
window
.
open
(
url
,
"_blank"
);
return
;
}
// 默认按公司/机构跳转(含 ENTITYTYPE === 'O' 或字段缺失)
const
companyId
=
item
?.
ENTITYID
||
item
?.
id
;
if
(
!
companyId
)
return
;
const
path
=
`/companyPages/
${
companyId
}
`
;
const
{
href
}
=
router
.
resolve
({
path
});
window
.
open
(
href
,
"_blank"
);
};
...
...
@@ -260,11 +282,21 @@ const filteredBackgroundList = computed(() => {
const
active2
=
ref
(
"涉华条款"
);
const
chineseNumbers
=
[
"一"
,
"二"
,
"三"
,
"四"
,
"五"
,
"六"
,
"七"
,
"八"
,
"九"
,
"十"
];
const
filteredClauseList
=
computed
(()
=>
{
const
list
=
Array
.
isArray
(
limitClauseData
.
value
)
?
limitClauseData
.
value
:
[];
if
(
active2
.
value
===
"全部条款"
)
{
return
limitClauseData
.
value
;
}
else
{
return
limitClauseData
.
value
.
filter
(
item
=>
item
.
ISCN
===
"Y"
);
// 展示全部条款及全部段落
return
list
.
map
((
item
)
=>
({
...
item
,
contentList
:
Array
.
isArray
(
item
?.
contentList
)
?
item
.
contentList
:
[]
}));
}
// 涉华条款:仅展示 contentList 中 ISCN=Y 的段落;若过滤后为空则不展示该条款
return
list
.
map
((
item
)
=>
{
const
contentList
=
(
Array
.
isArray
(
item
?.
contentList
)
?
item
.
contentList
:
[]).
filter
((
row
)
=>
row
?.
ISCN
===
"Y"
);
return
{
...
item
,
contentList
};
})
.
filter
((
item
)
=>
Array
.
isArray
(
item
?.
contentList
)
&&
item
.
contentList
.
length
>
0
);
});
const
dataList
=
ref
([
...
...
@@ -660,6 +692,12 @@ const dataList3 = ref([
img
{
width
:
24px
;
height
:
24px
;
border-radius
:
50%
;
display
:
inline-block
;
object-fit
:
cover
;
object-position
:
center
;
}
.name
{
...
...
@@ -923,7 +961,12 @@ const dataList3 = ref([
}
}
.clause-item-content
{
.clause-item-content-list
{
width
:
1022px
;
}
/* 每条段落的展示:padding / 描边 / 间距保持与旧版单条 CONTENT 一致 */
.clause-item-content-row
{
width
:
1022px
;
padding
:
12px
24px
12px
54px
;
font-size
:
16px
;
...
...
@@ -933,6 +976,17 @@ const dataList3 = ref([
color
:
rgb
(
59
,
65
,
75
);
border-bottom
:
1px
solid
rgb
(
234
,
236
,
238
);
white-space
:
pre-line
;
display
:
flex
;
gap
:
8px
;
.row-index
{
flex
:
0
0
auto
;
}
.row-text
{
flex
:
1
;
min-width
:
0
;
}
}
}
}
...
...
src/views/dataLibrary/bill/countryBill/index.vue
浏览文件 @
8e94a51d
...
...
@@ -94,11 +94,11 @@
<
/div
>
<
/div
>
<
div
class
=
"header-right"
>
<
div
class
=
"header-right-item item1"
>
<
div
class
=
"header-right-item item1"
@
click
=
"handleExport"
>
<
div
class
=
"icon"
>
<
img
src
=
"../../assets/icons/download.svg"
alt
=
""
>
<
/div
>
<
div
class
=
"text text-tip-1"
@
click
=
"handleExport"
>
{{
'导出'
}}
<
/div
>
<
div
class
=
"text text-tip-1"
>
{{
'导出'
}}
<
/div
>
<
/div
>
<
div
class
=
"header-right-item2 item2"
>
<
el
-
select
v
-
model
=
"curOperation"
placeholder
=
"批量操作"
style
=
"width: 120px"
>
...
...
@@ -833,13 +833,12 @@ const fetchTableData = async () => {
}
))
}
const
curDemensionItem
=
staticsDemensionList
.
value
.
filter
(
item
=>
{
return
item
.
name
===
curDemension
.
value
}
)[
0
]
activeChart
.
value
=
''
timer3
.
value
=
setTimeout
(()
=>
{
activeChart
.
value
=
curDemensionItem
.
chartTypeList
[
0
]
curChartData
.
value
=
curDemensionItem
.
data
...
...
@@ -1040,7 +1039,7 @@ const initParam = () => {
}
isInvolveCn
.
value
=
route
.
query
.
isInvolveCn
?
true
:
false
if
(
route
.
query
.
selectedStatus
)
{
selectedStatus
.
value
=
route
.
query
.
selectedStatus
===
'1'
?
'通过'
:
'提出'
selectedStatus
.
value
=
route
.
query
.
selectedStatus
}
else
{
selectedStatus
.
value
=
'全部阶段'
}
...
...
@@ -1061,7 +1060,7 @@ const initParam = () => {
}
isInvolveCn
.
value
=
savedQuery
.
isInvolveCn
?
true
:
false
if
(
savedQuery
.
selectedStatus
)
{
selectedStatus
.
value
=
savedQuery
.
selectedStatus
===
'1'
?
'通过'
:
'提出'
selectedStatus
.
value
=
savedQuery
.
selectedStatus
}
else
{
selectedStatus
.
value
=
'全部阶段'
}
...
...
@@ -1102,6 +1101,10 @@ const handlePerClick = item => {
// 导出
const
handleExport
=
()
=>
{
if
(
!
selectedCount
.
value
)
{
ElMessage
.
warning
(
'请至少选择一项!'
)
return
}
console
.
log
(
selectedMap
.
value
);
const
arr
=
Array
.
from
(
selectedMap
.
value
);
...
...
@@ -1111,7 +1114,7 @@ const handleExport = () => {
const
link
=
document
.
createElement
(
'a'
);
link
.
href
=
url
;
link
.
download
=
'
export
.json'
;
link
.
download
=
'
bill
.json'
;
link
.
click
();
URL
.
revokeObjectURL
(
url
);
...
...
src/views/dataLibrary/components/InputBox/index.vue
0 → 100644
浏览文件 @
8e94a51d
<
template
>
<div
class=
"input-wrapper"
>
<div
class=
"input-left text-tip-1"
>
{{
inputTitle
+
':'
}}
</div>
<div
class=
"input-right"
>
<el-input
v-model=
"inputValue"
:placeholder=
"placeholderName"
style=
"width: 240px"
/>
</div>
</div>
</
template
>
<
script
setup
>
import
{
computed
}
from
'vue'
;
const
props
=
defineProps
({
inputTitle
:
{
type
:
String
,
default
:
''
},
placeholderName
:
{
type
:
String
,
default
:
''
},
inputName
:
{
type
:
String
,
default
:
''
},
})
const
emit
=
defineEmits
([
'update:inputText'
,
'update:customTime'
])
const
inputValue
=
computed
({
get
:
()
=>
props
.
inputName
,
set
:
(
value
)
=>
emit
(
'update:inputText'
,
value
)
})
</
script
>
<
style
lang=
"scss"
scoped
>
.input-wrapper
{
width
:
348px
;
height
:
28px
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
gap
:
8px
;
.input-left
{
width
:
100px
;
height
:
24px
;
color
:
var
(
--
text-primary-65-color
);
}
.input-right
{
width
:
240px
;
display
:
flex
;
gap
:
8px
;
justify-content
:
space-between
;
:deep
(
.el-input__wrapper
)
{
border-radius
:
4px
;
border
:
1px
solid
var
(
--
bg-black-10
);
}
}
}
</
style
>
\ No newline at end of file
src/views/dataLibrary/decree/index.vue
浏览文件 @
8e94a51d
...
...
@@ -101,11 +101,11 @@
<
/div
>
<
/div
>
<
div
class
=
"header-right"
>
<
div
class
=
"header-right-item item1"
>
<
div
class
=
"header-right-item item1"
@
click
=
"handleExport"
>
<
div
class
=
"icon"
>
<
img
src
=
"../assets/icons/download.svg"
alt
=
""
>
<
/div
>
<
div
class
=
"text text-tip-1"
@
click
=
"handleExport"
>
{{
'导出'
}}
<
/div
>
<
div
class
=
"text text-tip-1"
>
{{
'导出'
}}
<
/div
>
<
/div
>
<
div
class
=
"header-right-item2 item2"
>
<
el
-
select
v
-
model
=
"curOperation"
placeholder
=
"批量操作"
style
=
"width: 120px"
>
...
...
@@ -137,7 +137,7 @@
<
el
-
table
-
column
label
=
"发布时间"
width
=
"120"
class
-
name
=
"date-column"
>
<
template
#
default
=
"scope"
>
{{
scope
.
row
.
date
}}
<
/template
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"发布机构"
width
=
"180"
>
<
el
-
table
-
column
label
=
"发布机构"
>
<
template
#
default
=
"scope"
>
<
span
class
=
"person-item text-compact"
@
click
=
"handlePerClick(scope.row)"
>
{{
scope
.
row
.
organizationName
}}
<
/span
>
...
...
@@ -396,6 +396,7 @@ const handleCloseCurTag = (tag, index) => {
break
case
'发布时间'
:
selectedDate
.
value
=
''
customTime
.
value
=
[]
break
case
'发布机构'
:
selectedIns
.
value
=
'全部机构'
...
...
@@ -765,6 +766,8 @@ const fetchTableData = async () => {
return
item
.
name
===
curDemension
.
value
}
)[
0
]
activeChart
.
value
=
''
setTimeout
(()
=>
{
activeChart
.
value
=
curDemensionItem
.
chartTypeList
[
0
]
curChartData
.
value
=
curDemensionItem
.
data
...
...
@@ -989,12 +992,12 @@ const initParam = () => {
const
handleClickToDetail
=
(
curDecree
)
=>
{
console
.
log
(
'curDecree'
,
curDecree
);
window
.
sessionStorage
.
setItem
(
"
bill
Id"
,
curDecree
.
id
);
window
.
sessionStorage
.
setItem
(
"
decree
Id"
,
curDecree
.
id
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
curDecree
.
title
);
const
route
=
router
.
resolve
({
path
:
"/decreeLayout"
,
query
:
{
billI
d
:
curDecree
.
id
i
d
:
curDecree
.
id
}
}
);
window
.
open
(
route
.
href
,
"_blank"
);
...
...
@@ -1340,4 +1343,6 @@ onMounted(async () => {
// :deep(.el-table__header th:first-child)
{
// background-color: #e6f7ff;
// color: #1890ff;
//
}
<
/style>
\ No newline at end of file
//
}
<
/style>
\ No newline at end of file
src/views/dataLibrary/thinkTank/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/decree/allOrganization/index.vue
浏览文件 @
8e94a51d
...
...
@@ -27,7 +27,7 @@
<img
:src=
"tipsTcon"
alt=
""
>
</div>
<div
class=
"date-text"
>
近期美国各联邦政府机构发布涉华政令数量汇总
</div>
<TimeTabPane
@
time-click=
"handleDateChange"
/>
<TimeTabPane
@
time-click=
"handleDateChange"
activeTime=
"近一年"
/>
</div>
<div
class=
"organization-list"
ref=
"refOrganization"
v-loading=
"organizationInfo.loading"
>
<div
class=
"organization-item"
v-for=
"(item, index) in organizationInfo.list"
:key=
"index"
...
...
@@ -77,7 +77,7 @@ const organizationInfo = reactive({
total
:
0
,
isSort
:
1
,
keyWord
:
""
,
day
:
7
,
day
:
365
,
list
:
[]
})
...
...
src/views/decree/decreeHome/index.vue
浏览文件 @
8e94a51d
...
...
@@ -34,7 +34,7 @@
<img
:src=
"tipsTcon"
alt=
""
>
</div>
<div
class=
"date-text"
>
近期美国各联邦政府机构发布涉华政令数量汇总
</div>
<TimeTabPane
@
time-click=
"onKeyOrganization"
/>
<TimeTabPane
@
time-click=
"onKeyOrganization"
activeTime=
"近一年"
/>
</div>
<div
class=
"home-main-header-item-box"
v-if=
"keyOrganizationList.length"
>
<div
class=
"organization-item"
v-for=
"(item, index) in keyOrganizationList"
:key=
"index"
@
click=
"handleToInstitution(item)"
>
...
...
@@ -767,7 +767,7 @@ const handleGetDecreeYearOrder = async () => {
chart1Data
.
value
.
dataY
=
res
.
data
.
map
(
item
=>
{
return
item
.
count
;
});
summarize1
.
value
=
await
onChartInterpretation
({
type
:
"柱状图"
,
name
:
"数量变化趋势"
,
data
:
res
.
data
}
)
onChartInterpretation
({
type
:
"柱状图"
,
name
:
"数量变化趋势"
,
data
:
res
.
data
},
summarize1
)
}
}
catch
(
error
)
{
console
.
error
(
"行政令发布频度error"
,
error
);
...
...
@@ -775,38 +775,52 @@ const handleGetDecreeYearOrder = async () => {
box5Params
.
loading
=
false
};
// AI智能总结
const
onChartInterpretation
=
async
(
text
)
=>
{
const
response
=
await
fetch
(
'/aiAnalysis/chart_interpretation'
,
{
method
:
'POST'
,
headers
:
{
"X-API-Key"
:
"aircasKEY19491001"
,
'Content-Type'
:
'application/json'
,
},
body
:
JSON
.
stringify
({
text
})
// 把参数转为JSON字符串
});
const
reader
=
response
.
body
.
getReader
();
const
decoder
=
new
TextDecoder
();
const
onChartInterpretation
=
async
(
text
,
param
)
=>
{
param
.
value
=
"正在生成..."
let
buffer
=
''
;
let
summarize
=
''
;
while
(
true
)
{
const
{
done
,
value
}
=
await
reader
.
read
();
if
(
done
)
break
;
buffer
+=
decoder
.
decode
(
value
,
{
stream
:
true
});
const
lines
=
buffer
.
split
(
'
\
n'
);
buffer
=
lines
.
pop
()
||
''
;
// 👇 新增:超时 + 终止请求(只加这一段)
const
controller
=
new
AbortController
();
const
timeout
=
setTimeout
(()
=>
controller
.
abort
(),
10000
);
// 10秒超时
try
{
const
response
=
await
fetch
(
'/aiAnalysis/chart_interpretation'
,
{
method
:
'POST'
,
headers
:
{
"X-API-Key"
:
"aircasKEY19491001"
,
'Content-Type'
:
'application/json'
,
},
body
:
JSON
.
stringify
({
text
}),
signal
:
controller
.
signal
// 👇 新增:绑定中断信号
});
clearTimeout
(
timeout
);
// 👇 新增:请求成功清除定时器
if
(
!
response
.
ok
)
throw
new
Error
(
`HTTP 错误
${
response
.
status
}
`
);
const
reader
=
response
.
body
.
getReader
();
const
decoder
=
new
TextDecoder
();
let
buffer
=
''
;
let
summarize
=
''
;
for
(
const
line
of
lines
)
{
if
(
line
.
startsWith
(
'data: '
))
{
const
content
=
line
.
substring
(
6
);
const
textMatch
=
content
.
match
(
/"解读":
\s
*"
([^
"
]
*
)
"/
);
if
(
textMatch
&&
textMatch
[
1
])
summarize
=
textMatch
[
1
];
while
(
true
)
{
const
{
done
,
value
}
=
await
reader
.
read
();
if
(
done
)
break
;
buffer
+=
decoder
.
decode
(
value
,
{
stream
:
true
});
const
lines
=
buffer
.
split
(
'
\
n'
);
buffer
=
lines
.
pop
()
||
''
;
for
(
const
line
of
lines
)
{
if
(
line
.
startsWith
(
'data: '
))
{
const
content
=
line
.
substring
(
6
);
const
textMatch
=
content
.
match
(
/"解读":
\s
*"
([^
"
]
*
)
"/
);
if
(
textMatch
&&
textMatch
[
1
])
summarize
=
textMatch
[
1
];
}
}
}
param
.
value
=
summarize
}
catch
(
err
)
{
param
.
value
=
"系统异常,生成失败"
;
}
return
summarize
}
const
handleBox5
=
async
()
=>
{
...
...
@@ -870,7 +884,7 @@ const handleGetDecreeArea = async () => {
value
:
item
.
count
};
});
summarize2
.
value
=
await
onChartInterpretation
({
type
:
"环形图"
,
name
:
"领域分布情况"
,
data
:
res
.
data
}
)
onChartInterpretation
({
type
:
"环形图"
,
name
:
"领域分布情况"
,
data
:
res
.
data
},
summarize2
)
}
}
catch
(
error
)
{
console
.
error
(
"政令科技领域error"
,
error
);
...
...
@@ -1194,7 +1208,7 @@ const handleSearch = () => {
// 关键机构
const
keyOrganizationList
=
ref
([]);
const
onKeyOrganization
=
async
(
event
)
=>
{
let
day
=
7
let
day
=
365
if
(
event
?.
time
===
'近一周'
)
day
=
7
if
(
event
?.
time
===
'近一月'
)
day
=
30
if
(
event
?.
time
===
'近一年'
)
day
=
365
...
...
src/views/decree/decreeLayout/influence/index.vue
浏览文件 @
8e94a51d
...
...
@@ -79,8 +79,9 @@
<
div
class
=
"graph-box"
v
-
if
=
"contentType==1"
>
<
ChartChain
:
listData
=
"fishbone.list"
:
baseData
=
"fishbone.base"
/>
<
/div
>
<
div
class
=
"graph-box"
v
-
if
=
"contentType==2 && graphInfo.nodes.length"
>
<
GraphChart
:
nodes
=
"graphInfo.nodes"
:
links
=
"graphInfo.links"
layoutType
=
"force"
/>
<
div
class
=
"graph-box"
v
-
if
=
"contentType==2"
>
<
GraphChart
v
-
if
=
"graphInfo.nodes?.length"
:
nodes
=
"graphInfo.nodes"
:
links
=
"graphInfo.links"
layoutType
=
"force"
/>
<
el
-
empty
v
-
else
style
=
"padding: 60px 0"
description
=
"暂无数据"
:
image
-
size
=
"100"
/>
<
/div
>
<
/div
>
<
/AnalysisBox
>
...
...
@@ -168,6 +169,7 @@ const onDecreeEntities = async (page=1) => {
const
contentType
=
ref
(
1
);
const
headerContentType
=
(
type
)
=>
{
contentType
.
value
=
type
;
if
(
!
entityInfo
.
total
)
return
;
headerChartData
(
entityInfo
.
node
)
}
;
const
headerChartData
=
(
row
)
=>
{
...
...
src/views/marketAccessRestrictions/assets/icons/open.png
0 → 100644
浏览文件 @
8e94a51d
1.2 KB
src/views/marketAccessRestrictions/com/AiTips.vue
0 → 100644
浏览文件 @
8e94a51d
<
template
>
<div
class=
"view-box"
>
<div
class=
"icon-left"
>
<img
src=
"@/assets/icons/box-footer-left-icon.png"
alt=
""
>
</div>
<div
class=
"tips-content"
>
{{
props
.
tips
}}
</div>
<div
class=
"icon-right"
>
<img
src=
"@/assets/icons/box-footer-right-icon.png"
alt=
""
>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
name=
"AiTips"
>
const
props
=
defineProps
({
tips
:
{
type
:
String
,
default
:
''
}
});
</
script
>
<
style
scoped
lang=
"scss"
>
.view-box
{
width
:
100%
;
display
:
flex
;
align-items
:
center
;
padding
:
7px
12px
;
border
:
1px
solid
rgba
(
231
,
243
,
255
,
1
);
border-radius
:
4px
;
background
:
rgba
(
246
,
250
,
255
,
1
);
.icon-left
{
width
:
20px
;
height
:
20px
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
contain
;
}
}
.tips-content
{
color
:
rgb
(
5
,
95
,
194
);
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
margin-left
:
13px
;
flex
:
1
;
}
.icon-right
{
width
:
24px
;
height
:
24px
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
contain
;
}
}
}
</
style
>
\ No newline at end of file
src/views/marketAccessRestrictions/com/RelatedEvent.vue
0 → 100644
浏览文件 @
8e94a51d
<
template
>
<AnalysisBox
:title=
"props.title"
:showAllBtn=
"false"
height=
"auto"
>
<div
class=
"box-main"
>
<div
v-for=
"(item, index) in props.listData"
:key=
"index"
class=
"box-item"
>
<div
class=
"item-tag"
>
行政令
</div>
<div
class=
"item-right"
>
<div
class=
"item-head"
>
<div
class=
"item-name one-line-ellipsis"
>
{{
item
.
name
}}
</div>
<div
class=
"item-time"
>
{{
item
.
time
}}
</div>
</div>
<div
class=
"item-text one-line-ellipsis"
>
{{
item
.
text
}}
</div>
</div>
</div>
</div>
</AnalysisBox>
</
template
>
<
script
setup
lang=
"ts"
name=
"RelatedEvent"
>
const
props
=
defineProps
({
listData
:
{
type
:
Array
as
any
,
default
:
()
=>
([])
},
title
:
{
type
:
String
,
default
:
""
}
})
</
script
>
<
style
scoped
lang=
"scss"
>
.box-main
{
padding
:
0
16px
16px
;
.box-item
{
border-top
:
1px
solid
var
(
--
bg-black-5
);
padding
:
6px
;
display
:
flex
;
font-size
:
16px
;
font-family
:
Source
Han
Sans
CN
;
.item-tag
{
width
:
80px
;
height
:
28px
;
line-height
:
28px
;
border-radius
:
14px
;
text-align
:
center
;
margin-right
:
16px
;
margin-top
:
7px
;
color
:
var
(
--
color-yellow-100
);
background-color
:
var
(
--
color-yellow-10
);
}
.item-right
{
width
:
20px
;
flex
:
auto
;
line-height
:
30px
;
.item-head
{
display
:
flex
;
.item-name
{
width
:
20px
;
flex
:
auto
;
font-weight
:
bold
;
color
:
var
(
--
text-primary-80-color
);
}
.item-time
{
margin-left
:
100px
;
flex
:
none
;
color
:
var
(
--
text-primary-65-color
);
}
}
.item-text
{
color
:
var
(
--
text-primary-65-color
);
}
}
}
.box-item
:last-child
{
border-bottom
:
1px
solid
var
(
--
bg-black-5
);
}
}
</
style
>
\ No newline at end of file
src/views/marketAccessRestrictions/com/SurveyConclusion.vue
0 → 100644
浏览文件 @
8e94a51d
<
template
>
<AnalysisBox
:title=
"title"
:showAllBtn=
"false"
height=
"auto"
>
<el-empty
v-if=
"!props.listData?.length"
description=
"暂无数据"
:image-size=
"200"
/>
<div
v-else
class=
"box-main"
>
<div
class=
"data-list"
>
<div
class=
"data-item"
v-for=
"(item, index) in props.listData"
:key=
"index"
>
<div
class=
"item-head"
>
<div
class=
"item-name"
>
{{
item
.
title
}}
</div>
<div
class=
"button-box"
>
<div
class=
"button-icon"
>
<img
src=
"../assets/icons/open.png"
alt=
""
/>
</div>
<div
class=
"button-text"
>
跳转原文
</div>
</div>
</div>
<div
class=
"item-down"
>
<div
class=
"item-text"
v-for=
"(text, num) in item.data"
:key=
"num"
>
{{
text
}}
</div>
</div>
</div>
</div>
<AiTips
:tips=
"tips"
></AiTips>
</div>
</AnalysisBox>
</
template
>
<
script
setup
lang=
"ts"
name=
"SurveyConclusion"
>
import
AiTips
from
"@/views/marketAccessRestrictions/com/AiTips.vue"
;
const
props
=
defineProps
({
listData
:
{
type
:
Array
as
any
,
default
:
()
=>
([])
},
title
:
{
type
:
String
,
default
:
""
},
tips
:
{
type
:
String
,
default
:
""
}
})
</
script
>
<
style
scoped
lang=
"scss"
>
.box-main
{
padding
:
0
22px
20px
;
.data-list
{
margin-bottom
:
16px
;
border-top
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
.data-item
{
.item-head
{
padding
:
0
20px
;
height
:
48px
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
background
:
rgba
(
247
,
248
,
249
,
1
);
display
:
flex
;
align-items
:
center
;
.item-name
{
width
:
20px
;
flex
:
auto
;
font-family
:
Source
Han
Sans
CN
;
font-size
:
18px
;
font-weight
:
bold
;
line-height
:
30px
;
color
:
var
(
--
text-primary-80-color
);
}
.button-box
{
display
:
flex
;
align-items
:
center
;
margin-left
:
50px
;
.button-icon
{
width
:
16px
;
height
:
16px
;
font-size
:
0
;
margin-right
:
4px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.button-text
{
color
:
var
(
--
color-primary-100
);
font-family
:
Microsoft
YaHei
;
font-size
:
12px
;
font-weight
:
400
;
line-height
:
12px
;
}
}
}
.item-text
{
letter-spacing
:
1px
;
padding
:
12px
20px
12px
40px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Source
Han
Sans
CN
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
30px
;
letter-spacing
:
0px
;
text-align
:
justify
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
}
}
}
}
</
style
>
\ No newline at end of file
src/views/marketAccessRestrictions/com/SurveyHistory.vue
0 → 100644
浏览文件 @
8e94a51d
<
template
>
<div
class=
"view-box"
>
<el-empty
v-if=
"!props.surveyList?.length"
description=
"当前条件下暂无数据"
:image-size=
"200"
/>
<div
class=
"timeline-item"
v-for=
"(item, index) in props.surveyList"
:key=
"item.searchid"
@
click=
"onNavigateToDetail(item)"
>
<div
class=
"timeline-date"
>
<div
class=
"date-text"
>
{{
item
.
searchdatezh
.
slice
(
0
,
4
)
}}
</div>
<div
class=
"date-text"
>
{{
item
.
searchdatezh
.
slice
(
5
)
}}
</div>
</div>
<div
class=
"timeline-line-box"
>
<div
class=
"timeline-icon"
>
<img
v-if=
"item.sortimageurl"
:src=
"item.sortimageurl"
alt=
""
/>
<div
v-else
class=
"default-dot"
></div>
</div>
<div
class=
"timeline-line"
v-if=
"index !== props.surveyList.length - 1"
></div>
</div>
<div
class=
"timeline-content-card"
>
<div
class=
"item-head"
>
<div
:class=
"`item-tag tag-$
{item.sortcode}`">
{{
item
.
sortcode
}}
</div>
<div
class=
"item-name"
>
{{
item
.
searchname
}}
</div>
<div
class=
"item-state"
>
<span
class=
"dot"
>
•
</span>
{{
item
.
casestatus
}}
</div>
</div>
<div
class=
"card-body"
>
{{
item
.
content
}}
</div>
<div
class=
"card-footer"
>
<div
class=
"footer-left-tags"
>
<AreaTag
v-for=
"(name, num) in item.searchArea"
:key=
"num"
:tagName=
"name"
></AreaTag>
</div>
<div
class=
"footer-right-flags"
>
<div
class=
"flag-icon"
v-for=
"(name, num) in item.countryImage"
:key=
"num"
>
<img
:src=
"name"
alt=
""
/>
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
name=
"SurveyHistory"
>
import
router
from
"@/router"
;
const
props
=
defineProps
({
surveyList
:
{
type
:
Array
,
default
:
()
=>
([]),
},
})
const
onNavigateToDetail
=
item
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
searchname
);
const
curRoute
=
router
.
resolve
({
path
:
"/marketSingleCaseLayout/overview"
,
query
:
{
id
:
item
.
sortcode
,
searchId
:
item
.
searchid
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
</
script
>
<
style
scoped
lang=
"scss"
>
.view-box
{
min-height
:
600px
;
width
:
100%
;
padding
:
18px
27px
0
24px
;
border-top
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
}
.timeline-item
{
display
:
flex
;
cursor
:
pointer
;
.timeline-date
{
width
:
80px
;
text-align
:
right
;
margin-right
:
16px
;
.date-text
{
height
:
24px
;
font-size
:
16px
;
font-weight
:
700
;
color
:
var
(
--
color-main-active
);
line-height
:
24px
;
letter-spacing
:
1px
;
}
}
.timeline-line-box
{
width
:
40px
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
position
:
relative
;
.timeline-icon
{
width
:
32px
;
height
:
32px
;
z-index
:
2
;
background
:
#fff
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
font-size
:
0
;
img
{
width
:
100%
;
height
:
100%
;
}
.default-dot
{
width
:
12px
;
height
:
12px
;
border-radius
:
50%
;
background
:
orange
;
}
}
.timeline-line
{
width
:
2px
;
flex
:
1
;
background
:
#eaeeef
;
margin
:
4px
0
;
}
}
.timeline-content-card
{
width
:
20px
;
flex
:
auto
;
padding
:
2px
16px
0
;
margin-bottom
:
30px
;
&
:hover
.item-head
.item-name
{
color
:
var
(
--
color-main-active
);
text-decoration
:
underline
;
}
.item-head
{
display
:
flex
;
align-items
:
center
;
margin-bottom
:
10px
;
.item-tag
{
width
:
48px
;
height
:
24px
;
line-height
:
24px
;
text-align
:
center
;
border-radius
:
4px
;
font-weight
:
bold
;
font-size
:
16px
;
margin-right
:
12px
;
}
.tag-337
{
border
:
1px
solid
#91caff
;
background
:
#e6f4ff
;
color
:
#055fc2
;
}
.tag-232
{
border
:
1px
solid
#b37feb
;
background
:
#f9f0ff
;
color
:
#722ed1
;
}
.tag-301
{
border
:
1px
solid
#ffd591
;
background
:
#fff7e6
;
color
:
#fa8c16
;
}
.item-name
{
font-size
:
18px
;
line-height
:
18px
;
font-weight
:
bold
;
color
:
#3b414b
;
width
:
20px
;
flex
:
auto
;
}
.item-state
{
font-size
:
16px
;
color
:
#84888e
;
color
:
var
(
--
color-main-active
);
margin-left
:
100px
;
}
}
.card-body
{
font-size
:
16px
;
color
:
#5f656c
;
line-height
:
30px
;
margin-bottom
:
8px
;
display
:
-
webkit-box
;
-webkit-box-orient
:
vertical
;
-webkit-line-clamp
:
2
;
line-clamp
:
2
;
overflow
:
hidden
;
}
.card-footer
{
display
:
flex
;
gap
:
8px
;
align-items
:
center
;
.footer-left-tags
{
display
:
flex
;
gap
:
8px
;
.area-tag
{
padding
:
2px
12px
;
background
:
#e6f7ff
;
border
:
1px
solid
#91d5ff
;
color
:
#1890ff
;
border-radius
:
4px
;
font-size
:
14px
;
}
}
.footer-right-flags
{
display
:
flex
;
gap
:
4px
;
.flag-icon
{
width
:
12px
;
height
:
24px
;
img
{
border-radius
:
50%
;
border
:
1px
solid
#eee
;
width
:
24px
;
height
:
100%
;
object-fit
:
cover
;
}
}
}
}
}
}
</
style
>
\ No newline at end of file
src/views/marketAccessRestrictions/marketAccessHome/assets/icons/icon_1599.png
0 → 100644
浏览文件 @
8e94a51d
581 Bytes
src/views/marketAccessRestrictions/marketAccessHome/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/case/232/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/case/301/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/case/337/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/case/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/overview/232/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/overview/301/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/overview/337/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/marketAccessLayout/overview/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/assets/images/232.png
0 → 100644
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/assets/images/301.png
0 → 100644
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/assets/images/337.png
0 → 100644
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/assets/images/icon_affiche.png
0 → 100644
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/deepdig/232/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/deepdig/337/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/deepdig/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/overview/232/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/overview/301/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/overview/337/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/marketAccessRestrictions/singleCaseLayout/overview/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/thinkTank/index.vue
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
src/views/thinkTank/utils/multiLineChart.js
浏览文件 @
8e94a51d
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论