diff --git a/VERSION b/VERSION index 9e11b32..d15723f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.1 +0.3.2 diff --git a/static/js/app.js b/static/js/app.js index ad85248..7afa8c6 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -84,6 +84,7 @@ const AppRoot = { + `, setup() { const appName = Api.CFG.appName; @@ -126,6 +127,7 @@ app.component('settings-view', SettingsView); app.component('asset-modal', AssetModal); app.component('provider-modal', ProviderModal); app.component('account-modal', AccountModal); +app.component('accounts-view-modal', AccountsViewModal); applyDark(); initRouter(); loadAll(); diff --git a/static/js/modals.js b/static/js/modals.js index a385aa0..657d2c7 100644 --- a/static/js/modals.js +++ b/static/js/modals.js @@ -247,3 +247,90 @@ const AccountModal = { 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, + }; + }, +}; diff --git a/static/js/store.js b/static/js/store.js index 13dd314..5b5a215 100644 --- a/static/js/store.js +++ b/static/js/store.js @@ -25,6 +25,7 @@ const store = reactive({ assetModal: { show: false, editing: null, form: null }, providerModal: { show: false, editing: null, form: null }, accountModal: { show: false, editing: null, form: null }, + accountsModal: { show: false, providerSlug: null }, // 账号查看弹窗:providerSlug 为 null 时看全部 }); function applyDark() { @@ -166,6 +167,9 @@ async function deleteProvider(p) { } /* ---------------- 账号操作 ---------------- */ +function openAccountsView(providerSlug) { + store.accountsModal = { show: true, providerSlug: providerSlug || null }; +} function openAccountCreate(platform) { store.accountModal = { show: true, editing: null, form: { name: '', platform: platform || '', remark: '' } }; } diff --git a/static/js/views/providers.js b/static/js/views/providers.js index e0c881a..2689eb0 100644 --- a/static/js/views/providers.js +++ b/static/js/views/providers.js @@ -9,28 +9,7 @@ const ProvidersView = {
- -
- - -
-
-

👤 我的账号({{ store.accounts.length }})

- -
-

暂无账号。添加后,可在资产表单「所属账号」中快速选择,区分同一平台下的多个账号。

-
-
-
-
{{ a.remark || a.name }} - @ {{ platformName(a.platform) }} -
-
{{ a.name }} · 关联 {{ a.asset_count }} 个资产
-
- - -
-
+
@@ -49,6 +28,7 @@ const ProvidersView = {
管理面板 ↗
📎 关联 {{ countOf(p) }} 个资产 + 已配置 API 未配置 API {{ p.enabled ? '启用' : '停用' }} @@ -83,14 +63,13 @@ const ProvidersView = { function countOf(p) { return (assetCounts.value['id:' + p.id] || 0) + (assetCounts.value['p:' + p.slug] || 0) + (assetCounts.value['p:' + p.name] || 0); } + // 平台名下账号数(账号按 platform slug 归属平台) + function accountsCountOf(p) { + return store.accounts.filter(a => a.platform === p.slug).length; + } function serviceList(p) { return (p.services || '').split(',').map(s => s.trim()).filter(Boolean); } - // 账号所属平台显示名:platform 存的是 slug,回退显示原值 - function platformName(slug) { - const p = store.providers.find(x => x.slug === slug); - return p ? p.name : slug; - } Vue.onMounted(async () => { try { const r = await Api.get('/providers/adapters'); supported.value = r.supported_types || []; capabilities.value = r.capabilities || {}; } catch (e) { /* ignore */ } }); @@ -123,6 +102,6 @@ const ProvidersView = { } catch (e) { results[p.id] = { ok: false, text: '✗ ' + e.message }; } finally { syncing[p.id] = false; } } - return { store, Fmt, testing, syncing, results, countOf, serviceList, platformName, isSupported, canSync, fmtTime, test, sync, seed: seedProviders, create: openProviderCreate, edit: openProviderEdit, del: deleteProvider, addAccount: () => openAccountCreate(''), editAccount: openAccountEdit, delAccount: deleteAccount }; + return { store, Fmt, testing, syncing, results, countOf, accountsCountOf, serviceList, isSupported, canSync, fmtTime, test, sync, seed: seedProviders, create: openProviderCreate, edit: openProviderEdit, del: deleteProvider, openAccounts: (p) => openAccountsView(p.slug), manageAccounts: () => openAccountsView(null) }; }, };