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 } }