feat: 并发分组系统 + 品牌/Logo 上传 + 兑换码开关 + 文档分辨率表
并发分组(新功能): - 新表 concurrency_groups(名称/上限/默认),用户加 concurrency_group_id - 启动自动建「默认并发」组(上限10、默认),老用户回填、新注册自动绑定 - 并发计数改用 Redis(自愈 sorted-set + TTL + fail-open): · 用户并发(画图台 + API key 合计)受其分组上限限制,0=不限制 → 超返回 429 · 账号级并发也从内存 gate 换成同一套 Redis(6 处调用点) · 移除旧的「已有正在生成的任务」单任务锁 - 后台「并发分组」新菜单:增删改、设默认、用户数;默认组不可删(删别的组成员转默认) - 用户管理:并发列 + 新建/编辑可选分组 - 个人设置页:账户信息卡(用户名/邮箱/角色/余额/并发);/me 暴露 concurrency_group/limit 品牌 / Logo(上传到 RustFS): - Logo 改成拖拽/点击上传,点保存才上传;替换自动删旧;branding/ 设为公开且被清理任务 pin 住(永不删) - 有自定义就用:前台左侧 nav + 后台侧栏 + favicon(浏览器标签);没有则默认 V 图标 - 前台页头还原成文字;首页 Hero 子标题用 site.subtitle(默认那句宣传语,设置页预填) - 邮件验证码标题用站点名;新增 POST/DELETE /settings/logo + POST /settings/asset(首页底图上传) 兑换码开关: - 系统设置→积分 新增「开启兑换码」(默认开);关闭后后端拒绝兑换、前台隐藏兑换入口(/site 暴露 cdk_redeem_enabled) 文档 / 分辨率: - 去掉 quality 参数:size(宽x高)同时决定比例 + 分辨率档(长边映射 1K/2K/4K) - 文档加「分辨率对照表」(14 个比例 × 1K/2K/4K → size 该传的值);guessRatio 与自定义模型 RATIO_OPTS 对齐到 14 个 其它: - 删模型时同步清掉各上游账号「支持模型」里的该 id - 首页设置/兑换码弹窗去固定高度滚动条;展示位弹窗浅色主题适配 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,13 @@ async function changePwd() {
|
||||
// ---- Credits: the REAL server-side balance of the logged-in user ----
|
||||
// (admin adjustments in 用户管理 write this same field). Top-up is via CDK.
|
||||
const balance = computed(() => Number(auth.user?.credits || 0))
|
||||
const roleLabel = computed(() => ({ user: '普通用户', agent: '代理', admin: '管理员' }[auth.user?.role] || '普通用户'))
|
||||
const concurrencyLabel = computed(() => {
|
||||
const n = Number(auth.user?.concurrency_limit || 0)
|
||||
const g = auth.user?.concurrency_group
|
||||
if (n <= 0) return g ? `不限制 · ${g}` : '不限制'
|
||||
return g ? `${n} · ${g}` : String(n)
|
||||
})
|
||||
|
||||
const cdkCode = ref('')
|
||||
const cdkBusy = ref(false)
|
||||
@@ -184,6 +191,36 @@ function toast(m) {
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<!-- ===== Account info ===== -->
|
||||
<section class="card p-6">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<Icon name="accounts" class="w-4 h-4 text-violet-300" />
|
||||
<h2 class="text-sm font-semibold">账户信息</h2>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 lg:grid-cols-5 gap-4 text-sm">
|
||||
<div>
|
||||
<div class="text-[11px] text-white/40 uppercase tracking-wider mb-1">用户名</div>
|
||||
<div class="text-white/90 font-medium truncate" :title="auth.user?.name || ''">{{ auth.user?.name || '—' }}</div>
|
||||
</div>
|
||||
<div class="col-span-2 lg:col-span-1">
|
||||
<div class="text-[11px] text-white/40 uppercase tracking-wider mb-1">绑定邮箱</div>
|
||||
<div class="text-white/90 font-mono text-xs break-all" :title="auth.user?.email || ''">{{ auth.user?.email || '—' }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-[11px] text-white/40 uppercase tracking-wider mb-1">角色</div>
|
||||
<div class="text-white/90">{{ roleLabel }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-[11px] text-white/40 uppercase tracking-wider mb-1">积分余额</div>
|
||||
<div class="text-amber-300 font-semibold tabular-nums">{{ pointsLabel(balance) }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-[11px] text-white/40 uppercase tracking-wider mb-1">并发上限</div>
|
||||
<div class="text-white/90 truncate" :title="concurrencyLabel">{{ concurrencyLabel }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== Two-column grid ===== -->
|
||||
<div class="grid lg:grid-cols-2 gap-5">
|
||||
|
||||
@@ -280,8 +317,8 @@ function toast(m) {
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<!-- CDK REDEEM -->
|
||||
<section class="relative card p-7 md:p-8 overflow-hidden">
|
||||
<!-- CDK REDEEM — hidden when the admin turns the 兑换码 switch off -->
|
||||
<section v-if="site.cdkRedeemEnabled" class="relative card p-7 md:p-8 overflow-hidden">
|
||||
<div class="inline-grid w-10 h-10 rounded-xl bg-emerald-500/15 ring-1 ring-emerald-400/30 grid place-items-center text-emerald-300">
|
||||
<Icon name="spark" class="w-4 h-4" />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user