Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
f58ff710
提交
f58ff710
authored
4月 21, 2026
作者:
朱政
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'pre' into zz-dev
上级
835f1f14
db5f7d4e
流水线
#579
已通过 于阶段
in 1 分 36 秒
变更
40
流水线
1
隐藏空白字符变更
内嵌
并排
正在显示
40 个修改的文件
包含
1259 行增加
和
703 行删除
+1259
-703
App copy.vue
src/App copy.vue
+0
-25
App.vue
src/App.vue
+0
-152
service-back.js
src/api/finance/service-back.js
+153
-0
service.js
src/api/finance/service.js
+54
-21
chart-bg.png
src/assets/images/chart-bg.png
+0
-0
down.svg
src/components/base/GradeSortSelectBox/down.svg
+6
-0
index.vue
src/components/base/GradeSortSelectBox/index.vue
+40
-0
up.svg
src/components/base/GradeSortSelectBox/up.svg
+6
-0
down.svg
src/components/base/HeatSortSelectBox/down.svg
+9
-0
index.vue
src/components/base/HeatSortSelectBox/index.vue
+40
-0
up.svg
src/components/base/HeatSortSelectBox/up.svg
+9
-0
index.vue
src/components/base/RelationCenterChart/index.vue
+14
-2
index.vue
src/components/base/RelationChart/index.vue
+30
-25
index.vue
src/components/base/RelationForceChart/index.vue
+17
-21
index.vue
src/components/base/SummaryCardsPanel/index.vue
+5
-1
down.svg
src/components/base/TimeSortSelectBox/down.svg
+8
-0
down1.svg
src/components/base/TimeSortSelectBox/down1.svg
+9
-0
down2.svg
src/components/base/TimeSortSelectBox/down2.svg
+6
-0
index.vue
src/components/base/TimeSortSelectBox/index.vue
+66
-0
up.svg
src/components/base/TimeSortSelectBox/up.svg
+8
-0
index.js
src/router/index.js
+5
-45
bill.js
src/router/modules/bill.js
+1
-1
index.vue
src/styles/components/TimeSortSelectBox/index.vue
+62
-0
index.vue
src/styles/components/index.vue
+6
-2
goToPage.js
src/utils/goToPage.js
+140
-3
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
+179
-107
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
+84
-41
barChart.js
src/views/dataLibrary/components/BarChart/barChart.js
+4
-0
lineChart.js
src/views/dataLibrary/components/LineChart/lineChart.js
+3
-0
index.vue
src/views/dataLibrary/financeControl/mREList/index.vue
+5
-5
index.vue
src/views/dataLibrary/financeControl/sDNList/index.vue
+8
-8
info.vue
src/views/exportControl/components/info.vue
+5
-0
index.vue
src/views/exportControl/index.vue
+79
-207
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
没有找到文件。
src/App copy.vue
浏览文件 @
f58ff710
...
@@ -225,31 +225,6 @@ const menuList = ref([
...
@@ -225,31 +225,6 @@ const menuList = ref([
}
}
]);
]);
const
handleToModule
=
item
=>
{
const
curRoute
=
router
.
resolve
({
path
:
item
.
path
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
const
searchText
=
ref
(
""
);
const
handleSearch
=
()
=>
{
const
curRoute
=
router
.
resolve
({
path
:
"/searchResults"
,
query
:
{
searchText
:
searchText
.
value
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
const
handleClickTitle
=
item
=>
{
if
(
item
.
name
===
"主要国家科技动向感知"
||
item
.
name
===
"主要国家竞争科技安全"
)
{
ElMessage
.
warning
(
"当前功能正在开发中,敬请期待!"
);
}
};
const
handleOpenPage
=
page
=>
{
const
handleOpenPage
=
page
=>
{
const
pageObj
=
{
const
pageObj
=
{
znwd
:
"/chat"
,
znwd
:
"/chat"
,
...
...
src/App.vue
浏览文件 @
f58ff710
...
@@ -27,7 +27,6 @@ import Menu12 from "@/assets/icons/overview/menu12.png";
...
@@ -27,7 +27,6 @@ import Menu12 from "@/assets/icons/overview/menu12.png";
import
{
ElMessage
}
from
"element-plus"
;
import
{
ElMessage
}
from
"element-plus"
;
const
router
=
useRouter
();
const
router
=
useRouter
();
const
route
=
useRoute
();
import
useTagsViewStore
from
'@/stores/tagsView.js'
import
useTagsViewStore
from
'@/stores/tagsView.js'
...
@@ -48,17 +47,6 @@ router.beforeEach((to, from, next) => {
...
@@ -48,17 +47,6 @@ router.beforeEach((to, from, next) => {
next
()
next
()
})
})
const
isShowAiBox
=
ref
(
false
);
const
closeAiBox
=
()
=>
{
isShowAiBox
.
value
=
false
;
};
const
openAiBox
=
()
=>
{
isShowAiBox
.
value
=
true
;
};
const
personTypeList
=
ref
([]);
const
personTypeList
=
ref
([]);
// 获取人物类别
// 获取人物类别
...
@@ -75,146 +63,6 @@ const handleGetPersonType = async () => {
...
@@ -75,146 +63,6 @@ const handleGetPersonType = async () => {
}
catch
(
error
)
{}
}
catch
(
error
)
{}
};
};
const
isCurrentOverview
=
computed
(()
=>
{
if
(
route
.
path
===
"/ZMOverView"
)
{
return
true
;
}
else
{
return
false
;
}
});
// 概览页标题列表
const
homeTitleList
=
ref
([
{
name
:
"中美科技博弈"
,
path
:
"/ZMOverView"
,
disabled
:
false
},
{
name
:
"主要国家科技动向感知"
,
path
:
""
,
disabled
:
true
},
{
name
:
"主要国家竞争科技安全"
,
path
:
""
,
disabled
:
true
}
]);
const
homeActiveTitleIndex
=
ref
(
0
);
const
isShowMenu
=
ref
(
false
);
const
handleShowMenu
=
(
index
,
isShow
)
=>
{
if
(
index
===
0
)
{
isShowMenu
.
value
=
isShow
;
}
};
const
handleHoverMenu
=
isShow
=>
{
isShowMenu
.
value
=
isShow
;
};
const
menuList
=
ref
([
{
title
:
"中美科技博弈概览"
,
icon
:
Menu1
,
path
:
"/ZMOverView"
},
{
title
:
"科技法案"
,
icon
:
Menu2
,
path
:
"/billHome"
},
{
title
:
"科技政令"
,
icon
:
Menu3
,
path
:
"/decree"
},
{
title
:
"美国科技智库"
,
icon
:
Menu4
,
path
:
"/thinkTank"
},
{
title
:
"出口管制"
,
icon
:
Menu5
,
path
:
"/exportControl"
},
{
title
:
"科研合作限制"
,
icon
:
Menu6
,
path
:
"/cooperationRestrictions"
},
{
title
:
"投融资限制"
,
icon
:
Menu7
,
path
:
"/finance"
},
{
title
:
"市场准入限制"
,
icon
:
Menu8
,
path
:
"/marketAccessRestrictions"
},
{
title
:
"规则限制"
,
icon
:
Menu9
,
path
:
"/ruleRestrictions"
},
{
title
:
"美国科技人物观点"
,
icon
:
Menu10
,
path
:
"/technologyFigures"
},
{
title
:
"美国主要创新主体动向"
,
icon
:
Menu11
,
path
:
"/innovationSubject"
},
{
title
:
"美国科研资助体系"
,
icon
:
Menu12
,
path
:
"/scientificFunding"
}
]);
const
handleToModule
=
item
=>
{
const
curRoute
=
router
.
resolve
({
path
:
item
.
path
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
const
searchText
=
ref
(
""
);
const
handleSearch
=
()
=>
{
const
curRoute
=
router
.
resolve
({
path
:
"/searchResults"
,
query
:
{
searchText
:
searchText
.
value
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
const
handleClickTitle
=
item
=>
{
if
(
item
.
name
===
"主要国家科技动向感知"
||
item
.
name
===
"主要国家竞争科技安全"
)
{
ElMessage
.
warning
(
"当前功能正在开发中,敬请期待!"
);
}
};
const
handleOpenPage
=
page
=>
{
const
pageObj
=
{
znwd
:
"/chat"
,
znxb
:
"/writtingAsstaint"
};
window
.
open
(
pageObj
[
page
],
"_blank"
);
};
const
handleClickToolBox
=
()
=>
{
ElMessage
.
warning
(
"当前功能正在开发中,敬请期待!"
);
};
onMounted
(()
=>
{
onMounted
(()
=>
{
handleGetPersonType
();
handleGetPersonType
();
});
});
...
...
src/api/finance/service-back.js
0 → 100644
浏览文件 @
f58ff710
// 引入 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
浏览文件 @
f58ff710
// 引入 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
*
1000
// 请求超时时间 30s
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/assets/images/chart-bg.png
0 → 100644
浏览文件 @
f58ff710
179.7 KB
src/components/base/GradeSortSelectBox/down.svg
0 → 100644
浏览文件 @
f58ff710
<svg
viewBox=
"0 0 16 16"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16.000000"
height=
"16.000000"
fill=
"none"
>
<rect
id=
"降序 12"
width=
"16.000000"
height=
"16.000000"
x=
"0.000000"
y=
"0.000000"
/>
<path
id=
"路径"
d=
"M12.6473 7.70235L14.0825 6.30313C14.1606 6.22657 14.2121 6.12657 14.2278 6.01719C14.27 5.74376 14.0793 5.49063 13.8059 5.45001L9.83871 4.87344L8.06527 1.27813C8.01683 1.17969 7.93715 1.10001 7.83871 1.05157C7.59183 0.929693 7.29183 1.03126 7.1684 1.27813L5.39496 4.87344L1.42777 5.45001C1.3184 5.46563 1.2184 5.51719 1.14183 5.59532C0.949647 5.79376 0.952772 6.10938 1.15121 6.30313L4.02152 9.10157L3.3434 13.0531C3.32465 13.1609 3.34183 13.2734 3.3934 13.3703C3.52152 13.6141 3.82465 13.7094 4.0684 13.5797L7.61684 11.7141L8.50394 12.1805"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
<path
id=
"矢量 1983"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,12,9)"
/>
<path
id=
"矢量 1984"
d=
"M10 12L12 14L14 12"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
</svg>
src/components/base/GradeSortSelectBox/index.vue
0 → 100644
浏览文件 @
f58ff710
<
template
>
<div
class=
"grade-sort-select-box"
>
<el-select
v-model=
"isSort"
placeholder=
"评分排序"
style=
"width: 130px"
@
change=
"handlePxChange"
>
<template
#
prefix
>
<div
style=
"display: flex; align-items: center; height: 100%"
>
<img
v-if=
"isSort"
src=
"./down.svg"
style=
"width: 16px; height: 16px"
/>
<img
v-else
src=
"./up.svg"
style=
"width: 16px; height: 16px"
/>
</div>
</
template
>
<el-option
v-for=
"item in gradeList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
</template>
<
script
setup
>
import
{
ref
}
from
'vue'
const
isSort
=
ref
(
true
)
const
gradeList
=
ref
([
{
label
:
"评分倒序"
,
value
:
true
},
{
label
:
"评分正序"
,
value
:
false
}
])
const
emits
=
defineEmits
([
'handlePxChange'
])
const
handlePxChange
=
()
=>
{
emits
(
'handlePxChange'
,
isSort
.
value
)
}
</
script
>
<
style
scoped
>
.grade-sort-select-box
{
height
:
42px
;
box-sizing
:
border-box
;
padding
:
5px
0
;
}
</
style
>
\ No newline at end of file
src/components/base/GradeSortSelectBox/up.svg
0 → 100644
浏览文件 @
f58ff710
<svg
viewBox=
"0 0 16 16"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16.000000"
height=
"16.000000"
fill=
"none"
>
<rect
id=
"降序 11"
width=
"16.000000"
height=
"16.000000"
x=
"0.000000"
y=
"0.000000"
/>
<path
id=
"矢量 1983"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,12,10)"
/>
<path
id=
"矢量 1984"
d=
"M10 10.9969L12.0003 9L14 10.9969"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
<path
id=
"路径"
d=
"M12.6473 7.70235L14.0825 6.30313C14.1606 6.22657 14.2121 6.12657 14.2278 6.01719C14.27 5.74376 14.0793 5.49063 13.8059 5.45001L9.83871 4.87344L8.06527 1.27813C8.01683 1.17969 7.93715 1.10001 7.83871 1.05157C7.59183 0.929693 7.29183 1.03126 7.1684 1.27813L5.39496 4.87344L1.42777 5.45001C1.3184 5.46563 1.2184 5.51719 1.14183 5.59532C0.949647 5.79376 0.952772 6.10938 1.15121 6.30313L4.02152 9.10157L3.3434 13.0531C3.32465 13.1609 3.34183 13.2734 3.3934 13.3703C3.52152 13.6141 3.82465 13.7094 4.0684 13.5797L7.61684 11.7141L9.39105 12.6469"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
</svg>
src/components/base/HeatSortSelectBox/down.svg
0 → 100644
浏览文件 @
f58ff710
<svg
viewBox=
"0 0 16 16"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16.000000"
height=
"16.000000"
fill=
"none"
>
<rect
id=
"降序 8"
width=
"16.000000"
height=
"16.000000"
x=
"0.000000"
y=
"0.000000"
/>
<rect
id=
"矩形 6349"
width=
"12.000000"
height=
"1.000000"
x=
"2.000000"
y=
"3.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6350"
width=
"12.000000"
height=
"1.000000"
x=
"2.000000"
y=
"6.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6351"
width=
"6.000000"
height=
"1.000000"
x=
"2.000000"
y=
"9.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6352"
width=
"6.000000"
height=
"1.000000"
x=
"2.000000"
y=
"12.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<path
id=
"矢量 1983"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,12,9)"
/>
<path
id=
"矢量 1984"
d=
"M10 12L12 14L14 12"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
</svg>
src/components/base/HeatSortSelectBox/index.vue
0 → 100644
浏览文件 @
f58ff710
<
template
>
<div
class=
"heat-sort-select-box"
>
<el-select
v-model=
"isSort"
placeholder=
"热度排序"
style=
"width: 130px"
@
change=
"handlePxChange"
>
<template
#
prefix
>
<div
style=
"display: flex; align-items: center; height: 100%"
>
<img
v-if=
"isSort"
src=
"./down.svg"
style=
"width: 16px; height: 16px"
/>
<img
v-else
src=
"./up.svg"
style=
"width: 16px; height: 16px"
/>
</div>
</
template
>
<el-option
v-for=
"item in heatList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
</template>
<
script
setup
>
import
{
ref
}
from
'vue'
const
isSort
=
ref
(
true
)
const
heatList
=
ref
([
{
label
:
"热度倒序"
,
value
:
true
},
{
label
:
"热度正序"
,
value
:
false
}
])
const
emits
=
defineEmits
([
'handlePxChange'
])
const
handlePxChange
=
()
=>
{
emits
(
'handlePxChange'
,
isSort
.
value
)
}
</
script
>
<
style
scoped
>
.heat-sort-select-box
{
height
:
42px
;
box-sizing
:
border-box
;
padding
:
5px
0
;
}
</
style
>
\ No newline at end of file
src/components/base/HeatSortSelectBox/up.svg
0 → 100644
浏览文件 @
f58ff710
<svg
viewBox=
"0 0 16 16"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16.000000"
height=
"16.000000"
fill=
"none"
>
<rect
id=
"降序 10"
width=
"16.000000"
height=
"16.000000"
x=
"0.000000"
y=
"0.000000"
/>
<path
id=
"矢量 1983"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,12,10)"
/>
<path
id=
"矢量 1984"
d=
"M10 10.9969L12.0003 9L14 10.9969"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
<rect
id=
"矩形 6349"
width=
"12.000000"
height=
"1.000000"
x=
"2.000000"
y=
"3.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6350"
width=
"12.000000"
height=
"1.000000"
x=
"2.000000"
y=
"6.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6351"
width=
"6.000000"
height=
"1.000000"
x=
"2.000000"
y=
"9.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6352"
width=
"6.000000"
height=
"1.000000"
x=
"2.000000"
y=
"12.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
</svg>
src/components/base/RelationCenterChart/index.vue
浏览文件 @
f58ff710
<
template
>
<
template
>
<RelationGraph
style=
"width: 100%; height: 100%;"
ref=
"graphRef"
:options=
"graphOptions"
@
node-click=
"onNodeClick"
<RelationGraph
class=
"graph-box"
style=
"width: 100%; height: 100%;"
ref=
"graphRef"
:options=
"graphOptions"
@
node-click=
"onNodeClick"
@
line-click=
"onLineClick"
/>
@
line-click=
"onLineClick"
/>
</
template
>
</
template
>
...
@@ -18,6 +18,13 @@ const graphOptions = {
...
@@ -18,6 +18,13 @@ const graphOptions = {
allowSwitchJunctionPoint
:
true
,
allowSwitchJunctionPoint
:
true
,
defaultLineShape
:
1
,
defaultLineShape
:
1
,
distance_coefficient
:
1
,
distance_coefficient
:
1
,
// 背景图配置
backgroundImage
:
new
URL
(
'@/assets/images/bg/companyGraph-bg.png'
,
import
.
meta
.
url
).
href
,
// Vite 引入本地图片
// backgroundImage: 'https://example.com/your-bg-image.png', // 或者直接用网络图片
backgroundImageNoRepeat
:
true
,
// 图片不重复
backgroundImageOffsetX
:
0
,
// X轴偏移
backgroundImageOffsetY
:
0
,
// Y轴偏移
// backgroundColor: '#f5f5f5', // 背景底色
layouts
:
[
layouts
:
[
{
{
layoutName
:
'center'
,
layoutName
:
'center'
,
...
@@ -123,4 +130,9 @@ onMounted(() => {
...
@@ -123,4 +130,9 @@ onMounted(() => {
});
});
</
script
>
</
script
>
<
style
scoped
lang=
"scss"
></
style
>
<
style
scoped
lang=
"scss"
>
// .graph-box{
// background: url('@/assets/images/bg/chart-bg.png');
// background: orange;
// }
</
style
>
src/components/base/RelationChart/index.vue
浏览文件 @
f58ff710
<
template
>
<
template
>
<RelationGraph
<RelationGraph
style=
"width: 100%; height: 100%"
ref=
"graphRef"
:options=
"currentGraphOptions"
style=
"width: 100%; height: 100%"
:on-node-click=
"onNodeClick"
:on-line-click=
"onLineClick"
>
ref=
"graphRef"
:options=
"currentGraphOptions"
:on-node-click=
"onNodeClick"
:on-line-click=
"onLineClick"
>
<template
#
node=
"
{ node }">
<template
#
node=
"
{ node }">
<div
<div
class=
"custom-node"
:style=
"
{
class=
"custom-node"
backgroundColor: node.color || 'var(--color-primary-50)'
:style=
"
{
}">
backgroundColor: node.color || 'var(--color-primary-50)'
<span
:style=
"
{
}"
color: node.fontColor || '#ffffff',
>
fontSize: node.customFontSize || '24px',
<span
fontWeight: 'normal',
:style=
"
{
textAlign: 'center',
color: node.fontColor || '#ffffff',
wordBreak: 'break-word',
fontSize: node.customFontSize || '24px',
padding: '0 8px'
fontWeight: 'normal',
}">
textAlign: 'center',
wordBreak: 'break-word',
padding: '0 8px'
}"
>
{{
node
.
text
}}
{{
node
.
text
}}
</span>
</span>
</div>
</div>
...
@@ -76,7 +66,14 @@ const baseGraphOptionsH = {
...
@@ -76,7 +66,14 @@ const baseGraphOptionsH = {
defaultNodeBorderColor
:
"var(--color-primary-100)"
,
defaultNodeBorderColor
:
"var(--color-primary-100)"
,
defaultLineColor
:
"var(--color-primary-50)"
,
defaultLineColor
:
"var(--color-primary-50)"
,
defaultNodeColor
:
"var(--color-primary-50)"
,
defaultNodeColor
:
"var(--color-primary-50)"
,
defaultNodeFontColor
:
"var(--text-primary-90-color)"
defaultNodeFontColor
:
"var(--text-primary-90-color)"
,
// 背景图配置
backgroundImage
:
new
URL
(
'@/assets/images/bg/companyGraph-bg.png'
,
import
.
meta
.
url
).
href
,
// Vite 引入本地图片
// backgroundImage: 'https://example.com/your-bg-image.png', // 或者直接用网络图片
backgroundImageNoRepeat
:
true
,
// 图片不重复
backgroundImageOffsetX
:
0
,
// X轴偏移
backgroundImageOffsetY
:
0
,
// Y轴偏移
// backgroundColor: '#f5f5f5', // 背景底色
};
};
// 基础垂直配置
// 基础垂直配置
...
@@ -102,7 +99,14 @@ const baseGraphOptionsV = {
...
@@ -102,7 +99,14 @@ const baseGraphOptionsV = {
defaultNodeBorderWidth
:
2
,
defaultNodeBorderWidth
:
2
,
defaultLineColor
:
"var(--color-primary-50)"
,
defaultLineColor
:
"var(--color-primary-50)"
,
defaultNodeColor
:
"var(--color-primary-50)"
,
defaultNodeColor
:
"var(--color-primary-50)"
,
defaultNodeFontColor
:
"var(--bg-white-100)"
defaultNodeFontColor
:
"var(--bg-white-100)"
,
// 背景图配置
backgroundImage
:
new
URL
(
'@/assets/images/bg/companyGraph-bg.png'
,
import
.
meta
.
url
).
href
,
// Vite 引入本地图片
// backgroundImage: 'https://example.com/your-bg-image.png', // 或者直接用网络图片
backgroundImageNoRepeat
:
true
,
// 图片不重复
backgroundImageOffsetX
:
0
,
// X轴偏移
backgroundImageOffsetY
:
0
,
// Y轴偏移
// backgroundColor: '#f5f5f5', // 背景底色
};
};
// 【核心修改】根据 isReversed 动态计算配置
// 【核心修改】根据 isReversed 动态计算配置
...
@@ -184,6 +188,7 @@ onMounted(() => {
...
@@ -184,6 +188,7 @@ onMounted(() => {
justify-content
:
center
;
justify-content
:
center
;
}
}
}
}
.custom-node
{
.custom-node
{
border-radius
:
50%
;
border-radius
:
50%
;
display
:
flex
;
display
:
flex
;
...
...
src/components/base/RelationForceChart/index.vue
浏览文件 @
f58ff710
<
template
>
<
template
>
<RelationGraph
<RelationGraph
style=
"width: 100%; height: 100%"
ref=
"graphRef"
:options=
"graphOptions"
@
node-click=
"onNodeClick"
style=
"width: 100%; height: 100%"
@
line-click=
"onLineClick"
>
ref=
"graphRef"
:options=
"graphOptions"
@
node-click=
"onNodeClick"
@
line-click=
"onLineClick"
>
<!-- 自定义节点插槽 - 这是官方推荐的方式 -->
<!-- 自定义节点插槽 - 这是官方推荐的方式 -->
<template
#
node=
"
{ node }">
<template
#
node=
"
{ node }">
<div
<div
class=
"custom-node"
:style=
"
{
class=
"custom-node"
backgroundColor: node.color || 'var(--color-primary-50)'
:style=
"
{
}">
backgroundColor: node.color || 'var(--color-primary-50)'
}"
>
{{
console
.
log
(
node
)
}}
{{
console
.
log
(
node
)
}}
<!-- 在这里自由控制文字样式 -->
<!-- 在这里自由控制文字样式 -->
<div
class=
"img"
v-if=
"node.data.pic"
>
<div
class=
"img"
v-if=
"node.data.pic"
>
<img
:src=
"node.data.pic"
alt=
""
/>
<img
:src=
"node.data.pic"
alt=
""
/>
</div>
</div>
<span
<span
class=
"text"
:style=
"
{
class=
"text"
color: node.fontColor || 'var(--text-primary-80-color)',
:style=
"
{
fontSize: node.customFontSize || '24px' // 可以从数据中读取
color: node.fontColor || 'var(--text-primary-80-color)',
}">
fontSize: node.customFontSize || '24px' // 可以从数据中读取
}"
>
{{
node
.
text
}}
{{
node
.
text
}}
</span>
</span>
</div>
</div>
...
@@ -57,7 +46,14 @@ const graphOptions = ref({
...
@@ -57,7 +46,14 @@ const graphOptions = ref({
layout
:
{
layout
:
{
layoutName
:
"force"
layoutName
:
"force"
},
},
defaultJunctionPoint
:
"border"
defaultJunctionPoint
:
"border"
,
// 背景图配置
backgroundImage
:
new
URL
(
'@/assets/images/bg/companyGraph-bg.png'
,
import
.
meta
.
url
).
href
,
// Vite 引入本地图片
// backgroundImage: 'https://example.com/your-bg-image.png', // 或者直接用网络图片
backgroundImageNoRepeat
:
true
,
// 图片不重复
backgroundImageOffsetX
:
0
,
// X轴偏移
backgroundImageOffsetY
:
0
,
// Y轴偏移
// backgroundColor: '#f5f5f5', // 背景底色
// defaultNodeWidth: 150, // 全局默认节点宽度
// defaultNodeWidth: 150, // 全局默认节点宽度
// defaultNodeHeight: 150, // 全局默认节点高度
// defaultNodeHeight: 150, // 全局默认节点高度
});
});
...
...
src/components/base/SummaryCardsPanel/index.vue
浏览文件 @
f58ff710
...
@@ -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/TimeSortSelectBox/down.svg
0 → 100644
浏览文件 @
f58ff710
<svg
viewBox=
"0 0 16 16"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16.000000"
height=
"16.000000"
fill=
"none"
>
<rect
id=
"降序 6"
width=
"16.000000"
height=
"16.000000"
x=
"0.000000"
y=
"0.000000"
/>
<path
id=
"椭圆 465"
d=
"M8 14.5C6.20507 14.5 4.67301 13.8654 3.40381 12.5962C2.1346 11.327 1.5 9.79492 1.5 8C1.5 6.20507 2.1346 4.67301 3.40381 3.40381C4.67301 2.1346 6.20507 1.5 8 1.5C9.79492 1.5 11.327 2.1346 12.5962 3.40381C13.8654 4.67301 14.5 6.20507 14.5 8L13.5 8C13.5 6.48122 12.963 5.18485 11.8891 4.11091C10.8151 3.03697 9.51878 2.5 8 2.5C6.48122 2.5 5.18485 3.03697 4.11091 4.11091C3.03697 5.18486 2.5 6.48122 2.5 8C2.5 9.51878 3.03697 10.8151 4.11091 11.8891C5.18485 12.963 6.48122 13.5 8 13.5L8 14.5ZM14.48 7.98L14.5 8C14.5 8.28 14.28 8.5 14 8.5C13.72 8.5 13.5 8.28 13.5 8L13.52 7.98L14.48 7.98ZM7.98 13.52L8 13.5C8.28 13.5 8.5 13.72 8.5 14C8.5 14.28 8.28 14.5 8 14.5L7.98 14.48L7.98 13.52Z"
fill=
"rgb(95, 101, 108)"
fill-rule=
"nonzero"
/>
<path
id=
"矢量 1981"
d=
"M4 8L8 8"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
<path
id=
"矢量 1982"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,8,4)"
/>
<path
id=
"矢量 1983"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,12,9)"
/>
<path
id=
"矢量 1984"
d=
"M10 12L12 14L14 12"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
</svg>
src/components/base/TimeSortSelectBox/down1.svg
0 → 100644
浏览文件 @
f58ff710
<svg
viewBox=
"0 0 16 16"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16.000000"
height=
"16.000000"
fill=
"none"
>
<rect
id=
"降序 8"
width=
"16.000000"
height=
"16.000000"
x=
"0.000000"
y=
"0.000000"
/>
<rect
id=
"矩形 6349"
width=
"12.000000"
height=
"1.000000"
x=
"2.000000"
y=
"3.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6350"
width=
"12.000000"
height=
"1.000000"
x=
"2.000000"
y=
"6.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6351"
width=
"6.000000"
height=
"1.000000"
x=
"2.000000"
y=
"9.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<rect
id=
"矩形 6352"
width=
"6.000000"
height=
"1.000000"
x=
"2.000000"
y=
"12.000000"
rx=
"0.500000"
fill=
"rgb(95, 101, 108)"
/>
<path
id=
"矢量 1983"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,12,9)"
/>
<path
id=
"矢量 1984"
d=
"M10 12L12 14L14 12"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
</svg>
src/components/base/TimeSortSelectBox/down2.svg
0 → 100644
浏览文件 @
f58ff710
<svg
viewBox=
"0 0 16 16"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16.000000"
height=
"16.000000"
fill=
"none"
>
<rect
id=
"降序 12"
width=
"16.000000"
height=
"16.000000"
x=
"0.000000"
y=
"0.000000"
/>
<path
id=
"路径"
d=
"M12.6473 7.70235L14.0825 6.30313C14.1606 6.22657 14.2121 6.12657 14.2278 6.01719C14.27 5.74376 14.0793 5.49063 13.8059 5.45001L9.83871 4.87344L8.06527 1.27813C8.01683 1.17969 7.93715 1.10001 7.83871 1.05157C7.59183 0.929693 7.29183 1.03126 7.1684 1.27813L5.39496 4.87344L1.42777 5.45001C1.3184 5.46563 1.2184 5.51719 1.14183 5.59532C0.949647 5.79376 0.952772 6.10938 1.15121 6.30313L4.02152 9.10157L3.3434 13.0531C3.32465 13.1609 3.34183 13.2734 3.3934 13.3703C3.52152 13.6141 3.82465 13.7094 4.0684 13.5797L7.61684 11.7141L8.50394 12.1805"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
<path
id=
"矢量 1983"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,12,9)"
/>
<path
id=
"矢量 1984"
d=
"M10 12L12 14L14 12"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
</svg>
src/components/base/TimeSortSelectBox/index.vue
0 → 100644
浏览文件 @
f58ff710
<
template
>
<div
class=
"time-sort-select-box"
>
<el-select
v-model=
"sortValue"
placeholder=
"排序方式"
style=
"width: 130px"
@
change=
"handlePxChange"
>
<template
#
prefix
>
<div
style=
"display: flex; align-items: center; height: 100%"
>
<img
v-if=
"sortValue === 1"
src=
"./down.svg"
style=
"width: 16px; height: 16px"
/>
<img
v-else-if=
"sortValue === 2"
src=
"./up.svg"
style=
"width: 16px; height: 16px"
/>
<img
v-else-if=
"sortValue === 3"
src=
"./down1.svg"
style=
"width: 16px; height: 16px"
/>
<img
v-else-if=
"sortValue === 4"
src=
"./down2.svg"
style=
"width: 16px; height: 16px"
/>
</div>
</
template
>
<el-option
v-for=
"item in sortList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
</template>
<
script
setup
>
import
{
computed
,
ref
}
from
'vue'
const
props
=
defineProps
({
sortDemension
:
{
type
:
Number
,
default
:
1
}
})
const
sortValue
=
ref
(
1
)
const
sortList
=
computed
(()
=>
{
if
(
props
.
sortDemension
===
1
)
{
return
[
{
label
:
"时间倒序"
,
value
:
1
},
{
label
:
"时间正序"
,
value
:
2
},
]
}
else
if
(
props
.
sortDemension
===
2
)
{
return
[
{
label
:
"时间倒序"
,
value
:
1
},
{
label
:
"时间正序"
,
value
:
2
},
{
label
:
"评分倒序"
,
value
:
3
},
]
}
else
{
return
[
{
label
:
"时间倒序"
,
value
:
1
},
{
label
:
"时间正序"
,
value
:
2
},
{
label
:
"评分倒序"
,
value
:
3
},
{
label
:
"热度倒序"
,
value
:
4
},
]
}
})
const
emits
=
defineEmits
([
'handlePxChange'
])
const
handlePxChange
=
()
=>
{
emits
(
'handlePxChange'
,
sortValue
.
value
)
}
</
script
>
<
style
scoped
>
.time-sort-select-box
{
height
:
42px
;
box-sizing
:
border-box
;
padding
:
5px
0
;
}
</
style
>
\ No newline at end of file
src/components/base/TimeSortSelectBox/up.svg
0 → 100644
浏览文件 @
f58ff710
<svg
viewBox=
"0 0 16 16"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16.000000"
height=
"16.000000"
fill=
"none"
>
<rect
id=
"降序 7"
width=
"16.000000"
height=
"16.000000"
x=
"0.000000"
y=
"0.000000"
/>
<path
id=
"椭圆 465"
d=
"M8 14.5C6.20507 14.5 4.67301 13.8654 3.40381 12.5962C2.1346 11.327 1.5 9.79492 1.5 8C1.5 6.20507 2.1346 4.67301 3.40381 3.40381C4.67301 2.1346 6.20507 1.5 8 1.5C9.79492 1.5 11.327 2.1346 12.5962 3.40381C13.8654 4.67301 14.5 6.20507 14.5 8L13.5 8C13.5 6.48122 12.963 5.18485 11.8891 4.11091C10.8151 3.03697 9.51878 2.5 8 2.5C6.48122 2.5 5.18485 3.03697 4.11091 4.11091C3.03697 5.18486 2.5 6.48122 2.5 8C2.5 9.51878 3.03697 10.8151 4.11091 11.8891C5.18485 12.963 6.48122 13.5 8 13.5L8 14.5ZM14.48 7.98L14.5 8C14.5 8.28 14.28 8.5 14 8.5C13.72 8.5 13.5 8.28 13.5 8L13.52 7.98L14.48 7.98ZM7.98 13.52L8 13.5C8.28 13.5 8.5 13.72 8.5 14C8.5 14.28 8.28 14.5 8 14.5L7.98 14.48L7.98 13.52Z"
fill=
"rgb(95, 101, 108)"
fill-rule=
"nonzero"
/>
<path
id=
"矢量 1981"
d=
"M4 8L8 8"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
<path
id=
"矢量 1982"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,8,4)"
/>
<path
id=
"矢量 1983"
d=
"M0 0L4 0"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
transform=
"matrix(0,1,-1,0,12,10)"
/>
<path
id=
"矢量 1984"
d=
"M10 10.9969L12.0003 9L14 10.9969"
stroke=
"rgb(95, 101, 108)"
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"1.000000"
/>
</svg>
src/router/index.js
浏览文件 @
f58ff710
...
@@ -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
浏览文件 @
f58ff710
...
@@ -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/styles/components/TimeSortSelectBox/index.vue
0 → 100644
浏览文件 @
f58ff710
<
template
>
<el-row
class=
"wrapper layout-grid-line"
>
<el-col
:span=
"span"
>
<pre>
{{
`
import TimeSortSelectBox from '@/components/base/TimeSortSelectBox/index.vue'
<div class="time-box">
<TimeSortSelectBox @handle-px-change="handleTimePx" />
<TimeSortSelectBox :sort-demension="2" @handle-px-change="handleTimePx" />
<TimeSortSelectBox :sort-demension="3" @handle-px-change="handleTimePx" />
</div>
`
}}
</pre>
<div
class=
"time-box"
>
<TimeSortSelectBox
@
handle-px-change=
"handleTimePx"
/>
<TimeSortSelectBox
:sort-demension=
"2"
@
handle-px-change=
"handleTimePx"
/>
<TimeSortSelectBox
:sort-demension=
"3"
@
handle-px-change=
"handleTimePx"
/>
</div>
</el-col>
</el-row>
</
template
>
<
script
setup
>
import
{
ref
}
from
'vue'
import
'@/styles/common.scss'
import
TimeSortSelectBox
from
'@/components/base/TimeSortSelectBox/index.vue'
import
HeatSortSelectBox
from
'@/components/base/HeatSortSelectBox/index.vue'
import
GradeSortSelectBox
from
'@/components/base/GradeSortSelectBox/index.vue'
const
span
=
12
const
handleTimePx
=
(
val
)
=>
{
alert
(
val
)
}
const
handleHeatPx
=
(
val
)
=>
{
alert
(
val
)
}
const
handleGradePx
=
(
val
)
=>
{
alert
(
val
)
}
</
script
>
<
style
lang=
"scss"
scoped
>
.time-box
{
width
:
700px
;
height
:
400px
;
padding
:
100px
;
background
:
#F2F8FF
;
border
:
1px
solid
var
(
--
bg-black-5
);
display
:
flex
;
gap
:
8px
;
}
</
style
>
\ No newline at end of file
src/styles/components/index.vue
浏览文件 @
f58ff710
...
@@ -8,8 +8,8 @@
...
@@ -8,8 +8,8 @@
<div
class=
"text-title-1-show"
>
文字样式
</div>
<div
class=
"text-title-1-show"
>
文字样式
</div>
<TextStyle
/>
<TextStyle
/>
<div
class=
"text-title-1-show"
>
通用样式/组件
</div>
<div
class=
"text-title-1-show"
>
通用样式/组件
</div>
<div
style=
"position: relative;
min-height: 7
00px;"
>
<div
style=
"position: relative;
height: 8
00px;"
>
<el-tabs
tabPosition=
"left"
class=
"tabs-nav-no-wrap left-float-nav-tabs dev-style-tabs"
>
<el-tabs
tabPosition=
"left"
style=
"position: relative; height: 700px;"
class=
"tabs-nav-no-wrap left-float-nav-tabs dev-style-tabs"
>
<el-tab-pane
label=
"通用"
lazy
>
<el-tab-pane
label=
"通用"
lazy
>
<common-page
/>
<common-page
/>
</el-tab-pane>
</el-tab-pane>
...
@@ -73,6 +73,9 @@
...
@@ -73,6 +73,9 @@
<el-tab-pane
label=
"激活工作框"
lazy
>
<el-tab-pane
label=
"激活工作框"
lazy
>
<WorkingBox
/>
<WorkingBox
/>
</el-tab-pane>
</el-tab-pane>
<el-tab-pane
label=
"自定义排序"
lazy
>
<TimeSortSelectBox
/>
</el-tab-pane>
</el-tabs>
</el-tabs>
</div>
</div>
</el-space>
</el-space>
...
@@ -107,6 +110,7 @@ import RelationChart from './RelationChart/index.vue'
...
@@ -107,6 +110,7 @@ import RelationChart from './RelationChart/index.vue'
import
RelationCenterChart
from
'./RelationCenterChart/index.vue'
import
RelationCenterChart
from
'./RelationCenterChart/index.vue'
import
RelationForceChart
from
'./RelationForceChart/index.vue'
import
RelationForceChart
from
'./RelationForceChart/index.vue'
import
WorkingBox
from
'./WorkingBox/index.vue'
import
WorkingBox
from
'./WorkingBox/index.vue'
import
TimeSortSelectBox
from
'./TimeSortSelectBox/index.vue'
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
...
...
src/utils/goToPage.js
浏览文件 @
f58ff710
import
{
useRouter
}
from
"vue-router"
;
import
{
useRouter
}
from
"vue-router"
;
import
{
getPersonSummaryInfo
}
from
"@/api/common/index"
;
const
router
=
useRouter
()
const
router
=
useRouter
()
// 跳转法案详情
// 跳转法案详情
...
@@ -27,8 +28,20 @@ export const goToDecree = (id, tabName) => {
...
@@ -27,8 +28,20 @@ export const goToDecree = (id, tabName) => {
window
.
open
(
route
.
href
,
"_blank"
);
window
.
open
(
route
.
href
,
"_blank"
);
};
};
// 跳转智库
// 跳转智库
详情
export
const
goToThinkTank
=
(
id
,
tabName
)
=>
{
export
const
goToThinkTank
=
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
tabName
);
const
curRoute
=
router
.
resolve
({
name
:
"ThinkTankDetail"
,
params
:
{
id
:
id
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
// 跳转智库报告详情
export
const
goToThinkTankReport
=
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
tabName
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
tabName
);
const
route
=
router
.
resolve
({
const
route
=
router
.
resolve
({
name
:
"ReportDetail"
,
name
:
"ReportDetail"
,
...
@@ -49,4 +62,129 @@ export const goToInstitution = (id, tabName) => {
...
@@ -49,4 +62,129 @@ export const goToInstitution = (id, tabName) => {
}
}
});
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
}
\ No newline at end of file
// 跳转人物详情
export
const
goToCharacterPage
=
async
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
'curTabName'
,
tabName
)
const
personTypeList
=
JSON
.
parse
(
window
.
sessionStorage
.
getItem
(
"personTypeList"
));
let
type
let
personTypeName
const
params
=
{
personId
:
id
}
// 先获取人物全局信息
try
{
const
res
=
await
getPersonSummaryInfo
(
params
)
if
(
res
.
code
===
200
&&
res
.
data
)
{
const
arr
=
personTypeList
.
filter
(
item
=>
{
return
item
.
typeId
===
res
.
data
.
personType
;
})
if
(
arr
&&
arr
.
length
)
{
personTypeName
=
arr
[
0
].
typeName
;
if
(
personTypeName
===
"科技企业领袖"
)
{
type
=
1
;
}
else
if
(
personTypeName
===
"国会议员"
)
{
type
=
2
;
}
else
if
(
personTypeName
===
"智库研究人员"
)
{
type
=
3
;
}
else
{
personTypeName
=
"其他类型"
;
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
return
;
}
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
type
:
type
,
// type=1为科技企业领袖,2为国会议员,3为智库研究人员
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
}
else
{
personTypeName
=
""
;
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
return
;
}
}
else
{
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
return
;
}
}
catch
(
error
)
{
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
return
;
}
}
// 跳转企业
export
const
goToCompanyPage
=
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
'curTabName'
,
tabName
)
const
route
=
router
.
resolve
({
name
:
"companyPages"
,
params
:
{
id
:
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
}
// 跳转新闻详情
export
const
goToNewsPage
=
(
id
,
tabName
)
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
tabName
);
const
route
=
router
.
resolve
({
path
:
"/newsAnalysis"
,
query
:
{
newsId
:
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
}
// 跳转搜索详情页
export
const
goToSearch
=
(
tabName
,
areaName
,
billSearchType
)
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
tabName
);
// if (!areaName) return;
const
query
=
{
searchText
:
tabName
,
areaName
:
areaName
};
if
(
enableBillTypeSwitch
)
{
query
.
billSearchType
=
billSearchType
}
const
curRoute
=
router
.
resolve
({
path
:
"/searchResults"
,
query
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
// 跳转数据资源库
src/views/bill/allCommittee/index.vue
浏览文件 @
f58ff710
...
@@ -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
浏览文件 @
f58ff710
1.2 KB
src/views/bill/billHome/index.vue
浏览文件 @
f58ff710
...
@@ -21,7 +21,7 @@
...
@@ -21,7 +21,7 @@
moreText=
"查看全部委员会"
moreText=
"查看全部委员会"
:moreCardMinCount=
"1"
:moreCardMinCount=
"1"
@
time-click=
"handleCommitteeTimeClick"
@
time-click=
"handleCommitteeTimeClick"
@
name-click=
"handleTo
DataLibrary
"
@
name-click=
"handleTo
Institution
"
@
count-click=
"handleToBillDataLibrary"
@
count-click=
"handleToBillDataLibrary"
@
more-click=
"handleToCommitteeMore"
@
more-click=
"handleToCommitteeMore"
/>
/>
...
@@ -56,7 +56,31 @@
...
@@ -56,7 +56,31 @@
<AreaTag
v-for=
"(item, index) in bill.hylyList"
:key=
"index"
:tagName=
"item.industryName"
>
<AreaTag
v-for=
"(item, index) in bill.hylyList"
:key=
"index"
:tagName=
"item.industryName"
>
</AreaTag>
</AreaTag>
</div>
</div>
<div
class=
"box1-main-divider"
></div>
<div
class=
"box1-main-left-info1"
>
<div
class=
"box1-main-left-info1"
>
<div
class=
"info1-box"
>
<div
class=
"icon"
></div>
<div
class=
"info1-box-left"
>
{{ "提出部门:" }}
</div>
<div
class=
"info1-box-right info1-box-right--committee"
>
<
template
v-if=
"getLimitedCommitteeList(bill.committeeList).length"
>
<div
v-for=
"committee in getLimitedCommitteeList(bill.committeeList)"
:key=
"committee.committeeId || committee.committeeName"
class=
"committee-item"
>
<img
class=
"committee-logo"
:src=
"committee.logoUrl || iconCommit"
:alt=
"committee.committeeName || '提案部门'"
/>
<div
class=
"committee-name"
>
{{
committee
.
committeeName
||
"--"
}}
</div>
</div>
</
template
>
<div
v-else
>
--
</div>
</div>
</div>
<div
class=
"info1-box"
>
<div
class=
"info1-box"
>
<div
class=
"icon"
></div>
<div
class=
"icon"
></div>
<div
class=
"info1-box-left"
>
{{ "提案人:" }}
</div>
<div
class=
"info1-box-left"
>
{{ "提案人:" }}
</div>
...
@@ -70,9 +94,11 @@
...
@@ -70,9 +94,11 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"box1-main-divider box1-main-divider--before-list"
></div>
<div
class=
"box1-main-left-info2"
>
<div
class=
"box1-main-left-info2"
>
<div
class=
"info2-item"
v-for=
"(item, index) in bill.dyqkList"
:key=
"index"
>
<div
class=
"info2-item"
v-for=
"(item, index) in getLimitedDyqkList(bill.dyqkList)"
<div
class=
"time-line"
v-if=
"index !== bill.dyqkList.length - 1"
></div>
:key=
"index"
>
<div
class=
"time-line"
v-if=
"!isLastDyqkItem(bill.dyqkList, index)"
></div>
<div
class=
"item-icon"
>
<div
class=
"item-icon"
>
<img
src=
"./assets/images/info2-icon.png"
alt=
""
/>
<img
src=
"./assets/images/info2-icon.png"
alt=
""
/>
</div>
</div>
...
@@ -147,7 +173,7 @@
...
@@ -147,7 +173,7 @@
</div>
</div>
</div>
</div>
</OverviewCard>
</OverviewCard>
<OverviewCard
class=
"overview-card--single box6"
title=
"领域分布情况"
:icon=
"box
6
HeaderIcon"
>
<OverviewCard
class=
"overview-card--single box6"
title=
"领域分布情况"
:icon=
"box
7
HeaderIcon"
>
<
template
#
right
>
<
template
#
right
>
<el-select
v-model=
"box9selectetedTime"
placeholder=
"选择时间"
style=
"width: 90px"
>
<el-select
v-model=
"box9selectetedTime"
placeholder=
"选择时间"
style=
"width: 90px"
>
<el-option
v-for=
"item in box9YearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
<el-option
v-for=
"item in box9YearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
...
@@ -186,7 +212,7 @@
...
@@ -186,7 +212,7 @@
<div
v-else
id=
"box7Chart"
class=
"overview-chart"
></div>
<div
v-else
id=
"box7Chart"
class=
"overview-chart"
></div>
</div>
</div>
<div
class=
"overview-tip-row"
>
<div
class=
"overview-tip-row"
>
<TipTab
class=
"overview-tip"
:text=
"'
提出涉华科技法
案委员会分布情况,数据来源:美国国会官网'"
/>
<TipTab
class=
"overview-tip"
:text=
"'
涉华科技法案提
案委员会分布情况,数据来源:美国国会官网'"
/>
<AiButton
class=
"overview-tip-action"
@
mouseenter=
"handleShowAiPane('box7')"
/>
<AiButton
class=
"overview-tip-action"
@
mouseenter=
"handleShowAiPane('box7')"
/>
</div>
</div>
<div
v-if=
"aiPaneVisible.box7"
class=
"overview-ai-pane"
@
mouseleave=
"handleHideAiPane('box7')"
>
<div
v-if=
"aiPaneVisible.box7"
class=
"overview-ai-pane"
@
mouseleave=
"handleHideAiPane('box7')"
>
...
@@ -194,7 +220,7 @@
...
@@ -194,7 +220,7 @@
</div>
</div>
</div>
</div>
</OverviewCard>
</OverviewCard>
<OverviewCard
class=
"overview-card--single box8"
title=
"进展分布情况"
:icon=
"box
7
HeaderIcon"
>
<OverviewCard
class=
"overview-card--single box8"
title=
"进展分布情况"
:icon=
"box
8
HeaderIcon"
>
<
template
#
right
>
<
template
#
right
>
<el-select
v-model=
"box8selectetedTime"
placeholder=
"选择时间"
style=
"width: 90px"
>
<el-select
v-model=
"box8selectetedTime"
placeholder=
"选择时间"
style=
"width: 90px"
>
<el-option
v-for=
"item in box8YearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
<el-option
v-for=
"item in box8YearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
...
@@ -217,7 +243,7 @@
...
@@ -217,7 +243,7 @@
</div>
</div>
</div>
</div>
</OverviewCard>
</OverviewCard>
<OverviewCard
class=
"overview-card--single box9"
title=
"关键条款词云"
:icon=
"box
7
HeaderIcon"
>
<OverviewCard
class=
"overview-card--single box9"
title=
"关键条款词云"
:icon=
"box
6
HeaderIcon"
>
<div
class=
"overview-card-body box9-main"
>
<div
class=
"overview-card-body box9-main"
>
<div
class=
"overview-chart-wrap"
v-loading=
"chartLoading.box9"
>
<div
class=
"overview-chart-wrap"
v-loading=
"chartLoading.box9"
>
<el-empty
v-if=
"!wordCloudHasData"
description=
"暂无数据"
:image-size=
"100"
/>
<el-empty
v-if=
"!wordCloudHasData"
description=
"暂无数据"
:image-size=
"100"
/>
...
@@ -290,6 +316,7 @@ import getDoublePieChart from "./utils/doublePieChart";
...
@@ -290,6 +316,7 @@ import getDoublePieChart from "./utils/doublePieChart";
import
box5HeaderIcon
from
"./assets/images/box5-header-icon.png"
;
import
box5HeaderIcon
from
"./assets/images/box5-header-icon.png"
;
import
box6HeaderIcon
from
"./assets/images/box6-header-icon.png"
;
import
box6HeaderIcon
from
"./assets/images/box6-header-icon.png"
;
import
box7HeaderIcon
from
"./assets/images/box7-header-icon.png"
;
import
box7HeaderIcon
from
"./assets/images/box7-header-icon.png"
;
import
box8HeaderIcon
from
"./assets/images/box8-header-icon.png"
import
iconCommit
from
"./assets/icons/icon-commit.png"
;
import
iconCommit
from
"./assets/icons/icon-commit.png"
;
import
iconILetter
from
"./assets/icons/icon-iLetter.png"
;
import
iconILetter
from
"./assets/icons/icon-iLetter.png"
;
...
@@ -386,7 +413,9 @@ const committeeCards = computed(() => {
...
@@ -386,7 +413,9 @@ const committeeCards = computed(() => {
orgId
:
item
.
orgId
,
orgId
:
item
.
orgId
,
name
:
item
.
name
,
name
:
item
.
name
,
subText
:
item
.
chamber
,
subText
:
item
.
chamber
,
count
:
item
.
count
count
:
item
.
total
,
delta
:
item
.
count
,
avatar
:
item
.
logoUrl
}));
}));
});
});
...
@@ -403,9 +432,11 @@ const handleGetCommitteeBillCount = async () => {
...
@@ -403,9 +432,11 @@ const handleGetCommitteeBillCount = async () => {
orgId
:
item
.
orgId
,
orgId
:
item
.
orgId
,
name
:
item
.
orgName
,
name
:
item
.
orgName
,
chamber
:
getChamberLabel
(
item
.
orgType
),
chamber
:
getChamberLabel
(
item
.
orgType
),
count
:
Number
(
item
.
count
||
0
)
total
:
Number
(
item
.
total
||
0
),
count
:
Number
(
item
.
count
||
0
),
logoUrl
:
item
.
logoUrl
||
""
}))
}))
.
sort
((
a
,
b
)
=>
(
b
.
count
||
0
)
-
(
a
.
count
||
0
));
.
sort
((
a
,
b
)
=>
(
b
.
total
||
0
)
-
(
a
.
total
||
0
));
committeeTotalCount
.
value
=
mappedList
.
length
;
committeeTotalCount
.
value
=
mappedList
.
length
;
committeeCardList
.
value
=
mappedList
.
slice
(
0
,
3
);
committeeCardList
.
value
=
mappedList
.
slice
(
0
,
3
);
}
else
{
}
else
{
...
@@ -431,6 +462,7 @@ const handleToCommitteeMore = () => {
...
@@ -431,6 +462,7 @@ const handleToCommitteeMore = () => {
const
hotBillList
=
ref
([]);
// 热门法案列表
const
hotBillList
=
ref
([]);
// 热门法案列表
const
carouselRef
=
ref
(
null
);
const
carouselRef
=
ref
(
null
);
const
MAX_DYQK_DISPLAY_COUNT
=
3
;
const
handleCarouselChange
=
index
=>
{
const
handleCarouselChange
=
index
=>
{
if
(
hotBillList
.
value
&&
hotBillList
.
value
.
length
>
0
)
{
if
(
hotBillList
.
value
&&
hotBillList
.
value
.
length
>
0
)
{
...
@@ -438,6 +470,20 @@ const handleCarouselChange = index => {
...
@@ -438,6 +470,20 @@ const handleCarouselChange = index => {
}
}
};
};
const
getLimitedDyqkList
=
dyqkList
=>
{
if
(
!
Array
.
isArray
(
dyqkList
))
return
[];
return
dyqkList
.
slice
(
0
,
MAX_DYQK_DISPLAY_COUNT
);
};
const
getLimitedCommitteeList
=
committeeList
=>
{
if
(
!
Array
.
isArray
(
committeeList
))
return
[];
return
committeeList
.
slice
(
0
,
2
);
};
const
isLastDyqkItem
=
(
dyqkList
,
index
)
=>
{
return
index
===
getLimitedDyqkList
(
dyqkList
).
length
-
1
;
};
// 切换热门法案
// 切换热门法案
const
handleSwithCurBill
=
name
=>
{
const
handleSwithCurBill
=
name
=>
{
if
(
name
===
"left"
)
{
if
(
name
===
"left"
)
{
...
@@ -500,25 +546,17 @@ const handleToMoreNews = () => {
...
@@ -500,25 +546,17 @@ const handleToMoreNews = () => {
// 风险信号
// 风险信号
const
warningList
=
ref
([]);
const
warningList
=
ref
([]);
const
box7selectetedTime
=
ref
(
"2025"
);
const
currentYear
=
new
Date
().
getFullYear
();
const
box7YearList
=
ref
([
const
recentFiveYearOptions
=
Array
.
from
({
length
:
5
},
(
_
,
index
)
=>
{
{
const
year
=
String
(
currentYear
-
index
);
label
:
"2025"
,
return
{
value
:
"2025"
label
:
year
,
},
value
:
year
{
};
label
:
"2024"
,
});
value
:
"2024"
},
const
box7selectetedTime
=
ref
(
String
(
currentYear
));
{
const
box7YearList
=
ref
(
recentFiveYearOptions
);
label
:
"2023"
,
value
:
"2023"
},
{
label
:
"2022"
,
value
:
"2022"
}
]);
const
aiPaneVisible
=
ref
({
const
aiPaneVisible
=
ref
({
box5
:
false
,
box5
:
false
,
...
@@ -684,25 +722,8 @@ const handleHideAiPane = key => {
...
@@ -684,25 +722,8 @@ const handleHideAiPane = key => {
};
};
};
};
const
box8selectetedTime
=
ref
(
"2025"
);
const
box8selectetedTime
=
ref
(
String
(
currentYear
));
const
box8YearList
=
ref
([
const
box8YearList
=
ref
(
recentFiveYearOptions
);
{
label
:
"2025"
,
value
:
"2025"
},
{
label
:
"2024"
,
value
:
"2024"
},
{
label
:
"2023"
,
value
:
"2023"
},
{
label
:
"2022"
,
value
:
"2022"
}
]);
// 涉华法案数量使用的领域分类列表
// 涉华法案数量使用的领域分类列表
const
categoryList
=
ref
([]);
const
categoryList
=
ref
([]);
...
@@ -757,7 +778,7 @@ const handleGetNews = async () => {
...
@@ -757,7 +778,7 @@ const handleGetNews = async () => {
newsList
.
value
=
res
.
data
.
map
(
item
=>
{
newsList
.
value
=
res
.
data
.
map
(
item
=>
{
return
{
return
{
...
item
,
...
item
,
from
:
`
${
item
.
news
Org
}
·
${
item
.
newsDate
?
item
.
newsDate
.
slice
(
5
)
:
""
}
`
from
:
`
${
item
.
news
Date
?
item
.
newsDate
:
""
}
·
${
item
.
newsOrg
||
""
}
`
};
};
});
});
}
else
{
}
else
{
...
@@ -947,50 +968,70 @@ const box7HasData = ref(true);
...
@@ -947,50 +968,70 @@ const box7HasData = ref(true);
const
box7AiData
=
ref
({
inner
:
[],
outer
:
[]
});
const
box7AiData
=
ref
({
inner
:
[],
outer
:
[]
});
const
handleBox7Data
=
async
()
=>
{
const
handleBox7Data
=
async
()
=>
{
chartLoading
.
value
=
{
...
chartLoading
.
value
,
box7
:
true
};
chartLoading
.
value
=
{
...
chartLoading
.
value
,
box7
:
true
};
const
selectParam
=
{
moduleType
:
'国会法案'
,
key
:
3
,
selectedDate
:
box7selectetedTime
.
value
?
JSON
.
stringify
([
box7selectetedTime
.
value
+
'-01-01'
,
box7selectetedTime
.
value
+
'-12-31'
])
:
''
,
isInvolveCn
:
true
}
try
{
try
{
const
res
=
await
getBillPostOrg
({
year
:
box7selectetedTime
.
value
});
const
res
=
await
getBillPostOrg
({
year
:
box7selectetedTime
.
value
});
console
.
log
(
"法案提出部门"
,
res
);
console
.
log
(
"法案提出部门"
,
res
);
const
orgBillNumList
=
res
?.
data
?.
orgBillNumList
||
[];
let
innerData
=
[];
const
orgBillNumMap
=
res
?.
data
?.
orgBillNumMap
||
{};
let
outerData
=
[];
if
(
res
.
code
===
200
&&
Array
.
isArray
(
orgBillNumList
)
&&
orgBillNumList
.
length
>
0
)
{
if
(
Array
.
isArray
(
res
?.
data
))
{
box7HasData
.
value
=
true
;
innerData
=
res
.
data
// 必须等待DOM更新,因为v-if切换可能导致元素刚被创建
.
map
(
item
=>
({
await
nextTick
();
name
:
item
?.
orgName
||
item
?.
orgType
||
""
,
value
:
Number
(
item
?.
count
||
0
)
}))
.
filter
(
item
=>
item
.
name
&&
item
.
value
>
0
);
outerData
=
res
.
data
.
flatMap
(
item
=>
{
const
typeName
=
item
?.
orgName
||
item
?.
orgType
||
""
;
const
list
=
Array
.
isArray
(
item
?.
orgBillNumList
)
?
item
.
orgBillNumList
:
[];
return
list
.
map
(
child
=>
({
name
:
child
?.
orgName
||
""
,
value
:
Number
(
child
?.
count
||
0
),
percent
:
typeof
child
?.
percent
===
"number"
?
child
.
percent
:
Number
(
child
?.
percent
||
0
),
type
:
child
?.
orgType
||
typeName
}))
.
filter
(
child
=>
child
.
name
&&
child
.
value
>
0
);
});
}
else
{
const
orgBillNumList
=
res
?.
data
?.
orgBillNumList
||
[];
const
orgBillNumMap
=
res
?.
data
?.
orgBillNumMap
||
{};
const
data1
=
[];
const
data1
=
[];
const
houseTotal
=
Number
(
orgBillNumMap
?.
House
||
0
);
const
houseTotal
=
Number
(
orgBillNumMap
?.
House
||
0
);
const
senateTotal
=
Number
(
orgBillNumMap
?.
Senate
||
0
);
const
senateTotal
=
Number
(
orgBillNumMap
?.
Senate
||
0
);
if
(
houseTotal
>
0
)
data1
.
push
({
name
:
"众议院"
,
value
:
houseTotal
});
if
(
houseTotal
>
0
)
data1
.
push
({
name
:
"众议院"
,
value
:
houseTotal
});
if
(
senateTotal
>
0
)
data1
.
push
({
name
:
"参议院"
,
value
:
senateTotal
});
if
(
senateTotal
>
0
)
data1
.
push
({
name
:
"参议院"
,
value
:
senateTotal
});
innerData
=
data1
;
const
getOrgTypeLabel
=
orgType
=>
(
orgType
===
"Senate"
?
"参议院"
:
"众议院"
);
outerData
=
orgBillNumList
const
typeOrderMap
=
{
众议院
:
0
,
参议院
:
1
};
const
data2
=
orgBillNumList
.
map
(
item
=>
({
.
map
(
item
=>
({
name
:
item
.
orgName
,
name
:
item
.
orgName
,
value
:
Number
(
item
.
count
||
0
),
value
:
Number
(
item
.
count
||
0
),
percent
:
typeof
item
.
percent
===
"number"
?
item
.
percent
:
Number
(
item
.
percent
||
0
),
percent
:
typeof
item
.
percent
===
"number"
?
item
.
percent
:
Number
(
item
.
percent
||
0
),
type
:
getOrgTypeLabel
(
item
.
orgType
)
type
:
item
.
orgType
===
"Senate"
?
"参议院"
:
"众议院"
}))
}))
// 关键:外环顺序必须按内环(众→参)分组,否则扇区角度会交错导致“不对应”
.
filter
(
item
=>
item
.
name
&&
item
.
value
>
0
);
.
sort
((
a
,
b
)
=>
{
}
const
t1
=
typeOrderMap
[
a
.
type
]
??
99
;
if
(
res
.
code
===
200
&&
innerData
.
length
>
0
&&
outerData
.
length
>
0
)
{
const
t2
=
typeOrderMap
[
b
.
type
]
??
99
;
box7HasData
.
value
=
true
;
if
(
t1
!==
t2
)
return
t1
-
t2
;
// 必须等待DOM更新,因为v-if切换可能导致元素刚被创建
return
(
b
.
value
??
0
)
-
(
a
.
value
??
0
);
await
nextTick
();
});
const
selectParam
=
{
const
typeOrderMap
=
new
Map
(
innerData
.
map
((
item
,
index
)
=>
[
item
.
name
,
index
]));
moduleType
:
'国会法案'
,
const
data2
=
outerData
.
sort
((
a
,
b
)
=>
{
key
:
3
,
const
t1
=
typeOrderMap
.
get
(
a
.
type
)
??
99
;
selectedDate
:
box7selectetedTime
.
value
?
JSON
.
stringify
([
box7selectetedTime
.
value
+
'-01-01'
,
box7selectetedTime
.
value
+
'-12-31'
])
:
''
,
const
t2
=
typeOrderMap
.
get
(
b
.
type
)
??
99
;
isInvolveCn
:
true
if
(
t1
!==
t2
)
return
t1
-
t2
;
}
return
(
b
.
value
??
0
)
-
(
a
.
value
??
0
);
});
const
box7Chart
=
getDoublePieChart
(
data1
,
data2
);
const
box7Chart
=
getDoublePieChart
(
innerData
,
data2
);
setChart
(
box7Chart
,
"box7Chart"
,
true
,
selectParam
);
setChart
(
box7Chart
,
"box7Chart"
,
true
,
selectParam
);
box7AiData
.
value
=
{
inner
:
data1
,
outer
:
data2
};
box7AiData
.
value
=
{
inner
:
innerData
,
outer
:
data2
};
}
else
{
}
else
{
// 接口异常(如500)时,清空图表数据以避免报错或显示错误信息
// 接口异常(如500)时,清空图表数据以避免报错或显示错误信息
box7HasData
.
value
=
false
;
box7HasData
.
value
=
false
;
...
@@ -1009,7 +1050,7 @@ const handleBox7Data = async () => {
...
@@ -1009,7 +1050,7 @@ const handleBox7Data = async () => {
watch
(
box7selectetedTime
,
()
=>
{
watch
(
box7selectetedTime
,
()
=>
{
handleBox7Data
();
handleBox7Data
();
});
});
// 查看
社交媒体
详情
// 查看
人物
详情
const
handleToSocialDetail
=
item
=>
{
const
handleToSocialDetail
=
item
=>
{
const
route
=
router
.
resolve
({
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
path
:
"/characterPage"
,
...
@@ -1057,7 +1098,7 @@ const handleBox6 = async () => {
...
@@ -1057,7 +1098,7 @@ const handleBox6 = async () => {
// 涉华领域分布
// 涉华领域分布
const
box9ChartData
=
ref
([]);
const
box9ChartData
=
ref
([]);
const
box9selectetedTime
=
ref
(
"2025"
);
const
box9selectetedTime
=
ref
(
String
(
currentYear
)
);
// 立法状态下拉:提出法案、众议院通过、参议院通过、解决分歧、呈交总统、完成立法
// 立法状态下拉:提出法案、众议院通过、参议院通过、解决分歧、呈交总统、完成立法
// v-model 存储的是接口需要的 status 值(直接作为接口参数)
// v-model 存储的是接口需要的 status 值(直接作为接口参数)
const
box9LegislativeStatus
=
ref
(
"提出法案"
);
const
box9LegislativeStatus
=
ref
(
"提出法案"
);
...
@@ -1069,28 +1110,7 @@ const box9LegislativeStatusList = ref([
...
@@ -1069,28 +1110,7 @@ const box9LegislativeStatusList = ref([
{
label
:
"呈交总统"
,
value
:
"呈交总统"
},
{
label
:
"呈交总统"
,
value
:
"呈交总统"
},
{
label
:
"完成立法"
,
value
:
"完成立法"
}
{
label
:
"完成立法"
,
value
:
"完成立法"
}
]);
]);
const
box9YearList
=
ref
([
const
box9YearList
=
ref
(
recentFiveYearOptions
);
{
label
:
"2026"
,
value
:
"2026"
},
{
label
:
"2025"
,
value
:
"2025"
},
{
label
:
"2024"
,
value
:
"2024"
},
{
label
:
"2023"
,
value
:
"2023"
},
{
label
:
"2022"
,
value
:
"2022"
}
]);
const
box9HasData
=
ref
(
true
);
const
box9HasData
=
ref
(
true
);
let
box9ChartInstance
=
null
;
let
box9ChartInstance
=
null
;
const
BOX9_MAX_DOMAIN_COUNT
=
7
;
const
BOX9_MAX_DOMAIN_COUNT
=
7
;
...
@@ -1149,7 +1169,7 @@ const handleBox9Data = async () => {
...
@@ -1149,7 +1169,7 @@ const handleBox9Data = async () => {
};
};
}),
}),
null
,
null
,
{
showCount
:
false
}
{
showCount
:
true
,
countUnit
:
"项"
}
);
);
// 记录埋点时,将当前选中的立法状态映射为序号(0-4)
// 记录埋点时,将当前选中的立法状态映射为序号(0-4)
const
selectedIndex
=
box9LegislativeStatusList
.
value
.
findIndex
(
const
selectedIndex
=
box9LegislativeStatusList
.
value
.
findIndex
(
...
@@ -1428,7 +1448,7 @@ const handleResize = () => {
...
@@ -1428,7 +1448,7 @@ const handleResize = () => {
};
};
// 下钻至资源库
// 下钻至资源库
const
handleTo
DataLibrary
=
(
item
)
=>
{
const
handleTo
Institution
=
(
item
)
=>
{
const
orgId
=
item
?.
orgId
||
item
?.
id
;
const
orgId
=
item
?.
orgId
||
item
?.
id
;
if
(
!
orgId
)
return
;
if
(
!
orgId
)
return
;
...
@@ -2076,12 +2096,22 @@ onUnmounted(() => {
...
@@ -2076,12 +2096,22 @@ onUnmounted(() => {
gap
:
8px
;
gap
:
8px
;
}
}
.box1-main-divider
{
margin-top
:
18px
;
margin-bottom
:
18px
;
width
:
468px
;
height
:
1px
;
background
:
var
(
--
bg-black-5
);
}
.box1-main-left-info1
{
.box1-main-left-info1
{
margin-top
:
25px
;
margin-top
:
0
;
margin-left
:
4px
;
margin-left
:
4px
;
.info1-box
{
.info1-box
{
display
:
flex
;
display
:
flex
;
min-height
:
30px
;
align-items
:
flex-start
;
.icon
{
.icon
{
margin-top
:
15px
;
margin-top
:
15px
;
...
@@ -2104,18 +2134,60 @@ onUnmounted(() => {
...
@@ -2104,18 +2134,60 @@ onUnmounted(() => {
.info1-box-right
{
.info1-box-right
{
margin-left
:
40px
;
margin-left
:
40px
;
height
:
30px
;
min-
height
:
30px
;
color
:
var
(
--
text-primary-65-color
);
color
:
var
(
--
text-primary-65-color
);
font-family
:
Microsoft
YaHei
;
font-family
:
Microsoft
YaHei
;
font-size
:
var
(
--
font-size-base
);
font-size
:
var
(
--
font-size-base
);
font-weight
:
400
;
font-weight
:
400
;
line-height
:
30px
;
line-height
:
30px
;
}
}
.info1-box-right--committee
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
gap
:
4px
;
height
:
auto
;
min-height
:
30px
;
line-height
:
22px
;
padding-top
:
4px
;
.committee-item
{
display
:
flex
;
align-items
:
center
;
gap
:
8px
;
min-width
:
0
;
}
.committee-logo
{
width
:
18px
;
height
:
18px
;
min-width
:
18px
;
border-radius
:
50%
;
object-fit
:
cover
;
background
:
var
(
--
bg-black-5
);
}
.committee-name
{
color
:
var
(
--
text-primary-65-color
);
font-family
:
Microsoft
YaHei
;
font-size
:
var
(
--
font-size-base
);
font-weight
:
400
;
line-height
:
22px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
}
}
.box1-main-divider--before-list
{
margin-top
:
18px
;
}
.box1-main-left-info2
{
.box1-main-left-info2
{
margin-top
:
21px
;
margin-top
:
0
;
height
:
200px
;
height
:
200px
;
width
:
440px
;
width
:
440px
;
position
:
relative
;
position
:
relative
;
...
@@ -2216,7 +2288,7 @@ onUnmounted(() => {
...
@@ -2216,7 +2288,7 @@ onUnmounted(() => {
left
:
0
;
left
:
0
;
bottom
:
0
;
bottom
:
0
;
box-sizing
:
border-box
;
box-sizing
:
border-box
;
padding
:
9px
10px
12px
1
0px
;
padding
:
9px
20px
12px
2
0px
;
.inner-box-header
{
.inner-box-header
{
height
:
30px
;
height
:
30px
;
...
...
src/views/bill/billHome/utils/doublePieChart.js
浏览文件 @
f58ff710
...
@@ -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
浏览文件 @
f58ff710
...
@@ -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
浏览文件 @
f58ff710
...
@@ -75,7 +75,7 @@
...
@@ -75,7 +75,7 @@
</div>
</div>
</div>
-->
</div>
-->
</div>
</div>
<div
class=
"main"
v-if=
"curArea !== '实体清单'"
>
<div
class=
"main"
v-if=
"curArea !== '实体清单'"
>
<div
class=
"item"
v-for=
"(item, index) in searchResults"
:key=
"index"
@
click=
"handleToPage(item)"
>
<div
class=
"item"
v-for=
"(item, index) in searchResults"
:key=
"index"
@
click=
"handleToPage(item)"
>
<div
class=
"item-left"
v-if=
"item.img"
>
<div
class=
"item-left"
v-if=
"item.img"
>
<img
:src=
"item?.img"
alt=
""
/>
<img
:src=
"item?.img"
alt=
""
/>
...
@@ -93,7 +93,7 @@
...
@@ -93,7 +93,7 @@
</div>
</div>
<el-empty
v-if=
"!searchResults.length"
></el-empty>
<el-empty
v-if=
"!searchResults.length"
></el-empty>
</div>
</div>
<div
class=
"main1"
v-if=
"curArea === '实体清单'"
>
<div
class=
"main1"
v-if=
"curArea === '实体清单'"
>
<div
class=
"item"
v-for=
"(item, index) in searchResults"
:key=
"index"
@
click=
"handleToPage(item)"
>
<div
class=
"item"
v-for=
"(item, index) in searchResults"
:key=
"index"
@
click=
"handleToPage(item)"
>
<div
class=
"main-header"
>
<div
class=
"main-header"
>
<div
class=
"title"
v-html=
"item?.originalTitle"
></div>
<div
class=
"title"
v-html=
"item?.originalTitle"
></div>
...
@@ -358,9 +358,9 @@ const handleSearch = async (isShowResultTip) => {
...
@@ -358,9 +358,9 @@ const handleSearch = async (isShowResultTip) => {
}
}
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
'error'
,
error
);
console
.
error
(
'error'
,
error
);
}
finally
{
}
finally
{
isLoading
.
value
=
false
isLoading
.
value
=
false
}
}
...
@@ -397,25 +397,44 @@ const handleToPage = async item => {
...
@@ -397,25 +397,44 @@ const handleToPage = async item => {
}
else
if
(
personTypeName
===
"智库研究人员"
)
{
}
else
if
(
personTypeName
===
"智库研究人员"
)
{
type
=
3
;
type
=
3
;
}
else
{
}
else
{
personTypeName
=
""
;
personTypeName
=
"其他类型"
;
ElMessage
.
warning
(
"找不到当前人员的类型值!"
);
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
return
;
return
;
}
}
const
route
=
router
.
resolve
({
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
path
:
"/characterPage"
,
query
:
{
query
:
{
type
:
type
,
// type=1为科技企业领袖,2为国会议员,3为智库研究人员
type
:
type
,
// type=1为科技企业领袖,2为国会议员,3为智库研究人员
personId
:
id
personId
:
i
tem
.
i
d
}
}
});
});
window
.
open
(
route
.
href
,
"_blank"
);
window
.
open
(
route
.
href
,
"_blank"
);
}
else
{
}
else
{
personTypeName
=
""
;
personTypeName
=
""
;
ElMessage
.
warning
(
"找不到当前人员的类型值!"
);
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
return
;
return
;
}
}
}
else
{
}
else
{
ElMessage
.
warning
(
"获取人物全局信息错误"
);
// ElMessage.warning("获取人物全局信息错误");
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
return
;
return
;
}
}
}
catch
(
error
)
{
}
}
catch
(
error
)
{
}
...
@@ -445,7 +464,7 @@ const handleToPage = async item => {
...
@@ -445,7 +464,7 @@ const handleToPage = async item => {
break
;
break
;
case
"智库"
:
case
"智库"
:
curRoute
=
router
.
resolve
({
curRoute
=
router
.
resolve
({
name
:
"
Report
Detail"
,
name
:
"
ThinkTank
Detail"
,
params
:
{
params
:
{
id
:
item
.
id
id
:
item
.
id
}
}
...
@@ -517,36 +536,36 @@ const handleToPage = async item => {
...
@@ -517,36 +536,36 @@ const handleToPage = async item => {
}
}
});
});
break
break
case
"商业管制清单事件"
:
//
case "商业管制清单事件":
curRoute
=
router
.
resolve
({
//
curRoute = router.resolve({
path
:
"/exportControl/singleSanction"
,
//
path: "/exportControl/singleSanction",
query
:
{
//
query: {
id
:
item
.
id
,
//
id: item.id,
sanTypeId
:
2
,
//
sanTypeId: 2,
date
:
item
.
date
//
date: item.date
}
//
}
});
//
});
break
//
break
case
"SDN清单事件"
:
//
case "SDN清单事件":
curRoute
=
router
.
resolve
({
//
curRoute = router.resolve({
path
:
"/exportControl/singleSanction"
,
//
path: "/exportControl/singleSanction",
query
:
{
//
query: {
id
:
item
.
id
,
//
id: item.id,
sanTypeId
:
2
,
//
sanTypeId: 2,
date
:
item
.
date
//
date: item.date
}
//
}
});
//
});
break
//
break
case
"涉军企业清单事件"
:
//
case "涉军企业清单事件":
curRoute
=
router
.
resolve
({
//
curRoute = router.resolve({
path
:
"/exportControl/singleSanction"
,
//
path: "/exportControl/singleSanction",
query
:
{
//
query: {
id
:
item
.
id
,
//
id: item.id,
sanTypeId
:
2
,
//
sanTypeId: 2,
date
:
item
.
date
//
date: item.date
}
//
}
});
//
});
break
//
break
case
"机构"
:
case
"机构"
:
curRoute
=
router
.
resolve
({
curRoute
=
router
.
resolve
({
path
:
"/institution"
,
path
:
"/institution"
,
...
@@ -998,6 +1017,18 @@ const handleCompClick = item => {
...
@@ -998,6 +1017,18 @@ const handleCompClick = item => {
letter-spacing
:
0px
;
letter-spacing
:
0px
;
text-align
:
left
;
text-align
:
left
;
overflow
:
hidden
;
overflow
:
hidden
;
/* 2. 关键属性:将元素转为弹性盒模型 */
display
:
-
webkit-box
;
/* 3. 限制显示的行数(修改数字即可改变行数) */
-webkit-line-clamp
:
2
;
/* 4. 设置文字垂直排列方向 */
-webkit-box-orient
:
vertical
;
/* 5. 隐藏超出部分 */
overflow
:
hidden
;
/* 6. 显示省略号 */
text-overflow
:
ellipsis
;
/* 可选:修复文字间距/换行问题 */
word-break
:
break-all
;
}
}
.item-right-footer
{
.item-right-footer
{
...
@@ -1164,7 +1195,7 @@ const handleCompClick = item => {
...
@@ -1164,7 +1195,7 @@ const handleCompClick = item => {
.content
{
.content
{
margin-top
:
10px
;
margin-top
:
10px
;
min-height
:
0
;
min-height
:
0
;
//
max-height: 48px;
max-height
:
48px
;
font-family
:
Microsoft
YaHei
;
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-size
:
16px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
...
@@ -1173,6 +1204,18 @@ const handleCompClick = item => {
...
@@ -1173,6 +1204,18 @@ const handleCompClick = item => {
letter-spacing
:
0px
;
letter-spacing
:
0px
;
text-align
:
left
;
text-align
:
left
;
overflow
:
hidden
;
overflow
:
hidden
;
/* 2. 关键属性:将元素转为弹性盒模型 */
display
:
-
webkit-box
;
/* 3. 限制显示的行数(修改数字即可改变行数) */
-webkit-line-clamp
:
2
;
/* 4. 设置文字垂直排列方向 */
-webkit-box-orient
:
vertical
;
/* 5. 隐藏超出部分 */
overflow
:
hidden
;
/* 6. 显示省略号 */
text-overflow
:
ellipsis
;
/* 可选:修复文字间距/换行问题 */
word-break
:
break-all
;
}
}
.time
{
.time
{
...
...
src/views/dataLibrary/components/BarChart/barChart.js
浏览文件 @
f58ff710
...
@@ -12,6 +12,10 @@ const getBarChart = (data) => {
...
@@ -12,6 +12,10 @@ const getBarChart = (data) => {
},
},
yAxis
:
{
yAxis
:
{
type
:
'value'
,
type
:
'value'
,
name
:
'数量'
,
nameTextStyle
:
{
padding
:
[
-
10
,
0
,
0
,
-
40
]
// [上, 右, 下, 左],向左移动10px
},
splitLine
:
{
splitLine
:
{
show
:
true
,
show
:
true
,
lineStyle
:
{
lineStyle
:
{
...
...
src/views/dataLibrary/components/LineChart/lineChart.js
浏览文件 @
f58ff710
...
@@ -24,6 +24,9 @@ const getLineChart = (dataX, dataY) => {
...
@@ -24,6 +24,9 @@ const getLineChart = (dataX, dataY) => {
yAxis
:
{
yAxis
:
{
type
:
'value'
,
type
:
'value'
,
name
:
'数量'
,
name
:
'数量'
,
nameTextStyle
:
{
padding
:
[
-
10
,
0
,
0
,
-
40
]
// [上, 右, 下, 左],向左移动10px
},
splitLine
:
{
splitLine
:
{
show
:
true
,
show
:
true
,
lineStyle
:
{
lineStyle
:
{
...
...
src/views/dataLibrary/financeControl/mREList/index.vue
浏览文件 @
f58ff710
...
@@ -199,7 +199,7 @@ const staticsDemensionList = ref([
...
@@ -199,7 +199,7 @@ const staticsDemensionList = ref([
name
:
'制裁时间'
,
name
:
'制裁时间'
,
active
:
true
,
active
:
true
,
chartTypeList
:
[
'折线图'
,
'柱状图'
],
chartTypeList
:
[
'折线图'
,
'柱状图'
],
chartTitle
:
'
商业管制
清单制裁时间变化趋势'
,
chartTitle
:
'
涉军企业
清单制裁时间变化趋势'
,
data
:
{
data
:
{
dataX
:
[],
dataX
:
[],
dataY
:
[]
dataY
:
[]
...
@@ -217,14 +217,14 @@ const staticsDemensionList = ref([
...
@@ -217,14 +217,14 @@ const staticsDemensionList = ref([
name
:
'科技领域'
,
name
:
'科技领域'
,
active
:
false
,
active
:
false
,
chartTypeList
:
[
'饼状图'
],
chartTypeList
:
[
'饼状图'
],
chartTitle
:
'
商业管制
清单科技领域分布'
,
chartTitle
:
'
涉军企业
清单科技领域分布'
,
data
:
[]
data
:
[]
}
,
}
,
{
{
name
:
'物项类别'
,
name
:
'物项类别'
,
active
:
false
,
active
:
false
,
chartTypeList
:
[
'饼状图'
],
chartTypeList
:
[
'饼状图'
],
chartTitle
:
'
商业管制
清单物项类别分布'
,
chartTitle
:
'
涉军企业
清单物项类别分布'
,
data
:
[]
data
:
[]
}
}
...
@@ -908,13 +908,13 @@ const initParam = () => {
...
@@ -908,13 +908,13 @@ const initParam = () => {
}
}
// 跳转
政令
详情
// 跳转
企业
详情
const
handleClickToDetail
=
(
curEntity
)
=>
{
const
handleClickToDetail
=
(
curEntity
)
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
curEntity
.
title
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
curEntity
.
title
);
const
route
=
router
.
resolve
({
const
route
=
router
.
resolve
({
name
:
"companyPages"
,
name
:
"companyPages"
,
params
:
{
params
:
{
id
:
curEntity
.
i
d
id
:
curEntity
.
organizationI
d
}
}
}
);
}
);
window
.
open
(
route
.
href
,
"_blank"
);
window
.
open
(
route
.
href
,
"_blank"
);
...
...
src/views/dataLibrary/financeControl/sDNList/index.vue
浏览文件 @
f58ff710
...
@@ -234,7 +234,7 @@ const staticsDemensionList = ref([
...
@@ -234,7 +234,7 @@ const staticsDemensionList = ref([
name
:
'制裁时间'
,
name
:
'制裁时间'
,
active
:
true
,
active
:
true
,
chartTypeList
:
[
'折线图'
,
'柱状图'
],
chartTypeList
:
[
'折线图'
,
'柱状图'
],
chartTitle
:
'
实体
清单制裁时间变化趋势'
,
chartTitle
:
'
SDN
清单制裁时间变化趋势'
,
data
:
{
data
:
{
dataX
:
[],
dataX
:
[],
dataY
:
[]
dataY
:
[]
...
@@ -252,28 +252,28 @@ const staticsDemensionList = ref([
...
@@ -252,28 +252,28 @@ const staticsDemensionList = ref([
name
:
'科技领域'
,
name
:
'科技领域'
,
active
:
false
,
active
:
false
,
chartTypeList
:
[
'饼状图'
],
chartTypeList
:
[
'饼状图'
],
chartTitle
:
'
实体
清单科技领域分布'
,
chartTitle
:
'
SDN
清单科技领域分布'
,
data
:
[]
data
:
[]
}
,
}
,
{
{
name
:
'
实体
类型'
,
name
:
'
SDN
类型'
,
active
:
false
,
active
:
false
,
chartTypeList
:
[
'饼状图'
],
chartTypeList
:
[
'饼状图'
],
chartTitle
:
'
实体
类型分布'
,
chartTitle
:
'
SDN
类型分布'
,
data
:
[]
data
:
[]
}
,
}
,
{
{
name
:
'
实体
国家地区'
,
name
:
'
SDN
国家地区'
,
active
:
false
,
active
:
false
,
chartTypeList
:
[
'饼状图'
],
chartTypeList
:
[
'饼状图'
],
chartTitle
:
'
实体
国家地区分布'
,
chartTitle
:
'
SDN
国家地区分布'
,
data
:
[]
data
:
[]
}
,
}
,
{
{
name
:
'
实体
省份'
,
name
:
'
SDN
省份'
,
active
:
false
,
active
:
false
,
chartTypeList
:
[
'饼状图'
],
chartTypeList
:
[
'饼状图'
],
chartTitle
:
'
实体
省份分布'
,
chartTitle
:
'
SDN
省份分布'
,
data
:
[]
data
:
[]
}
}
])
])
...
...
src/views/exportControl/components/info.vue
浏览文件 @
f58ff710
...
@@ -157,6 +157,11 @@ const desMap = {
...
@@ -157,6 +157,11 @@ const desMap = {
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
align-items
:
flex-end
;
align-items
:
flex-end
;
&
:hover
{
text-decoration
:
underline
;
background
:
var
(
--
color-primary-2
);
}
.quantity-title-des
{
.quantity-title-des
{
display
:
flex
;
display
:
flex
;
...
...
src/views/exportControl/index.vue
浏览文件 @
f58ff710
...
@@ -3,25 +3,12 @@
...
@@ -3,25 +3,12 @@
<div
class=
"home-main"
ref=
"homeMainRef"
>
<div
class=
"home-main"
ref=
"homeMainRef"
>
<div
class=
"home-top-bg"
></div>
<div
class=
"home-top-bg"
></div>
<div
class=
"home-main-header"
>
<div
class=
"home-main-header"
>
<SearchContainer
<SearchContainer
style=
"margin-bottom: 0; margin-top: 48px; height: fit-content"
v-if=
"homeMainRef"
style=
"margin-bottom: 0; margin-top: 48px; height: fit-content"
placeholder=
"搜索出口管制"
:containerRef=
"homeMainRef"
areaName=
"实体清单"
/>
v-if=
"homeMainRef"
placeholder=
"搜索出口管制"
:containerRef=
"homeMainRef"
areaName=
"实体清单"
/>
<div
class=
"home-main-header-footer-info"
>
<div
class=
"home-main-header-footer-info"
>
<InfoCard
<InfoCard
v-for=
"(item, index) in infoList"
:key=
"item.id"
:title=
"item.nameZh"
:subtitle=
"item.nameAbbr"
v-for=
"(item, index) in infoList"
:description=
"item.description"
:quantity=
"item.postCount"
:unit=
"item.unit"
:color=
"infoListColor[index]"
:key=
"item.id"
@
click=
"handleToEntityListNoId(item)"
/>
:title=
"item.nameZh"
:subtitle=
"item.nameAbbr"
:description=
"item.description"
:quantity=
"item.postCount"
:unit=
"item.unit"
:color=
"infoListColor[index]"
@
click=
"handleToEntityListNoId(item)"
/>
</div>
</div>
</div>
</div>
...
@@ -50,7 +37,7 @@
...
@@ -50,7 +37,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 +46,7 @@
...
@@ -59,9 +46,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 +58,7 @@
...
@@ -73,13 +58,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"
...
@@ -92,18 +71,10 @@
...
@@ -92,18 +71,10 @@
<div
class=
"box1-bottom-sanTypeId"
v-if=
"item.sanEntities?.length"
>
<div
class=
"box1-bottom-sanTypeId"
v-if=
"item.sanEntities?.length"
>
<div
class=
"box1-bottom-title"
>
· 涉及主要实体:
</div>
<div
class=
"box1-bottom-title"
>
· 涉及主要实体:
</div>
<div
class=
"box1-bottom-content"
>
<div
class=
"box1-bottom-content"
>
<div
<div
class=
"box1-bottom-content-item"
v-for=
"(ett, index) in item.sanEntities"
:key=
"index"
class=
"box1-bottom-content-item"
@
click=
"handleEntityClick(ett)"
>
v-for=
"(ett, index) in item.sanEntities"
<el-image
v-if=
"ett.img"
class=
"box1-bottom-content-item-img"
:src=
"ett.img"
:key=
"index"
alt=
""
></el-image>
@
click=
"handleEntityClick(ett)"
>
<el-image
v-if=
"ett.img"
class=
"box1-bottom-content-item-img"
:src=
"ett.img"
alt=
""
></el-image>
<div
v-else
class=
"box1-bottom-content-item-imgUndefined"
>
<div
v-else
class=
"box1-bottom-content-item-imgUndefined"
>
{{
{{
(
ett
.
orgName
||
ett
.
orgNameZh
)?.
match
(
(
ett
.
orgName
||
ett
.
orgNameZh
)?.
match
(
...
@@ -120,12 +91,8 @@
...
@@ -120,12 +91,8 @@
<div
class=
"box1-bottom-sanTypeId"
v-if=
"item.sanItems?.length > 0"
>
<div
class=
"box1-bottom-sanTypeId"
v-if=
"item.sanItems?.length > 0"
>
<div
class=
"box1-bottom-title"
>
· 涉及管制物项:
</div>
<div
class=
"box1-bottom-title"
>
· 涉及管制物项:
</div>
<div
class=
"box1-bottom-content__wx"
>
<div
class=
"box1-bottom-content__wx"
>
<div
<div
class=
"box1-bottom-content__wx-item"
v-for=
"(ett, index) in item.sanItems"
:key=
"index"
class=
"box1-bottom-content__wx-item"
@
click=
"handleWxClick(item)"
>
v-for=
"(ett, index) in item.sanItems"
:key=
"index"
@
click=
"handleWxClick(item)"
>
<div
class=
"box1-bottom-content__wx-item-id"
>
<div
class=
"box1-bottom-content__wx-item-id"
>
{{
ett
.
id
}}
{{
ett
.
id
}}
</div>
</div>
...
@@ -146,7 +113,7 @@
...
@@ -146,7 +113,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>
...
@@ -199,14 +166,8 @@
...
@@ -199,14 +166,8 @@
</div>
</div>
</template>
</template>
</custom-container> -->
</custom-container> -->
<RiskSignal
<RiskSignal
:list=
"warningList"
@
item-click=
"handleToRiskSignalDetail"
@
more-click=
"handleToMoreRiskSignal"
:list=
"warningList"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
/>
@
item-click=
"handleToRiskSignalDetail"
@
more-click=
"handleToMoreRiskSignal"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
/>
</el-col>
</el-col>
</el-row>
</el-row>
...
@@ -229,19 +190,11 @@
...
@@ -229,19 +190,11 @@
</custom-container>
</custom-container>
</el-col> -->
</el-col> -->
<div
class=
"center-center"
>
<div
class=
"center-center"
>
<NewsList
<NewsList
:newsList=
"newsList"
@
item-click=
"handleNewsInfoClick"
@
more-click=
"handleToMoreNews"
:newsList=
"newsList"
content=
"newsContent"
/>
@
item-click=
"handleNewsInfoClick"
@
more-click=
"handleToMoreNews"
<MessageBubble
:messageList=
"socialMediaList"
@
person-click=
"handlePerClick"
imageUrl=
"avatar"
content=
"newsContent"
@
more-click=
"handleToSocialDetail"
/>
/>
<MessageBubble
:messageList=
"socialMediaList"
@
person-click=
"handlePerClick"
imageUrl=
"avatar"
@
more-click=
"handleToSocialDetail"
/>
<!-- <custom-container title="社交媒体" :titleIcon="dialogIcon" height="450px">
<!-- <custom-container title="社交媒体" :titleIcon="dialogIcon" height="450px">
<template #default>
<template #default>
<div class="dialog-list">
<div class="dialog-list">
...
@@ -261,30 +214,20 @@
...
@@ -261,30 +214,20 @@
<div
class=
"box3"
>
<div
class=
"box3"
>
<div
class=
"box3-content"
>
<div
class=
"box3-content"
>
<div
class=
"box3-content-title"
>
实体清单发布频次统计
</div>
<div
class=
"box3-content-title"
>
实体清单发布频次统计
</div>
<el-table
<el-table
:data=
"entityListReleaseFreq"
stripe
style=
"width: 100%"
@
row-click=
"handleEntityRowClick"
>
:data=
"entityListReleaseFreq"
stripe
style=
"width: 100%"
@
row-click=
"handleEntityRowClick"
>
<el-table-column
prop=
"year"
label=
"年份"
width=
"200"
/>
<el-table-column
prop=
"year"
label=
"年份"
width=
"200"
/>
<el-table-column
label=
"发布次数"
width=
"300"
>
<el-table-column
label=
"发布次数"
width=
"300"
>
<template
#
default=
"scope"
>
<template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:percentage=
"scope.row.percent * 100"
:status=
"getStatus(scope.row.percent)"
/>
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"重点领域"
width=
"220"
align=
"center"
>
<el-table-column
label=
"重点领域"
width=
"220"
align=
"center"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
<div
style=
"display: flex; justify-content: center; align-items: center; gap: 5px"
>
style=
"display: flex; justify-content: center; align-items: center; gap: 5px"
>
<AreaTag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:tagName=
"tag"
/>
<AreaTag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:tagName=
"tag"
/>
<!--
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"getTagType(tag)"
>
{{
<!--
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"getTagType(tag)"
>
{{
tag
tag
...
@@ -306,30 +249,21 @@
...
@@ -306,30 +249,21 @@
</div>
</div>
<div
class=
"box3-content"
>
<div
class=
"box3-content"
>
<div
class=
"box3-content-title"
>
商业管制清单发布频次统计
</div>
<div
class=
"box3-content-title"
>
商业管制清单发布频次统计
</div>
<el-table
<el-table
:data=
"commerceControlListReleaseFreq"
stripe
style=
"width: 100%"
:data=
"commerceControlListReleaseFreq"
@
row-click=
"handleCommercialRowClick"
>
stripe
style=
"width: 100%"
@
row-click=
"handleCommercialRowClick"
>
<el-table-column
prop=
"year"
label=
"年份"
width=
"200"
/>
<el-table-column
prop=
"year"
label=
"年份"
width=
"200"
/>
<el-table-column
label=
"发布次数"
width=
"300"
>
<el-table-column
label=
"发布次数"
width=
"300"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:percentage=
"scope.row.percent * 100"
:status=
"getStatus(scope.row.percent)"
/>
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"重点领域"
width=
"220"
align=
"center"
>
<el-table-column
label=
"重点领域"
width=
"220"
align=
"center"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
<div
style=
"display: flex; justify-content: center; align-items: center; gap: 5px"
>
style=
"display: flex; justify-content: center; align-items: center; gap: 5px"
>
<AreaTag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:tagName=
"tag"
/>
<AreaTag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:tagName=
"tag"
/>
<!--
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"getTagType(tag)"
>
{{
<!--
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"getTagType(tag)"
>
{{
tag
tag
...
@@ -359,11 +293,8 @@
...
@@ -359,11 +293,8 @@
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:percentage=
"scope.row.percent * 100"
:status=
"getStatus(scope.row.percent)"
/>
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
...
@@ -391,12 +322,8 @@
...
@@ -391,12 +322,8 @@
<el-checkbox
v-model=
"domainChecked"
label=
"50%规则"
size=
"large"
/>
<el-checkbox
v-model=
"domainChecked"
label=
"50%规则"
size=
"large"
/>
</
template
>
</
template
>
<
template
#
default
>
<
template
#
default
>
<EChart
<EChart
:option=
"radarOption"
autoresize
:style=
"
{ height: '420px' }"
:option=
"radarOption"
@chart-click="handleRadarChartClick" />
autoresize
:style=
"
{ height: '420px' }"
@chart-click="handleRadarChartClick"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
<img
:src=
"tipsIcon"
alt=
""
/>
...
@@ -414,24 +341,15 @@
...
@@ -414,24 +341,15 @@
<custom-container
title=
"制裁清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"540px"
>
<custom-container
title=
"制裁清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"540px"
>
<
template
#
header-right
>
<
template
#
header-right
>
<div
style=
"display: flex; align-items: center; gap: 16px"
>
<div
style=
"display: flex; align-items: center; gap: 16px"
>
<el-checkbox
<el-checkbox
v-if=
"selectedEntityId != '13'"
v-model=
"trendChecked"
label=
"50%规则"
size=
"large"
/>
v-if=
"selectedEntityId != '13'"
v-model=
"trendChecked"
label=
"50%规则"
size=
"large"
/>
<el-select
v-model=
"selectedEntityId"
placeholder=
"请选择清单类型"
style=
"width: 160px"
>
<el-select
v-model=
"selectedEntityId"
placeholder=
"请选择清单类型"
style=
"width: 160px"
>
<el-option
v-for=
"item in infoList"
:key=
"item.id"
:label=
"item.nameZh"
:value=
"item.id"
/>
<el-option
v-for=
"item in infoList"
:key=
"item.id"
:label=
"item.nameZh"
:value=
"item.id"
/>
</el-select>
</el-select>
</div>
</div>
</
template
>
</
template
>
<
template
#
default
>
<
template
#
default
>
<EChart
<EChart
:option=
"trendOption"
autoresize
:style=
"
{ height: '420px' }"
:option=
"trendOption"
@chart-click="handleMultiBarChartClick" />
autoresize
:style=
"
{ height: '420px' }"
@chart-click="handleMultiBarChartClick"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
<img
:src=
"tipsIcon"
alt=
""
/>
...
@@ -450,13 +368,9 @@
...
@@ -450,13 +368,9 @@
<el-row
:gutter=
"16"
style=
"width: 1600px; margin: 0 auto; margin-top: 39px; padding-bottom: 60px"
>
<el-row
:gutter=
"16"
style=
"width: 1600px; margin: 0 auto; margin-top: 39px; padding-bottom: 60px"
>
<CustomTitle
id=
"position4"
title=
"资源库"
style=
"margin-top: 0px"
/>
<CustomTitle
id=
"position4"
title=
"资源库"
style=
"margin-top: 0px"
/>
<div
class=
"resource-tabs"
>
<div
class=
"resource-tabs"
>
<div
<div
v-for=
"tab in resourceTabs"
:key=
"tab.value"
class=
"resource-tab-item"
v-for=
"tab in resourceTabs"
:key=
"tab.value"
class=
"resource-tab-item"
:class=
"{ active: activeResourceTab == tab.value, disabled: tab.disabled }"
:class=
"{ active: activeResourceTab == tab.value, disabled: tab.disabled }"
@
click=
"handleResourceTabClick(tab)"
@
click=
"handleResourceTabClick(tab)"
>
>
{{ tab.label }}
{{ tab.label }}
</div>
</div>
</div>
</div>
...
@@ -469,25 +383,15 @@
...
@@ -469,25 +383,15 @@
<div
class=
"box4-item"
v-for=
"(item, idx) in sanctionProcessList"
:key=
"item.title"
>
<div
class=
"box4-item"
v-for=
"(item, idx) in sanctionProcessList"
:key=
"item.title"
>
<div
class=
"box4-item-left"
>
<div
class=
"box4-item-left"
>
<el-image
:src=
"dotIcon"
alt=
"图片"
class=
"box4-item-left-icon"
/>
<el-image
:src=
"dotIcon"
alt=
"图片"
class=
"box4-item-left-icon"
/>
<div
<div
class=
"box4-item-left-line"
v-if=
"idx + 1 != sanctionProcessList.length"
></div>
class=
"box4-item-left-line"
v-if=
"idx + 1 != sanctionProcessList.length"
></div>
</div>
</div>
<div
class=
"box4-item-right"
>
<div
class=
"box4-item-right"
>
<div
class=
"box4-item-right-header"
@
click=
"handleSanc(item)"
>
<div
class=
"box4-item-right-header"
@
click=
"handleSanc(item)"
>
<span
class=
"box4-item-right-header-title"
<span
class=
"box4-item-right-header-title"
>
{{
item
.
postDate
}}
—
{{
item
.
title
}}
</span>
>
{{
item
.
postDate
}}
—
{{
item
.
title
}}
</span
>
<span
class=
"box4-item-right-header-desc"
>
{{
item
.
desc
}}
</span>
<span
class=
"box4-item-right-header-desc"
>
{{
item
.
desc
}}
</span>
</div>
</div>
<el-tooltip
<el-tooltip
effect=
"dark"
:content=
"item.content"
popper-class=
"common-prompt-popper"
effect=
"dark"
placement=
"top"
:show-after=
"500"
>
:content=
"item.content"
popper-class=
"common-prompt-popper"
placement=
"top"
:show-after=
"500"
>
<div
class=
"box4-item-right-content"
>
<div
class=
"box4-item-right-content"
>
{{
item
.
content
}}
{{
item
.
content
}}
</div>
</div>
...
@@ -495,12 +399,8 @@
...
@@ -495,12 +399,8 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div
<div
class=
"box4-footer"
:style=
"
{ marginTop: sanctionProcessList.length > 0 ? '0px' : 'auto' }">
class=
"box4-footer"
<el-button
type=
"primary"
link
@
click=
"handleGetMore"
>
查看更多
:style=
"
{ marginTop: sanctionProcessList.length > 0 ? '0px' : 'auto' }"
>
<el-button
type=
"primary"
link
@
click=
"handleGetMore"
>
查看更多
<el-icon>
<el-icon>
<DArrowRight
/>
<DArrowRight
/>
</el-icon>
</el-icon>
...
@@ -517,24 +417,13 @@
...
@@ -517,24 +417,13 @@
</
template
>
</
template
>
<
template
#
default
>
<
template
#
default
>
<div
class=
"box5"
>
<div
class=
"box5"
>
<el-table
<el-table
:data=
"entitiesList"
class=
"sanction-table"
stripe
empty-text=
"暂无数据"
height=
"700px"
:data=
"entitiesList"
header-row-class-name=
"table-header"
row-class-name=
"table-row"
>
class=
"sanction-table"
stripe
empty-text=
"暂无数据"
height=
"700px"
header-row-class-name=
"table-header"
row-class-name=
"table-row"
>
<el-table-column
prop=
"name"
label=
"实体名称"
min-width=
"200"
>
<el-table-column
prop=
"name"
label=
"实体名称"
min-width=
"200"
>
<template
#
default=
"scope"
>
<template
#
default=
"scope"
>
<div
class=
"tableName"
@
click=
"handleCompClick(scope.row)"
>
<div
class=
"tableName"
@
click=
"handleCompClick(scope.row)"
>
<el-image
<el-image
v-if=
"scope.row.img"
class=
"box1-bottom-content-item-img"
:src=
"scope.row.img"
v-if=
"scope.row.img"
alt=
""
></el-image>
class=
"box1-bottom-content-item-img"
:src=
"scope.row.img"
alt=
""
></el-image>
<div
v-else
class=
"box1-bottom-content-item-imgUndefined"
>
<div
v-else
class=
"box1-bottom-content-item-imgUndefined"
>
{{
{{
(
scope
.
row
.
name
||
scope
.
row
.
enName
)?.
match
(
(
scope
.
row
.
name
||
scope
.
row
.
enName
)?.
match
(
...
@@ -588,19 +477,13 @@
...
@@ -588,19 +477,13 @@
<el-table-column
prop=
"revenue"
label=
"50%规则子企业"
width=
"280"
align=
"right"
>
<el-table-column
prop=
"revenue"
label=
"50%规则子企业"
width=
"280"
align=
"right"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
class=
"num-item"
v-if=
"scope.row.ruleOrgCount > 0"
>
<div
class=
"num-item"
v-if=
"scope.row.ruleOrgCount > 0"
>
<div
<div
class=
"name-item"
:class=
"[
class=
"name-item"
'revenue-cell',
:class=
"[
scope.row.revenue === '无营收数据' ? 'no-revenue' : ''
'revenue-cell',
]"
>
scope.row.revenue === '无营收数据' ? 'no-revenue' : ''
]"
>
{{
scope
.
row
.
ruleOrgList
[
0
].
orgName
}}
...等
{{
scope
.
row
.
ruleOrgList
[
0
].
orgName
}}
...等
</div>
</div>
<div
<div
style=
"width: 50px; color: #409eff; cursor: pointer"
@
click=
"handleOrgClick(scope.row)"
>
style=
"width: 50px; color: #409eff; cursor: pointer"
@
click=
"handleOrgClick(scope.row)"
>
{{
scope
.
row
.
ruleOrgCount
}}
家>
{{
scope
.
row
.
ruleOrgCount
}}
家>
</div>
</div>
</div>
</div>
...
@@ -612,15 +495,8 @@
...
@@ -612,15 +495,8 @@
<!-- <div class="pagination-info">
<!-- <div class="pagination-info">
第{{ currentPage }}页,共{{ totalPages }}页
第{{ currentPage }}页,共{{ totalPages }}页
</div> -->
</div> -->
<el-pagination
<el-pagination
v-model:current-page=
"currentPage"
:page-size=
"pageSize"
:total=
"total"
v-model:current-page=
"currentPage"
:pager-count=
"5"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChange"
/>
:page-size=
"pageSize"
:total=
"total"
:pager-count=
"5"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChange"
/>
</div>
</div>
</div>
</div>
</template>
</template>
...
@@ -686,14 +562,8 @@
...
@@ -686,14 +562,8 @@
</div>
</div>
<div
class=
"right-footer"
>
<div
class=
"right-footer"
>
<div
class=
"total-count"
>
共
{{
totalAll
}}
项
</div>
<div
class=
"total-count"
>
共
{{
totalAll
}}
项
</div>
<el-pagination
<el-pagination
v-model:current-page=
"currentPageAll"
:page-size=
"pageSizeAll"
:total=
"totalAll"
v-model:current-page=
"currentPageAll"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChangeAll"
/>
:page-size=
"pageSizeAll"
:total=
"totalAll"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChangeAll"
/>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -706,12 +576,8 @@
...
@@ -706,12 +576,8 @@
</
template
>
</
template
>
</el-row>
</el-row>
</div>
</div>
<RuleSubsidiaryDialog
<RuleSubsidiaryDialog
v-model=
"dialogVisible"
:company-name=
"currentRuleCompany"
:total-count=
"currentRuleCount"
v-model=
"dialogVisible"
:data-list=
"currentOrgList"
/>
:company-name=
"currentRuleCompany"
:total-count=
"currentRuleCount"
:data-list=
"currentOrgList"
/>
</div>
</div>
<el-dialog
v-model=
"mediaVisible"
title=
"社交媒体信息"
width=
"500"
:before-close=
"handleMediaClose"
>
<el-dialog
v-model=
"mediaVisible"
title=
"社交媒体信息"
width=
"500"
:before-close=
"handleMediaClose"
>
<div
class=
"dialog-content"
>
<div
class=
"dialog-content"
>
...
@@ -724,13 +590,8 @@
...
@@ -724,13 +590,8 @@
</div>
</div>
</
template
>
</
template
>
</el-dialog>
</el-dialog>
<RiskSignalOverviewDetailDialog
<RiskSignalOverviewDetailDialog
v-model=
"isRiskOverviewDetailOpen"
:row=
"riskOverviewDetailRow"
v-model=
"isRiskOverviewDetailOpen"
name-field=
"signalTitle"
post-date-field=
"signalTime"
risk-level-field=
"signalLevel"
/>
:row=
"riskOverviewDetailRow"
name-field=
"signalTitle"
post-date-field=
"signalTime"
risk-level-field=
"signalLevel"
/>
</template>
</template>
<
script
setup
>
<
script
setup
>
...
@@ -1457,7 +1318,7 @@ const fetchSanctionList = async () => {
...
@@ -1457,7 +1318,7 @@ const fetchSanctionList = async () => {
});
});
totalAll
.
value
=
res
.
totalElements
;
totalAll
.
value
=
res
.
totalElements
;
}
}
}
catch
(
error
)
{}
}
catch
(
error
)
{
}
};
};
const
handlePageChangeAll
=
val
=>
{
const
handlePageChangeAll
=
val
=>
{
...
@@ -1751,7 +1612,7 @@ const handleGetHylyList = async () => {
...
@@ -1751,7 +1612,7 @@ const handleGetHylyList = async () => {
hylymc
:
"全部分类"
hylymc
:
"全部分类"
};
};
categoryList
.
value
=
[
obj
,
...
categoryList
.
value
];
categoryList
.
value
=
[
obj
,
...
categoryList
.
value
];
}
catch
(
error
)
{}
}
catch
(
error
)
{
}
};
};
const
chart1Data
=
ref
({
const
chart1Data
=
ref
({
...
@@ -1961,11 +1822,12 @@ const handleMediaClick = item => {
...
@@ -1961,11 +1822,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 +1851,7 @@ const handleMediaClick = item => {
...
@@ -1989,7 +1851,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
;
...
@@ -2024,6 +1886,7 @@ const handleMediaClick = item => {
...
@@ -2024,6 +1886,7 @@ const handleMediaClick = item => {
box-sizing
:
border-box
;
box-sizing
:
border-box
;
background
:
linear-gradient
(
to
right
,
rgba
(
206
,
79
,
81
,
0
)
,
rgba
(
206
,
79
,
81
,
0
.3
));
background
:
linear-gradient
(
to
right
,
rgba
(
206
,
79
,
81
,
0
)
,
rgba
(
206
,
79
,
81
,
0
.3
));
cursor
:
pointer
;
cursor
:
pointer
;
&
-des
{
&
-des
{
display
:
flex
;
display
:
flex
;
gap
:
5px
;
gap
:
5px
;
...
@@ -2053,6 +1916,10 @@ const handleMediaClick = item => {
...
@@ -2053,6 +1916,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 +1946,7 @@ const handleMediaClick = item => {
...
@@ -2079,7 +1946,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
;
...
@@ -2095,18 +1962,21 @@ const handleMediaClick = item => {
...
@@ -2095,18 +1962,21 @@ const handleMediaClick = item => {
padding-left
:
10px
;
padding-left
:
10px
;
height
:
156px
;
height
:
156px
;
overflow
:
auto
;
overflow
:
auto
;
&
-item
{
&
-item
{
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
flex-start
;
justify-content
:
flex-start
;
gap
:
10px
;
gap
:
10px
;
cursor
:
pointer
;
cursor
:
pointer
;
&
-id
{
&
-id
{
font-family
:
"Source Han Sans CN"
;
font-family
:
"Source Han Sans CN"
;
font-size
:
16px
;
font-size
:
16px
;
font-weight
:
700
;
font-weight
:
700
;
color
:
rgb
(
95
,
101
,
108
);
color
:
rgb
(
95
,
101
,
108
);
}
}
&
-txt
{
&
-txt
{
font-size
:
16px
;
font-size
:
16px
;
font-weight
:
400
;
font-weight
:
400
;
...
@@ -2115,6 +1985,7 @@ const handleMediaClick = item => {
...
@@ -2115,6 +1985,7 @@ const handleMediaClick = item => {
}
}
}
}
}
}
&
-content
{
&
-content
{
display
:
flex
;
display
:
flex
;
gap
:
15px
;
gap
:
15px
;
...
@@ -2347,6 +2218,7 @@ const handleMediaClick = item => {
...
@@ -2347,6 +2218,7 @@ const handleMediaClick = item => {
}
}
.box3-content
{
.box3-content
{
// flex: 1;
// flex: 1;
.el-progress--line
{
.el-progress--line
{
width
:
82px
;
width
:
82px
;
...
...
src/views/finance/index.vue
浏览文件 @
f58ff710
...
@@ -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
浏览文件 @
f58ff710
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
浏览文件 @
f58ff710
// 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
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论