213 lines
6.5 KiB
JavaScript
213 lines
6.5 KiB
JavaScript
|
|
import { reactive, ref, onMounted } from 'vue'
|
|||
|
|
import {
|
|||
|
|
getAuthPluginOverviewApi,
|
|||
|
|
getAuthPluginDetailApi,
|
|||
|
|
getAuthPluginTokenStrategiesApi,
|
|||
|
|
getAuthPluginConfigSchemaApi,
|
|||
|
|
validateAuthPluginConfigApi
|
|||
|
|
} from '@/apis'
|
|||
|
|
import { unwrap } from './utils'
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 认证插件 Composable
|
|||
|
|
*
|
|||
|
|
* 封装认证插件模块的数据获取与状态管理,覆盖 5 个业务场景:
|
|||
|
|
* - 总览列表(overview):卡片网格数据源
|
|||
|
|
* - 详情(detail):详情抽屉基本信息
|
|||
|
|
* - Token 刷新策略(tokenStrategies):详情抽屉 Token 策略区块
|
|||
|
|
* - 配置 Schema(detailSchema / schemaDrawer):详情抽屉与 Schema 抽屉独立维护
|
|||
|
|
* - 校验(validate):校验弹窗提交与结果
|
|||
|
|
*
|
|||
|
|
* 错误处理遵循 VNC §12 三层分工:
|
|||
|
|
* - API 层处理 401/403/500 全局错误
|
|||
|
|
* - Composable 捕获异常存入 error 字段
|
|||
|
|
* - 组件层 watch error 显示 message.error() 或内联错误
|
|||
|
|
*
|
|||
|
|
* 注意:detailSchema 与 schemaDrawer 分别为详情抽屉、Schema 抽屉独立维护,
|
|||
|
|
* 避免两个抽屉同时打开时配置 Schema 状态互相覆盖。
|
|||
|
|
*/
|
|||
|
|
export function useAuthPlugin() {
|
|||
|
|
// ===== 总览状态 =====
|
|||
|
|
const overview = reactive({ data: null, loading: false, error: '' })
|
|||
|
|
|
|||
|
|
// ===== 详情抽屉状态 =====
|
|||
|
|
const detail = reactive({ data: null, loading: false, error: '' })
|
|||
|
|
const tokenStrategies = reactive({ data: null, loading: false, error: '' })
|
|||
|
|
const detailSchema = reactive({ data: null, loading: false, error: '' })
|
|||
|
|
|
|||
|
|
// ===== Schema 抽屉状态(独立于详情抽屉) =====
|
|||
|
|
const schemaDrawer = reactive({ data: null, loading: false, error: '' })
|
|||
|
|
|
|||
|
|
// ===== 校验状态 =====
|
|||
|
|
const validating = ref(false)
|
|||
|
|
const validateResult = ref(null)
|
|||
|
|
const validateError = ref('')
|
|||
|
|
|
|||
|
|
// ===== 请求序列号(防止快速切换适配器上下文导致响应错位) =====
|
|||
|
|
// 每次 fetch 递增 seq,响应返回时若 seq 不匹配最新值则丢弃,避免旧数据覆盖新数据。
|
|||
|
|
const detailSeq = ref(0)
|
|||
|
|
const detailSchemaSeq = ref(0)
|
|||
|
|
const schemaDrawerSeq = ref(0)
|
|||
|
|
|
|||
|
|
// ===== 总览 =====
|
|||
|
|
const fetchOverview = async () => {
|
|||
|
|
overview.loading = true
|
|||
|
|
overview.error = ''
|
|||
|
|
try {
|
|||
|
|
overview.data = unwrap(await getAuthPluginOverviewApi())
|
|||
|
|
} catch (error) {
|
|||
|
|
overview.error = error.message
|
|||
|
|
} finally {
|
|||
|
|
overview.loading = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 详情 =====
|
|||
|
|
const fetchDetail = async (authType, adapterType) => {
|
|||
|
|
const seq = ++detailSeq.value
|
|||
|
|
detail.loading = true
|
|||
|
|
detail.error = ''
|
|||
|
|
try {
|
|||
|
|
const params = adapterType ? { adapter_type: adapterType } : undefined
|
|||
|
|
// 丢弃过期响应:用户在请求期间已切换到其他适配器上下文
|
|||
|
|
if (seq !== detailSeq.value) return
|
|||
|
|
detail.data = unwrap(await getAuthPluginDetailApi(authType, params))
|
|||
|
|
} catch (error) {
|
|||
|
|
if (seq !== detailSeq.value) return
|
|||
|
|
detail.error = error.message
|
|||
|
|
} finally {
|
|||
|
|
if (seq === detailSeq.value) {
|
|||
|
|
detail.loading = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== Token 刷新策略 =====
|
|||
|
|
const fetchTokenStrategies = async () => {
|
|||
|
|
tokenStrategies.loading = true
|
|||
|
|
tokenStrategies.error = ''
|
|||
|
|
try {
|
|||
|
|
tokenStrategies.data = unwrap(await getAuthPluginTokenStrategiesApi())
|
|||
|
|
} catch (error) {
|
|||
|
|
tokenStrategies.error = error.message
|
|||
|
|
} finally {
|
|||
|
|
tokenStrategies.loading = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 配置 Schema(详情抽屉) =====
|
|||
|
|
const fetchDetailSchema = async (authType, adapterType) => {
|
|||
|
|
const seq = ++detailSchemaSeq.value
|
|||
|
|
detailSchema.loading = true
|
|||
|
|
detailSchema.error = ''
|
|||
|
|
try {
|
|||
|
|
const params = adapterType ? { adapter_type: adapterType } : undefined
|
|||
|
|
if (seq !== detailSchemaSeq.value) return
|
|||
|
|
detailSchema.data = unwrap(await getAuthPluginConfigSchemaApi(authType, params))
|
|||
|
|
} catch (error) {
|
|||
|
|
if (seq !== detailSchemaSeq.value) return
|
|||
|
|
detailSchema.error = error.message
|
|||
|
|
} finally {
|
|||
|
|
if (seq === detailSchemaSeq.value) {
|
|||
|
|
detailSchema.loading = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 配置 Schema(Schema 抽屉,独立状态) =====
|
|||
|
|
const fetchSchemaDrawer = async (authType, adapterType) => {
|
|||
|
|
const seq = ++schemaDrawerSeq.value
|
|||
|
|
schemaDrawer.loading = true
|
|||
|
|
schemaDrawer.error = ''
|
|||
|
|
try {
|
|||
|
|
const params = adapterType ? { adapter_type: adapterType } : undefined
|
|||
|
|
if (seq !== schemaDrawerSeq.value) return
|
|||
|
|
schemaDrawer.data = unwrap(await getAuthPluginConfigSchemaApi(authType, params))
|
|||
|
|
} catch (error) {
|
|||
|
|
if (seq !== schemaDrawerSeq.value) return
|
|||
|
|
schemaDrawer.error = error.message
|
|||
|
|
} finally {
|
|||
|
|
if (seq === schemaDrawerSeq.value) {
|
|||
|
|
schemaDrawer.loading = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 校验配置 =====
|
|||
|
|
// 校验端点返回 200 + {valid, errors}(业务校验结果),非 422。
|
|||
|
|
// 网络异常(401/403/500/连接失败)存入 validateError,业务结果存入 validateResult。
|
|||
|
|
const validateConfig = async (authType, authConfig, adapterType) => {
|
|||
|
|
validating.value = true
|
|||
|
|
validateError.value = ''
|
|||
|
|
validateResult.value = null
|
|||
|
|
try {
|
|||
|
|
const params = adapterType ? { adapter_type: adapterType } : undefined
|
|||
|
|
validateResult.value = unwrap(
|
|||
|
|
await validateAuthPluginConfigApi(authType, { auth_config: authConfig }, params)
|
|||
|
|
)
|
|||
|
|
} catch (error) {
|
|||
|
|
validateError.value = error.message
|
|||
|
|
} finally {
|
|||
|
|
validating.value = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 状态重置 =====
|
|||
|
|
const resetDetail = () => {
|
|||
|
|
detailSeq.value++ // 使任何在途请求失效
|
|||
|
|
detail.data = null
|
|||
|
|
detail.error = ''
|
|||
|
|
detail.loading = false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const resetDetailSchema = () => {
|
|||
|
|
detailSchemaSeq.value++
|
|||
|
|
detailSchema.data = null
|
|||
|
|
detailSchema.error = ''
|
|||
|
|
detailSchema.loading = false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const resetSchemaDrawer = () => {
|
|||
|
|
schemaDrawerSeq.value++
|
|||
|
|
schemaDrawer.data = null
|
|||
|
|
schemaDrawer.error = ''
|
|||
|
|
schemaDrawer.loading = false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const resetValidate = () => {
|
|||
|
|
validateResult.value = null
|
|||
|
|
validateError.value = ''
|
|||
|
|
validating.value = false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 生命周期 =====
|
|||
|
|
onMounted(() => {
|
|||
|
|
fetchOverview()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
// 总览
|
|||
|
|
overview,
|
|||
|
|
fetchOverview,
|
|||
|
|
// 详情抽屉
|
|||
|
|
detail,
|
|||
|
|
tokenStrategies,
|
|||
|
|
detailSchema,
|
|||
|
|
fetchDetail,
|
|||
|
|
fetchTokenStrategies,
|
|||
|
|
fetchDetailSchema,
|
|||
|
|
resetDetail,
|
|||
|
|
resetDetailSchema,
|
|||
|
|
// Schema 抽屉
|
|||
|
|
schemaDrawer,
|
|||
|
|
fetchSchemaDrawer,
|
|||
|
|
resetSchemaDrawer,
|
|||
|
|
// 校验
|
|||
|
|
validating,
|
|||
|
|
validateResult,
|
|||
|
|
validateError,
|
|||
|
|
validateConfig,
|
|||
|
|
resetValidate
|
|||
|
|
}
|
|||
|
|
}
|