import { computed, ref } from 'vue' import { loginBootstrapAdmin, saveBootstrapConfig, testBootstrapDatabase, testBootstrapRuntime } from '../services/bootstrap.js' import { useToast } from './useToast.js' const AUTH_STORAGE_KEY = 'x-financial-authenticated' function readClientBootstrapState() { const env = import.meta.env return { initialized: String(env.VITE_SETUP_COMPLETED || '').toLowerCase() === 'true', company: { name: env.VITE_COMPANY_NAME || '', code: env.VITE_COMPANY_CODE || '', admin_email: env.VITE_ADMIN_EMAIL || '' }, web: { host: env.VITE_WEB_HOST || '127.0.0.1', port: Number(env.VITE_WEB_PORT || 5173) }, server: { host: env.VITE_SERVER_HOST || '127.0.0.1', port: Number(env.VITE_SERVER_PORT || 8000) }, database: { driver: 'postgresql', host: env.VITE_POSTGRES_HOST || '127.0.0.1', port: Number(env.VITE_POSTGRES_PORT || 5432), name: env.VITE_POSTGRES_DB || 'x_financial', username: env.VITE_POSTGRES_USER || 'postgres', password_configured: false }, redis: { enabled: Boolean(env.VITE_REDIS_URL), url: env.VITE_REDIS_URL || '' } } } function readAuthState() { if (typeof window === 'undefined') { return false } return window.sessionStorage.getItem(AUTH_STORAGE_KEY) === 'true' } function persistAuthState(value) { if (typeof window === 'undefined') { return } if (value) { window.sessionStorage.setItem(AUTH_STORAGE_KEY, 'true') return } window.sessionStorage.removeItem(AUTH_STORAGE_KEY) } const bootstrapState = ref(readClientBootstrapState()) const setupSubmitting = ref(false) const setupError = ref('') const runtimeTesting = ref(false) const databaseTesting = ref(false) const runtimeTestPassed = ref(false) const databaseTestPassed = ref(false) const runtimeTestMessage = ref('') const databaseTestMessage = ref('') const loginSubmitting = ref(false) const loginError = ref('') const loggedIn = ref(readAuthState()) const { toast } = useToast() const companyProfile = computed(() => ({ name: bootstrapState.value.company?.name || '', code: bootstrapState.value.company?.code || '', adminEmail: bootstrapState.value.company?.admin_email || '' })) const isInitialized = computed(() => Boolean(bootstrapState.value.initialized)) function applyBootstrapState(state) { bootstrapState.value = state if (!state.initialized) { loggedIn.value = false persistAuthState(false) } } function clearSetupRuntimeState() { runtimeTesting.value = false databaseTesting.value = false runtimeTestPassed.value = false databaseTestPassed.value = false runtimeTestMessage.value = '' databaseTestMessage.value = '' setupError.value = '' } function resetFromClientEnv() { applyBootstrapState(readClientBootstrapState()) clearSetupRuntimeState() loginError.value = '' } async function handleSetupSubmit(payload) { if (!runtimeTestPassed.value) { setupError.value = '请先完成运行端口检测。' toast(setupError.value) return false } if (!databaseTestPassed.value) { setupError.value = '请先完成数据库连接检测。' toast(setupError.value) return false } setupSubmitting.value = true setupError.value = '' try { const state = await saveBootstrapConfig(payload) applyBootstrapState(state) toast('初始化配置已写入。现在可以进入登录页。') return true } catch (error) { setupError.value = error.message || '初始化配置写入失败,请稍后重试。' toast(setupError.value) return false } finally { setupSubmitting.value = false } } async function handleRuntimeTest(payload) { runtimeTesting.value = true runtimeTestMessage.value = '' setupError.value = '' try { const result = await testBootstrapRuntime(payload) runtimeTestPassed.value = true runtimeTestMessage.value = result.detail || '端口占用检测通过。' toast(runtimeTestMessage.value) } catch (error) { runtimeTestPassed.value = false runtimeTestMessage.value = error.message || '端口占用检测失败。' toast(runtimeTestMessage.value) } finally { runtimeTesting.value = false } } async function handleDatabaseTest(payload) { databaseTesting.value = true databaseTestMessage.value = '' setupError.value = '' try { const result = await testBootstrapDatabase(payload) databaseTestPassed.value = true databaseTestMessage.value = result.detail || '数据库连接检测通过。' toast(databaseTestMessage.value) } catch (error) { databaseTestPassed.value = false databaseTestMessage.value = error.message || '数据库连接检测失败。' toast(databaseTestMessage.value) } finally { databaseTesting.value = false } } function handleRuntimeDirty() { runtimeTestPassed.value = false runtimeTestMessage.value = '' if (setupError.value === '请先完成运行端口检测。') { setupError.value = '' } } function handleDatabaseDirty() { databaseTestPassed.value = false databaseTestMessage.value = '' if (setupError.value === '请先完成数据库连接检测。') { setupError.value = '' } } async function handleLogin(credentials) { loginSubmitting.value = true loginError.value = '' try { await loginBootstrapAdmin({ username: credentials.username, password: credentials.password }) loggedIn.value = true persistAuthState(true) return true } catch (error) { loggedIn.value = false persistAuthState(false) loginError.value = error.message || '登录失败,请检查管理员账号和密码。' toast(loginError.value) return false } finally { loginSubmitting.value = false } } function logout() { loggedIn.value = false persistAuthState(false) } function handleRecoverPassword() { toast('请联系系统管理员重置密码。管理员密码不会写入 .env。') } function handleSsoLogin() { toast('SSO 登录暂未启用。') } function resolveEntryRoute() { if (!isInitialized.value) { return { name: 'setup' } } if (!loggedIn.value) { return { name: 'login' } } return { name: 'app-overview' } } export function useSystemState() { return { bootstrapState, companyProfile, databaseTestMessage, databaseTestPassed, databaseTesting, handleDatabaseDirty, handleDatabaseTest, handleLogin, handleRecoverPassword, handleRuntimeDirty, handleRuntimeTest, handleSetupSubmit, handleSsoLogin, isInitialized, loggedIn, loginError, loginSubmitting, logout, resetFromClientEnv, resolveEntryRoute, runtimeTestMessage, runtimeTestPassed, runtimeTesting, setupError, setupSubmitting } }