Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
0204674d
提交
0204674d
authored
4月 21, 2026
作者:
张烨
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'origin/pre' into zy-dev
上级
d3315d67
f0cdfc5f
流水线
#567
已通过 于阶段
in 1 分 34 秒
变更
41
流水线
1
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
41 个修改的文件
包含
945 行增加
和
395 行删除
+945
-395
service-back.js
src/api/finance/service-back.js
+153
-0
service.js
src/api/finance/service.js
+55
-22
index.js
src/api/zmOverview/risk/index.js
+8
-0
risk-signal-overview-detail-dialog.scss
...rviewDetailDialog/risk-signal-overview-detail-dialog.scss
+23
-1
index.vue
src/components/base/SummaryCardsPanel/index.vue
+5
-1
index.vue
src/components/base/moduleHeader/index.vue
+37
-48
index.vue
src/components/base/riskSignal/index.vue
+8
-3
index.js
src/router/index.js
+5
-45
bill.js
src/router/modules/bill.js
+1
-1
goToPage.js
src/utils/goToPage.js
+53
-0
riskSignalOverviewDetailHelpers.js
src/utils/riskSignalOverviewDetailHelpers.js
+4
-4
index.vue
src/views/ZMOverView/components/newRisk/index.vue
+118
-37
index.vue
src/views/bill/allCommittee/index.vue
+63
-5
box8-header-icon.png
src/views/bill/billHome/assets/images/box8-header-icon.png
+0
-0
index.vue
src/views/bill/billHome/index.vue
+0
-0
doublePieChart.js
src/views/bill/billHome/utils/doublePieChart.js
+1
-1
piechart.js
src/views/bill/billHome/utils/piechart.js
+2
-1
index.vue
src/views/comprehensiveSearch/searchResults/index.vue
+0
-0
index.vue
src/views/coopRestriction/components/dataSub/index.vue
+43
-46
index.vue
src/views/coopRestriction/components/resLib/index.vue
+56
-32
index.vue
src/views/coopRestriction/detail/index.vue
+19
-5
index.vue
src/views/coopRestriction/index.vue
+1
-0
index.vue
src/views/dataLibrary/bill/countryBill/index.vue
+3
-3
lineChart.js
src/views/dataLibrary/components/LineChart/lineChart.js
+1
-0
piechart.js
src/views/dataLibrary/components/PieChart/piechart.js
+4
-3
index.vue
src/views/dataLibrary/index.vue
+16
-8
index.vue
src/views/dataLibrary/news/index.vue
+1
-1
index.vue
src/views/decree/institution/index.vue
+44
-11
index.vue
src/views/exportControl/index.vue
+12
-15
index.vue
src/views/finance/index.vue
+24
-22
common-back.js
src/views/finance/utils/common-back.js
+63
-0
common.js
src/views/finance/utils/common.js
+45
-8
index.vue
...views/marketAccessRestrictions/marketAccessHome/index.vue
+1
-0
ModeuleNews.vue
src/views/newsBrief/ModeuleNews.vue
+76
-72
index.vue
src/views/ruleRestriction/detail/index.vue
+0
-0
index.vue
src/views/thinkTank/index.vue
+0
-0
danger.svg
src/views/viewRiskSignal/assets/images/danger.svg
+0
-0
warning.svg
src/views/viewRiskSignal/assets/images/warning.svg
+0
-0
index.vue
src/views/viewRiskSignal/index.vue
+0
-0
cleandarHeat.js
src/views/viewRiskSignal/utils/cleandarHeat.js
+0
-0
vite.config.js
vite.config.js
+0
-0
没有找到文件。
src/api/finance/service-back.js
0 → 100644
浏览文件 @
0204674d
// 引入 axios 请求
import
axios
from
'axios'
// 引入 element-plus 里面的消息提示
import
{
ElMessage
}
from
'element-plus'
import
{
getToken
,
setToken
,
removeToken
,
formatBearerAuthorization
}
from
'@/api/request.js'
export
{
getToken
,
setToken
,
removeToken
}
// 【新增】全局 AbortController,用于管理所有通过此 service 发出的请求
let
globalAbortController
=
new
AbortController
()
// 【新增】暴露一个方法,供外部(如路由守卫)调用以取消所有正在进行的请求
export
const
cancelAllRequests
=
()
=>
{
if
(
globalAbortController
)
{
globalAbortController
.
abort
()
// 创建一个新的 Controller 以备下次使用
globalAbortController
=
new
AbortController
()
}
}
// 创建 axios 实例
const
service
=
axios
.
create
({
timeout
:
30
*
1000
// 请求超时时间
})
// request 拦截器:与主 request 一致,就地改 config,避免 mergeConfig 破坏 url
service
.
interceptors
.
request
.
use
(
config
=>
{
const
raw
=
getToken
()
const
token
=
raw
?
String
(
raw
).
trim
()
:
""
if
(
!
config
.
headers
)
{
config
.
headers
=
new
axios
.
AxiosHeaders
()
}
else
if
(
!
(
config
.
headers
instanceof
axios
.
AxiosHeaders
))
{
config
.
headers
=
axios
.
AxiosHeaders
.
from
(
config
.
headers
)
}
if
(
token
)
{
config
.
headers
.
set
(
'token'
,
token
,
true
)
}
else
{
config
.
headers
.
delete
(
'token'
)
config
.
headers
.
delete
(
'Token'
)
}
const
reqUrl
=
String
(
config
.
url
??
''
)
if
(
reqUrl
.
includes
(
'aiAnalysis'
))
{
const
aiApiKey
=
import
.
meta
.
env
.
VITE_AI_ANALYSIS_API_KEY
if
(
aiApiKey
)
{
if
(
!
config
.
headers
)
{
config
.
headers
=
new
axios
.
AxiosHeaders
()
}
else
if
(
!
(
config
.
headers
instanceof
axios
.
AxiosHeaders
))
{
config
.
headers
=
axios
.
AxiosHeaders
.
from
(
config
.
headers
)
}
config
.
headers
.
set
(
'X-API-Key'
,
aiApiKey
)
}
}
// 【新增】将全局控制器的 signal 注入到当前请求中
// 注意:如果 config 中已经手动传入了 signal(例如组件内单独控制),则优先使用组件内的
if
(
!
config
.
signal
)
{
config
.
signal
=
globalAbortController
.
signal
}
return
config
},
error
=>
{
console
.
log
(
error
)
return
Promise
.
reject
(
error
)
})
// response 拦截器
service
.
interceptors
.
response
.
use
(
response
=>
{
const
res
=
response
?.
data
if
(
!
res
)
{
return
Promise
.
reject
(
new
Error
(
'响应数据为空'
))
}
// 根据需求:接口返回 code 不等于 200 的时候报错
if
(
res
.
code
!==
200
)
{
ElMessage
({
message
:
res
.
message
||
'请求失败'
,
type
:
'error'
,
duration
:
3
*
1000
})
return
Promise
.
reject
(
res
)
}
return
res
.
data
},
error
=>
{
console
.
log
(
'err'
+
error
)
const
isCanceledError
=
error
?.
code
===
'ERR_CANCELED'
||
error
?.
name
===
'CanceledError'
||
error
?.
name
===
'AbortError'
||
(
typeof
error
?.
message
===
'string'
&&
/canceled/i
.
test
(
error
.
message
))
if
(
isCanceledError
)
return
Promise
.
reject
(
error
)
// 处理 token 过期或无效的情况
const
errUrl
=
String
(
error
.
config
?.
url
||
''
)
const
isAiAnalysisRequest
=
errUrl
.
includes
(
'aiAnalysis'
)
if
(
error
.
response
&&
(
error
.
response
.
status
===
401
||
error
.
response
.
status
===
403
)
&&
!
isAiAnalysisRequest
)
{
ElMessage
({
message
:
'Token 已过期,请重新登录'
,
type
:
'error'
,
duration
:
3
*
1000
})
const
h
=
error
.
config
?.
headers
const
hadToken
=
h
&&
(
typeof
h
.
get
===
'function'
?
Boolean
(
h
.
get
(
'token'
)
||
h
.
get
(
'Token'
)
)
:
Boolean
(
h
.
token
||
h
.
Token
))
if
(
hadToken
)
removeToken
()
}
else
{
ElMessage
({
message
:
typeof
error
?.
message
===
'string'
?
error
.
message
:
'请求失败'
,
type
:
'error'
,
duration
:
3
*
1000
})
}
return
Promise
.
reject
(
error
)
}
)
// 封装通用请求函数(支持 http(config) 和 http.get/post 等调用方式)
function
http
(
config
)
{
return
service
(
config
)
}
// 为 http 函数添加快捷方法
http
.
get
=
function
(
url
,
params
)
{
return
service
({
url
,
method
:
'get'
,
params
})
}
http
.
post
=
function
(
url
,
data
)
{
return
service
({
url
,
method
:
'post'
,
data
})
}
http
.
put
=
function
(
url
,
data
)
{
return
service
({
url
,
method
:
'put'
,
data
})
}
http
.
delete
=
function
(
url
,
params
)
{
return
service
({
url
,
method
:
'delete'
,
params
})
}
export
{
http
}
export
default
service
\ No newline at end of file
src/api/finance/service.js
浏览文件 @
0204674d
// 引入 axios 请求
// src/api/finance/service.js
import
axios
from
'axios'
import
axios
from
'axios'
// 引入 element-plus 里面的消息提示
import
{
ElMessage
}
from
'element-plus'
import
{
ElMessage
}
from
'element-plus'
import
{
getToken
,
setToken
,
removeToken
,
formatBearerAuthorization
}
from
'@/api/request.js'
import
{
getToken
,
setToken
,
removeToken
}
from
'@/api/request.js'
export
{
getToken
,
setToken
,
removeToken
}
export
{
getToken
,
setToken
,
removeToken
}
// 定义全局控制器,以便在取消后重新赋值
let
currentAbortController
=
new
AbortController
()
/**
* 获取当前有效的 AbortSignal
* 供 axios 拦截器和 fetch 请求共同使用
*/
export
const
getAbortSignal
=
()
=>
{
return
currentAbortController
.
signal
}
/**
* 取消所有正在进行的请求
* 路由守卫中调用此方法
*/
export
const
cancelAllRequests
=
()
=>
{
// 1. 终止当前控制器的所有请求
currentAbortController
.
abort
()
// 2. 创建一个新的控制器,供后续新请求使用
currentAbortController
=
new
AbortController
()
}
// 创建 axios 实例
// 创建 axios 实例
const
service
=
axios
.
create
({
const
service
=
axios
.
create
({
timeout
:
30
0
*
1000
// 请求超时时间
timeout
:
30
*
1000
// 请求超时时间 30s
})
})
// request 拦截器
:与主 request 一致,就地改 config,避免 mergeConfig 破坏 url
// request 拦截器
service
.
interceptors
.
request
.
use
(
config
=>
{
service
.
interceptors
.
request
.
use
(
config
=>
{
const
raw
=
getToken
()
const
raw
=
getToken
()
const
token
=
raw
?
String
(
raw
).
trim
()
:
""
const
token
=
raw
?
String
(
raw
).
trim
()
:
""
// 处理 Headers
if
(
!
config
.
headers
)
{
if
(
!
config
.
headers
)
{
config
.
headers
=
new
axios
.
AxiosHeaders
()
config
.
headers
=
new
axios
.
AxiosHeaders
()
}
else
if
(
!
(
config
.
headers
instanceof
axios
.
AxiosHeaders
))
{
}
else
if
(
!
(
config
.
headers
instanceof
axios
.
AxiosHeaders
))
{
config
.
headers
=
axios
.
AxiosHeaders
.
from
(
config
.
headers
)
config
.
headers
=
axios
.
AxiosHeaders
.
from
(
config
.
headers
)
}
}
// 设置 Token
if
(
token
)
{
if
(
token
)
{
config
.
headers
.
set
(
'token'
,
token
,
true
)
config
.
headers
.
set
(
'token'
,
token
,
true
)
}
else
{
}
else
{
config
.
headers
.
delete
(
'token'
)
config
.
headers
.
delete
(
'token'
)
config
.
headers
.
delete
(
'Token'
)
config
.
headers
.
delete
(
'Token'
)
// ===== 旧逻辑保留(勿删):Authorization: Bearer <token> =====
// config.headers.delete('Authorization')
// config.headers.delete('authorization')
}
}
// 处理 AI 分析接口的特殊 Header
const
reqUrl
=
String
(
config
.
url
??
''
)
const
reqUrl
=
String
(
config
.
url
??
''
)
if
(
reqUrl
.
includes
(
'aiAnalysis'
))
{
if
(
reqUrl
.
includes
(
'aiAnalysis'
))
{
const
aiApiKey
=
import
.
meta
.
env
.
VITE_AI_ANALYSIS_API_KEY
const
aiApiKey
=
import
.
meta
.
env
.
VITE_AI_ANALYSIS_API_KEY
if
(
aiApiKey
)
{
if
(
aiApiKey
)
{
// 确保 headers 存在
if
(
!
config
.
headers
)
{
if
(
!
config
.
headers
)
{
config
.
headers
=
new
axios
.
AxiosHeaders
()
config
.
headers
=
new
axios
.
AxiosHeaders
()
}
else
if
(
!
(
config
.
headers
instanceof
axios
.
AxiosHeaders
))
{
}
else
if
(
!
(
config
.
headers
instanceof
axios
.
AxiosHeaders
))
{
...
@@ -42,6 +67,13 @@ service.interceptors.request.use(config => {
...
@@ -42,6 +67,13 @@ service.interceptors.request.use(config => {
config
.
headers
.
set
(
'X-API-Key'
,
aiApiKey
)
config
.
headers
.
set
(
'X-API-Key'
,
aiApiKey
)
}
}
}
}
// 将全局控制器的 signal 注入到 axios 请求中
// 如果用户手动传入了 signal,则优先使用用户的(虽然少见)
if
(
!
config
.
signal
)
{
config
.
signal
=
getAbortSignal
()
}
return
config
return
config
},
error
=>
{
},
error
=>
{
console
.
log
(
error
)
console
.
log
(
error
)
...
@@ -55,7 +87,6 @@ service.interceptors.response.use(
...
@@ -55,7 +87,6 @@ service.interceptors.response.use(
if
(
!
res
)
{
if
(
!
res
)
{
return
Promise
.
reject
(
new
Error
(
'响应数据为空'
))
return
Promise
.
reject
(
new
Error
(
'响应数据为空'
))
}
}
// 根据需求:接口返回 code 不等于 200 的时候报错
if
(
res
.
code
!==
200
)
{
if
(
res
.
code
!==
200
)
{
ElMessage
({
ElMessage
({
message
:
res
.
message
||
'请求失败'
,
message
:
res
.
message
||
'请求失败'
,
...
@@ -67,19 +98,25 @@ service.interceptors.response.use(
...
@@ -67,19 +98,25 @@ service.interceptors.response.use(
return
res
.
data
return
res
.
data
},
},
error
=>
{
error
=>
{
console
.
log
(
'err'
+
error
)
// 精准识别取消错误,避免弹窗骚扰用户
const
isCanceledError
=
const
isCanceledError
=
axios
.
isCancel
(
error
)
||
error
?.
code
===
'ERR_CANCELED'
||
error
?.
code
===
'ERR_CANCELED'
||
error
?.
name
===
'CanceledError'
||
error
?.
name
===
'CanceledError'
||
error
?.
name
===
'AbortError'
||
error
?.
name
===
'AbortError'
||
(
typeof
error
?.
message
===
'string'
&&
/canceled/i
.
test
(
error
.
message
))
(
typeof
error
?.
message
===
'string'
&&
/canceled/i
.
test
(
error
.
message
))
if
(
isCanceledError
)
return
Promise
.
reject
(
error
)
if
(
isCanceledError
)
{
// 静默处理取消错误,不弹窗,不打印.error
return
Promise
.
reject
(
error
)
}
console
.
log
(
'err'
+
error
)
// 处理
token 过期或无效的情况
// 处理
Token 过期
const
errUrl
=
String
(
error
.
config
?.
url
||
''
)
const
errUrl
=
String
(
error
.
config
?.
url
||
''
)
const
isAiAnalysisRequest
=
errUrl
.
includes
(
'aiAnalysis'
)
const
isAiAnalysisRequest
=
errUrl
.
includes
(
'aiAnalysis'
)
if
(
if
(
error
.
response
&&
error
.
response
&&
(
error
.
response
.
status
===
401
||
error
.
response
.
status
===
403
)
&&
(
error
.
response
.
status
===
401
||
error
.
response
.
status
===
403
)
&&
...
@@ -94,14 +131,11 @@ service.interceptors.response.use(
...
@@ -94,14 +131,11 @@ service.interceptors.response.use(
const
hadToken
=
const
hadToken
=
h
&&
h
&&
(
typeof
h
.
get
===
'function'
(
typeof
h
.
get
===
'function'
?
Boolean
(
?
Boolean
(
h
.
get
(
'token'
)
||
h
.
get
(
'Token'
))
h
.
get
(
'token'
)
||
h
.
get
(
'Token'
)
:
Boolean
(
h
.
token
||
h
.
Token
))
)
:
Boolean
(
h
.
token
||
h
.
Token
))
if
(
hadToken
)
removeToken
()
if
(
hadToken
)
removeToken
()
}
else
{
}
else
{
// 只有非取消、非 Token 过期的错误才弹出通用提示
ElMessage
({
ElMessage
({
message
:
typeof
error
?.
message
===
'string'
?
error
.
message
:
'请求失败'
,
message
:
typeof
error
?.
message
===
'string'
?
error
.
message
:
'请求失败'
,
type
:
'error'
,
type
:
'error'
,
...
@@ -112,12 +146,11 @@ service.interceptors.response.use(
...
@@ -112,12 +146,11 @@ service.interceptors.response.use(
}
}
)
)
// 封装通用请求函数
(支持 http(config) 和 http.get/post 等调用方式)
// 封装通用请求函数
function
http
(
config
)
{
function
http
(
config
)
{
return
service
(
config
)
return
service
(
config
)
}
}
// 为 http 函数添加快捷方法
http
.
get
=
function
(
url
,
params
)
{
http
.
get
=
function
(
url
,
params
)
{
return
service
({
url
,
method
:
'get'
,
params
})
return
service
({
url
,
method
:
'get'
,
params
})
}
}
...
...
src/api/zmOverview/risk/index.js
浏览文件 @
0204674d
...
@@ -17,6 +17,14 @@ export function getLatestRisks() {
...
@@ -17,6 +17,14 @@ export function getLatestRisks() {
});
});
}
}
// 中美博弈概览V2:首页最新风险动态(10条 + 各类数量/总数)
export
function
getLatestRisk
()
{
return
request
({
method
:
"GET"
,
url
:
`/api/rivalryIndexV2/LatestRisk`
});
}
// 中美博弈概览V2:美对华制裁措施数量趋势
// 中美博弈概览V2:美对华制裁措施数量趋势
export
function
geDomainContainmentTrend
(
params
)
{
export
function
geDomainContainmentTrend
(
params
)
{
return
request
({
return
request
({
...
...
src/components/base/RiskSignalOverviewDetailDialog/risk-signal-overview-detail-dialog.scss
浏览文件 @
0204674d
...
@@ -132,6 +132,28 @@
...
@@ -132,6 +132,28 @@
position
:
relative
;
position
:
relative
;
}
}
.risk-signal-detail-dialog
.el-dialog__headerbtn
{
top
:
11px
!
important
;
right
:
16px
!
important
;
width
:
32px
!
important
;
height
:
32px
!
important
;
display
:
inline-flex
;
align-items
:
center
;
justify-content
:
center
;
}
.risk-signal-detail-dialog
.el-dialog__headerbtn
.el-dialog__close
{
width
:
16px
;
height
:
16px
;
color
:
rgb
(
59
,
65
,
75
)
!
important
;
}
.risk-signal-detail-dialog
.el-dialog__headerbtn
.el-dialog__close
svg
,
.risk-signal-detail-dialog
.el-dialog__headerbtn
.el-dialog__close
svg
path
{
fill
:
rgb
(
59
,
65
,
75
)
!
important
;
stroke
:
rgb
(
59
,
65
,
75
)
!
important
;
}
.
risk-signal-detail-dialog
.
el-dialog__header
:
:
after
{
.
risk-signal-detail-dialog
.
el-dialog__header
:
:
after
{
content
:
""
;
content
:
""
;
position
:
absolute
;
position
:
absolute
;
...
@@ -234,7 +256,7 @@
...
@@ -234,7 +256,7 @@
.risk-signal-detail-dialog
.risk-signal-detail-dialog__read-indicator
{
.risk-signal-detail-dialog
.risk-signal-detail-dialog__read-indicator
{
position
:
absolute
;
position
:
absolute
;
right
:
115
px
;
right
:
61
px
;
top
:
50%
;
top
:
50%
;
transform
:
translateY
(
-50%
);
transform
:
translateY
(
-50%
);
display
:
inline-flex
;
display
:
inline-flex
;
...
...
src/components/base/SummaryCardsPanel/index.vue
浏览文件 @
0204674d
...
@@ -25,7 +25,7 @@
...
@@ -25,7 +25,7 @@
<el-icon
color=
"var(--color-primary-100)"
>
<el-icon
color=
"var(--color-primary-100)"
>
<ArrowRightBold
/>
<ArrowRightBold
/>
</el-icon>
</el-icon>
<div
class=
"item-dot"
v-if=
"item.delta"
>
+
{{ item.delta }}
</div>
<div
class=
"item-dot"
v-if=
"item.delta"
>
{{ dotPrefix }}
{{ item.delta }}
</div>
</div>
</div>
<div
v-if=
"shouldShowMoreCard"
class=
"summary-item"
@
click=
"emit('more-click')"
>
<div
v-if=
"shouldShowMoreCard"
class=
"summary-item"
@
click=
"emit('more-click')"
>
...
@@ -100,6 +100,10 @@ const props = defineProps({
...
@@ -100,6 +100,10 @@ const props = defineProps({
loading
:
{
loading
:
{
type
:
Boolean
,
type
:
Boolean
,
default
:
false
default
:
false
},
dotPrefix
:
{
type
:
String
,
default
:
"+"
}
}
});
});
...
...
src/components/base/moduleHeader/index.vue
浏览文件 @
0204674d
<
template
>
<
template
>
<div
class=
"module-header-wrapper"
>
<div
class=
"module-header-wrapper"
@
mouseleave=
"handleHideUserPanel"
>
<div
class=
"nav-content"
:class=
"
{ 'nav-content-library': isShowDataLibrary }">
<div
class=
"nav-content"
:class=
"
{ 'nav-content-library': isShowDataLibrary }">
<div
class=
"nav-left"
:class=
"
{ 'flex-start': isShowSearchBar }">
<div
class=
"nav-left"
:class=
"
{ 'flex-start': isShowSearchBar }">
<div
class=
"icon"
>
<div
class=
"icon"
>
...
@@ -24,36 +24,36 @@
...
@@ -24,36 +24,36 @@
<div
class=
"mail"
@
click=
"handleClickToolBox"
>
<div
class=
"mail"
@
click=
"handleClickToolBox"
>
<img
src=
"@/assets/icons/overview/mail.png"
alt=
""
/>
<img
src=
"@/assets/icons/overview/mail.png"
alt=
""
/>
</div>
</div>
<div
class=
"user-trigger"
>
<div
class=
"user-trigger"
@
mouseenter=
"handleShowUserPanel"
>
<div
class=
"user"
@
click
.
stop
=
"handleToggleUserPanel"
>
<div
class=
"user"
@
click
.
stop
>
<img
src=
"@/assets/icons/overview/user.png"
alt=
""
/>
<img
src=
"@/assets/icons/overview/user.png"
alt=
""
/>
</div>
</div>
</div
>
<div
v-if=
"isShowUserPanel"
class=
"user-panel"
>
<div
v-if=
"isShowUserPanel"
class=
"user-panel"
>
<div
class=
"user-panel-row"
>
<div
class=
"user-panel-row"
>
<div
class=
"blue-solid"
></div
>
<div
class=
"blue-solid"
></div
>
<span
class=
"user-panel-value user-panel-value--nickname"
>
{{
userNickname
}}
</span
>
<span
class=
"user-panel-value user-panel-value--nickname"
>
{{
userNickname
}}
</span
>
<div
class=
"role-box"
>
<div
class=
"role-box"
>
<span
class=
"user-panel-value user-panel-value--role"
>
{{
roleName
}}
</span
>
<
span
class=
"user-panel-value user-panel-value--role"
>
{{
roleName
}}
</span
>
<
/div
>
</div>
</div>
</div>
<div
class=
"user-panel-row user-panel-row--single"
>
<div
class=
"user-panel-row user-panel-row--single"
>
<span
class=
"user-panel-value user-panel-value--organ"
>
{{
organName
}}
</span>
<span
class=
"user-panel-value user-panel-value--organ"
>
{{
organName
}}
</span>
</div>
</div>
<div
class=
"solid"
></div>
<div
class=
"solid"
></div>
<div
class=
"user-panel-logout"
@
click
.
stop=
"handleUserCommand('logout')"
><img
src=
"./back.png"
<div
class=
"user-panel-logout"
@
click
.
stop=
"handleUserCommand('logout')"
><img
src=
"./back.png"
class=
"back-image"
/>
{{
"退出登录"
}}
class=
"back-image"
/>
{{
"退出登录"
}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"menu-box"
v-
show
=
"isShowMenu"
@
mouseenter=
"handleHoverMenu(true)"
<div
class=
"menu-box"
v-
if
=
"isShowMenu"
@
mouseenter=
"handleHoverMenu(true)"
@
mouseleave=
"handleHoverMenu(false)"
>
@
mouseleave=
"handleHoverMenu(false)"
>
<div
class=
"menu-content"
>
<div
class=
"menu-content"
>
<div
class=
"menu-item"
v-for=
"(item, index) in menuList"
:key=
"index"
@
click=
"handleToModule(item, 1)"
>
<div
class=
"menu-item"
v-for=
"(item, index) in menuList"
:key=
"index"
@
click=
"handleToModule(item, 1)"
>
...
@@ -64,9 +64,9 @@
...
@@ -64,9 +64,9 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"tool-box"
v-
show
=
"isShowTool"
@
mouseenter=
"handleHoverTool(true)"
<div
class=
"tool-box"
v-
if
=
"isShowTool"
@
mouseenter=
"handleHoverTool(true)"
@
mouseleave=
"handleHoverTool(false)"
>
@
mouseleave=
"handleHoverTool(false)"
>
<div
class=
"
menu
-content"
>
<div
class=
"
tool
-content"
>
<div
class=
"menu-item"
v-for=
"(item, index) in toolList"
:key=
"index"
@
click=
"handleToModule(item, 2)"
>
<div
class=
"menu-item"
v-for=
"(item, index) in toolList"
:key=
"index"
@
click=
"handleToModule(item, 2)"
>
<div
class=
"icon"
>
<div
class=
"icon"
>
<img
:src=
"item.icon"
alt=
""
/>
<img
:src=
"item.icon"
alt=
""
/>
...
@@ -404,8 +404,8 @@ const handleClickToolBox = () => {
...
@@ -404,8 +404,8 @@ const handleClickToolBox = () => {
ElMessage
.
warning
(
"当前功能正在开发中,敬请期待!"
);
ElMessage
.
warning
(
"当前功能正在开发中,敬请期待!"
);
};
};
const
handle
Toggle
UserPanel
=
()
=>
{
const
handle
Show
UserPanel
=
()
=>
{
isShowUserPanel
.
value
=
!
isShowUserPanel
.
val
ue
;
isShowUserPanel
.
value
=
tr
ue
;
};
};
const
handleHideUserPanel
=
()
=>
{
const
handleHideUserPanel
=
()
=>
{
...
@@ -662,10 +662,13 @@ onMounted(() => {
...
@@ -662,10 +662,13 @@ onMounted(() => {
top
:
calc
(
32px
+
21px
);
top
:
calc
(
32px
+
21px
);
width
:
240px
;
width
:
240px
;
height
:
141px
;
height
:
141px
;
// 与“中美科技博弈”下方菜单框(.menu-box)保持一致的透明/模糊效果
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
1
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
1
);
border-radius
:
10px
;
border-radius
:
10px
;
backdrop-filter
:
blur
(
30px
);
-webkit-backdrop-filter
:
blur
(
30px
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
...
@@ -785,6 +788,13 @@ onMounted(() => {
...
@@ -785,6 +788,13 @@ onMounted(() => {
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
margin-left
:
8px
;
margin-left
:
8px
;
transition
:
color
0
.15s
ease
,
font-size
0
.15s
ease
,
font-weight
0
.15s
ease
;
&
:hover
{
color
:
var
(
--
color-main-active
);
font-size
:
18px
;
font-weight
:
700
;
}
.back-image
{
.back-image
{
width
:
16px
;
width
:
16px
;
...
@@ -805,23 +815,6 @@ onMounted(() => {
...
@@ -805,23 +815,6 @@ onMounted(() => {
}
}
.menu-box
{
.menu-box
{
// position: absolute;
// z-index: 999999999;
// width: 713px;
// height: 413px;
// top: 52px;
// left: 0;
// box-sizing: border-box;
// border-radius: 10px;
// backdrop-filter: blur(10px);
// -webkit-backdrop-filter: blur(10px);
// box-shadow: 0px 8px 32px 0px rgba(31, 38, 135, 0.15);
// background: rgba(255, 255, 255, 0.25);
// backdrop-filter: blur(10px);
// -webkit-backdrop-filter: blur(10px);
// border: 1px solid rgba(255, 255, 255, 0.3);
// background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.2) 100%);
// box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
position
:
absolute
;
position
:
absolute
;
z-index
:
999999
;
z-index
:
999999
;
width
:
713px
;
width
:
713px
;
...
@@ -902,21 +895,17 @@ onMounted(() => {
...
@@ -902,21 +895,17 @@ onMounted(() => {
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
.
menu
-content
{
.
tool
-content
{
width
:
562
px
;
width
:
130
px
;
height
:
348
px
;
height
:
120
px
;
margin-top
:
8px
;
margin-top
:
8px
;
margin-left
:
72px
;
margin-left
:
72px
;
.menu-item
{
.menu-item
{
margin-top
:
36px
;
margin-top
:
36px
;
width
:
280px
;
width
:
100%
;
height
:
24px
;
height
:
24px
;
display
:
flex
;
display
:
flex
;
cursor
:
pointer
;
cursor
:
pointer
;
&
:hover
{
&
:hover
{
.title
{
.title
{
color
:
var
(
--
color-main-active
);
color
:
var
(
--
color-main-active
);
...
...
src/components/base/riskSignal/index.vue
浏览文件 @
0204674d
...
@@ -12,14 +12,14 @@
...
@@ -12,14 +12,14 @@
<div
class=
"box2-main"
>
<div
class=
"box2-main"
>
<div
class=
"box2-main-item"
v-for=
"(item, index) in showRiskSignalList"
:key=
"index"
@
click=
"handleItemClick(item, index)"
>
<div
class=
"box2-main-item"
v-for=
"(item, index) in showRiskSignalList"
:key=
"index"
@
click=
"handleItemClick(item, index)"
>
<div
:class=
"
{
<div
v-if=
"!isRiskLevelNoData(item?.[props.riskLevel])"
:class=
"
{
itemLeftStatus1: item[props.riskLevel] === '特别重大',
itemLeftStatus1: item[props.riskLevel] === '特别重大',
itemLeftStatus2: item[props.riskLevel] === '重大风险',
itemLeftStatus2: item[props.riskLevel] === '重大风险',
itemLeftStatus3: item[props.riskLevel] === '较大风险',
itemLeftStatus3: item[props.riskLevel] === '较大风险',
itemLeftStatus4: item[props.riskLevel] === '一般风险'
|| !item[props.riskLevel]
,
itemLeftStatus4: item[props.riskLevel] === '一般风险',
itemLeftStatus5: item[props.riskLevel] === '低风险',
itemLeftStatus5: item[props.riskLevel] === '低风险',
}">
}">
{{
item
[
props
.
riskLevel
]
||
"暂无数据"
}}
{{
item
[
props
.
riskLevel
]
}}
</div>
</div>
<div
class=
"item-right"
>
<div
class=
"item-right"
>
<div
class=
"text"
>
<span
class=
"text-inner"
>
{{
item
[
props
.
name
]
}}
</span></div>
<div
class=
"text"
>
<span
class=
"text-inner"
>
{{
item
[
props
.
name
]
}}
</span></div>
...
@@ -76,6 +76,11 @@ const props = defineProps({
...
@@ -76,6 +76,11 @@ const props = defineProps({
});
});
const
isRiskLevelNoData
=
(
level
)
=>
{
const
t
=
String
(
level
??
""
).
trim
();
return
!
t
||
t
===
"暂无数据"
||
t
===
"暂无数值"
;
};
const
showRiskSignalList
=
computed
(()
=>
{
const
showRiskSignalList
=
computed
(()
=>
{
return
props
.
list
.
slice
(
0
,
6
)
return
props
.
list
.
slice
(
0
,
6
)
})
})
...
...
src/router/index.js
浏览文件 @
0204674d
...
@@ -2,6 +2,8 @@ import { createRouter, createWebHistory } from "vue-router";
...
@@ -2,6 +2,8 @@ import { createRouter, createWebHistory } from "vue-router";
import
{
setToken
,
removeToken
,
getToken
}
from
"@/api/request.js"
;
import
{
setToken
,
removeToken
,
getToken
}
from
"@/api/request.js"
;
import
{
AUTH_LOGOUT_CHANNEL
}
from
"@/utils/authCrossTabLogout.js"
;
import
{
AUTH_LOGOUT_CHANNEL
}
from
"@/utils/authCrossTabLogout.js"
;
import
{
cancelAllRequests
}
from
"@/api/finance/service.js"
/** localStorage:跨标签页记录当前前端的 bootId(与 vite define 的 __APP_BOOT_ID__ 对齐) */
/** localStorage:跨标签页记录当前前端的 bootId(与 vite define 的 __APP_BOOT_ID__ 对齐) */
const
VITE_BOOT_STORAGE_KEY
=
"app_vite_boot_id"
;
const
VITE_BOOT_STORAGE_KEY
=
"app_vite_boot_id"
;
/** 退出后强制回登录页(跨标签页/刷新生效) */
/** 退出后强制回登录页(跨标签页/刷新生效) */
...
@@ -145,51 +147,9 @@ const router = createRouter({
...
@@ -145,51 +147,9 @@ const router = createRouter({
// 2)登录成功回跳带 ?token=:先 setToken 并同步 bootId,再去掉 URL 中的 token(须先于 clearTokenIfNewDevBoot,避免误清刚写入的登录态)
// 2)登录成功回跳带 ?token=:先 setToken 并同步 bootId,再去掉 URL 中的 token(须先于 clearTokenIfNewDevBoot,避免误清刚写入的登录态)
// 3)已有本地 token:正常走前端路由
// 3)已有本地 token:正常走前端路由
router
.
beforeEach
((
to
,
from
,
next
)
=>
{
router
.
beforeEach
((
to
,
from
,
next
)
=>
{
// ===== SSO/重定向逻辑(切线上接口时停用,保留注释) =====
// 【新增】在每次路由跳转开始前,取消上一个页面所有未完成的请求
// const queryToken = to.query && to.query.token != null && String(to.query.token).trim() !== ""
// 这能防止旧页面的数据回来覆盖新页面,也能减少服务器压力
// ? String(to.query.token).trim()
cancelAllRequests
();
// : "";
//
// if (queryToken) {
// setToken(queryToken);
// // 成功回跳拿到 token,说明统一登录链路已完成,清除强制标记
// try {
// if (typeof window !== "undefined") {
// window.sessionStorage.removeItem(FORCE_SSO_LOGIN_KEY);
// }
// } catch {
// // ignore
// }
// persistViteBootIdOnly();
// const restQuery = { ...to.query };
// delete restQuery.token;
// const isGatewayCallback =
// to.path === "/callback" || to.path.replace(/\/$/, "") === "/callback";
// const targetPath = isGatewayCallback ? SSO_POST_LOGIN_PATH : to.path;
// next({
// path: targetPath,
// query: restQuery,
// hash: to.hash,
// replace: true,
// });
// return;
// }
//
// // 若用户点了“退出登录”,即使本地还有残留 token/或别处写回,也强制先走统一登录链路
// try {
// if (typeof window !== "undefined" && window.sessionStorage.getItem(FORCE_SSO_LOGIN_KEY) === "1") {
// removeToken();
// const targetUrl = `${SSO_GATEWAY_ORIGIN}/api/v2${to.fullPath || "/"}`;
// window.location.replace(targetUrl);
// next(false);
// return;
// }
// } catch {
// // ignore
// }
// 外网/线上版本:不因重启清登录态;仅开发环境需要此逻辑
// clearTokenIfNewDevBoot();
if
(
import
.
meta
.
env
.
DEV
)
{
if
(
import
.
meta
.
env
.
DEV
)
{
clearTokenIfNewDevBoot
();
clearTokenIfNewDevBoot
();
}
}
...
...
src/router/modules/bill.js
浏览文件 @
0204674d
...
@@ -35,7 +35,7 @@ const billRoutes = [
...
@@ -35,7 +35,7 @@ const billRoutes = [
component
:
BillAllCommittee
,
component
:
BillAllCommittee
,
meta
:
{
meta
:
{
title
:
"法案委员会列表"
,
title
:
"法案委员会列表"
,
isShowHeader
:
tru
e
isShowHeader
:
fals
e
}
}
},
},
{
{
...
...
src/utils/goToPage.js
0 → 100644
浏览文件 @
0204674d
import
{
useRouter
}
from
"vue-router"
;
const
router
=
useRouter
()
// 跳转法案详情
export
const
goToBill
=
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
"billId"
,
id
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
tabName
);
const
route
=
router
.
resolve
({
path
:
"/billLayout"
,
query
:
{
billId
:
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 跳转政令详情
export
const
goToDecree
=
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
"decreeId"
,
id
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
tabName
);
const
route
=
router
.
resolve
({
path
:
"/decreeLayout"
,
query
:
{
id
:
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 跳转智库
export
const
goToThinkTank
=
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
tabName
);
const
route
=
router
.
resolve
({
name
:
"ReportDetail"
,
params
:
{
id
:
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
}
// 跳转机构详情
export
const
goToInstitution
=
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
'curTabName'
,
tabName
)
const
curRoute
=
router
.
resolve
({
path
:
"/institution"
,
query
:
{
id
:
id
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
\ No newline at end of file
src/utils/riskSignalOverviewDetailHelpers.js
浏览文件 @
0204674d
...
@@ -223,14 +223,14 @@ export function getRiskDetailLevelModifier(level) {
...
@@ -223,14 +223,14 @@ export function getRiskDetailLevelModifier(level) {
if
(
t
===
"低风险"
)
{
if
(
t
===
"低风险"
)
{
return
"lv5"
;
return
"lv5"
;
}
}
if
(
t
===
"一般风险"
||
!
t
||
t
===
"暂无数据"
)
{
if
(
t
===
"一般风险"
||
!
t
||
t
===
"暂无数据"
||
t
===
"风险信号暂无评估"
)
{
return
"lv4"
;
return
"lv4"
;
}
}
return
"lv4"
;
return
"lv4"
;
}
}
/**
与 `@/components/base/riskSignal` 左侧等级一致:空 / null 等展示「暂无数据
」 */
/**
详情弹窗标题区等级文案:空 / null 等展示「风险信号暂无评估
」 */
export
const
RISK_SIGNAL_LIST_LEVEL_EMPTY_TEXT
=
"
暂无数据
"
;
export
const
RISK_SIGNAL_LIST_LEVEL_EMPTY_TEXT
=
"
风险信号暂无评估
"
;
/**
/**
* 列表行风险等级 → 弹窗标题区文案(null、空串与「暂无数值」等与列表「暂无数据」对齐)
* 列表行风险等级 → 弹窗标题区文案(null、空串与「暂无数值」等与列表「暂无数据」对齐)
...
@@ -241,7 +241,7 @@ export function normalizeRiskSignalListLevelText(raw) {
...
@@ -241,7 +241,7 @@ export function normalizeRiskSignalListLevelText(raw) {
return
RISK_SIGNAL_LIST_LEVEL_EMPTY_TEXT
;
return
RISK_SIGNAL_LIST_LEVEL_EMPTY_TEXT
;
}
}
const
s
=
String
(
raw
).
trim
();
const
s
=
String
(
raw
).
trim
();
if
(
s
===
""
||
s
===
"null"
||
s
===
"undefined"
||
s
===
"暂无数值"
)
{
if
(
s
===
""
||
s
===
"null"
||
s
===
"undefined"
||
s
===
"暂无数值"
||
s
===
"暂无数据"
)
{
return
RISK_SIGNAL_LIST_LEVEL_EMPTY_TEXT
;
return
RISK_SIGNAL_LIST_LEVEL_EMPTY_TEXT
;
}
}
return
s
;
return
s
;
...
...
src/views/ZMOverView/components/newRisk/index.vue
浏览文件 @
0204674d
...
@@ -43,15 +43,10 @@
...
@@ -43,15 +43,10 @@
<div
style=
"display: flex"
>
<div
style=
"display: flex"
>
<!-- 风险信号列表 -->
<!-- 风险信号列表 -->
<div
class=
"risk-signals"
ref=
"riskSignalsRef"
>
<div
class=
"risk-signals"
ref=
"riskSignalsRef"
>
<div
<div
class=
"risk-signals-item"
v-for=
"(item, index) in warningList"
class=
"risk-signals-item"
v-for=
"(item, index) in warningList"
:key=
"item.signalId != null ? String(item.signalId) : 'risk-' + index"
:key=
"item.signalId != null ? String(item.signalId) : 'risk-' + index"
@
mouseenter=
"onMouseEnter(item, index)"
@
mouseenter=
"onMouseEnter(item, index)"
@
mouseleave=
"onMouseLeave"
@
click
.
stop
@
mouseleave=
"onMouseLeave"
:class=
"['risk-signals-item',
{ 'risk-signals-item-hightLight': riskSignalActiveIndex === index }]">
@
click
.
stop
:class=
"['risk-signals-item',
{ 'risk-signals-item-hightLight': riskSignalActiveIndex === index }]"
>
<div
class=
"item-left"
:class=
"
{
<div
class=
"item-left"
:class=
"
{
'item-status-1': item.signalLevel === '特别重大',
'item-status-1': item.signalLevel === '特别重大',
'item-status-2': item.signalLevel === '重大风险',
'item-status-2': item.signalLevel === '重大风险',
...
@@ -132,7 +127,8 @@
...
@@ -132,7 +127,8 @@
import
{
color
}
from
"echarts"
;
import
{
color
}
from
"echarts"
;
import
{
onMounted
,
ref
,
onUnmounted
,
computed
}
from
"vue"
;
import
{
onMounted
,
ref
,
onUnmounted
,
computed
}
from
"vue"
;
import
WaveBall
from
"./WaveBall.vue"
;
import
WaveBall
from
"./WaveBall.vue"
;
import
{
getLatestRiskUpdates
,
getLatestRisks
}
from
"@/api/zmOverview/risk/index.js"
;
import
{
getLatestRisk
}
from
"@/api/zmOverview/risk/index.js"
;
import
{
getRiskSignalInfoById
}
from
"@/api/riskSignal/index.js"
;
import
router
from
"@/router/index"
;
import
router
from
"@/router/index"
;
import
{
navigateToViewRiskSignal
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
{
navigateToViewRiskSignal
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
icon1
from
"./icon/title-1.svg"
;
import
icon1
from
"./icon/title-1.svg"
;
...
@@ -315,12 +311,14 @@ const cardShowIndex4 = ref(0);
...
@@ -315,12 +311,14 @@ const cardShowIndex4 = ref(0);
// 最新风险动态统计
// 最新风险动态统计
const
handleGetLatestRiskUpdates
=
async
()
=>
{
const
handleGetLatestRiskUpdates
=
async
()
=>
{
try
{
try
{
const
params
=
{
const
res
=
await
getLatestRisk
();
currentDate
:
"本周"
console
.
log
(
"最新风险动态"
,
res
);
};
const
res
=
await
getLatestRiskUpdates
(
params
);
console
.
log
(
"最新风险动态统计1"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
if
(
res
.
code
===
200
&&
res
.
data
)
{
const
d
=
res
.
data
;
const
formatChange
=
(
n
)
=>
{
const
v
=
Number
(
n
)
||
0
;
return
v
===
0
?
"无新增"
:
String
(
v
);
};
sections
.
value
=
[
sections
.
value
=
[
{
{
// title: res.data.policiesRegulations.hotspotTitle,
// title: res.data.policiesRegulations.hotspotTitle,
...
@@ -328,16 +326,16 @@ const handleGetLatestRiskUpdates = async () => {
...
@@ -328,16 +326,16 @@ const handleGetLatestRiskUpdates = async () => {
waveBall
:
[
waveBall
:
[
{
{
percent
:
30
,
// 估算的百分比
percent
:
30
,
// 估算的百分比
count
:
res
.
data
.
bill
.
total
,
count
:
d
.
billRiskTotal
??
0
,
change
:
res
.
data
.
bill
.
dailyIncrement
,
change
:
formatChange
(
d
.
billRiskNum
)
,
unit
:
"项"
,
unit
:
"项"
,
title
:
"法案(提出)"
,
title
:
"法案(提出)"
,
type
:
"法案"
type
:
"法案"
},
},
{
{
percent
:
20
,
// 估算的百分比
percent
:
20
,
// 估算的百分比
count
:
res
.
data
.
administrativeOrder
.
total
,
count
:
d
.
orderRiskTotal
??
0
,
change
:
res
.
data
.
administrativeOrder
.
dailyIncrement
,
change
:
formatChange
(
d
.
orderRiskNum
)
,
unit
:
"个"
,
unit
:
"个"
,
title
:
"政令"
,
title
:
"政令"
,
type
:
"行政令"
type
:
"行政令"
...
@@ -350,8 +348,8 @@ const handleGetLatestRiskUpdates = async () => {
...
@@ -350,8 +348,8 @@ const handleGetLatestRiskUpdates = async () => {
waveBall
:
[
waveBall
:
[
{
{
percent
:
10
,
// 估算的百分比
percent
:
10
,
// 估算的百分比
count
:
res
.
data
.
Entities
.
total
,
count
:
d
.
entityRiskTotal
??
0
,
change
:
res
.
data
.
Entities
.
dailyIncrement
,
change
:
formatChange
(
d
.
entityRiskNum
)
,
unit
:
"次"
,
unit
:
"次"
,
title
:
"实体清单"
,
title
:
"实体清单"
,
...
@@ -359,8 +357,8 @@ const handleGetLatestRiskUpdates = async () => {
...
@@ -359,8 +357,8 @@ const handleGetLatestRiskUpdates = async () => {
},
},
{
{
percent
:
20
,
// 估算的百分比
percent
:
20
,
// 估算的百分比
count
:
res
.
data
.
CCL
.
total
,
count
:
d
.
cclRiskTotal
??
0
,
change
:
res
.
data
.
CCL
.
dailyIncrement
,
change
:
formatChange
(
d
.
cclRiskNum
)
,
unit
:
"次"
,
unit
:
"次"
,
title
:
"CCL"
,
title
:
"CCL"
,
type
:
"CCL"
type
:
"CCL"
...
@@ -373,16 +371,16 @@ const handleGetLatestRiskUpdates = async () => {
...
@@ -373,16 +371,16 @@ const handleGetLatestRiskUpdates = async () => {
waveBall
:
[
waveBall
:
[
{
{
percent
:
15
,
// 估算的百分比
percent
:
15
,
// 估算的百分比
count
:
res
.
data
.
SDN
.
total
,
count
:
d
.
sdnRiskTotal
??
0
,
change
:
res
.
data
.
SDN
.
dailyIncrement
,
change
:
formatChange
(
d
.
sdnRiskNum
)
,
unit
:
"次"
,
unit
:
"次"
,
title
:
"SDN"
,
title
:
"SDN"
,
type
:
"SDN"
type
:
"SDN"
},
},
{
{
percent
:
5
,
// 估算的百分比
percent
:
5
,
// 估算的百分比
count
:
res
.
data
.
militaryInvolvement
.
total
,
count
:
d
.
armyRiskTotal
??
0
,
change
:
res
.
data
.
militaryInvolvement
.
dailyIncrement
,
change
:
formatChange
(
d
.
armyRiskNum
)
,
unit
:
"家"
,
unit
:
"家"
,
title
:
"涉军企业"
,
title
:
"涉军企业"
,
type
:
"涉军企业"
type
:
"涉军企业"
...
@@ -395,24 +393,24 @@ const handleGetLatestRiskUpdates = async () => {
...
@@ -395,24 +393,24 @@ const handleGetLatestRiskUpdates = async () => {
waveBall
:
[
waveBall
:
[
{
{
percent
:
3
,
// 估算的百分比
percent
:
3
,
// 估算的百分比
count
:
res
.
data
[
"337Survey"
].
total
,
count
:
d
.
m337RiskTotal
??
0
,
change
:
res
.
data
[
"337Survey"
].
dailyIncrement
,
change
:
formatChange
(
d
.
m337RiskNum
)
,
unit
:
"次"
,
unit
:
"次"
,
title
:
"337调查"
,
title
:
"337调查"
,
type
:
"337调查"
type
:
"337调查"
},
},
{
{
percent
:
3
,
// 估算的百分比
percent
:
3
,
// 估算的百分比
count
:
res
.
data
[
"232Survey"
].
total
,
count
:
d
.
m232RiskTotal
??
0
,
change
:
res
.
data
[
"232Survey"
].
dailyIncrement
,
change
:
formatChange
(
d
.
m232RiskNum
)
,
unit
:
"次"
,
unit
:
"次"
,
title
:
"232调查"
,
title
:
"232调查"
,
type
:
"232调查"
type
:
"232调查"
},
},
{
{
percent
:
3
,
// 估算的百分比
percent
:
3
,
// 估算的百分比
count
:
res
.
data
[
"301Survey"
].
total
,
count
:
d
.
m301RiskTotal
??
0
,
change
:
res
.
data
[
"301Survey"
].
dailyIncrement
,
change
:
formatChange
(
d
.
m301RiskNum
)
,
unit
:
"次"
,
unit
:
"次"
,
title
:
"301调查"
,
title
:
"301调查"
,
type
:
"301调查"
type
:
"301调查"
...
@@ -454,12 +452,60 @@ const hotNewsList = ref([
...
@@ -454,12 +452,60 @@ const hotNewsList = ref([
//最新风险信号
//最新风险信号
const
handleGetLatestRisks
=
async
()
=>
{
const
handleGetLatestRisks
=
async
()
=>
{
try
{
try
{
const
res
=
await
getLatestRisk
s
();
const
res
=
await
getLatestRisk
();
console
.
log
(
"最新风险
信号
"
,
res
);
console
.
log
(
"最新风险
动态(列表)
"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
if
(
res
.
code
===
200
&&
res
.
data
)
{
warningList
.
value
=
res
.
data
.
riskVOS
;
const
d
=
res
.
data
;
hotNewsList
.
value
=
res
.
data
.
hotspotVOS
;
const
list
=
Array
.
isArray
(
d
.
riskSignals
)
?
d
.
riskSignals
:
[];
riskTotal
.
value
=
res
.
data
.
riskCount
;
const
getEventTypeFromModule
=
(
code
)
=>
{
const
c
=
String
(
code
??
""
).
trim
();
if
(
c
===
"0100"
)
return
"法案"
;
if
(
c
===
"0101"
)
return
"行政令"
;
if
(
c
===
"0102"
)
return
"智库报告"
;
if
(
c
===
"0103"
)
return
"出口管制"
;
if
(
c
===
"0104"
)
return
"市场准入"
;
if
(
c
===
"0105"
)
return
"创新主体"
;
if
(
c
===
"0106"
)
return
"合作限制"
;
if
(
c
===
"0107"
)
return
"科研资助体系"
;
if
(
c
===
"0108"
)
return
"规则限制"
;
if
(
c
===
"0109"
)
return
"投融资限制"
;
if
(
c
===
"01031"
)
return
"实体清单"
;
if
(
c
===
"01032"
)
return
"CCL"
;
if
(
c
===
"01091"
)
return
"SDN"
;
if
(
c
===
"01092"
)
return
"涉军企业"
;
if
(
c
===
"01041"
)
return
"337调查"
;
if
(
c
===
"01042"
)
return
"232调查"
;
if
(
c
===
"01043"
)
return
"301调查"
;
return
c
;
};
warningList
.
value
=
list
.
map
((
x
)
=>
({
signalId
:
x
.
id
,
signalTitle
:
x
.
title
,
signalTime
:
x
.
eventTime
,
signalLevel
:
x
.
riskLevel
,
signalCountryId
:
x
.
riskCountryId
,
dealStatus
:
x
.
dealStatus
,
eventType
:
getEventTypeFromModule
(
x
.
sanModuleCode
)
}));
riskTotal
.
value
=
warningList
.
value
.
length
;
// 右侧轮播:同样使用 LatestRisk 的 riskSignals(字段映射到现有模板使用的热点字段名)
hotNewsList
.
value
=
list
.
map
((
x
)
=>
({
signalId
:
x
.
id
,
hotspotID
:
x
.
id
,
hotspotType
:
getEventTypeFromModule
(
x
.
sanModuleCode
),
hotspotTitle
:
x
.
title
,
// 轮播题目右侧标签:切换轮播时用详情接口 domains 覆盖
hotspotTag
:
""
,
hotspotDesc
:
x
.
description
||
""
,
hotspotDate
:
x
.
eventTime
||
""
,
domainList
:
[],
eventTitle
:
x
.
issuingOrgId
||
""
}));
// 首次加载:主动拉取当前轮播项详情以展示题目右侧标签
await
fetchCarouselDetailForIndex
(
curHotNewsListIndex
.
value
||
0
);
cardList1
.
value
=
warningList
.
value
cardList1
.
value
=
warningList
.
value
.
filter
(
item
=>
{
.
filter
(
item
=>
{
return
item
.
eventType
===
"法案"
||
item
.
eventType
===
"行政令"
;
return
item
.
eventType
===
"法案"
||
item
.
eventType
===
"行政令"
;
...
@@ -520,11 +566,46 @@ const handleGetLatestRisks = async () => {
...
@@ -520,11 +566,46 @@ const handleGetLatestRisks = async () => {
const
curNews
=
ref
({});
const
curNews
=
ref
({});
const
carouselRef
=
ref
(
null
);
const
carouselRef
=
ref
(
null
);
const
curHotNewsListIndex
=
ref
(
0
);
const
curHotNewsListIndex
=
ref
(
0
);
const
carouselDetailCache
=
ref
({});
const
applyHotspotTagById
=
(
id
,
tagText
)
=>
{
const
sid
=
String
(
id
??
""
).
trim
();
if
(
!
sid
)
return
;
hotNewsList
.
value
=
(
hotNewsList
.
value
||
[]).
map
((
n
)
=>
{
if
(
String
(
n
.
hotspotID
??
""
).
trim
()
!==
sid
)
return
n
;
return
{
...
n
,
hotspotTag
:
tagText
};
});
};
const
fetchCarouselDetailForIndex
=
async
(
index
)
=>
{
const
item
=
hotNewsList
.
value
?.[
index
];
if
(
!
item
)
return
;
const
id
=
String
(
item
.
hotspotID
??
""
).
trim
();
if
(
!
id
)
return
;
if
(
carouselDetailCache
.
value
[
id
])
{
applyHotspotTagById
(
id
,
carouselDetailCache
.
value
[
id
]);
return
;
}
try
{
const
res
=
await
getRiskSignalInfoById
(
id
);
if
(
res
&&
res
.
code
===
200
&&
res
.
data
)
{
const
tagText
=
String
(
res
.
data
.
domains
??
""
).
trim
();
if
(
tagText
)
{
carouselDetailCache
.
value
=
{
...
carouselDetailCache
.
value
,
[
id
]:
tagText
};
applyHotspotTagById
(
id
,
tagText
);
}
}
}
catch
(
error
)
{
console
.
error
(
"轮播风险信号详情获取失败"
,
error
);
}
};
const
handleCarouselChange
=
index
=>
{
const
handleCarouselChange
=
index
=>
{
curHotNewsListIndex
.
value
=
index
;
curHotNewsListIndex
.
value
=
index
;
if
(
hotNewsList
.
value
&&
hotNewsList
.
value
.
length
>
0
)
{
if
(
hotNewsList
.
value
&&
hotNewsList
.
value
.
length
>
0
)
{
curNews
.
value
=
hotNewsList
.
value
[
index
];
curNews
.
value
=
hotNewsList
.
value
[
index
];
}
}
fetchCarouselDetailForIndex
(
index
);
};
};
// 查看详情
// 查看详情
...
...
src/views/bill/allCommittee/index.vue
浏览文件 @
0204674d
...
@@ -14,6 +14,12 @@
...
@@ -14,6 +14,12 @@
placeholder=
"搜索委员会"
placeholder=
"搜索委员会"
/>
/>
</div>
</div>
<div
class=
"hard-select"
>
<el-select
v-model=
"committeeInfo.metricType"
@
change=
"onAllCommittee()"
placeholder=
"统计口径"
style=
"width: 160px; margin-left: 8px"
>
<el-option
label=
"政令数据总量"
:value=
"1"
/>
<el-option
label=
"政令新增数量"
:value=
"2"
/>
</el-select>
</div>
</div>
</div>
<div
class=
"date-box"
>
<div
class=
"date-box"
>
...
@@ -30,7 +36,7 @@
...
@@ -30,7 +36,7 @@
<div
class=
"item-name one-line-ellipsis"
>
{{
item
.
name
}}
</div>
<div
class=
"item-name one-line-ellipsis"
>
{{
item
.
name
}}
</div>
<div
class=
"item-chamber one-line-ellipsis"
>
{{
item
.
chamber
}}
</div>
<div
class=
"item-chamber one-line-ellipsis"
>
{{
item
.
chamber
}}
</div>
</div>
</div>
<div
class=
"item-total"
>
{{
item
.
count
}}
项
</div>
<div
class=
"item-total"
>
{{
getDisplayCount
(
item
)
}}
项
</div>
<el-icon
color=
"var(--color-primary-100)"
>
<el-icon
color=
"var(--color-primary-100)"
>
<ArrowRightBold
/>
<ArrowRightBold
/>
</el-icon>
</el-icon>
...
@@ -48,6 +54,12 @@
...
@@ -48,6 +54,12 @@
/>
/>
</div>
</div>
</div>
</div>
<div
class=
"back-bnt"
@
click=
"handleBack"
>
<el-icon>
<Back
/>
</el-icon>
<div
class=
"back-text"
>
返回
</div>
</div>
</div>
</div>
</
template
>
</
template
>
...
@@ -55,6 +67,7 @@
...
@@ -55,6 +67,7 @@
import
{
onMounted
,
reactive
,
ref
}
from
"vue"
;
import
{
onMounted
,
reactive
,
ref
}
from
"vue"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
{
ArrowRightBold
}
from
"@element-plus/icons-vue"
;
import
{
ArrowRightBold
}
from
"@element-plus/icons-vue"
;
import
{
Back
}
from
"@element-plus/icons-vue"
;
import
router
from
"@/router"
;
import
router
from
"@/router"
;
import
TimeTabPane
from
"@/components/base/TimeTabPane/index.vue"
;
import
TimeTabPane
from
"@/components/base/TimeTabPane/index.vue"
;
import
{
getStatisticsBillCountByCommittee
}
from
"@/api/bill/billHome"
;
import
{
getStatisticsBillCountByCommittee
}
from
"@/api/bill/billHome"
;
...
@@ -66,6 +79,7 @@ const committeeInfo = reactive({
...
@@ -66,6 +79,7 @@ const committeeInfo = reactive({
pageSize
:
8
,
pageSize
:
8
,
total
:
0
,
total
:
0
,
keyWord
:
""
,
keyWord
:
""
,
metricType
:
1
,
dateDesc
:
"近一年"
,
dateDesc
:
"近一年"
,
list
:
[]
list
:
[]
});
});
...
@@ -89,10 +103,11 @@ const onAllCommittee = async num => {
...
@@ -89,10 +103,11 @@ const onAllCommittee = async num => {
id
:
`
${
item
.
orgType
||
""
}
-
${
item
.
orgName
||
""
}
`
,
id
:
`
${
item
.
orgType
||
""
}
-
${
item
.
orgName
||
""
}
`
,
name
:
item
.
orgName
,
name
:
item
.
orgName
,
chamber
:
getChamberLabel
(
item
.
orgType
),
chamber
:
getChamberLabel
(
item
.
orgType
),
count
:
Number
(
item
.
count
||
0
)
totalCount
:
Number
(
item
.
count
||
0
),
recentCount
:
Number
(
item
.
countRecent
||
item
.
totalRecent
||
item
.
recentCount
||
item
.
recent
||
item
.
newCount
||
0
)
}))
}))
.
filter
(
item
=>
!
committeeInfo
.
keyWord
||
item
.
name
?.
includes
(
committeeInfo
.
keyWord
))
.
filter
(
item
=>
!
committeeInfo
.
keyWord
||
item
.
name
?.
includes
(
committeeInfo
.
keyWord
))
.
sort
((
a
,
b
)
=>
(
b
.
count
||
0
)
-
(
a
.
count
||
0
));
.
sort
((
a
,
b
)
=>
getSortValue
(
b
)
-
getSortValue
(
a
));
committeeInfo
.
total
=
source
.
length
;
committeeInfo
.
total
=
source
.
length
;
const
start
=
(
committeeInfo
.
pageNum
-
1
)
*
committeeInfo
.
pageSize
;
const
start
=
(
committeeInfo
.
pageNum
-
1
)
*
committeeInfo
.
pageSize
;
...
@@ -108,20 +123,36 @@ const onAllCommittee = async num => {
...
@@ -108,20 +123,36 @@ const onAllCommittee = async num => {
committeeInfo
.
loading
=
false
;
committeeInfo
.
loading
=
false
;
};
};
const
getSortValue
=
item
=>
{
if
(
committeeInfo
.
metricType
===
2
)
return
Number
(
item
?.
recentCount
||
0
);
return
Number
(
item
?.
totalCount
||
0
);
};
const
getDisplayCount
=
item
=>
{
return
getSortValue
(
item
);
};
const
handleDateChange
=
event
=>
{
const
handleDateChange
=
event
=>
{
committeeInfo
.
dateDesc
=
event
?.
time
||
"近一年"
;
committeeInfo
.
dateDesc
=
event
?.
time
||
"近一年"
;
onAllCommittee
();
onAllCommittee
();
};
};
const
handleToDataLibrary
=
item
=>
{
const
handleToDataLibrary
=
item
=>
{
const
route
=
router
.
resolve
({
router
.
push
({
path
:
"/dataLibrary/countryBill"
,
path
:
"/dataLibrary/countryBill"
,
query
:
{
query
:
{
selectedOrg
:
item
.
name
,
selectedOrg
:
item
.
name
,
selectedCongress
:
item
.
chamber
selectedCongress
:
item
.
chamber
}
}
});
});
window
.
open
(
route
.
href
,
"_blank"
);
};
const
handleBack
=
()
=>
{
if
(
window
.
history
.
length
>
1
)
{
router
.
back
();
return
;
}
router
.
push
(
"/billHome"
);
};
};
const
refCommittee
=
ref
();
const
refCommittee
=
ref
();
...
@@ -143,6 +174,28 @@ onMounted(() => {
...
@@ -143,6 +174,28 @@ onMounted(() => {
background-size
:
100%
100%
;
background-size
:
100%
100%
;
display
:
flex
;
display
:
flex
;
justify-content
:
center
;
justify-content
:
center
;
position
:
relative
;
.back-bnt
{
position
:
absolute
;
top
:
16px
;
left
:
30px
;
width
:
86px
;
height
:
38px
;
background-color
:
white
;
border-radius
:
19px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
color
:
var
(
--
text-primary-65-color
);
font-family
:
Source
Han
Sans
CN
;
font-size
:
16px
;
cursor
:
pointer
;
}
.back-text
{
margin-left
:
6px
;
}
.container-box
{
.container-box
{
width
:
1600px
;
width
:
1600px
;
...
@@ -180,6 +233,11 @@ onMounted(() => {
...
@@ -180,6 +233,11 @@ onMounted(() => {
width
:
180px
;
width
:
180px
;
height
:
32px
;
height
:
32px
;
}
}
.hard-select
{
height
:
42px
;
padding
:
5px
0
;
}
}
}
.date-box
{
.date-box
{
...
...
src/views/bill/billHome/assets/images/box8-header-icon.png
0 → 100644
浏览文件 @
0204674d
1.2 KB
src/views/bill/billHome/index.vue
浏览文件 @
0204674d
差异被折叠。
点击展开。
src/views/bill/billHome/utils/doublePieChart.js
浏览文件 @
0204674d
...
@@ -69,7 +69,7 @@ const getDoublePieChart = (data1, data2) => {
...
@@ -69,7 +69,7 @@ const getDoublePieChart = (data1, data2) => {
const
name
=
truncateLabel
(
params
?.
name
,
6
)
const
name
=
truncateLabel
(
params
?.
name
,
6
)
const
value
=
params
?.
value
??
0
const
value
=
params
?.
value
??
0
const
percent
=
typeof
params
?.
percent
===
'number'
?
params
.
percent
:
0
const
percent
=
typeof
params
?.
percent
===
'number'
?
params
.
percent
:
0
return
`{name|
${
name
}
}\n{time|
${
value
}
条
${
percent
}
%}`
return
`{name|
${
name
}
}\n{time|
${
value
}
项
${
percent
}
%}`
},
},
minMargin
:
5
,
minMargin
:
5
,
edgeDistance
:
10
,
edgeDistance
:
10
,
...
...
src/views/bill/billHome/utils/piechart.js
浏览文件 @
0204674d
...
@@ -10,6 +10,7 @@ const truncateLabel = (value, maxLen = 6) => {
...
@@ -10,6 +10,7 @@ const truncateLabel = (value, maxLen = 6) => {
const
getPieChart
=
(
data
,
colorList
,
options
=
{})
=>
{
const
getPieChart
=
(
data
,
colorList
,
options
=
{})
=>
{
const
showCount
=
options
.
showCount
!==
false
const
showCount
=
options
.
showCount
!==
false
const
countUnit
=
options
.
countUnit
||
'条'
const
chartColors
=
Array
.
isArray
(
colorList
)
&&
colorList
.
length
?
colorList
:
MUTICHARTCOLORS
const
chartColors
=
Array
.
isArray
(
colorList
)
&&
colorList
.
length
?
colorList
:
MUTICHARTCOLORS
let
option
=
{
let
option
=
{
color
:
chartColors
,
color
:
chartColors
,
...
@@ -38,7 +39,7 @@ const getPieChart = (data, colorList, options = {}) => {
...
@@ -38,7 +39,7 @@ const getPieChart = (data, colorList, options = {}) => {
const
name
=
truncateLabel
(
params
?.
name
,
6
)
const
name
=
truncateLabel
(
params
?.
name
,
6
)
const
value
=
params
?.
value
??
0
const
value
=
params
?.
value
??
0
const
percent
=
typeof
params
?.
percent
===
'number'
?
params
.
percent
:
0
const
percent
=
typeof
params
?.
percent
===
'number'
?
params
.
percent
:
0
const
labelText
=
showCount
?
`
${
value
}
条
${
percent
}
%`
:
`
${
percent
}
%`
const
labelText
=
showCount
?
`
${
value
}
${
countUnit
}
${
percent
}
%`
:
`
${
percent
}
%`
return
`{name|
${
name
}
}\n{time|
${
labelText
}
}`
return
`{name|
${
name
}
}\n{time|
${
labelText
}
}`
},
},
minMargin
:
5
,
minMargin
:
5
,
...
...
src/views/comprehensiveSearch/searchResults/index.vue
浏览文件 @
0204674d
差异被折叠。
点击展开。
src/views/coopRestriction/components/dataSub/index.vue
浏览文件 @
0204674d
...
@@ -602,9 +602,7 @@ const initRightChart = () => {
...
@@ -602,9 +602,7 @@ const initRightChart = () => {
const
domains
=
Array
.
from
(
domainsSet
);
const
domains
=
Array
.
from
(
domainsSet
);
const
types
=
Array
.
from
(
typesSet
);
const
types
=
Array
.
from
(
typesSet
);
const
legendSplitAt
=
Math
.
ceil
(
types
.
length
/
2
);
const
legendData
=
types
;
const
legendFirstLine
=
types
.
slice
(
0
,
legendSplitAt
);
const
legendSecondLine
=
types
.
slice
(
legendSplitAt
);
const
indicators
=
domains
.
map
((
domain
)
=>
{
const
indicators
=
domains
.
map
((
domain
)
=>
{
const
domainData
=
rawData
.
filter
((
item
)
=>
item
.
AREA
===
domain
);
const
domainData
=
rawData
.
filter
((
item
)
=>
item
.
AREA
===
domain
);
...
@@ -630,57 +628,56 @@ const initRightChart = () => {
...
@@ -630,57 +628,56 @@ const initRightChart = () => {
const
option
=
{
const
option
=
{
color
:
colorMap
,
color
:
colorMap
,
// 避免自动换行导致“第二行不居中”:拆成两行 legend,每行各自居中
// 图例尽量单行居中;放不下则横向滚动(不换行)
legend
:
[
legend
:
{
{
show
:
true
,
show
:
true
,
type
:
"scroll"
,
type
:
"plain"
,
orient
:
"horizontal"
,
data
:
legendFirstLine
,
data
:
legendData
,
top
:
8
,
top
:
8
,
left
:
"center"
,
left
:
"center"
,
icon
:
"circle"
,
width
:
"90%"
,
itemWidth
:
12
,
height
:
24
,
itemHeight
:
12
,
icon
:
"circle"
,
itemGap
:
24
,
itemWidth
:
12
,
textStyle
:
{
itemHeight
:
12
,
color
:
"rgb(95, 101, 108)"
,
itemGap
:
24
,
fontSize
:
16
,
pageButtonPosition
:
"end"
,
fontFamily
:
"Microsoft YaHei"
,
pageIconSize
:
12
,
fontWeight
:
400
,
pageTextStyle
:
{
lineHeight
:
24
color
:
"rgb(95, 101, 108)"
,
}
fontSize
:
12
,
fontFamily
:
"Microsoft YaHei"
},
},
{
textStyle
:
{
show
:
legendSecondLine
.
length
>
0
,
color
:
"rgb(95, 101, 108)"
,
type
:
"plain"
,
fontSize
:
16
,
data
:
legendSecondLine
,
fontFamily
:
"Microsoft YaHei"
,
top
:
32
,
fontWeight
:
400
,
left
:
"center"
,
lineHeight
:
24
icon
:
"circle"
,
itemWidth
:
12
,
itemHeight
:
12
,
itemGap
:
24
,
textStyle
:
{
color
:
"rgb(95, 101, 108)"
,
fontSize
:
16
,
fontFamily
:
"Microsoft YaHei"
,
fontWeight
:
400
,
lineHeight
:
24
}
}
}
]
,
}
,
radar
:
{
radar
:
{
// 对齐左侧折线图(grid top=34%)的“图例到图形”间距:下移雷达中心并略缩半径
// 对齐左侧折线图(grid top=34%)的“图例到图形”间距:下移雷达中心并略缩半径
center
:
[
"50%"
,
"
62
%"
],
center
:
[
"50%"
,
"
57
%"
],
radius
:
"
60
%"
,
radius
:
"
58
%"
,
indicator
:
indicators
,
indicator
:
indicators
,
axisName
:
{
axisName
:
{
color
:
"rgba(132, 136, 142, 1)"
,
fontFamily
:
"Source Han Sans CN"
,
fontSize
:
14
,
fontWeight
:
700
,
fontWeight
:
400
fontSize
:
16
,
lineHeight
:
24
,
letterSpacing
:
1
,
color
:
"rgb(59, 65, 75)"
},
},
splitLine
:
{
lineStyle
:
{
color
:
[
"#e6e6e6"
]
}
},
splitLine
:
{
lineStyle
:
{
color
:
[
"#e6e6e6"
]
}
},
splitArea
:
{
show
:
false
}
splitArea
:
{
show
:
true
,
areaStyle
:
{
// 从最内圈白色开始,向外层交替浅灰
color
:
[
"#ffffff"
,
"rgb(247, 248, 249)"
]
}
}
},
},
series
:
[
series
:
[
{
{
...
...
src/views/coopRestriction/components/resLib/index.vue
浏览文件 @
0204674d
...
@@ -7,8 +7,7 @@
...
@@ -7,8 +7,7 @@
</div>
</div>
</div>
</div>
<el-select
v-model=
"sortModel"
placeholder=
"发布时间"
class=
"select"
popper-class=
"coop-select-dropdown"
<el-select
v-model=
"sortModel"
placeholder=
"发布时间"
class=
"select"
popper-class=
"coop-select-dropdown"
:teleported=
"true"
placement=
"bottom-start"
:teleported=
"true"
placement=
"bottom-start"
:popper-options=
"sortPopperOptions"
@
change=
"handleSortChange"
>
:popper-options=
"sortPopperOptions"
@
change=
"handleSortChange"
>
<template
#
prefix
>
<template
#
prefix
>
<img
v-if=
"sortModel !== true"
src=
"@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image down.png"
<img
v-if=
"sortModel !== true"
src=
"@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image down.png"
class=
"select-prefix-img"
alt=
""
@
click
.
stop=
"toggleSortPrefix"
/>
class=
"select-prefix-img"
alt=
""
@
click
.
stop=
"toggleSortPrefix"
/>
...
@@ -37,35 +36,42 @@
...
@@ -37,35 +36,42 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"right"
>
<div
class=
"right"
:class=
"{ 'right--empty': !(mainDataList && mainDataList.length) }"
>
<div
class=
"right-title"
>
<div
class=
"right-title"
>
<img
src=
"./assets/icon01.png"
alt=
""
/>
<img
src=
"./assets/icon01.png"
alt=
""
/>
<div>
合作限制历程
</div>
<div>
合作限制历程
</div>
</div>
</div>
<div
class=
"right-main"
>
<div
class=
"right-main"
>
<div
class=
"main-content"
>
<
template
v-if=
"mainDataList && mainDataList.length"
>
<div
v-for=
"item in mainDataList"
:key=
"item.id"
class=
"main-item"
>
<div
class=
"main-content"
>
<div
class=
"date"
>
{{ formatDateCn(item.date) }}
</div>
<div
v-for=
"item in mainDataList"
:key=
"item.id"
class=
"main-item"
>
<img
:src=
"item.img"
alt=
""
class=
"img"
/>
<div
class=
"date"
>
{{
formatDateCn
(
item
.
date
)
}}
</div>
<div
class=
"box"
>
<img
:src=
"item.img"
alt=
""
class=
"img"
/>
<div
class=
"title"
@
click=
"handleClick(item)"
>
{{ item.title }}
</div>
<div
class=
"box"
>
<div
class=
"content"
@
click=
"handleClick(item)"
>
{{ item.content }}
</div>
<div
class=
"title"
@
click=
"handleClick(item)"
>
{{
item
.
title
}}
</div>
<div
class=
"domain"
>
<div
class=
"content"
@
click=
"handleClick(item)"
>
{{
item
.
content
}}
</div>
<AreaTag
v-for=
"(domain, i) in item.domain"
:key=
"i"
"
:tagName=
"domain"
>
<div
class=
"domain"
>
</AreaTag>
<AreaTag
v-for=
"(domain, i) in item.domain"
:key=
"i"
"
:tagName=
"domain"
>
</div>
</AreaTag>
</div>
<div
class=
"type"
:class=
"getTypeClass(item.type)"
>
{{ item.type }}
<div
class=
"type"
:class=
"getTypeClass(item.type)"
>
{{
item
.
type
}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"page"
>
<div
class=
"page"
>
<div
class=
"count"
>
共
{{
total
}}
项调查
</div>
<div
class=
"count"
>
共 {{ total }} 项调查
</div>
<el-pagination
v-model:current-page=
"currentPage"
:page-size=
"pageSize"
:total=
"total"
<el-pagination
v-model:current-page=
"currentPage"
:page-size=
"pageSize"
:total=
"total"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChange"
/>
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChange"
/>
</div>
</div>
</
template
>
<
template
v-else
>
<div
class=
"right-main-empty"
>
<el-empty
class=
"right-el-empty"
description=
"暂无数据"
:image-size=
"100"
/>
</div>
</
template
>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -533,6 +539,13 @@ watch(currentPage, () => {
...
@@ -533,6 +539,13 @@ watch(currentPage, () => {
border-radius
:
10px
;
border-radius
:
10px
;
background-color
:
#fff
;
background-color
:
#fff
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
display
:
flex
;
flex-direction
:
column
;
&
.right--empty
{
// 与左侧筛选框等高
height
:
432px
;
}
.right-title
{
.right-title
{
width
:
1224px
;
width
:
1224px
;
...
@@ -563,10 +576,28 @@ watch(currentPage, () => {
...
@@ -563,10 +576,28 @@ watch(currentPage, () => {
.right-main
{
.right-main
{
width
:
1224px
;
width
:
1224px
;
flex
:
1
;
padding
:
12px
0px
80px
0px
;
padding
:
12px
0px
80px
0px
;
position
:
relative
;
position
:
relative
;
.right-main-empty
{
height
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
padding
:
24px
;
:deep
(
.el-empty__image
)
{
margin-bottom
:
0
;
}
.right-el-empty
{
padding
:
0
;
margin
:
0
;
}
}
.main-content
{
.main-content
{
width
:
1224px
;
width
:
1224px
;
...
@@ -594,15 +625,7 @@ watch(currentPage, () => {
...
@@ -594,15 +625,7 @@ watch(currentPage, () => {
}
}
&
:last-child::after
{
&
:last-child::after
{
content
:
""
;
content
:
none
;
position
:
absolute
;
top
:
37px
;
bottom
:
-37px
;
left
:
108px
;
width
:
2px
;
background-color
:
rgb
(
230
,
231
,
232
);
z-index
:
1
;
height
:
calc
(
100%
-
37px
);
}
}
.date
{
.date
{
...
@@ -635,6 +658,7 @@ watch(currentPage, () => {
...
@@ -635,6 +658,7 @@ watch(currentPage, () => {
.title
{
.title
{
font-size
:
20px
;
font-size
:
20px
;
width
:
950px
;
font-weight
:
700
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
font-family
:
"Microsoft YaHei"
;
line-height
:
26px
;
line-height
:
26px
;
...
...
src/views/coopRestriction/detail/index.vue
浏览文件 @
0204674d
...
@@ -5,13 +5,13 @@
...
@@ -5,13 +5,13 @@
<img
:src=
"coopData?.IMAGEURL || defaultImg"
alt=
""
/>
<img
:src=
"coopData?.IMAGEURL || defaultImg"
alt=
""
/>
<div
class=
"content"
>
<div
class=
"content"
>
<div
class=
"cl1"
>
{{
coopData
?.
LIMITNAMEZH
}}
</div>
<div
class=
"cl1"
>
{{
coopData
?.
LIMITNAMEZH
}}
</div>
<div
class=
"cl2"
>
{{
coopData
?.
LIMITNAME
}}
</div>
<div
v-if=
"hasLimitNameEn"
class=
"cl2"
>
{{
coopData
?.
LIMITNAME
}}
</div>
<div
class=
"cl3"
>
{{
coopData
?.
LIMITDATE
}}
·
{{
coopData
?.
LIMITORGNAME
}}
</div>
<div
class=
"cl3"
>
{{
coopData
?.
LIMITDATE
}}
·
{{
coopData
?.
LIMITORGNAME
}}
</div>
</div>
</div>
<div
class=
"btn"
>
<div
class=
"btn"
>
<button
class=
"btn1"
><img
src=
"./assets/icon01.png"
alt=
""
/>
查看原文
</button>
<!--
<button
class=
"btn1"
><img
src=
"./assets/icon02.png"
alt=
""
/>
查看官网
</button>
-->
<!--
<button
class=
"btn1"
><img
src=
"./assets/icon02.png"
alt=
""
/>
查看官网
</button>
-->
<button
class=
"btn1 active"
><img
src=
"./assets/icon03.png"
alt=
""
/>
分析报告
</button>
<button
class=
"btn1 active"
@
click=
"handleOpenWrittingAsstaint"
><img
src=
"./assets/icon03.png"
alt=
""
/>
分析报告
</button>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -81,7 +81,8 @@
...
@@ -81,7 +81,8 @@
<img
src=
"./assets/打开按钮.png"
alt=
""
>
<img
src=
"./assets/打开按钮.png"
alt=
""
>
</div>
</div>
<!-- contentList:单条按原样式展示;多条则逐条展示并加 1.2.3. 前缀 -->
<!-- contentList:单条按原样式展示;多条则逐条展示并加 1.2.3. 前缀 -->
<div
v-if=
"Array.isArray(item.contentList) && item.contentList.length > 1"
class=
"clause-item-content-list"
>
<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"
>
<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-index"
>
{{
i
+
1
}}
.
</span>
<span
class=
"row-text"
>
{{
row
.
CONTENT
}}
</span>
<span
class=
"row-text"
>
{{
row
.
CONTENT
}}
</span>
...
@@ -117,6 +118,15 @@ import Rubio from "./assets/卢比奥.png";
...
@@ -117,6 +118,15 @@ import Rubio from "./assets/卢比奥.png";
import
Bondi
from
"./assets/邦迪.png"
;
import
Bondi
from
"./assets/邦迪.png"
;
import
Nome
from
"./assets/诺姆.png"
;
import
Nome
from
"./assets/诺姆.png"
;
const
hasLimitNameEn
=
computed
(()
=>
{
return
Boolean
(
String
(
coopData
.
value
?.
LIMITNAME
??
""
).
trim
());
});
const
handleOpenWrittingAsstaint
=
()
=>
{
const
{
href
}
=
router
.
resolve
({
path
:
"/writtingAsstaint"
});
window
.
open
(
href
,
"_blank"
);
};
// 合作限制-查询限制条款
// 合作限制-查询限制条款
const
limitClauseData
=
ref
([]);
const
limitClauseData
=
ref
([]);
const
getlimitClauseData
=
async
()
=>
{
const
getlimitClauseData
=
async
()
=>
{
...
@@ -474,9 +484,13 @@ const dataList3 = ref([
...
@@ -474,9 +484,13 @@ const dataList3 = ref([
.btn
{
.btn
{
width
:
376px
;
width
:
376px
;
height
:
36
px
;
height
:
48
px
;
display
:
flex
;
display
:
flex
;
justify-content
:
right
;
justify-content
:
right
;
position
:
absolute
;
bottom
:
0
;
margin-left
:
1224px
;
.btn1
{
.btn1
{
border-radius
:
6px
;
border-radius
:
6px
;
...
...
src/views/coopRestriction/index.vue
浏览文件 @
0204674d
...
@@ -164,6 +164,7 @@ const handleToPosi = id => {
...
@@ -164,6 +164,7 @@ const handleToPosi = id => {
background-size
:
100%
100%
;
background-size
:
100%
100%
;
position
:
absolute
;
position
:
absolute
;
width
:
100%
;
width
:
100%
;
height
:
100%
;
z-index
:
-100
;
z-index
:
-100
;
top
:
-64px
;
top
:
-64px
;
...
...
src/views/dataLibrary/bill/countryBill/index.vue
浏览文件 @
0204674d
...
@@ -124,7 +124,7 @@
...
@@ -124,7 +124,7 @@
<
el
-
table
ref
=
"tableRef"
:
data
=
"tableData"
row
-
key
=
"id"
@
selection
-
change
=
"handleSelectionChange"
<
el
-
table
ref
=
"tableRef"
:
data
=
"tableData"
row
-
key
=
"id"
@
selection
-
change
=
"handleSelectionChange"
@
select
=
"handleSelect"
@
select
-
all
=
"handleSelectAll"
style
=
"width: 100%"
:
row
-
style
=
"{ height: '52px'
}
"
>
@
select
=
"handleSelect"
@
select
-
all
=
"handleSelectAll"
style
=
"width: 100%"
:
row
-
style
=
"{ height: '52px'
}
"
>
<
el
-
table
-
column
type
=
"selection"
width
=
"40"
/>
<
el
-
table
-
column
type
=
"selection"
width
=
"40"
/>
<
el
-
table
-
column
label
=
"法案名称"
width
=
"
455
"
>
<
el
-
table
-
column
label
=
"法案名称"
width
=
"
600
"
>
<
template
#
default
=
"scope"
>
<
template
#
default
=
"scope"
>
<
span
class
=
"title-item text-compact-bold"
@
click
=
"handleClickToDetail(scope.row)"
>
{{
<
span
class
=
"title-item text-compact-bold"
@
click
=
"handleClickToDetail(scope.row)"
>
{{
scope
.
row
.
originalTitle
scope
.
row
.
originalTitle
...
@@ -134,14 +134,14 @@
...
@@ -134,14 +134,14 @@
<
el
-
table
-
column
label
=
"日期"
width
=
"120"
class
-
name
=
"date-column"
>
<
el
-
table
-
column
label
=
"日期"
width
=
"120"
class
-
name
=
"date-column"
>
<
template
#
default
=
"scope"
>
{{
scope
.
row
.
date
}}
<
/template
>
<
template
#
default
=
"scope"
>
{{
scope
.
row
.
date
}}
<
/template
>
<
/el-table-column
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"提案人"
width
=
"
48
0"
>
<
el
-
table
-
column
label
=
"提案人"
width
=
"
30
0"
>
<
template
#
default
=
"scope"
>
<
template
#
default
=
"scope"
>
<
span
class
=
"person-item text-compact"
@
click
=
"handlePerClick(scope.row)"
>
{{
scope
.
row
.
sponsorPersonName
<
span
class
=
"person-item text-compact"
@
click
=
"handlePerClick(scope.row)"
>
{{
scope
.
row
.
sponsorPersonName
}}
<
/span
>
}}
<
/span
>
<
/template
>
<
/template
>
<
/el-table-column
>
<
/el-table-column
>
<
el
-
table
-
column
property
=
"affiliation"
label
=
"所属党派"
width
=
"120"
/>
<
el
-
table
-
column
property
=
"affiliation"
label
=
"所属党派"
width
=
"120"
/>
<
el
-
table
-
column
property
=
"originDepart"
label
=
"提出委员会"
width
=
"180"
/>
<
el
-
table
-
column
property
=
"originDepart"
label
=
"提出委员会"
/>
<
el
-
table
-
column
property
=
"status"
label
=
"所处阶段"
width
=
"120"
/>
<
el
-
table
-
column
property
=
"status"
label
=
"所处阶段"
width
=
"120"
/>
<
/el-table
>
<
/el-table
>
<
/div
>
<
/div
>
...
...
src/views/dataLibrary/components/LineChart/lineChart.js
浏览文件 @
0204674d
...
@@ -23,6 +23,7 @@ const getLineChart = (dataX, dataY) => {
...
@@ -23,6 +23,7 @@ const getLineChart = (dataX, dataY) => {
},
},
yAxis
:
{
yAxis
:
{
type
:
'value'
,
type
:
'value'
,
name
:
'数量'
,
splitLine
:
{
splitLine
:
{
show
:
true
,
show
:
true
,
lineStyle
:
{
lineStyle
:
{
...
...
src/views/dataLibrary/components/PieChart/piechart.js
浏览文件 @
0204674d
...
@@ -2,8 +2,8 @@ import { MUTICHARTCOLORS } from "@/common/constant";
...
@@ -2,8 +2,8 @@ import { MUTICHARTCOLORS } from "@/common/constant";
const
getPieChart
=
(
data
)
=>
{
const
getPieChart
=
(
data
)
=>
{
const
colorList
=
MUTICHARTCOLORS
const
colorList
=
MUTICHARTCOLORS
let
showData
=
data
let
showData
=
data
if
(
data
.
length
>
1
4
)
{
if
(
data
.
length
>
1
2
)
{
showData
=
data
.
slice
(
0
,
1
3
)
showData
=
data
.
slice
(
0
,
1
1
)
let
num
=
0
let
num
=
0
data
.
slice
(
13
,).
forEach
(
item
=>
{
data
.
slice
(
13
,).
forEach
(
item
=>
{
num
=
num
+
item
.
value
num
=
num
+
item
.
value
...
@@ -22,8 +22,9 @@ const getPieChart = (data) => {
...
@@ -22,8 +22,9 @@ const getPieChart = (data) => {
radius
:
[
150
,
180
],
radius
:
[
150
,
180
],
// height: '96%',
// height: '96%',
left
:
'center'
,
left
:
'center'
,
top
:
24
,
top
:
60
,
width
:
'98%'
,
width
:
'98%'
,
height
:
'90%'
,
itemStyle
:
{
itemStyle
:
{
borderColor
:
'#fff'
,
borderColor
:
'#fff'
,
borderWidth
:
1
borderWidth
:
1
...
...
src/views/dataLibrary/index.vue
浏览文件 @
0204674d
...
@@ -134,16 +134,15 @@ const siderList = ref([
...
@@ -134,16 +134,15 @@ const siderList = ref([
active
:
false
active
:
false
},
},
{
{
name
:
"
实体清单事件
"
,
name
:
"
商业管制清单
"
,
path
:
"/dataLibrary/data
EntityListEven
t"
,
path
:
"/dataLibrary/data
CommerceControlLis
t"
,
active
:
false
active
:
false
},
},
{
{
name
:
"
商业管制清单
"
,
name
:
"
实体清单事件
"
,
path
:
"/dataLibrary/data
CommerceControlLis
t"
,
path
:
"/dataLibrary/data
EntityListEven
t"
,
active
:
false
active
:
false
},
},
{
{
name
:
"商业管制清单事件"
,
name
:
"商业管制清单事件"
,
path
:
"/dataLibrary/dataCommerceControlListEvent"
,
path
:
"/dataLibrary/dataCommerceControlListEvent"
,
...
@@ -257,6 +256,10 @@ const siderList = ref([
...
@@ -257,6 +256,10 @@ const siderList = ref([
]);
]);
const
handleSiderItem
=
item
=>
{
const
handleSiderItem
=
item
=>
{
if
(
item
.
name
===
'风险信号'
||
item
.
name
===
'市场准入限制'
)
{
ElMessage
.
warning
(
'当前模块开发中,敬请期待!'
)
return
}
siderList
.
value
.
forEach
(
val
=>
{
siderList
.
value
.
forEach
(
val
=>
{
val
.
active
=
false
;
val
.
active
=
false
;
val
.
isExpanded
=
false
;
val
.
isExpanded
=
false
;
...
@@ -282,6 +285,10 @@ const handleSiderItem = item => {
...
@@ -282,6 +285,10 @@ const handleSiderItem = item => {
};
};
const
handleSiderSecondItem
=
item
=>
{
const
handleSiderSecondItem
=
item
=>
{
if
(
item
.
name
===
'州法案'
||
item
.
name
===
'研究型大学'
||
item
.
name
===
'重点实验室'
)
{
ElMessage
.
warning
(
'当前模块开发中,敬请期待!'
)
return
}
siderList
.
value
.
forEach
(
item
=>
{
siderList
.
value
.
forEach
(
item
=>
{
if
(
item
.
children
.
length
)
{
if
(
item
.
children
.
length
)
{
item
.
children
.
forEach
(
val
=>
{
item
.
children
.
forEach
(
val
=>
{
...
@@ -437,17 +444,16 @@ onMounted(() => {
...
@@ -437,17 +444,16 @@ onMounted(() => {
siderList
.
value
[
3
].
isExpanded
=
true
;
siderList
.
value
[
3
].
isExpanded
=
true
;
siderList
.
value
[
3
].
children
[
0
].
active
=
true
;
siderList
.
value
[
3
].
children
[
0
].
active
=
true
;
break
;
break
;
case
"/dataLibrary/data
EntityListEven
t"
:
case
"/dataLibrary/data
CommerceControlLis
t"
:
siderList
.
value
[
3
].
active
=
true
;
siderList
.
value
[
3
].
active
=
true
;
siderList
.
value
[
3
].
isExpanded
=
true
;
siderList
.
value
[
3
].
isExpanded
=
true
;
siderList
.
value
[
3
].
children
[
1
].
active
=
true
;
siderList
.
value
[
3
].
children
[
1
].
active
=
true
;
break
;
break
;
case
"/dataLibrary/data
CommerceControlLis
t"
:
case
"/dataLibrary/data
EntityListEven
t"
:
siderList
.
value
[
3
].
active
=
true
;
siderList
.
value
[
3
].
active
=
true
;
siderList
.
value
[
3
].
isExpanded
=
true
;
siderList
.
value
[
3
].
isExpanded
=
true
;
siderList
.
value
[
3
].
children
[
2
].
active
=
true
;
siderList
.
value
[
3
].
children
[
2
].
active
=
true
;
break
;
break
;
case
"/dataLibrary/dataCommerceControlListEvent"
:
case
"/dataLibrary/dataCommerceControlListEvent"
:
siderList
.
value
[
3
].
active
=
true
;
siderList
.
value
[
3
].
active
=
true
;
siderList
.
value
[
3
].
isExpanded
=
true
;
siderList
.
value
[
3
].
isExpanded
=
true
;
...
@@ -559,6 +565,7 @@ onBeforeUnmount(() => {
...
@@ -559,6 +565,7 @@ onBeforeUnmount(() => {
height
:
100%
;
height
:
100%
;
}
}
}
}
.title
{
.title
{
color
:
var
(
--
color-primary-100
);
color
:
var
(
--
color-primary-100
);
}
}
...
@@ -737,6 +744,7 @@ onBeforeUnmount(() => {
...
@@ -737,6 +744,7 @@ onBeforeUnmount(() => {
.tab-item-active
{
.tab-item-active
{
border-bottom
:
2px
solid
var
(
--
color-primary-100
)
!
important
;
border-bottom
:
2px
solid
var
(
--
color-primary-100
)
!
important
;
background
:
var
(
--
color-primary-2
);
}
}
}
}
...
...
src/views/dataLibrary/news/index.vue
浏览文件 @
0204674d
...
@@ -105,7 +105,7 @@
...
@@ -105,7 +105,7 @@
<
el
-
table
ref
=
"tableRef"
:
data
=
"tableData"
row
-
key
=
"id"
@
selection
-
change
=
"handleSelectionChange"
<
el
-
table
ref
=
"tableRef"
:
data
=
"tableData"
row
-
key
=
"id"
@
selection
-
change
=
"handleSelectionChange"
@
select
=
"handleSelect"
@
select
-
all
=
"handleSelectAll"
style
=
"width: 100%"
:
row
-
style
=
"{ height: '52px'
}
"
>
@
select
=
"handleSelect"
@
select
-
all
=
"handleSelectAll"
style
=
"width: 100%"
:
row
-
style
=
"{ height: '52px'
}
"
>
<
el
-
table
-
column
type
=
"selection"
width
=
"40"
/>
<
el
-
table
-
column
type
=
"selection"
width
=
"40"
/>
<
el
-
table
-
column
label
=
"新闻标题"
width
=
"
60
0"
>
<
el
-
table
-
column
label
=
"新闻标题"
width
=
"
42
0"
>
<
template
#
default
=
"scope"
>
<
template
#
default
=
"scope"
>
<
span
class
=
"title-item text-compact-bold"
@
click
=
"handleClickToDetail(scope.row)"
>
{{
<
span
class
=
"title-item text-compact-bold"
@
click
=
"handleClickToDetail(scope.row)"
>
{{
scope
.
row
.
originalTitle
scope
.
row
.
originalTitle
...
...
src/views/decree/institution/index.vue
浏览文件 @
0204674d
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
<div
class=
"en-title"
>
{{
institutionInfo
.
enName
}}
</div>
<div
class=
"en-title"
>
{{
institutionInfo
.
enName
}}
</div>
<div
class=
"desc"
>
{{
institutionInfo
.
desc
}}
</div>
<div
class=
"desc"
>
{{
institutionInfo
.
desc
}}
</div>
<div
class=
"tag-box"
>
<div
class=
"tag-box"
>
<div
class=
"tag"
v-for=
"(tag, index) in
institutionInfo.t
agList"
:key=
"index"
>
<div
class=
"tag"
v-for=
"(tag, index) in
showT
agList"
:key=
"index"
>
{{
tag
}}
{{
tag
}}
</div>
</div>
</div>
</div>
...
@@ -22,13 +22,8 @@
...
@@ -22,13 +22,8 @@
</div>
-->
</div>
-->
</div>
</div>
<div
class=
"tab-box"
>
<div
class=
"tab-box"
>
<div
<div
class=
"tab"
@
click=
"handleClickTab(item)"
:class=
"
{ tabActive: activeTabName == item.name }"
class=
"tab"
v-for="(item, index) in tabList" :key="index">
@
click=
"handleClickTab(item)"
:class=
"
{ tabActive: activeTabName == item.name }"
v-for="(item, index) in tabList"
:key="index"
>
{{
item
.
name
}}
{{
item
.
name
}}
</div>
</div>
</div>
</div>
...
@@ -61,6 +56,14 @@ const institutionInfo = ref({
...
@@ -61,6 +56,14 @@ const institutionInfo = ref({
logo
:
""
logo
:
""
});
});
const
showTagList
=
computed
(()
=>
{
if
(
institutionInfo
.
value
.
tagList
.
length
>
10
)
{
return
institutionInfo
.
value
.
tagList
.
slice
(
0
,
10
)
}
else
{
return
institutionInfo
.
value
.
tagList
}
})
const
handleGetInfo
=
async
()
=>
{
const
handleGetInfo
=
async
()
=>
{
const
params
=
{
const
params
=
{
id
:
route
.
query
.
id
id
:
route
.
query
.
id
...
@@ -75,7 +78,7 @@ const handleGetInfo = async () => {
...
@@ -75,7 +78,7 @@ const handleGetInfo = async () => {
institutionInfo
.
value
.
desc
=
res
.
data
.
orgIntroduction
;
institutionInfo
.
value
.
desc
=
res
.
data
.
orgIntroduction
;
institutionInfo
.
value
.
name
=
res
.
data
.
orgName
;
institutionInfo
.
value
.
name
=
res
.
data
.
orgName
;
}
}
}
catch
(
error
)
{}
}
catch
(
error
)
{
}
};
};
handleGetInfo
();
handleGetInfo
();
...
@@ -95,7 +98,7 @@ const tabList = ref([
...
@@ -95,7 +98,7 @@ const tabList = ref([
]);
]);
const
handleClickTab
=
val
=>
{
const
handleClickTab
=
val
=>
{
if
(
val
.
name
===
'深度挖掘'
||
val
.
name
===
'对华制裁'
)
{
if
(
val
.
name
===
'深度挖掘'
||
val
.
name
===
'对华制裁'
)
{
ElMessage
.
warning
(
'当前功能开发中,敬请期待!'
)
ElMessage
.
warning
(
'当前功能开发中,敬请期待!'
)
return
return
}
}
...
@@ -125,6 +128,7 @@ onUnmounted(() => {
...
@@ -125,6 +128,7 @@ onUnmounted(() => {
background-repeat
:
no-repeat
;
background-repeat
:
no-repeat
;
background-size
:
100%
100%
;
background-size
:
100%
100%
;
padding-top
:
16px
;
padding-top
:
16px
;
.header
{
.header
{
width
:
1600px
;
width
:
1600px
;
height
:
200px
;
height
:
200px
;
...
@@ -136,20 +140,23 @@ onUnmounted(() => {
...
@@ -136,20 +140,23 @@ onUnmounted(() => {
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
display
:
flex
;
display
:
flex
;
position
:
relative
;
position
:
relative
;
.header-left
{
.header-left
{
width
:
160px
;
width
:
160px
;
height
:
160px
;
height
:
160px
;
margin
:
20px
;
margin
:
20px
;
img
{
img
{
width
:
100%
;
width
:
100%
;
height
:
100%
;
height
:
100%
;
}
}
}
}
.header-right
{
.header-right
{
margin-left
:
24px
;
margin-left
:
24px
;
width
:
1350px
;
width
:
1350px
;
overflow
:
hidden
;
overflow
:
hidden
;
overflow-y
:
auto
;
.title
{
.title
{
margin-top
:
26px
;
margin-top
:
26px
;
height
:
42px
;
height
:
42px
;
...
@@ -164,6 +171,7 @@ onUnmounted(() => {
...
@@ -164,6 +171,7 @@ onUnmounted(() => {
text-overflow
:
ellipsis
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
white-space
:
nowrap
;
}
}
.en-title
{
.en-title
{
margin-top
:
8px
;
margin-top
:
8px
;
height
:
24px
;
height
:
24px
;
...
@@ -178,7 +186,9 @@ onUnmounted(() => {
...
@@ -178,7 +186,9 @@ onUnmounted(() => {
text-overflow
:
ellipsis
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
white-space
:
nowrap
;
}
}
.desc
{
.desc
{
height
:
48px
;
margin-top
:
6px
;
margin-top
:
6px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-family
:
Microsoft
YaHei
;
...
@@ -187,11 +197,25 @@ onUnmounted(() => {
...
@@ -187,11 +197,25 @@ onUnmounted(() => {
line-height
:
24px
;
line-height
:
24px
;
letter-spacing
:
0px
;
letter-spacing
:
0px
;
text-align
:
justify
;
text-align
:
justify
;
overflow
:
hidden
;
display
:
-
webkit-box
;
/* 3. 限制显示的行数(修改数字即可改变行数) */
-webkit-line-clamp
:
2
;
/* 4. 设置文字垂直排列方向 */
-webkit-box-orient
:
vertical
;
/* 5. 隐藏超出部分 */
overflow
:
hidden
;
/* 6. 显示省略号 */
text-overflow
:
ellipsis
;
/* 可选:修复文字间距/换行问题 */
word-break
:
break-all
;
}
}
.tag-box
{
.tag-box
{
margin-top
:
14px
;
margin-top
:
14px
;
display
:
flex
;
display
:
flex
;
gap
:
8px
;
gap
:
8px
;
.tag
{
.tag
{
height
:
24px
;
height
:
24px
;
padding
:
0px
8px
;
padding
:
0px
8px
;
...
@@ -206,6 +230,7 @@ onUnmounted(() => {
...
@@ -206,6 +230,7 @@ onUnmounted(() => {
}
}
}
}
}
}
.header-btn
{
.header-btn
{
position
:
absolute
;
position
:
absolute
;
top
:
26px
;
top
:
26px
;
...
@@ -219,14 +244,17 @@ onUnmounted(() => {
...
@@ -219,14 +244,17 @@ onUnmounted(() => {
justify-content
:
center
;
justify-content
:
center
;
align-items
:
center
;
align-items
:
center
;
cursor
:
pointer
;
cursor
:
pointer
;
.icon
{
.icon
{
width
:
16px
;
width
:
16px
;
height
:
16px
;
height
:
16px
;
img
{
img
{
width
:
100%
;
width
:
100%
;
height
:
100%
;
height
:
100%
;
}
}
}
}
.text
{
.text
{
height
:
22px
;
height
:
22px
;
color
:
rgba
(
255
,
255
,
255
,
1
);
color
:
rgba
(
255
,
255
,
255
,
1
);
...
@@ -237,6 +265,7 @@ onUnmounted(() => {
...
@@ -237,6 +265,7 @@ onUnmounted(() => {
}
}
}
}
}
}
.tab-box
{
.tab-box
{
width
:
1600px
;
width
:
1600px
;
height
:
64px
;
height
:
64px
;
...
@@ -249,6 +278,7 @@ onUnmounted(() => {
...
@@ -249,6 +278,7 @@ onUnmounted(() => {
display
:
flex
;
display
:
flex
;
justify-content
:
space-between
;
justify-content
:
space-between
;
align-items
:
center
;
align-items
:
center
;
.tab
{
.tab
{
width
:
526px
;
width
:
526px
;
height
:
54px
;
height
:
54px
;
...
@@ -263,10 +293,12 @@ onUnmounted(() => {
...
@@ -263,10 +293,12 @@ onUnmounted(() => {
font-weight
:
400
;
font-weight
:
400
;
letter-spacing
:
0px
;
letter-spacing
:
0px
;
cursor
:
pointer
;
cursor
:
pointer
;
&
:hover
{
&
:hover
{
background
:
rgba
(
231
,
243
,
255
,
1
);
background
:
rgba
(
231
,
243
,
255
,
1
);
}
}
}
}
.tabActive
{
.tabActive
{
border
:
2px
solid
rgba
(
174
,
214
,
255
,
1
);
border
:
2px
solid
rgba
(
174
,
214
,
255
,
1
);
background
:
rgba
(
231
,
243
,
255
,
1
);
background
:
rgba
(
231
,
243
,
255
,
1
);
...
@@ -275,6 +307,7 @@ onUnmounted(() => {
...
@@ -275,6 +307,7 @@ onUnmounted(() => {
font-weight
:
700
;
font-weight
:
700
;
}
}
}
}
.main
{
.main
{
height
:
800px
;
height
:
800px
;
width
:
1600px
;
width
:
1600px
;
...
...
src/views/exportControl/index.vue
浏览文件 @
0204674d
...
@@ -50,7 +50,7 @@
...
@@ -50,7 +50,7 @@
<el-carousel
<el-carousel
ref=
"carouselRef"
ref=
"carouselRef"
height=
"370px"
height=
"370px"
:autoplay=
"
tru
e"
:autoplay=
"
fals
e"
:interval=
"3000"
:interval=
"3000"
arrow=
"never"
arrow=
"never"
indicator-position=
"none"
indicator-position=
"none"
...
@@ -59,9 +59,7 @@
...
@@ -59,9 +59,7 @@
<el-carousel-item
v-for=
"(item, index) in entitiesDataInfoList"
:key=
"item.id + index"
>
<el-carousel-item
v-for=
"(item, index) in entitiesDataInfoList"
:key=
"item.id + index"
>
<div>
<div>
<div
class=
"box1-top"
>
<div
class=
"box1-top"
>
<div
class=
"box1-top-title"
>
<div
class=
"box1-top-title"
>
{{
item
.
postDate
}}
——
{{
item
.
name
}}
</div>
{{
item
.
postDate
}}
——BIS《实体清单增列与修订条目》
</div>
<div
class=
"box1-top-content"
>
<div
class=
"box1-top-content"
>
<div
class=
"box1-top-content-item"
>
<div
class=
"box1-top-content-item"
>
<span
class=
"box1-top-content-item-title"
>
· 发布机构:
</span>
<span
class=
"box1-top-content-item-title"
>
· 发布机构:
</span>
...
@@ -73,13 +71,7 @@
...
@@ -73,13 +71,7 @@
</div>
</div>
<div
class=
"box1-top-content-item"
>
<div
class=
"box1-top-content-item"
>
<span
class=
"box1-top-content-item-title"
>
· 涉及领域:
</span>
<span
class=
"box1-top-content-item-title"
>
· 涉及领域:
</span>
<!--
<div
class=
"box1-top-content-item-tags"
v-for=
"(domainItem, index) in item.domains"
:key=
"index"
>
<el-tag
:type=
"getTagType(domainItem)"
>
{{
domainItem
}}
</el-tag>
</div>
-->
<AreaTag
<AreaTag
v-for=
"(domainItem, index) in item.domains"
v-for=
"(domainItem, index) in item.domains"
:key=
"index"
:key=
"index"
...
@@ -146,7 +138,7 @@
...
@@ -146,7 +138,7 @@
}}
</span>
}}
</span>
</div>
</div>
<div
class=
"box1-absolute-num"
>
<div
class=
"box1-absolute-num"
>
{{
item
.
cnEntityCount
}}{{
item
.
sanTypeId
==
allSanTypeIds
[
0
]
?
"家"
:
"
类
"
}}
{{
item
.
cnEntityCount
}}{{
item
.
sanTypeId
==
allSanTypeIds
[
0
]
?
"家"
:
"
项
"
}}
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -1961,11 +1953,12 @@ const handleMediaClick = item => {
...
@@ -1961,11 +1953,12 @@ const handleMediaClick = item => {
flex-direction
:
column
;
flex-direction
:
column
;
gap
:
20px
;
gap
:
20px
;
position
:
relative
;
position
:
relative
;
width
:
1036px
;
.box1-left-arrow
{
.box1-left-arrow
{
position
:
absolute
;
position
:
absolute
;
z-index
:
9999
;
z-index
:
9999
;
left
:
-2
0
px
;
left
:
-2
4
px
;
top
:
135px
;
top
:
135px
;
width
:
24px
!
important
;
width
:
24px
!
important
;
height
:
48px
;
height
:
48px
;
...
@@ -1989,7 +1982,7 @@ const handleMediaClick = item => {
...
@@ -1989,7 +1982,7 @@ const handleMediaClick = item => {
.box1-right-arrow
{
.box1-right-arrow
{
position
:
absolute
;
position
:
absolute
;
z-index
:
9999
;
z-index
:
9999
;
right
:
-2
0px
;
right
:
0px
;
top
:
135px
;
top
:
135px
;
width
:
24px
;
width
:
24px
;
height
:
48px
;
height
:
48px
;
...
@@ -2053,6 +2046,10 @@ const handleMediaClick = item => {
...
@@ -2053,6 +2046,10 @@ const handleMediaClick = item => {
color
:
$base-color
;
color
:
$base-color
;
margin-top
:
10px
;
margin-top
:
10px
;
margin-bottom
:
15px
;
margin-bottom
:
15px
;
max-width
:
80%
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
&
-content
{
&
-content
{
...
@@ -2079,7 +2076,7 @@ const handleMediaClick = item => {
...
@@ -2079,7 +2076,7 @@ const handleMediaClick = item => {
height
:
172px
;
height
:
172px
;
padding-top
:
16px
;
padding-top
:
16px
;
box-sizing
:
border-box
;
box-sizing
:
border-box
;
padding-right
:
24px
;
&
-title
{
&
-title
{
font-size
:
16px
;
font-size
:
16px
;
font-weight
:
700
;
font-weight
:
700
;
...
...
src/views/finance/index.vue
浏览文件 @
0204674d
...
@@ -60,9 +60,10 @@
...
@@ -60,9 +60,10 @@
<div>
<div>
<div
class=
"box1-top"
>
<div
class=
"box1-top"
>
<div
class=
"box1-top-title"
>
<div
class=
"box1-top-title"
>
{{
item
.
postDate
}}
——
{{
<!--
{{
item
.
postDate
}}
——
{{
item
.
sanTypeId
==
allSanTypeIds
[
0
]
?
"OFAC"
:
"DoD"
item
.
sanTypeId
==
allSanTypeIds
[
0
]
?
"OFAC"
:
"DoD"
}}
《实体清单增列与修订条目》
}}
《实体清单增列与修订条目》 -->
{{
item
.
postDate
}}
——
{{
item
.
name
}}
</div>
</div>
<div
class=
"box1-top-content"
>
<div
class=
"box1-top-content"
>
<div
class=
"box1-top-content-item"
>
<div
class=
"box1-top-content-item"
>
...
@@ -1073,7 +1074,7 @@ const handleToEntityList = item => {
...
@@ -1073,7 +1074,7 @@ const handleToEntityList = item => {
console
.
log
(
"这是什么数据1 =>"
,
item
);
console
.
log
(
"这是什么数据1 =>"
,
item
);
let
id
=
item
?.
id
;
let
id
=
item
?.
id
;
let
sanTypeId
=
item
?.
sanTypeId
||
1
;
let
sanTypeId
=
item
?.
sanTypeId
||
1
;
let
date
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
].
postDate
let
date
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
].
postDate
;
if
(
!
id
)
{
if
(
!
id
)
{
const
currentItem
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
];
const
currentItem
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
];
id
=
currentItem
?.
id
;
id
=
currentItem
?.
id
;
...
@@ -1826,14 +1827,20 @@ const handleToDataLibrary = item => {
...
@@ -1826,14 +1827,20 @@ const handleToDataLibrary = item => {
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
console
.
log
(
"finance 页面 mounted"
);
console
.
log
(
"finance 页面 mounted"
);
try
{
try
{
// 获取趋势图数据
fetchTrendData
();
fetchRiskSignals
(
"0109"
);
// 获取社交媒体信息
fetchSocialMediaInfo
();
// 获取新闻资讯
fetchNewsInfo
();
const
[
dataCount
,
entitiesDataInfo
,
industryCountByYear
,
cclList
]
=
await
Promise
.
all
([
const
[
dataCount
,
entitiesDataInfo
,
industryCountByYear
,
cclList
]
=
await
Promise
.
all
([
getDataCount
(),
getDataCount
(),
getLatestEntityListInfo
(),
getLatestEntityListInfo
(),
getReleaseCount
(
2
)
getReleaseCount
(
2
)
// getReleaseCount(3)
// getReleaseCount(3)
]);
]);
// 交换第二个和第三个元素
// [dataCount[1], dataCount[2]] = [dataCount[2], dataCount[1]];
console
.
log
(
"dataCount"
,
dataCount
);
console
.
log
(
"dataCount"
,
dataCount
);
infoList
.
value
=
dataCount
.
slice
(
0
,
2
).
map
((
item
,
idx
)
=>
{
infoList
.
value
=
dataCount
.
slice
(
0
,
2
).
map
((
item
,
idx
)
=>
{
return
{
return
{
...
@@ -1874,6 +1881,11 @@ onMounted(async () => {
...
@@ -1874,6 +1881,11 @@ onMounted(async () => {
tags
:
item
.
domain
tags
:
item
.
domain
};
};
});
});
await
fetchSanctionProcess
(
sanctionPage
.
value
,
10
);
// 获取雷达图数据
await
fetchRadarData
(
domainChecked
.
value
);
// 获取出口管制制裁措施
await
fetchSanctionList
();
entityListReleaseFreqChart
.
interpret
({
entityListReleaseFreqChart
.
interpret
({
type
:
"柱状图"
,
type
:
"柱状图"
,
name
:
"美国商务部发布实体清单的频次"
,
name
:
"美国商务部发布实体清单的频次"
,
...
@@ -1892,21 +1904,6 @@ onMounted(async () => {
...
@@ -1892,21 +1904,6 @@ onMounted(async () => {
name
:
"美国商务部发布商业管制清单的频次"
,
name
:
"美国商务部发布商业管制清单的频次"
,
data
:
commerceControlListReleaseFreq
.
value
data
:
commerceControlListReleaseFreq
.
value
});
});
// 获取趋势图数据
fetchTrendData
();
fetchRiskSignals
(
"0109"
);
// 获取社交媒体信息
fetchSocialMediaInfo
();
// 获取新闻资讯
fetchNewsInfo
();
// fetchEntitiesList(currentPage.value, pageSize.value);
await
fetchSanctionProcess
(
sanctionPage
.
value
,
10
);
// 获取雷达图数据
await
fetchRadarData
(
domainChecked
.
value
);
// 获取出口管制制裁措施
await
fetchSanctionList
();
}
catch
(
err
)
{
}
catch
(
err
)
{
console
.
log
(
"此处报错?"
);
console
.
log
(
"此处报错?"
);
console
.
log
(
err
);
console
.
log
(
err
);
...
@@ -1957,11 +1954,12 @@ const handleMediaClick = item => {
...
@@ -1957,11 +1954,12 @@ const handleMediaClick = item => {
flex-direction
:
column
;
flex-direction
:
column
;
gap
:
20px
;
gap
:
20px
;
position
:
relative
;
position
:
relative
;
width
:
1036px
;
.box1-left-arrow
{
.box1-left-arrow
{
position
:
absolute
;
position
:
absolute
;
z-index
:
9999
;
z-index
:
9999
;
left
:
-2
0
px
;
left
:
-2
4
px
;
top
:
135px
;
top
:
135px
;
width
:
24px
!
important
;
width
:
24px
!
important
;
height
:
48px
;
height
:
48px
;
...
@@ -1985,7 +1983,7 @@ const handleMediaClick = item => {
...
@@ -1985,7 +1983,7 @@ const handleMediaClick = item => {
.box1-right-arrow
{
.box1-right-arrow
{
position
:
absolute
;
position
:
absolute
;
z-index
:
9999
;
z-index
:
9999
;
right
:
-2
0px
;
right
:
0px
;
top
:
135px
;
top
:
135px
;
width
:
24px
;
width
:
24px
;
height
:
48px
;
height
:
48px
;
...
@@ -2050,6 +2048,10 @@ const handleMediaClick = item => {
...
@@ -2050,6 +2048,10 @@ const handleMediaClick = item => {
color
:
$base-color
;
color
:
$base-color
;
margin-top
:
10px
;
margin-top
:
10px
;
margin-bottom
:
15px
;
margin-bottom
:
15px
;
max-width
:
80%
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
&
-content
{
&
-content
{
...
...
src/views/finance/utils/common-back.js
0 → 100644
浏览文件 @
0204674d
import
{
ref
}
from
"vue"
;
export
const
useChartInterpretation
=
()
=>
{
const
loading
=
ref
(
false
);
const
interpretation
=
ref
(
""
);
const
error
=
ref
(
null
);
const
interpret
=
async
text
=>
{
loading
.
value
=
true
;
error
.
value
=
null
;
interpretation
.
value
=
""
;
try
{
const
response
=
await
fetch
(
"/aiAnalysis/chart_interpretation"
,
{
method
:
"POST"
,
headers
:
{
"X-API-Key"
:
"aircasKEY19491001"
,
"Content-Type"
:
"application/json"
},
body
:
JSON
.
stringify
({
text
})
});
if
(
!
response
.
ok
)
{
throw
new
Error
(
`HTTP error! status:
${
response
.
status
}
`
);
}
const
reader
=
response
.
body
.
getReader
();
const
decoder
=
new
TextDecoder
();
let
buffer
=
""
;
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
])
{
interpretation
.
value
=
textMatch
[
1
];
}
}
}
}
}
catch
(
err
)
{
error
.
value
=
err
.
message
||
"AI 解读失败"
;
console
.
error
(
"AI Chart Interpretation Error:"
,
err
);
}
finally
{
loading
.
value
=
false
;
}
};
return
{
loading
,
interpretation
,
error
,
interpret
};
};
src/views/finance/utils/common.js
浏览文件 @
0204674d
// src/views/finance/utils/common.js
import
{
ref
}
from
"vue"
;
import
{
ref
}
from
"vue"
;
// 【新增】引入获取全局 Signal 的方法
import
{
getAbortSignal
}
from
"@/api/finance/service.js"
;
export
const
useChartInterpretation
=
()
=>
{
export
const
useChartInterpretation
=
()
=>
{
const
loading
=
ref
(
false
);
const
loading
=
ref
(
false
);
...
@@ -10,14 +14,20 @@ export const useChartInterpretation = () => {
...
@@ -10,14 +14,20 @@ export const useChartInterpretation = () => {
error
.
value
=
null
;
error
.
value
=
null
;
interpretation
.
value
=
""
;
interpretation
.
value
=
""
;
// 【新增】在请求发起前获取当前的 Signal
// 注意:必须在每次调用 interpret 时重新获取,以确保拿到最新的 controller 的 signal
const
signal
=
getAbortSignal
();
try
{
try
{
// 【修改】在 fetch 中传入 signal
const
response
=
await
fetch
(
"/aiAnalysis/chart_interpretation"
,
{
const
response
=
await
fetch
(
"/aiAnalysis/chart_interpretation"
,
{
method
:
"POST"
,
method
:
"POST"
,
headers
:
{
headers
:
{
"X-API-Key"
:
"aircasKEY19491001"
,
"X-API-Key"
:
"aircasKEY19491001"
,
"Content-Type"
:
"application/json"
"Content-Type"
:
"application/json"
},
},
body
:
JSON
.
stringify
({
text
})
body
:
JSON
.
stringify
({
text
}),
signal
:
signal
// 【关键】绑定取消信号
});
});
if
(
!
response
.
ok
)
{
if
(
!
response
.
ok
)
{
...
@@ -29,6 +39,7 @@ export const useChartInterpretation = () => {
...
@@ -29,6 +39,7 @@ export const useChartInterpretation = () => {
let
buffer
=
""
;
let
buffer
=
""
;
while
(
true
)
{
while
(
true
)
{
// reader.read() 会在 signal abort 时抛出 AbortError
const
{
done
,
value
}
=
await
reader
.
read
();
const
{
done
,
value
}
=
await
reader
.
read
();
if
(
done
)
break
;
if
(
done
)
break
;
...
@@ -39,18 +50,43 @@ export const useChartInterpretation = () => {
...
@@ -39,18 +50,43 @@ export const useChartInterpretation = () => {
for
(
const
line
of
lines
)
{
for
(
const
line
of
lines
)
{
if
(
line
.
startsWith
(
"data: "
))
{
if
(
line
.
startsWith
(
"data: "
))
{
const
content
=
line
.
substring
(
6
);
const
content
=
line
.
substring
(
6
);
const
textMatch
=
content
.
match
(
/"解读":
\s
*"
([^
"
]
*
)
"/
);
// 尝试解析 JSON
if
(
textMatch
&&
textMatch
[
1
])
{
try
{
interpretation
.
value
=
textMatch
[
1
];
const
jsonMatch
=
content
.
match
(
/
\{
.*
\}
/
);
}
if
(
jsonMatch
)
{
const
parsed
=
JSON
.
parse
(
jsonMatch
[
0
]);
if
(
parsed
[
"解读"
])
{
interpretation
.
value
=
parsed
[
"解读"
];
}
}
else
{
// 兼容旧的正则匹配
const
textMatch
=
content
.
match
(
/"解读":
\s
*"
([^
"
]
*
)
"/
);
if
(
textMatch
&&
textMatch
[
1
])
{
interpretation
.
value
=
textMatch
[
1
];
}
}
}
catch
(
e
)
{
// 忽略解析错误
}
}
}
}
}
}
}
}
catch
(
err
)
{
}
catch
(
err
)
{
// 【关键】判断是否是因路由切换导致的取消
if
(
err
.
name
===
'AbortError'
)
{
console
.
log
(
'AI 解读请求已取消'
);
loading
.
value
=
false
;
// 关闭 loading
return
;
// 直接返回,不设置 error,不弹窗
}
error
.
value
=
err
.
message
||
"AI 解读失败"
;
error
.
value
=
err
.
message
||
"AI 解读失败"
;
console
.
error
(
"AI Chart Interpretation Error:"
,
err
);
console
.
error
(
"AI Chart Interpretation Error:"
,
err
);
}
finally
{
}
finally
{
loading
.
value
=
false
;
// 只有在非 AbortError 的情况下,才由 finally 统一关闭 loading
// 如果上面 catch 中已经 return 了,这里不会执行
if
(
err
?.
name
!==
'AbortError'
)
{
loading
.
value
=
false
;
}
}
}
};
};
...
@@ -60,4 +96,4 @@ export const useChartInterpretation = () => {
...
@@ -60,4 +96,4 @@ export const useChartInterpretation = () => {
error
,
error
,
interpret
interpret
};
};
};
};
\ No newline at end of file
src/views/marketAccessRestrictions/marketAccessHome/index.vue
浏览文件 @
0204674d
...
@@ -2029,6 +2029,7 @@ onMounted(async () => {
...
@@ -2029,6 +2029,7 @@ onMounted(async () => {
font
-
family
:
Source
Han
Sans
CN
;
font
-
family
:
Source
Han
Sans
CN
;
font
-
size
:
16
px
;
font
-
size
:
16
px
;
color
:
var
(
--
text
-
primary
-
65
-
color
);
color
:
var
(
--
text
-
primary
-
65
-
color
);
font
-
weight
:
400
;
}
}
}
}
}
}
...
...
src/views/newsBrief/ModeuleNews.vue
浏览文件 @
0204674d
<
template
>
<
template
>
<el-space
direction=
"vertical"
class=
"full-width news-image-background"
>
<el-space
direction=
"vertical"
class=
"full-width news-image-background"
>
<el-button
class=
"float-btn"
@
click=
"gotoNewsBrief(false)"
><el-icon>
<el-button
class=
"float-btn"
@
click=
"gotoNewsBrief(false)"
<back
/>
><el-icon>
</el-icon>
返回
</el-button>
<Back
/>
<el-space
style=
"width: 993px;"
direction=
"vertical"
alignment=
"flex-start"
>
</el-icon>
<div
id=
"ref-news-list"
style=
"margin-top: 50px; margin-bottom: 24px; margin-left: 24px;"
>
返回
</el-button
<common-text
class=
"text-title-0-show"
color=
"var(--text-primary-90-color)"
>
{{
>
moduleName
<el-space
style=
"width: 993px"
direction=
"vertical"
alignment=
"flex-start"
>
}}
</common-text>
<div
id=
"ref-news-list"
style=
"margin-top: 50px; margin-bottom: 24px; margin-left: 24px"
>
<common-text
class=
"text-regular"
<common-text
class=
"text-title-0-show"
color=
"var(--text-primary-90-color)"
>
{{
moduleName
}}
</common-text>
color=
"var(--text-primary-65-color)"
>
基于情报价值评估预测算法,掌握全球重要潜在动向
</common-text>
<common-text
class=
"text-regular"
color=
"var(--text-primary-65-color)"
</div>
>
基于情报价值评估预测算法,掌握全球重要潜在动向
</common-text
<el-space
direction=
"vertical"
fill
alignment=
"flex-start"
class=
"background-as-card common-padding"
>
>
<el-radio-group
v-model=
"currentAreaId"
class=
"radio-group-as-gap-btn"
>
</div>
<el-space
direction=
"horizontal"
wrap
alignment=
"center"
>
<el-space
direction=
"vertical"
fill
alignment=
"flex-start"
class=
"background-as-card common-padding"
>
<el-radio-button
:label=
"''"
@
click=
"changeArea('')"
>
全部
</el-radio-button>
<el-radio-group
v-model=
"currentAreaId"
class=
"radio-group-as-gap-btn"
>
<el-radio-button
v-for=
"(t, i) in AreaList"
:key=
"i"
:label=
"t.id"
@
click=
"changeArea(t.id)"
>
{{
<el-space
direction=
"horizontal"
wrap
alignment=
"center"
>
t
.
name
}}
<el-radio-button
:label=
"''"
@
click=
"changeArea('')"
>
全部
</el-radio-button>
</el-radio-button>
<el-radio-button
v-for=
"(t, i) in AreaList"
:key=
"i"
:label=
"t.id"
@
click=
"changeArea(t.id)"
</el-space>
>
{{
t
.
name
}}
</el-radio-group>
</el-radio-button>
<el-divider
style=
"margin: 10px 0px;"
></el-divider>
</el-space>
<div
v-if=
"NewsData?.content?.length > 0"
>
</el-radio-group>
<news-list
:news=
"NewsData.content"
/>
<el-divider
style=
"margin: 10px 0px"
></el-divider>
</div>
<div
v-if=
"NewsData?.content?.length > 0"
>
<el-empty
v-else
></el-empty>
<news-list
:news=
"NewsData.content"
/>
<el-pagination
background
layout=
"total, ->, prev, pager, next"
:current-page=
"modulePage"
</div>
:total=
"NewsData?.totalElements ?? 0"
v-on:current-change=
"onCurrentChange"
/>
<el-empty
v-else
></el-empty>
</el-space>
<el-pagination
</el-space>
background
</el-space>
layout=
"total, ->, prev, pager, next"
:current-page=
"modulePage"
:total=
"NewsData?.totalElements ?? 0"
v-on:current-change=
"onCurrentChange"
/>
</el-space>
</el-space>
</el-space>
</
template
>
</
template
>
<
script
setup
>
<
script
setup
>
import
{
ref
,
onMounted
}
from
"vue"
;
import
{
ref
,
onMounted
}
from
"vue"
;
import
{
useRoute
}
from
'vue-router'
;
import
{
useRoute
}
from
"vue-router"
;
import
'@/styles/container.scss'
;
import
"@/styles/container.scss"
;
import
'@/styles/radio.scss'
;
import
"@/styles/radio.scss"
;
import
NewsList
from
"./NewsList.vue"
;
import
NewsList
from
"./NewsList.vue"
;
import
{
getAreaList
,
getHotNewsByArea
}
from
"@/api/news/newsBrief"
;
import
{
getAreaList
,
getHotNewsByArea
}
from
"@/api/news/newsBrief"
;
import
{
ElSpace
,
ElDivider
,
ElRadioButton
,
ElRadioGroup
,
ElButton
,
ElIcon
,
ElEmpty
,
ElPagination
}
from
"element-plus"
;
import
{
ElSpace
,
ElDivider
,
ElRadioButton
,
ElRadioGroup
,
ElButton
,
ElIcon
,
ElEmpty
,
ElPagination
}
from
"element-plus"
;
import
{
Back
}
from
"@element-plus/icons-vue"
;
import
CommonText
from
"@/components/base/texts/CommonText.vue"
;
import
CommonText
from
"@/components/base/texts/CommonText.vue"
;
import
{
useGotoNewsBrief
}
from
"@/router/modules/news"
;
import
{
useGotoNewsBrief
}
from
"@/router/modules/news"
;
import
{
scrollToElement
}
from
"@/router/common"
;
import
{
scrollToElement
}
from
"@/router/common"
;
import
{
number
}
from
"echarts"
;
const
route
=
useRoute
();
const
route
=
useRoute
();
const
gotoNewsBrief
=
useGotoNewsBrief
();
const
gotoNewsBrief
=
useGotoNewsBrief
();
const
moduleId
=
ref
(
route
.
params
.
id
);
const
moduleId
=
ref
(
route
.
params
.
id
);
...
@@ -54,52 +61,50 @@ const AreaList = ref([]);
...
@@ -54,52 +61,50 @@ const AreaList = ref([]);
const
currentAreaId
=
ref
(
""
);
const
currentAreaId
=
ref
(
""
);
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
console
.
log
(
route
.
query
.
name
,
moduleId
.
value
,
moduleName
.
value
);
console
.
log
(
route
.
query
.
name
,
moduleId
.
value
,
moduleName
.
value
);
const
{
data
:
areaList
}
=
await
getAreaList
();
const
{
data
:
areaList
}
=
await
getAreaList
();
AreaList
.
value
=
areaList
??
[];
AreaList
.
value
=
areaList
??
[];
await
updateDate
(
""
)
await
updateDate
(
""
);
});
});
const
onCurrentChange
=
async
e
=>
{
const
onCurrentChange
=
async
e
=>
{
await
updateDate
(
currentAreaId
.
value
,
e
-
1
)
await
updateDate
(
currentAreaId
.
value
,
e
-
1
);
scrollToElement
(
"ref-news-list"
);
scrollToElement
(
"ref-news-list"
);
}
}
;
async
function
updateDate
(
id
,
page
=
0
)
{
async
function
updateDate
(
id
,
page
=
0
)
{
const
{
data
}
=
await
getHotNewsByArea
({
const
{
data
}
=
await
getHotNewsByArea
({
moduleId
:
moduleId
.
value
,
moduleId
:
moduleId
.
value
,
industryId
:
id
?
id
:
null
,
industryId
:
id
?
id
:
null
,
currentPage
:
page
,
currentPage
:
page
});
});
data
?.
content
?.
forEach
(
item
=>
{
data
?.
content
?.
forEach
(
item
=>
{
item
.
newsImage
=
item
.
coverUrl
??
""
item
.
newsImage
=
item
.
coverUrl
??
""
;
})
});
NewsData
.
value
=
data
??
[];
NewsData
.
value
=
data
??
[];
modulePage
.
value
=
(
data
?.
number
??
0
)
+
1
;
modulePage
.
value
=
(
data
?.
number
??
0
)
+
1
;
}
}
async
function
changeArea
(
id
)
{
async
function
changeArea
(
id
)
{
await
updateDate
(
id
,
0
)
await
updateDate
(
id
,
0
);
}
}
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
@use
'@/styles/common.scss'
as
*
;
@use
"@/styles/common.scss"
as
*
;
@import
url("./style.css")
;
@import
url("./style.css")
;
.float-btn
{
.float-btn
{
position
:
absolute
;
position
:
absolute
;
top
:
24px
;
top
:
24px
;
left
:
40px
;
left
:
40px
;
width
:
92px
;
width
:
92px
;
height
:
40px
;
height
:
40px
;
display
:
flex
;
display
:
flex
;
gap
:
4px
;
gap
:
4px
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
center
;
box-sizing
:
border-box
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
255
,
255
,
255
,
1
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
1
);
border-radius
:
32px
;
border-radius
:
32px
;
@extend
.text-regular
;
@extend
.text-regular
;
color
:
var
(
--
text-primary-65-color
);
color
:
var
(
--
text-primary-65-color
);
}
}
</
style
>
</
style
>
\ No newline at end of file
src/views/ruleRestriction/detail/index.vue
浏览文件 @
0204674d
差异被折叠。
点击展开。
src/views/thinkTank/index.vue
浏览文件 @
0204674d
差异被折叠。
点击展开。
src/views/viewRiskSignal/assets/images/danger.svg
0 → 100644
浏览文件 @
0204674d
差异被折叠。
点击展开。
src/views/viewRiskSignal/assets/images/warning.svg
0 → 100644
浏览文件 @
0204674d
差异被折叠。
点击展开。
src/views/viewRiskSignal/index.vue
浏览文件 @
0204674d
差异被折叠。
点击展开。
src/views/viewRiskSignal/utils/cleandarHeat.js
浏览文件 @
0204674d
差异被折叠。
点击展开。
vite.config.js
浏览文件 @
0204674d
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论