feat: 版本号管理机制(VERSION文件+git哈希,部署/启动/UI/health均展示) + 平台账号管理(accounts表CRUD,资产所属账号候选联动,重命名同步引用)
This commit is contained in:
@@ -9,6 +9,28 @@ const ProvidersView = {
|
||||
<div class="flex gap-2">
|
||||
<button @click="seed" class="text-sm px-3 py-1.5 rounded-lg border border-slate-300 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-800">初始化预设平台</button>
|
||||
<button @click="create" class="text-sm px-3 py-1.5 rounded-lg bg-blue-600 text-white hover:bg-blue-700">+ 自定义平台</button>
|
||||
<button @click="addAccount" class="text-sm px-3 py-1.5 rounded-lg border border-blue-300 dark:border-blue-700 text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20">+ 账号</button>
|
||||
</div>
|
||||
|
||||
<!-- 账号管理:同一平台多账号时区分资产归属,资产表单「所属账号」引用此处 -->
|
||||
<div class="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 p-4">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="font-semibold text-sm">👤 我的账号({{ store.accounts.length }})</h3>
|
||||
<button @click="addAccount" class="text-xs text-blue-600 dark:text-blue-400">+ 新增账号</button>
|
||||
</div>
|
||||
<p v-if="!store.accounts.length" class="text-xs text-slate-400">暂无账号。添加后,可在资产表单「所属账号」中快速选择,区分同一平台下的多个账号。</p>
|
||||
<div v-else class="divide-y divide-slate-100 dark:divide-slate-800">
|
||||
<div v-for="a in store.accounts" :key="a.id" class="py-2 flex items-center gap-2">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-sm truncate">{{ a.name }}
|
||||
<span v-if="a.platform" class="text-xs text-slate-400">@ {{ platformName(a.platform) }}</span>
|
||||
</div>
|
||||
<div class="text-xs text-slate-400">关联 {{ a.asset_count }} 个资产<span v-if="a.remark"> · {{ a.remark }}</span></div>
|
||||
</div>
|
||||
<button @click="editAccount(a)" class="text-xs text-blue-600 dark:text-blue-400">编辑</button>
|
||||
<button @click="delAccount(a)" class="text-xs text-red-600 dark:text-red-400">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
||||
<div v-for="p in store.providers" :key="p.id" class="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 p-4">
|
||||
@@ -64,6 +86,11 @@ const ProvidersView = {
|
||||
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 */ }
|
||||
});
|
||||
@@ -96,6 +123,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, isSupported, canSync, fmtTime, test, sync, seed: seedProviders, create: openProviderCreate, edit: openProviderEdit, del: deleteProvider };
|
||||
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 };
|
||||
},
|
||||
};
|
||||
|
||||
@@ -37,11 +37,18 @@ const SettingsView = {
|
||||
</div>
|
||||
<div v-if="dataResult" class="mt-2 text-xs px-3 py-2 rounded-lg bg-slate-50 dark:bg-slate-800/50">{{ dataResult }}</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 p-4">
|
||||
<h3 class="font-semibold text-sm mb-2">版本信息</h3>
|
||||
<div class="text-xs text-slate-500">当前运行版本:<span class="text-slate-700 dark:text-slate-300 font-mono">v{{ version }} ({{ commit }})</span></div>
|
||||
<p class="text-xs text-slate-400 mt-1">与本地 git rev-parse --short HEAD 比对,可确认线上是否为最新代码。</p>
|
||||
</div>
|
||||
</div>`,
|
||||
setup() {
|
||||
const notifyChannels = Vue.ref([]);
|
||||
const notifyResult = Vue.ref('');
|
||||
const dataResult = Vue.ref('');
|
||||
const version = Api.CFG.version || 'dev';
|
||||
const commit = Api.CFG.commit || 'unknown';
|
||||
Vue.onMounted(async () => {
|
||||
try { const r = await Api.get('/notify/channels'); notifyChannels.value = r.channels || []; } catch (e) { /* ignore */ }
|
||||
});
|
||||
@@ -91,6 +98,6 @@ const SettingsView = {
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
return { store, settings, save: saveSettings, applyDark, notifyChannels, notifyResult, testNotify, checkRenewals, dataResult, exportData, onImportFile };
|
||||
return { store, settings, save: saveSettings, applyDark, notifyChannels, notifyResult, testNotify, checkRenewals, dataResult, exportData, onImportFile, version, commit };
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user