fix: reuse upstream keys for account import
This commit is contained in:
@@ -98,6 +98,16 @@
|
||||
<div class="panel-title">我的网站分组</div>
|
||||
<div class="panel-sub">{{ selectedWebsite?.name || '请选择网站' }}</div>
|
||||
</div>
|
||||
<el-select
|
||||
:model-value="selectedWebsite?.id"
|
||||
size="small"
|
||||
filterable
|
||||
class="site-switcher"
|
||||
placeholder="切换网站"
|
||||
@change="onSelectedWebsiteChange"
|
||||
>
|
||||
<el-option v-for="site in websites" :key="site.id" :label="site.name" :value="site.id" />
|
||||
</el-select>
|
||||
<el-button size="small" :disabled="!selectedWebsite" :loading="groupsLoading" @click="loadWebsiteGroups">拉取分组</el-button>
|
||||
</div>
|
||||
<el-table :data="websiteGroups" v-loading="groupsLoading" row-key="id" size="small" style="width:100%">
|
||||
@@ -116,11 +126,24 @@
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-head">
|
||||
<div class="panel-title">分组绑定</div>
|
||||
<div>
|
||||
<div class="panel-title">分组绑定</div>
|
||||
<div class="panel-sub">{{ selectedWebsite?.name || '请选择网站' }}</div>
|
||||
</div>
|
||||
<el-select
|
||||
:model-value="selectedWebsite?.id"
|
||||
size="small"
|
||||
filterable
|
||||
class="site-switcher"
|
||||
placeholder="切换网站"
|
||||
@change="onSelectedWebsiteChange"
|
||||
>
|
||||
<el-option v-for="site in websites" :key="site.id" :label="site.name" :value="site.id" />
|
||||
</el-select>
|
||||
<el-button size="small" text :disabled="websites.length === 0" @click="openBindingCreate(selectedWebsite || websites[0])">新增绑定</el-button>
|
||||
</div>
|
||||
<div class="binding-list" v-loading="bindingLoading">
|
||||
<div v-for="binding in bindings" :key="binding.id" class="binding-item">
|
||||
<div v-for="binding in selectedWebsiteBindings" :key="binding.id" class="binding-item">
|
||||
<div class="binding-main">
|
||||
<div class="binding-title">{{ binding.website_name }} / {{ binding.target_group_name || binding.target_group_id }}</div>
|
||||
<div class="binding-meta">
|
||||
@@ -135,7 +158,7 @@
|
||||
<el-button size="small" text type="danger" @click="deleteBinding(binding)"><el-icon><Delete /></el-icon></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!bindingLoading && bindings.length === 0" class="empty-hint">暂无绑定</div>
|
||||
<div v-if="!bindingLoading && selectedWebsiteBindings.length === 0" class="empty-hint">暂无绑定</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -331,7 +354,7 @@
|
||||
<el-icon><Refresh /></el-icon>刷新导入状态
|
||||
</el-button>
|
||||
<span v-if="importSyncStatus" style="font-size:12px;color:var(--text-muted);margin-left:8px">
|
||||
已校验 {{ importSyncStatus.total }} 个,清除 {{ importSyncStatus.cleared }} 个失效标记
|
||||
已校验已导入标记 {{ importSyncStatus.total }} 个,清除 {{ importSyncStatus.cleared }} 个失效标记
|
||||
</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -366,6 +389,9 @@
|
||||
<el-button size="small" text @click="selectAllImportableKeys">全选可导入 Key</el-button>
|
||||
<el-button size="small" text @click="clearImportAccountSelection">清空</el-button>
|
||||
</div>
|
||||
<div v-if="importGeneratedKeys.length" class="import-stats">
|
||||
总计 {{ importGeneratedKeys.length }} 个,现可导入 {{ importableGeneratedKeys.length }} 个,已导入 {{ importedGeneratedKeyCount }} 个,无明文 {{ missingPlaintextKeyCount }} 个
|
||||
</div>
|
||||
<el-select
|
||||
v-model="importAccountsForm.upstream_key_ids"
|
||||
multiple
|
||||
@@ -573,6 +599,7 @@ const importSourceGroups = computed(() => snapshotsByUpstream.value[importGroups
|
||||
|
||||
function isImportableGeneratedKey(item: GeneratedUpstreamKey) {
|
||||
return item.id !== null
|
||||
&& item.has_key_value
|
||||
&& item.status !== 'failed'
|
||||
&& !(item.imported_website_id === importAccountsForm.value.website_id && item.imported_account_id)
|
||||
}
|
||||
@@ -581,6 +608,21 @@ const importableGeneratedKeys = computed(() =>
|
||||
importGeneratedKeys.value.filter(isImportableGeneratedKey),
|
||||
)
|
||||
|
||||
const importedGeneratedKeyCount = computed(() =>
|
||||
importGeneratedKeys.value.filter((item) =>
|
||||
item.imported_website_id === importAccountsForm.value.website_id && Boolean(item.imported_account_id),
|
||||
).length,
|
||||
)
|
||||
|
||||
const missingPlaintextKeyCount = computed(() =>
|
||||
importGeneratedKeys.value.filter((item) => !item.has_key_value).length,
|
||||
)
|
||||
|
||||
const selectedWebsiteBindings = computed(() => {
|
||||
if (!selectedWebsite.value) return []
|
||||
return bindings.value.filter((binding) => binding.website_id === selectedWebsite.value?.id)
|
||||
})
|
||||
|
||||
const selectedAccountGroups = computed(() => {
|
||||
const selected = new Set(importAccountsForm.value.upstream_key_ids)
|
||||
const rows = importableGeneratedKeys.value.filter((item) => item.id !== null && selected.has(item.id))
|
||||
@@ -605,6 +647,14 @@ async function loadWebsites() {
|
||||
}
|
||||
}
|
||||
|
||||
async function onSelectedWebsiteChange(value: number | string) {
|
||||
const nextId = Number(value)
|
||||
const next = websites.value.find((site) => site.id === nextId)
|
||||
if (!next) return
|
||||
selectedWebsite.value = next
|
||||
await loadWebsiteGroups()
|
||||
}
|
||||
|
||||
async function loadUpstreamGroups() {
|
||||
const upstreamRes = await upstreamsApi.list()
|
||||
upstreams.value = upstreamRes.data
|
||||
@@ -682,12 +732,13 @@ async function loadLogs() {
|
||||
async function syncImportStatus() {
|
||||
const websiteId = importAccountsForm.value.website_id
|
||||
const upstreamId = importAccountsForm.value.upstream_id
|
||||
if (!websiteId || !upstreamId) return
|
||||
if (!websiteId || !upstreamId) return false
|
||||
syncingImportStatus.value = true
|
||||
let reloaded = false
|
||||
try {
|
||||
const res = await websitesApi.syncImportedUpstreamKeys(websiteId, { upstream_id: upstreamId })
|
||||
// 校验请求完成时表单未切换
|
||||
if (importAccountsForm.value.website_id !== websiteId || importAccountsForm.value.upstream_id !== upstreamId) return
|
||||
if (importAccountsForm.value.website_id !== websiteId || importAccountsForm.value.upstream_id !== upstreamId) return false
|
||||
const items = res.data.items
|
||||
importSyncStatus.value = {
|
||||
total: items.length,
|
||||
@@ -699,12 +750,14 @@ async function syncImportStatus() {
|
||||
}
|
||||
if (importAccountsForm.value.upstream_id === upstreamId) {
|
||||
await loadImportGeneratedKeys(upstreamId)
|
||||
reloaded = true
|
||||
}
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e.response?.data?.detail || '同步导入状态失败')
|
||||
} finally {
|
||||
syncingImportStatus.value = false
|
||||
}
|
||||
return reloaded
|
||||
}
|
||||
|
||||
async function loadImportGeneratedKeys(upstreamId: number) {
|
||||
@@ -977,30 +1030,26 @@ async function openImportAccounts(site?: WebsiteData | null) {
|
||||
}
|
||||
importAccountResults.value = []
|
||||
importSyncStatus.value = null
|
||||
await Promise.all([
|
||||
loadImportTargetGroups(importAccountsForm.value.website_id),
|
||||
loadImportGeneratedKeys(importAccountsForm.value.upstream_id),
|
||||
])
|
||||
await loadImportTargetGroups(importAccountsForm.value.website_id)
|
||||
// 打开弹窗后自动同步导入状态(校验远端账号是否仍存在)
|
||||
await syncImportStatus()
|
||||
await loadImportGeneratedKeys(importAccountsForm.value.upstream_id)
|
||||
const reloaded = await syncImportStatus()
|
||||
if (!reloaded) await loadImportGeneratedKeys(importAccountsForm.value.upstream_id)
|
||||
importAccountsDialog.value = true
|
||||
}
|
||||
|
||||
async function onImportAccountWebsiteChange(value: number) {
|
||||
importAccountsForm.value.target_group_map = {}
|
||||
await loadImportTargetGroups(value)
|
||||
await syncImportStatus()
|
||||
await loadImportGeneratedKeys(importAccountsForm.value.upstream_id)
|
||||
const reloaded = await syncImportStatus()
|
||||
if (!reloaded) await loadImportGeneratedKeys(importAccountsForm.value.upstream_id)
|
||||
}
|
||||
|
||||
async function onImportAccountUpstreamChange(value: number) {
|
||||
importAccountsForm.value.upstream_key_ids = []
|
||||
importAccountsForm.value.target_group_map = {}
|
||||
importAccountResults.value = []
|
||||
await loadImportGeneratedKeys(value)
|
||||
await syncImportStatus()
|
||||
await loadImportGeneratedKeys(value)
|
||||
const reloaded = await syncImportStatus()
|
||||
if (!reloaded) await loadImportGeneratedKeys(value)
|
||||
}
|
||||
|
||||
function onPlatformModeChange(value: string) {
|
||||
@@ -1199,6 +1248,11 @@ onMounted(loadAll)
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.site-switcher {
|
||||
width: 180px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.binding-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1216,6 +1270,11 @@ onMounted(loadAll)
|
||||
--el-button-border-color: var(--el-color-danger-light-5, #fbc4c4);
|
||||
}
|
||||
.binding-list { min-height: 120px; }
|
||||
.import-stats {
|
||||
margin: 0 0 8px;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
.binding-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user