import { ref } from 'vue' import { useToast } from './useToast' import { GetAccounts, QueryXiaodianAssets, QueryXiaodianRoles, GetXiaodianBindQRCode, BindXiaodianRole, DeleteAccounts, QueryScore, ReloadAccounts, VerifyAllExchange, VerifyExchange } from '@wails/go/app/App' export interface Account { index: number name: string cookie: string } export interface AccountStatus { ok?: boolean pending?: boolean message?: string } const accounts = ref([]) const selectedIndices = ref>(new Set()) const statusMap = ref>({}) const scoreMap = ref>({}) const accountProductMap = ref>({}) export interface XiaodianAssets { success: boolean coupons: number fragments: number error?: string } const xiaodianAssetsMap = ref>({}) export interface XiaodianRole { success: boolean roleId?: string roleName?: string openId?: string type?: string platId?: number areaId?: number error?: string } export interface XiaodianQRCode { success: boolean accountName?: string url?: string gameRoleBindUrl?: string error?: string } const xiaodianRolesMap = ref>({}) const xiaodianQRCode = ref(null) export function useAccounts() { const { showToast } = useToast() const loadAccounts = async () => { const data = await GetAccounts() accounts.value = data || [] // 清理无效选择 selectedIndices.value = new Set( [...selectedIndices.value].filter(i => i >= 0 && i < accounts.value.length) ) saveSelection() } const reloadAccounts = async () => { const data = await ReloadAccounts() await loadAccounts() showToast('账号已刷新', `共 ${data.count} 个账号`, 'success') } const deleteAccount = async (accountName: string) => { if (!accountName) return false if (!window.confirm(`确定删除账号「${accountName}」及其 CK 吗?`)) return false try { const result = await DeleteAccounts([accountName]) if (!result.success) { showToast('删除失败', result.error || '账号文件未更新', 'error') return false } selectedIndices.value = new Set() saveSelection() delete statusMap.value[accountName] delete accountProductMap.value[accountName] delete xiaodianAssetsMap.value[accountName] delete xiaodianRolesMap.value[accountName] localStorage.setItem('statusMap', JSON.stringify(statusMap.value)) localStorage.setItem('accountProducts', JSON.stringify(accountProductMap.value)) await loadAccounts() showToast('删除成功', `已删除 ${accountName} 及其 CK`, 'success') return true } catch (e: any) { showToast('删除失败', e?.message || '', 'error') return false } } const toggleAccount = (index: number) => { if (selectedIndices.value.has(index)) { selectedIndices.value.delete(index) } else { selectedIndices.value.add(index) } saveSelection() } const toggleAll = () => { if (selectedIndices.value.size === accounts.value.length) { selectedIndices.value.clear() } else { accounts.value.forEach((_, i) => selectedIndices.value.add(i)) } saveSelection() } const clearSelection = () => { selectedIndices.value = new Set() saveSelection() } const saveSelection = () => { localStorage.setItem('selAccs', JSON.stringify([...selectedIndices.value])) } const restoreSelection = () => { const saved = localStorage.getItem('selAccs') if (saved) { try { selectedIndices.value = new Set(JSON.parse(saved)) } catch {} } const savedStatus = localStorage.getItem('statusMap') if (savedStatus) { try { statusMap.value = JSON.parse(savedStatus) } catch {} } const savedProducts = localStorage.getItem('accountProducts') if (savedProducts) { try { accountProductMap.value = JSON.parse(savedProducts) } catch {} } } const queryAllScore = async () => { showToast('查询积分', '正在并发查询...', 'info') const tasks = accounts.value.map(async (a) => { try { const d = await QueryScore(a.name) const score = d.score ?? 'N/A' scoreMap.value[a.name] = String(score) localStorage.setItem('accScore_' + a.name, String(score)) } catch {} }) await Promise.all(tasks) showToast('积分查询完成', '', 'success') } const queryXiaodianAssets = async (accountNames: string[], automatic = false) => { if (accountNames.length === 0) { if (!automatic) showToast('查询点券和碎片', '请先勾选要查询的账号', 'warn') return false } showToast(automatic ? '抢购完成' : '查询点券和碎片', automatic ? '正在刷新本次抢购账号的资产...' : '正在查询账号资产...', 'info') try { const data = await QueryXiaodianAssets(accountNames) const queriedResults = data?.results || {} xiaodianAssetsMap.value = { ...xiaodianAssetsMap.value, ...queriedResults } const successCount = Object.values(queriedResults).filter(item => item.success).length showToast(automatic ? '抢购后资产已刷新' : '资产查询完成', `成功 ${successCount}/${accountNames.length} 个账号`, successCount > 0 ? 'success' : 'warn') return successCount > 0 } catch (e: any) { showToast('资产查询失败', e?.message || '', 'error') return false } } const queryAllXiaodianAssets = async () => queryXiaodianAssets(selectedAccountNames()) const queryAllXiaodianRoles = async () => { const accountNames = selectedAccountNames() if (accountNames.length === 0) { showToast('查询角色信息', '请先勾选要查询的账号', 'warn') return } showToast('查询角色信息', '正在查询小店绑定角色...', 'info') try { const data = await QueryXiaodianRoles(accountNames) const queriedResults = data?.results || {} xiaodianRolesMap.value = { ...xiaodianRolesMap.value, ...queriedResults } const successCount = Object.values(queriedResults).filter(item => item.success).length showToast('角色查询完成', `成功 ${successCount}/${accountNames.length} 个账号`, successCount > 0 ? 'success' : 'warn') } catch (e: any) { showToast('角色查询失败', e?.message || '', 'error') } } const getXiaodianRole = (name: string): XiaodianRole | undefined => xiaodianRolesMap.value[name] const getXiaodianBindQRCode = async (accountName: string) => { if (!accountName) { showToast('获取二维码', '请先选择一个账号', 'warn') return false } try { const result = await GetXiaodianBindQRCode(accountName) if (!result?.success || !result.url) { xiaodianQRCode.value = null showToast('获取二维码失败', result?.error || '接口未返回二维码链接', 'error') return false } xiaodianQRCode.value = result return true } catch (e: any) { showToast('获取二维码失败', e?.message || '', 'error') return false } } const bindXiaodianRole = async () => { const accountName = xiaodianQRCode.value?.accountName || '' if (!accountName) return false try { const result = await BindXiaodianRole(accountName) xiaodianRolesMap.value = { ...xiaodianRolesMap.value, [accountName]: result } if (!result?.success || !result.roleName) { showToast('绑定失败', result?.error || '尚未检测到绑定角色,请先扫码', 'warn') return false } showToast('绑定成功', `${accountName}:${result.roleName}`, 'success') return true } catch (e: any) { showToast('绑定失败', e?.message || '', 'error') return false } } const closeXiaodianQRCode = () => { xiaodianQRCode.value = null } const getScore = (name: string): string => { return scoreMap.value[name] || localStorage.getItem('accScore_' + name) || '-' } const getXiaodianAssets = (name: string): XiaodianAssets | undefined => xiaodianAssetsMap.value[name] const resetStatus = () => { statusMap.value = {} localStorage.removeItem('statusMap') } const setStatuses = (statuses: Record) => { statusMap.value = statuses if (Object.keys(statusMap.value).length > 0) { localStorage.setItem('statusMap', JSON.stringify(statusMap.value)) } else { localStorage.removeItem('statusMap') } } const mergeStatuses = (statuses: Record) => { setStatuses({ ...statusMap.value, ...statuses }) } const setStatus = (name: string, status: AccountStatus | boolean) => { mergeStatuses({ [name]: status }) } const selectedAccountNames = (): string[] => { return [...selectedIndices.value] .map(i => accounts.value[i]?.name) .filter(Boolean) as string[] } const markSelectedStatus = (status: AccountStatus | boolean) => { const next: Record = {} selectedAccountNames().forEach(name => { next[name] = typeof status === 'object' ? { ...status } : status }) mergeStatuses(next) } const markSelectedPending = (message = '抢购中,等待后端结果') => { markSelectedStatus({ pending: true, message }) } const setAccountProduct = (accountName: string, productId: string) => { if (productId) { accountProductMap.value[accountName] = productId } else { delete accountProductMap.value[accountName] } localStorage.setItem('accountProducts', JSON.stringify(accountProductMap.value)) } const getAccountProduct = (accountName: string): string => { return accountProductMap.value[accountName] || '' } const buildAccountProducts = (productId: string, respectOverrides = true): Record | null => { if (selectedIndices.value.size === 0) { showToast('提示', '请勾选要抢购的账号', 'warn') return null } const ap: Record = {} selectedIndices.value.forEach(i => { const account = accounts.value[i] if (account) { const selectedProduct = respectOverrides ? getAccountProduct(account.name) : '' const assignedProduct = selectedProduct || productId if (assignedProduct) { ap[account.name] = assignedProduct } } }) if (Object.keys(ap).length === 0) { showToast('提示', '请先选择商品,或为每个账号分配商品', 'warn') return null } if (Object.keys(ap).length !== selectedIndices.value.size) { showToast('提示', '还有已选账号没有商品', 'warn') return null } return ap } return { accounts, selectedIndices, statusMap, scoreMap, xiaodianAssetsMap, xiaodianRolesMap, xiaodianQRCode, accountProductMap, loadAccounts, reloadAccounts, deleteAccount, toggleAccount, toggleAll, clearSelection, restoreSelection, queryAllScore, queryXiaodianAssets, queryAllXiaodianAssets, queryAllXiaodianRoles, getXiaodianRole, getXiaodianBindQRCode, bindXiaodianRole, closeXiaodianQRCode, getScore, getXiaodianAssets, resetStatus, setStatuses, mergeStatuses, setStatus, markSelectedStatus, markSelectedPending, setAccountProduct, getAccountProduct, selectedAccountNames, buildAccountProducts } } export function useVerifyExchange() { const { accounts } = useAccounts() const verifyResults = ref>({}) const verifying = ref(false) const verifyAccount = async (accountName: string) => { try { const result = await VerifyExchange(accountName) verifyResults.value[accountName] = result return result } catch (e: any) { verifyResults.value[accountName] = { success: false, error: e.message } return { success: false, error: e.message } } } const verifyAll = async () => { verifying.value = true try { // 使用后端批量查询接口,自带间隔 const results = await VerifyAllExchange() verifyResults.value = results?.results || {} } catch (e: any) { console.error('批量复验失败:', e) } finally { verifying.value = false } } const clearResults = () => { verifyResults.value = {} } return { verifyResults, verifying, verifyAccount, verifyAll, clearResults } }