feat(frontend): implement P0 optimization baseline
This commit is contained in:
@@ -33,11 +33,11 @@ export function getAdminRole() {
|
||||
return role
|
||||
}
|
||||
|
||||
return 'operator'
|
||||
return 'support'
|
||||
}
|
||||
|
||||
export function hasAdminRole(role: 'admin' | 'operator' | 'support') {
|
||||
if (!getAdminToken()) {
|
||||
if (!hasAdminSession()) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -74,5 +74,26 @@ export function clearAdminSession() {
|
||||
}
|
||||
|
||||
export function hasAdminSession() {
|
||||
return Boolean(getAdminToken())
|
||||
const token = getAdminToken()
|
||||
const expiresAt = getAdminTokenExpiresAt()
|
||||
|
||||
if (!token) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isExpired(expiresAt)) {
|
||||
clearAdminSession()
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function isExpired(expiresAt: string) {
|
||||
if (!expiresAt) {
|
||||
return false
|
||||
}
|
||||
|
||||
const expiresAtMs = Date.parse(expiresAt)
|
||||
return Number.isFinite(expiresAtMs) && expiresAtMs <= Date.now()
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ const pagination = ref<AdminPagination>({
|
||||
})
|
||||
|
||||
const canReplay = hasAdminRole('admin')
|
||||
let latestRequestId = 0
|
||||
|
||||
const summary = computed(() => ({
|
||||
processedCount: items.value.filter((item) => item.processed).length,
|
||||
@@ -38,6 +39,7 @@ const summary = computed(() => ({
|
||||
}))
|
||||
|
||||
async function loadEvents(page = pagination.value.page) {
|
||||
const requestId = ++latestRequestId
|
||||
loading.value = true
|
||||
errorMessage.value = ''
|
||||
|
||||
@@ -54,12 +56,23 @@ async function loadEvents(page = pagination.value.page) {
|
||||
dateFrom: dateFrom.value.trim(),
|
||||
dateTo: dateTo.value.trim(),
|
||||
})
|
||||
|
||||
if (requestId !== latestRequestId) {
|
||||
return
|
||||
}
|
||||
|
||||
items.value = response.data.items
|
||||
pagination.value = response.data.pagination
|
||||
} catch (error) {
|
||||
if (requestId !== latestRequestId) {
|
||||
return
|
||||
}
|
||||
|
||||
errorMessage.value = error instanceof Error ? error.message : '读取 webhook 列表失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
if (requestId === latestRequestId) {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
const allowedHosts = parseAllowedHosts(env.VITE_ALLOWED_HOSTS)
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
@@ -28,11 +29,8 @@ export default defineConfig(({ mode }) => {
|
||||
},
|
||||
},
|
||||
server: {
|
||||
// 👇 加入这行,允许通过 IP 和网络访问
|
||||
host: true,
|
||||
// 👇 加入这行,允许所有外部域名(包括 Cloudflare 分配的域名)访问
|
||||
allowedHosts: true,
|
||||
|
||||
host: env.VITE_DEV_HOST === 'true',
|
||||
allowedHosts: env.VITE_ALLOW_ALL_HOSTS === 'true' ? true : allowedHosts,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: env.VITE_API_TARGET || 'http://localhost:3000',
|
||||
@@ -42,3 +40,12 @@ export default defineConfig(({ mode }) => {
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
function parseAllowedHosts(value?: string) {
|
||||
const hosts = value
|
||||
?.split(',')
|
||||
.map((host) => host.trim())
|
||||
.filter(Boolean)
|
||||
|
||||
return hosts && hosts.length > 0 ? hosts : ['localhost', '127.0.0.1']
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user