feat: persist browser sessions and update admin workflows
This commit is contained in:
@@ -1,23 +1,11 @@
|
||||
<template>
|
||||
<div class="shell-page shell-page-fluid page-section websites-page">
|
||||
<div class="page-header surface-card page-block">
|
||||
<div class="page-heading">
|
||||
<p class="page-kicker">Sync Orchestration</p>
|
||||
<h2 class="page-title">网站管理</h2>
|
||||
<p class="page-desc">管理自己的 sub2api 网站,并把网站分组倍率同步到上游监听结果</p>
|
||||
</div>
|
||||
<el-button type="primary" @click="openWebsiteCreate">
|
||||
<el-icon><Plus /></el-icon> 新增网站
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-head">
|
||||
<div class="panel-title">网站</div>
|
||||
<div class="panel-title">检测与变更控制台</div>
|
||||
<div class="panel-actions">
|
||||
<el-button size="small" text :disabled="websites.length === 0" @click="openImportGroups(selectedWebsite || websites[0])">导入上游分组</el-button>
|
||||
<el-button size="small" text :disabled="websites.length === 0" @click="openImportAccounts(selectedWebsite || websites[0])">导入为账号管理账号</el-button>
|
||||
<el-button size="small" text @click="loadAll">刷新</el-button>
|
||||
<el-button size="small" type="primary" @click="openWebsiteCreate">新增网站</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="websites" v-loading="websiteLoading" row-key="id" style="width:100%">
|
||||
@@ -48,43 +36,16 @@
|
||||
<span v-else class="muted">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="240" align="right">
|
||||
<el-table-column label="操作" width="340">
|
||||
<template #default="{ row }">
|
||||
<div class="action-row">
|
||||
<el-tooltip content="编辑网站配置" placement="top" :show-after="300">
|
||||
<el-button size="small" text class="btn-edit" @click="openWebsiteEdit(row)">
|
||||
<el-icon class="btn-edit-icon"><Edit /></el-icon><span>编辑</span>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="查看分组" placement="top" :show-after="300">
|
||||
<el-button size="small" circle text @click="selectWebsite(row)">
|
||||
<el-icon><Grid /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-dropdown trigger="click" @command="(cmd: string) => handleMoreAction(cmd, row)">
|
||||
<el-button size="small" text class="btn-more" :loading="row._testing">
|
||||
更多<el-icon v-if="!row._testing" class="el-icon--right"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="test" :disabled="row._testing">
|
||||
<el-icon><Connection /></el-icon>连接测试
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="binding">
|
||||
<el-icon><Link /></el-icon>新增绑定
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="importGroups">
|
||||
<el-icon><Upload /></el-icon>导入上游分组
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="importAccounts">
|
||||
<el-icon><Key /></el-icon>导入为账号管理账号
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided command="delete" class="btn-more-delete">
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button size="small" text @click="openWebsiteEdit(row)" title="编辑网站配置(API凭证、参数等)">编辑</el-button>
|
||||
<el-button size="small" text @click="selectWebsite(row)" title="查看当前网站的分组和绑定配置">查看</el-button>
|
||||
<el-button size="small" text @click="testWebsite(row)" :loading="row._testing" title="仅验证连通性,测试API是否正常响应">测试连接</el-button>
|
||||
<el-button size="small" text @click="openBindingCreate(row)" title="为此网站创建一个新的上游倍率绑定规则">新增绑定</el-button>
|
||||
<el-button size="small" text @click="openImportGroups(row)" title="一键从上游导入可用分组到此网站">导入分组</el-button>
|
||||
<el-button size="small" text @click="openImportAccounts(row)" title="将此网站下的所有账户批量导入账号管理">导入账号</el-button>
|
||||
<el-button size="small" text type="danger" @click="deleteWebsite(row)" title="删除此网站及其所有的绑定配置">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -380,7 +341,25 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="优先级">
|
||||
<el-input-number v-model="importAccountsForm.priority" :min="0" style="width:100%" />
|
||||
<template #label>
|
||||
<span>优先级</span>
|
||||
<el-tooltip content="按倍率自动分配优先级:倍率最低的上游分组优先级最高(priority=1),依次递增" placement="top" :show-after="300">
|
||||
<el-icon style="margin-left:4px;vertical-align:middle;color:var(--text-muted)"><WarningFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<div style="display:flex;align-items:center;gap:8px">
|
||||
<el-switch
|
||||
v-model="importAccountsForm.auto_priority_by_rate"
|
||||
active-text="按倍率自动分配"
|
||||
inactive-text="手动设置"
|
||||
/>
|
||||
<el-input-number
|
||||
v-if="!importAccountsForm.auto_priority_by_rate"
|
||||
v-model="importAccountsForm.priority"
|
||||
:min="0"
|
||||
style="width:160px"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -458,7 +437,7 @@ import { computed, onMounted, ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import dayjs from 'dayjs'
|
||||
import { ArrowDown, Delete, Edit, Plus, Grid, Connection, Link, Upload, Key, Refresh } from '@element-plus/icons-vue'
|
||||
import { ArrowDown, Delete, Edit, Plus, Grid, Connection, Link, Upload, Key, Refresh, WarningFilled } from '@element-plus/icons-vue'
|
||||
import {
|
||||
upstreamsApi,
|
||||
websitesApi,
|
||||
@@ -571,6 +550,7 @@ const importAccountsForm = ref({
|
||||
platform_mode: 'auto',
|
||||
concurrency: 10,
|
||||
priority: 1,
|
||||
auto_priority_by_rate: true,
|
||||
})
|
||||
const importAccountResults = ref<ImportAccountItem[]>([])
|
||||
|
||||
@@ -1027,6 +1007,7 @@ async function openImportAccounts(site?: WebsiteData | null) {
|
||||
platform_mode: 'auto',
|
||||
concurrency: 10,
|
||||
priority: 1,
|
||||
auto_priority_by_rate: true,
|
||||
}
|
||||
importAccountResults.value = []
|
||||
importSyncStatus.value = null
|
||||
@@ -1151,6 +1132,7 @@ async function submitImportAccounts() {
|
||||
platform_mode: importAccountsForm.value.platform_mode,
|
||||
concurrency: importAccountsForm.value.concurrency,
|
||||
priority: importAccountsForm.value.priority,
|
||||
auto_priority_by_rate: importAccountsForm.value.auto_priority_by_rate,
|
||||
})
|
||||
importAccountResults.value = res.data.items
|
||||
ElMessage[res.data.success ? 'success' : 'warning'](res.data.message)
|
||||
@@ -1205,47 +1187,12 @@ onMounted(loadAll)
|
||||
.error-text { font-size: 12px; color: var(--color-danger); cursor: pointer; }
|
||||
.rate-value { font-weight: 600; color: var(--color-primary-strong); font-family: monospace; }
|
||||
.action-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
flex-wrap: nowrap;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 0;
|
||||
}
|
||||
.action-row .el-button.is-circle {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin-left: 0;
|
||||
}
|
||||
.action-row .btn-edit {
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
gap: 3px;
|
||||
padding: 0 6px;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.action-row .btn-edit-icon {
|
||||
font-size: 13px;
|
||||
}
|
||||
.action-row .btn-edit:hover {
|
||||
color: var(--el-color-primary);
|
||||
background: var(--el-color-primary-light-9);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.action-row .btn-more {
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
.action-row .btn-more:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
.action-row .btn-more .el-icon--right {
|
||||
margin-left: 1px;
|
||||
}
|
||||
.btn-more-delete {
|
||||
color: var(--el-color-danger);
|
||||
.action-row .el-button {
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
.site-switcher {
|
||||
|
||||
Reference in New Issue
Block a user