Compare commits

..

No commits in common. "38c8c34839ef4e5115f2ee56372db9cca0bc2c56" and "3c24350bede07f5d56fc19b27720991b9648b6c3" have entirely different histories.

11 changed files with 56 additions and 230 deletions

View File

@ -1,5 +1,4 @@
import request from '@/config/axios' import request from '@/config/axios'
import { createAccessToken } from '@/api/system/oauth2/token'
/** 风险分布数据项 */ /** 风险分布数据项 */
export interface RiskDistributionVO { export interface RiskDistributionVO {
@ -58,68 +57,15 @@ export interface FocusPersonPageReqVO {
areaId?: number 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: 'admin',
password: 'admin123',
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 */ /** AI心航360° API */
export const AiDashEntryApi = { export const AiDashEntryApi = {
/** 获取AI心航360°统计数据 */ /** 获取AI心航360°统计数据 */
getStatistics: async (): Promise<AiDashEntryStatisticsVO> => { getStatistics: async (): Promise<AiDashEntryStatisticsVO> => {
return await authRequest<AiDashEntryStatisticsVO>({ return await request.get({ url: '/prison/dashboard/ai-dash-entry/statistics' })
url: '/prison/dashboard/ai-dash-entry/statistics'
})
}, },
/** 获取重点关注对象分页列表 */ /** 获取重点关注对象分页列表 */
getFocusPersonPage: async (params: FocusPersonPageReqVO) => { getFocusPersonPage: async (params: FocusPersonPageReqVO) => {
return await authRequest({ return await request.get({ url: '/prison/dashboard/ai-dash-entry/focus-person-page', params })
url: '/prison/dashboard/ai-dash-entry/focus-person-page',
params
})
} }
} }

View File

@ -1,53 +1,4 @@
import request from '@/config/axios' 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: 'admin',
password: 'admin123',
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 { export interface DashboardStatisticsVO {
@ -268,9 +219,6 @@ export const DashboardApi = {
// 获取罪犯Dashboard统计信息 // 获取罪犯Dashboard统计信息
getPrisonerStats: async (prisonerId: number): Promise<PrisonerDashboardStatsRespVO> => { getPrisonerStats: async (prisonerId: number): Promise<PrisonerDashboardStatsRespVO> => {
return await authRequest<PrisonerDashboardStatsRespVO>({ return await request.get({ url: '/prison/dashboard/prisoner-stats', params: { prisonerId } })
url: '/prison/dashboard/prisoner-stats',
params: { prisonerId }
})
} }
} }

View File

@ -1,27 +1,14 @@
import request from '@/config/axios' import request from '@/config/axios'
import axios from 'axios'
import { config } from '@/config/axios/config'
export interface OAuth2TokenVO { export interface OAuth2TokenVO {
id: number id: number
access_token: string accessToken: string
refresh_token: string refreshToken: string
user_id: number userId: number
user_type: number userType: number
client_id: string clientId: string
create_time: Date createTime: Date
expires_in: number // 过期时间(秒) expiresTime: Date
token_type: string
}
/** OAuth2 token 请求参数 */
export interface OAuth2TokenReqVO {
grant_type: string
username: string
password: string
scope?: string
client_id?: string
client_secret?: string
} }
// 查询 token列表 // 查询 token列表
@ -33,43 +20,3 @@ export const getAccessTokenPage = (params: PageParam) => {
export const deleteAccessToken = (accessToken: string) => { export const deleteAccessToken = (accessToken: string) => {
return request.delete({ url: '/system/oauth2-token/delete?accessToken=' + accessToken }) return request.delete({ url: '/system/oauth2-token/delete?accessToken=' + accessToken })
} }
/**
* OAuth2访问令牌
* 使tokenBasic认证
* @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
}

View File

@ -54,7 +54,7 @@ const whiteList = [
'/bind', '/bind',
'/register', '/register',
'/oauthLogin/gitee', '/oauthLogin/gitee',
'/prisoner/prisoner/dashboard', // Dashboard 页面 '/dashboard', // Dashboard 页面
'/ai-dash-entry' // DashEntry 页面 '/ai-dash-entry' // DashEntry 页面
] ]
@ -62,10 +62,6 @@ const whiteList = [
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
start() start()
loadStart() loadStart()
if (to.path === '/prisoner/prisoner/dashboard' || to.path === '/ai-dash-entry') {
next()
return
}
if (getAccessToken()) { if (getAccessToken()) {
if (to.path === '/login') { if (to.path === '/login') {
next({ path: '/' }) next({ path: '/' })

View File

@ -185,16 +185,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
noTagsView: true noTagsView: true
} }
}, },
{
path: '/ai-dash-entry',
component: () => import('@/views/DashEntry/DashEntry.vue'),
name: 'aiDashEntry',
meta: {
hidden: true,
title: '画像入口',
noTagsView: true
}
},
{ {
path: '/login', path: '/login',
component: () => import('@/views/Login/Login.vue'), component: () => import('@/views/Login/Login.vue'),
@ -767,7 +758,9 @@ const remainingRouter: AppRouteRecordRaw[] = [
component: () => import('@/views/iot/ota/firmware/detail/index.vue') component: () => import('@/views/iot/ota/firmware/detail/index.vue')
} }
] ]
} },
] ]
export default remainingRouter export default remainingRouter

View File

@ -85,7 +85,7 @@
</div> </div>
<div class="dashboard-content-bottom-right"> <div class="dashboard-content-bottom-right">
<div class="dashboard-content-bottom-right-title">大帐统计</div> <div class="dashboard-content-bottom-right-title">大帐统计</div>
<BarChart :height="'200px'" :data="barChartData" :card-data="barCardData" /> <BarChart :height="'240px'" :data="barChartData" :card-data="barCardData" />
</div> </div>
</div> </div>
</div> </div>
@ -640,7 +640,7 @@ onUnmounted(() => {
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
color: #ffffff; color: #ffffff;
margin-bottom: 10px; margin-bottom: 12px;
} }
} }
</style> </style>

View File

@ -269,25 +269,26 @@ watch(
.chart-cards { .chart-cards {
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
margin-bottom: 15px;
flex-shrink: 0; flex-shrink: 0;
} }
.chart-card-item { .chart-card-item {
text-align: center; text-align: center;
padding: 4px; padding: 15px 25px;
background: rgba(56, 102, 141, 0.3); background: rgba(56, 102, 141, 0.3);
border-radius: 8px; border-radius: 8px;
min-width: 100px; min-width: 100px;
.card-value { .card-value {
font-size: 14px; font-size: 28px;
font-weight: bold; font-weight: bold;
color: #00d4ff; color: #00d4ff;
margin-bottom: 4px; margin-bottom: 8px;
} }
.card-label { .card-label {
font-size: 10px; font-size: 16px;
color: rgba(255, 255, 255, 0.8); color: rgba(255, 255, 255, 0.8);
} }
} }

View File

@ -155,7 +155,7 @@ watch(
.consumption-records-title { .consumption-records-title {
text-align: center; text-align: center;
font-size: 14px; font-size: 16px;
font-weight: bold; font-weight: bold;
color: #ffffff; color: #ffffff;
} }
@ -218,14 +218,13 @@ watch(
} }
.record-date { .record-date {
font-size: 10px; font-size: 12px;
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.record-name { .record-name {
font-size: 10px; font-size: 12px;
font-weight: 500; font-weight: 500;
color: #a855f7;
&.name-purple { &.name-purple {
color: #a855f7; color: #a855f7;
@ -253,12 +252,12 @@ watch(
} }
.record-category { .record-category {
font-size: 10px; font-size: 12px;
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.record-amount { .record-amount {
font-size: 10px; font-size: 12px;
font-weight: 500; font-weight: 500;
color: white; color: white;
text-align: right; text-align: right;
@ -269,7 +268,6 @@ watch(
} }
.relationship-item { .relationship-item {
background: #422b1f; background: #422b1f;
color: #ffa500;
padding: 6px 12px; padding: 6px 12px;
border-radius: 6px; border-radius: 6px;
display: flex; display: flex;
@ -297,10 +295,9 @@ watch(
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
margin-top: 2px; margin-top: 2px;
color: #ffa500;
svg { svg {
width: 12px; width: 14px;
height: 14px; height: 16px;
} }
&.icon-orange { &.icon-orange {
color: #ffa500; color: #ffa500;
@ -317,11 +314,11 @@ watch(
} }
.relationship-name { .relationship-name {
font-size: 11px; font-size: 13px;
font-weight: 500; font-weight: 500;
} }
.relationship-relate { .relationship-relate {
font-size: 11px; font-size: 12px;
opacity: 0.8; opacity: 0.8;
} }
</style> </style>

View File

@ -168,7 +168,7 @@ const props = withDefaults(
} }
.header-title { .header-title {
font-size: 14px; font-size: 16px;
margin-right: 6px; margin-right: 6px;
color: white; color: white;
font-weight: bold; font-weight: bold;
@ -190,11 +190,11 @@ const props = withDefaults(
} }
.info-tag { .info-tag {
padding: 4px 10px; padding: 6px 10px;
background: #3f6973; background: #3f6973;
border: 1px solid rgba(56, 102, 141, 0.5); border: 1px solid rgba(56, 102, 141, 0.5);
border-radius: 4px; border-radius: 4px;
font-size: 10px; font-size: 12px;
color: #d8f0ff; color: #d8f0ff;
white-space: nowrap; white-space: nowrap;
} }
@ -206,7 +206,7 @@ const props = withDefaults(
} }
.records-content-title { .records-content-title {
font-size: 10px; font-size: 14px;
color: #d8f0ff; color: #d8f0ff;
font-weight: bold; font-weight: bold;
} }
@ -214,13 +214,13 @@ const props = withDefaults(
.info-list { .info-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 6px;
} }
.info-item { .info-item {
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 10px; font-size: 13px;
color: white; color: white;
} }
@ -239,7 +239,7 @@ const props = withDefaults(
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 2px; gap: 2px;
height: 162px; height: 150px;
overflow-y: auto; overflow-y: auto;
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
@ -283,14 +283,14 @@ const props = withDefaults(
} }
.record-date { .record-date {
font-size: 10px; font-size: 12px;
font-weight: 600; font-weight: 600;
color: white; color: white;
margin-bottom: 2px; margin-bottom: 2px;
} }
.record-text { .record-text {
font-size: 10px; font-size: 12px;
color: #d8f0ff; color: #d8f0ff;
line-height: 1.5; line-height: 1.5;
} }

View File

@ -41,7 +41,7 @@ defineOptions({ name: 'RecentRewardsPunishments' })
interface RewardPunishmentItem { interface RewardPunishmentItem {
date?: string // date?: string //
type: 'reward' | 'danger' type: 'reward' | 'punishment'
typeText: string // (/) typeText: string // (/)
content: string // content: string //
} }
@ -65,7 +65,7 @@ const filteredList = computed(() => {
} else if (activeFilter.value === 'reward') { } else if (activeFilter.value === 'reward') {
return listData.value.filter((item) => item.type === 'reward') return listData.value.filter((item) => item.type === 'reward')
} else { } else {
return listData.value.filter((item) => item.type === 'danger') return listData.value.filter((item) => item.type === 'punishment')
} }
}) })
@ -179,13 +179,14 @@ watch(
// 线 // 线
.timeline-dot { .timeline-dot {
position: absolute; position: absolute;
left: -8px; left: -6px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
width: 10px; width: 10px;
height: 10px; height: 10px;
border-radius: 50%; border-radius: 50%;
background: rgba(3, 173, 252, 0.8); border: 2px solid rgba(13, 30, 50, 0.8);
background: rgba(13, 30, 50, 0.8);
z-index: 1; z-index: 1;
&.reward { &.reward {
@ -206,7 +207,7 @@ watch(
border: 1px solid rgba(56, 102, 141, 0.3); border: 1px solid rgba(56, 102, 141, 0.3);
border-radius: 4px; border-radius: 4px;
padding: 8px 12px; padding: 8px 12px;
margin-left: 1px; margin-left: 8px;
} }
.card-type { .card-type {
@ -225,7 +226,7 @@ watch(
} }
.card-description { .card-description {
font-size: 10px; font-size: 12px;
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
line-height: 1.5; line-height: 1.5;
} }

View File

@ -73,13 +73,7 @@ watch(
() => props.data, () => props.data,
(newData) => { (newData) => {
if (newData && newData.length > 0) { if (newData && newData.length > 0) {
scoreData.value = newData.map((item:any) => ( scoreData.value = newData
{
...item,
level: item?.level === '良好' ? 'good' :
item?.level === '较差' ? 'poor' : 'exllent'
}
))
} }
}, },
{ immediate: true, deep: true } { immediate: true, deep: true }
@ -107,7 +101,7 @@ watch(
} }
.header-title { .header-title {
font-size: 14px; font-size: 16px;
margin-right: 6px; margin-right: 6px;
color: white; color: white;
font-weight: bold; font-weight: bold;
@ -138,7 +132,7 @@ watch(
} }
.header-cell { .header-cell {
font-size: 11px; font-size: 13px;
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
font-weight: 500; font-weight: 500;
display: flex; display: flex;
@ -179,7 +173,7 @@ watch(
} }
.row-cell { .row-cell {
font-size: 11px; font-size: 13px;
color: #ffffff; color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
@ -219,8 +213,11 @@ watch(
color: #ffffff; color: #ffffff;
white-space: nowrap; white-space: nowrap;
font-size: 12px; font-size: 12px;
background: #51869290;
border: 1px solid #518692; &.level-excellent {
background: #51869290;
border: 1px solid #518692;
}
&.level-good { &.level-good {
background: #47363390; background: #47363390;