权限调整
This commit is contained in:
parent
3c24350bed
commit
a78808ffa5
@ -1,4 +1,5 @@
|
||||
import request from '@/config/axios'
|
||||
import { createAccessToken } from '@/api/system/oauth2/token'
|
||||
|
||||
/** 风险分布数据项 */
|
||||
export interface RiskDistributionVO {
|
||||
@ -57,15 +58,68 @@ export interface FocusPersonPageReqVO {
|
||||
areaId?: number
|
||||
}
|
||||
|
||||
// Token 缓存
|
||||
let cachedToken: string | null = null
|
||||
let tokenExpireTime: number = 0
|
||||
|
||||
/**
|
||||
* 获取并缓存 access token
|
||||
*/
|
||||
const getAuthToken = async (): Promise<string> => {
|
||||
const now = Date.now()
|
||||
|
||||
// 如果 token 还未过期,直接返回缓存的 token
|
||||
if (cachedToken && tokenExpireTime > now) {
|
||||
return cachedToken
|
||||
}
|
||||
|
||||
// 调用 token 接口获取新的 token
|
||||
const tokenData = await createAccessToken(
|
||||
{
|
||||
grant_type: 'password',
|
||||
username: 'andp',
|
||||
password: 'an123',
|
||||
scope: 'prison:ai-dash-entry:query'
|
||||
},
|
||||
1, // 租户ID
|
||||
'android-app',
|
||||
'android-secret-key-2024'
|
||||
)
|
||||
|
||||
// 缓存 token,设置为过期时间前5分钟失效
|
||||
cachedToken = tokenData.access_token
|
||||
tokenExpireTime = Date.now() + (tokenData.expires_in - 5 * 60) * 1000
|
||||
|
||||
return cachedToken
|
||||
}
|
||||
|
||||
/**
|
||||
* 带认证的请求方法
|
||||
*/
|
||||
const authRequest = async <T>(options: { url: string; params?: any }): Promise<T> => {
|
||||
const token = await getAuthToken()
|
||||
return await request.get<T>({
|
||||
...options,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** AI心航360° API */
|
||||
export const AiDashEntryApi = {
|
||||
/** 获取AI心航360°统计数据 */
|
||||
getStatistics: async (): Promise<AiDashEntryStatisticsVO> => {
|
||||
return await request.get({ url: '/prison/dashboard/ai-dash-entry/statistics' })
|
||||
return await authRequest<AiDashEntryStatisticsVO>({
|
||||
url: '/prison/dashboard/ai-dash-entry/statistics'
|
||||
})
|
||||
},
|
||||
|
||||
/** 获取重点关注对象分页列表 */
|
||||
getFocusPersonPage: async (params: FocusPersonPageReqVO) => {
|
||||
return await request.get({ url: '/prison/dashboard/ai-dash-entry/focus-person-page', params })
|
||||
return await authRequest({
|
||||
url: '/prison/dashboard/ai-dash-entry/focus-person-page',
|
||||
params
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,53 @@
|
||||
import request from '@/config/axios'
|
||||
import { createAccessToken } from '@/api/system/oauth2/token'
|
||||
|
||||
// Token 缓存
|
||||
let cachedToken: string | null = null
|
||||
let tokenExpireTime: number = 0
|
||||
|
||||
/**
|
||||
* 获取并缓存 access token
|
||||
*/
|
||||
const getAuthToken = async (): Promise<string> => {
|
||||
const now = Date.now()
|
||||
|
||||
// 如果 token 还未过期,直接返回缓存的 token
|
||||
if (cachedToken && tokenExpireTime > now) {
|
||||
return cachedToken
|
||||
}
|
||||
|
||||
// 调用 token 接口获取新的 token
|
||||
const tokenData = await createAccessToken(
|
||||
{
|
||||
grant_type: 'password',
|
||||
username: 'andp',
|
||||
password: 'an123',
|
||||
scope: 'prison:ai-dash-entry:query'
|
||||
},
|
||||
1, // 租户ID
|
||||
'android-app',
|
||||
'android-secret-key-2024'
|
||||
)
|
||||
|
||||
// 缓存 token,设置为过期时间前5分钟失效
|
||||
cachedToken = tokenData.access_token
|
||||
tokenExpireTime = Date.now() + (tokenData.expires_in - 5 * 60) * 1000
|
||||
|
||||
return cachedToken
|
||||
}
|
||||
|
||||
/**
|
||||
* 带认证的请求方法
|
||||
*/
|
||||
const authRequest = async <T>(options: { url: string; params?: any }): Promise<T> => {
|
||||
const token = await getAuthToken()
|
||||
return await request.get<T>({
|
||||
...options,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 看板统计响应 */
|
||||
export interface DashboardStatisticsVO {
|
||||
@ -219,6 +268,9 @@ export const DashboardApi = {
|
||||
|
||||
// 获取罪犯Dashboard统计信息
|
||||
getPrisonerStats: async (prisonerId: number): Promise<PrisonerDashboardStatsRespVO> => {
|
||||
return await request.get({ url: '/prison/dashboard/prisoner-stats', params: { prisonerId } })
|
||||
return await authRequest<PrisonerDashboardStatsRespVO>({
|
||||
url: '/prison/dashboard/prisoner-stats',
|
||||
params: { prisonerId }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,27 @@
|
||||
import request from '@/config/axios'
|
||||
import axios from 'axios'
|
||||
import { config } from '@/config/axios/config'
|
||||
|
||||
export interface OAuth2TokenVO {
|
||||
id: number
|
||||
accessToken: string
|
||||
refreshToken: string
|
||||
userId: number
|
||||
userType: number
|
||||
clientId: string
|
||||
createTime: Date
|
||||
expiresTime: Date
|
||||
access_token: string
|
||||
refresh_token: string
|
||||
user_id: number
|
||||
user_type: number
|
||||
client_id: string
|
||||
create_time: Date
|
||||
expires_in: number // 过期时间(秒)
|
||||
token_type: string
|
||||
}
|
||||
|
||||
/** OAuth2 token 请求参数 */
|
||||
export interface OAuth2TokenReqVO {
|
||||
grant_type: string
|
||||
username: string
|
||||
password: string
|
||||
scope?: string
|
||||
client_id?: string
|
||||
client_secret?: string
|
||||
}
|
||||
|
||||
// 查询 token列表
|
||||
@ -20,3 +33,43 @@ export const getAccessTokenPage = (params: PageParam) => {
|
||||
export const deleteAccessToken = (accessToken: string) => {
|
||||
return request.delete({ url: '/system/oauth2-token/delete?accessToken=' + accessToken })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取OAuth2访问令牌
|
||||
* 使用密码模式获取token,需要Basic认证
|
||||
* @param params token请求参数
|
||||
* @param tenantId 租户ID
|
||||
* @param clientId 客户端ID(可选,默认使用配置的clientId)
|
||||
* @param clientSecret 客户端密钥(可选)
|
||||
*/
|
||||
export const createAccessToken = async (
|
||||
params: OAuth2TokenReqVO,
|
||||
tenantId: string | number,
|
||||
clientId?: string,
|
||||
clientSecret?: string
|
||||
): Promise<OAuth2TokenVO> => {
|
||||
const { base_url } = config
|
||||
|
||||
// 构建Basic认证头
|
||||
const authHeader = btoa(`${clientId || 'android-app'}:${clientSecret || 'android-secret-key-2024'}`)
|
||||
|
||||
// 发送请求
|
||||
const response = await axios.post(
|
||||
`${base_url}/system/oauth2/token`,
|
||||
new URLSearchParams({
|
||||
grant_type: params.grant_type,
|
||||
username: params.username,
|
||||
password: params.password,
|
||||
scope: params.scope || 'prison:ai-dash-entry:query'
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Basic ${authHeader}`,
|
||||
'Tenant-ID': String(tenantId),
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return response.data.data
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ const whiteList = [
|
||||
'/bind',
|
||||
'/register',
|
||||
'/oauthLogin/gitee',
|
||||
'/dashboard', // Dashboard 页面
|
||||
'/prisoner/prisoner/dashboard', // Dashboard 页面
|
||||
'/ai-dash-entry' // DashEntry 页面
|
||||
]
|
||||
|
||||
@ -62,6 +62,10 @@ const whiteList = [
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
start()
|
||||
loadStart()
|
||||
if (to.path === '/prisoner/prisoner/dashboard' || to.path === '/ai-dash-entry') {
|
||||
next()
|
||||
return
|
||||
}
|
||||
if (getAccessToken()) {
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' })
|
||||
|
||||
@ -185,7 +185,16 @@ const remainingRouter: AppRouteRecordRaw[] = [
|
||||
noTagsView: true
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
path: '/ai-dash-entry',
|
||||
component: () => import('@/views/DashEntry/DashEntry.vue'),
|
||||
name: 'aiDashEntry',
|
||||
meta: {
|
||||
hidden: true,
|
||||
title: '画像入口',
|
||||
noTagsView: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
component: () => import('@/views/Login/Login.vue'),
|
||||
@ -758,9 +767,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
|
||||
component: () => import('@/views/iot/ota/firmware/detail/index.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
export default remainingRouter
|
||||
|
||||
@ -85,7 +85,7 @@
|
||||
</div>
|
||||
<div class="dashboard-content-bottom-right">
|
||||
<div class="dashboard-content-bottom-right-title">大帐统计</div>
|
||||
<BarChart :height="'240px'" :data="barChartData" :card-data="barCardData" />
|
||||
<BarChart :height="'200px'" :data="barChartData" :card-data="barCardData" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -640,7 +640,7 @@ onUnmounted(() => {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -269,26 +269,25 @@ watch(
|
||||
.chart-cards {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chart-card-item {
|
||||
text-align: center;
|
||||
padding: 15px 25px;
|
||||
padding: 4px;
|
||||
background: rgba(56, 102, 141, 0.3);
|
||||
border-radius: 8px;
|
||||
min-width: 100px;
|
||||
|
||||
.card-value {
|
||||
font-size: 28px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #00d4ff;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: 16px;
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ watch(
|
||||
|
||||
.consumption-records-title {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
@ -218,13 +218,14 @@ watch(
|
||||
}
|
||||
|
||||
.record-date {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.record-name {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
color: #a855f7;
|
||||
|
||||
&.name-purple {
|
||||
color: #a855f7;
|
||||
@ -252,12 +253,12 @@ watch(
|
||||
}
|
||||
|
||||
.record-category {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.record-amount {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
text-align: right;
|
||||
@ -268,6 +269,7 @@ watch(
|
||||
}
|
||||
.relationship-item {
|
||||
background: #422b1f;
|
||||
color: #ffa500;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
@ -295,9 +297,10 @@ watch(
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
color: #ffa500;
|
||||
svg {
|
||||
width: 14px;
|
||||
height: 16px;
|
||||
width: 12px;
|
||||
height: 14px;
|
||||
}
|
||||
&.icon-orange {
|
||||
color: #ffa500;
|
||||
@ -314,11 +317,11 @@ watch(
|
||||
}
|
||||
|
||||
.relationship-name {
|
||||
font-size: 13px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.relationship-relate {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -168,7 +168,7 @@ const props = withDefaults(
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
margin-right: 6px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
@ -190,11 +190,11 @@ const props = withDefaults(
|
||||
}
|
||||
|
||||
.info-tag {
|
||||
padding: 6px 10px;
|
||||
padding: 4px 10px;
|
||||
background: #3f6973;
|
||||
border: 1px solid rgba(56, 102, 141, 0.5);
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
color: #d8f0ff;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@ -206,7 +206,7 @@ const props = withDefaults(
|
||||
}
|
||||
|
||||
.records-content-title {
|
||||
font-size: 14px;
|
||||
font-size: 10px;
|
||||
color: #d8f0ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
@ -214,13 +214,13 @@ const props = withDefaults(
|
||||
.info-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
font-size: 10px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@ -239,7 +239,7 @@ const props = withDefaults(
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
height: 150px;
|
||||
height: 162px;
|
||||
overflow-y: auto;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
@ -283,14 +283,14 @@ const props = withDefaults(
|
||||
}
|
||||
|
||||
.record-date {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.record-text {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
color: #d8f0ff;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ defineOptions({ name: 'RecentRewardsPunishments' })
|
||||
|
||||
interface RewardPunishmentItem {
|
||||
date?: string // 日期(可选)
|
||||
type: 'reward' | 'punishment'
|
||||
type: 'reward' | 'danger'
|
||||
typeText: string // 类型文本(表扬奖励/警告等)
|
||||
content: string // 内容
|
||||
}
|
||||
@ -65,7 +65,7 @@ const filteredList = computed(() => {
|
||||
} else if (activeFilter.value === 'reward') {
|
||||
return listData.value.filter((item) => item.type === 'reward')
|
||||
} else {
|
||||
return listData.value.filter((item) => item.type === 'punishment')
|
||||
return listData.value.filter((item) => item.type === 'danger')
|
||||
}
|
||||
})
|
||||
|
||||
@ -179,14 +179,13 @@ watch(
|
||||
// 时间线标记点
|
||||
.timeline-dot {
|
||||
position: absolute;
|
||||
left: -6px;
|
||||
left: -8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(13, 30, 50, 0.8);
|
||||
background: rgba(13, 30, 50, 0.8);
|
||||
background: rgba(3, 173, 252, 0.8);
|
||||
z-index: 1;
|
||||
|
||||
&.reward {
|
||||
@ -207,7 +206,7 @@ watch(
|
||||
border: 1px solid rgba(56, 102, 141, 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 8px 12px;
|
||||
margin-left: 8px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.card-type {
|
||||
@ -226,7 +225,7 @@ watch(
|
||||
}
|
||||
|
||||
.card-description {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@ -73,7 +73,13 @@ watch(
|
||||
() => props.data,
|
||||
(newData) => {
|
||||
if (newData && newData.length > 0) {
|
||||
scoreData.value = newData
|
||||
scoreData.value = newData.map((item:any) => (
|
||||
{
|
||||
...item,
|
||||
level: item?.level === '良好' ? 'good' :
|
||||
item?.level === '较差' ? 'poor' : 'exllent'
|
||||
}
|
||||
))
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
@ -101,7 +107,7 @@ watch(
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
margin-right: 6px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
@ -132,7 +138,7 @@ watch(
|
||||
}
|
||||
|
||||
.header-cell {
|
||||
font-size: 13px;
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
@ -173,7 +179,7 @@ watch(
|
||||
}
|
||||
|
||||
.row-cell {
|
||||
font-size: 13px;
|
||||
font-size: 11px;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -213,11 +219,8 @@ watch(
|
||||
color: #ffffff;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
|
||||
&.level-excellent {
|
||||
background: #51869290;
|
||||
border: 1px solid #518692;
|
||||
}
|
||||
background: #51869290;
|
||||
border: 1px solid #518692;
|
||||
|
||||
&.level-good {
|
||||
background: #47363390;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user