feat: add one-click sync for website group bindings

This commit is contained in:
liumangmang
2026-06-01 09:06:01 +08:00
parent 890432e1a5
commit 518e3e8efc
6 changed files with 329 additions and 11 deletions
+10
View File
@@ -267,6 +267,15 @@ export interface ImportAccountItem {
raw: Record<string, any>
}
export interface WebsiteBatchSyncResponse {
total: number
success: number
failed: number
skipped: number
message: string
logs: WebsiteSyncLog[]
}
export const websitesApi = {
list: () => api.get<WebsiteData[]>('/api/websites'),
create: (data: WebsiteForm) => api.post<WebsiteData>('/api/websites', data),
@@ -293,6 +302,7 @@ export const websitesApi = {
updateBinding: (id: number, data: Partial<GroupBindingForm>) => api.put<GroupBindingData>(`/api/group-bindings/${id}`, data),
deleteBinding: (id: number) => api.delete(`/api/group-bindings/${id}`),
syncNow: (id: number) => api.post<WebsiteSyncLog>(`/api/group-bindings/${id}/sync-now`),
syncWebsiteBindings: (id: number) => api.post<WebsiteBatchSyncResponse>(`/api/websites/${id}/group-bindings/sync-now`),
logs: (params?: { website_id?: number; binding_id?: number; limit?: number; offset?: number }) =>
api.get<WebsiteSyncLog[]>('/api/website-sync-logs', { params }),
}
+38 -11
View File
@@ -101,6 +101,16 @@
>
<el-option v-for="site in websites" :key="site.id" :label="site.name" :value="site.id" />
</el-select>
<el-button
size="small"
text
:loading="batchSyncLoading"
:disabled="!selectedWebsite || selectedWebsiteBindings.length === 0"
@click="syncAllWebsiteBindings"
title="同步当前网站的所有分组绑定"
>
一键同步
</el-button>
<el-button size="small" text :disabled="websites.length === 0" @click="openBindingCreate(selectedWebsite || websites[0])">新增绑定</el-button>
</div>
<div class="binding-list" v-loading="bindingLoading">
@@ -469,6 +479,7 @@ const websiteLoading = ref(false)
const groupsLoading = ref(false)
const bindingLoading = ref(false)
const logLoading = ref(false)
const batchSyncLoading = ref(false)
const importingGroups = ref(false)
const importingAccounts = ref(false)
const generatedKeyLoading = ref(false)
@@ -924,16 +935,6 @@ async function saveBinding() {
}
}
async function toggleBinding(row: GroupBindingData) {
try {
await websitesApi.updateBinding(row.id, { enabled: row.enabled })
ElMessage.success(row.enabled ? '已启用绑定' : '已停用绑定')
} catch {
row.enabled = !row.enabled
ElMessage.error('操作失败')
}
}
async function syncBinding(row: GroupBindingData & { _syncing?: boolean }) {
row._syncing = true
try {
@@ -946,9 +947,35 @@ async function syncBinding(row: GroupBindingData & { _syncing?: boolean }) {
}
}
async function syncAllWebsiteBindings() {
if (!selectedWebsite.value) return
batchSyncLoading.value = true
try {
const res = await websitesApi.syncWebsiteBindings(selectedWebsite.value.id)
ElMessage.success(res.data.message)
// 刷新相关数据
await Promise.all([loadLogs(), loadWebsiteGroups(), loadBindings()])
} catch (e: any) {
ElMessage.error(e.response?.data?.detail || '批量同步失败')
} finally {
batchSyncLoading.value = false
}
}
async function toggleBinding(row: GroupBindingData) {
try {
await websitesApi.updateBinding(row.id, { enabled: row.enabled })
ElMessage.success(row.enabled ? '已启用' : '已禁用')
await loadLogs()
} catch (e: any) {
row.enabled = !row.enabled
ElMessage.error(e.response?.data?.detail || '更新失败')
}
}
async function deleteBinding(row: GroupBindingData) {
try {
await ElMessageBox.confirm('确认删除该绑定?', '删除确认', { type: 'warning' })
await ElMessageBox.confirm('确认删除该绑定规则', '删除确认', { type: 'warning' })
await websitesApi.deleteBinding(row.id)
ElMessage.success('已删除')
await loadBindings()