/* 资产编辑模态框 */ const AssetModal = { template: `

{{ store.assetModal.editing ? '编辑资产' : '新增资产' }}

VPS 详情
域名详情
AI 账号详情
Cloudflare 子资产详情
`, setup() { const f = Vue.computed(() => store.assetModal.form); const providersForType = Vue.computed(() => { const t = f.value ? f.value.asset_type : null; const map = { vps: 'vps', domain: 'domain', ai_agent: 'ai_agent', cloudflare: 'cloudflare' }; const cat = map[t]; if (!cat) return store.providers; // 综合平台按 services 过滤(如阿里云可同时选 vps/domain);services 为空时回退分类匹配 return store.providers.filter(p => { if (p.services) return p.services.split(',').map(s => s.trim()).includes(cat); return p.category === cat || p.category === 'other'; }); }); function onProviderChange() { const p = store.providers.find(x => x.id === f.value.provider_id); if (p) f.value.provider = p.slug; } // 账号候选显示:说明优先,其次平台名(platform 存的是 slug,回退原值) function accountLabel(a) { if (a.remark) return a.remark + ' · ' + a.name; const p = store.providers.find(x => x.slug === a.platform); return p ? a.name + '(' + p.name + ')' : a.name; } return { store, Fmt, f, providersForType, onProviderChange, accountLabel, save: saveAsset }; }, }; /* 平台编辑模态框 */ const ProviderModal = { template: `

{{ store.providerModal.editing ? '编辑平台' : '新增平台' }}

提供服务(可多选,综合平台全选)
API 凭证(加密存储)
该 SDK 类型暂无预设凭证字段(可后续扩展)
`, setup() { const f = Vue.computed(() => store.providerModal.form); const adapterMeta = Vue.ref([]); const apiFields = Vue.reactive({}); Vue.onMounted(async () => { try { const r = await Api.get('/providers/adapters'); adapterMeta.value = r.adapters || []; } catch (e) { /* ignore */ } }); const sdkOptions = Vue.computed(() => { const opts = []; for (const m of adapterMeta.value) for (const t of (m.sdk_types || [])) opts.push({ type: t, fields: m.required_config || [] }); return opts; }); const currentFields = Vue.computed(() => { const opt = sdkOptions.value.find(o => o.type === (f.value && f.value.sdk_type)); return opt ? opt.fields : []; }); // 提供服务多选:services 逗号分隔字符串 <-> checkbox 集合 const servicesSet = Vue.computed(() => new Set((f.value && f.value.services || '').split(',').map(s => s.trim()).filter(Boolean))); function toggleService(k) { const arr = (f.value.services || '').split(',').map(s => s.trim()).filter(Boolean); const idx = arr.indexOf(k); if (idx >= 0) arr.splice(idx, 1); else arr.push(k); f.value.services = arr.join(','); } // 模态框每次打开时清空上次残留的凭证输入,避免串号 Vue.watch(() => store.providerModal.show, (show) => { if (show) { for (const k of Object.keys(apiFields)) delete apiFields[k]; } }); function save() { const cfg = {}; for (const field of currentFields.value) if (apiFields[field]) cfg[field] = apiFields[field]; if (Object.keys(cfg).length) f.value.api_config = JSON.stringify(cfg); saveProvider(); } return { store, Fmt, f, sdkOptions, currentFields, servicesSet, toggleService, apiFields, save }; }, }; /* 账号编辑模态框(z-[60]:可能叠加在账号查看弹窗 z-50 之上打开,需更高层级) */ const AccountModal = { template: `

{{ store.accountModal.editing ? '编辑账号' : '新增账号' }}

修改账号标识后,引用该账号的资产会自动同步更新。

`, setup() { const f = Vue.computed(() => store.accountModal.form); return { store, f, save: saveAccount }; }, }; /* 账号查看弹窗:平台 → 账号 → 资产 三层结构,展开账号看名下资产 */ const AccountsViewModal = { template: `

👤 {{ title }}({{ accountList.length }})

暂无账号。一个平台可有多个账号(如代管/公司账号),添加后可在资产表单「所属账号」中选择。

{{ g.platform ? platformName(g.platform) : '未指定平台' }}
{{ a.remark || a.name }}
{{ a.name }} · 关联 {{ assetsOf(a).length }} 个资产

该账号下暂无资产(编辑资产时在「所属账号」选择 {{ a.name }} 即可关联)

{{ Fmt.TYPE_LABELS[asset.asset_type] }} {{ asset.name }} {{ asset.expiry_date }} 到期
`, setup() { const expanded = Vue.reactive({}); const singleProvider = Vue.computed(() => !!store.accountsModal.providerSlug); const title = Vue.computed(() => { const slug = store.accountsModal.providerSlug; if (!slug) return '全部账号'; const p = store.providers.find(x => x.slug === slug); return (p ? p.name : slug) + ' 的账号'; }); const accountList = Vue.computed(() => { const slug = store.accountsModal.providerSlug; return slug ? store.accounts.filter(a => a.platform === slug) : store.accounts; }); // 全部模式下按平台分组,保持 平台→账号→资产 层级 const groups = Vue.computed(() => { const m = new Map(); for (const a of accountList.value) { const key = a.platform || ''; if (!m.has(key)) m.set(key, []); m.get(key).push(a); } return [...m.entries()].map(([platform, accounts]) => ({ platform, accounts })); }); function platformName(slug) { const p = store.providers.find(x => x.slug === slug); return p ? p.name : slug; } function assetsOf(a) { return store.assets.filter(x => x.account === a.name); } function toggle(id) { expanded[id] = !expanded[id]; } // 每次打开重置展开状态 Vue.watch(() => store.accountsModal.show, (show) => { if (show) for (const k of Object.keys(expanded)) delete expanded[k]; }); return { store, Fmt, expanded, singleProvider, title, accountList, groups, platformName, assetsOf, toggle, add: () => openAccountCreate(store.accountsModal.providerSlug || ''), edit: openAccountEdit, del: deleteAccount, }; }, };