feat: multi-feature update
This commit is contained in:
Vendored
+139
@@ -0,0 +1,139 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import SettingsPanel from './components/SettingsPanel.vue'
|
||||
import ImageGenerator from './components/ImageGenerator.vue'
|
||||
import Gallery from './components/Gallery.vue'
|
||||
import { probeSession, listModels, getSelf, type NewApiUser, type Auth } from './lib/api'
|
||||
import { loadSettings } from './lib/settings'
|
||||
|
||||
const user = ref<NewApiUser | null>(null)
|
||||
const auth = ref<Auth>({ kind: 'session' })
|
||||
const baseUrl = ref<string>(loadSettings().baseUrl)
|
||||
const models = ref<string[]>([])
|
||||
const error = ref<string>('')
|
||||
const settingsRef = ref<InstanceType<typeof SettingsPanel> | null>(null)
|
||||
const galleryRef = ref<InstanceType<typeof Gallery> | null>(null)
|
||||
const checking = ref<boolean>(true)
|
||||
|
||||
async function refreshSession() {
|
||||
checking.value = true
|
||||
try {
|
||||
const u = await probeSession(baseUrl.value)
|
||||
user.value = u
|
||||
error.value = ''
|
||||
if (u) {
|
||||
try {
|
||||
models.value = await listModels(baseUrl.value, { kind: 'session' })
|
||||
} catch (e) {
|
||||
error.value = `已登录,但拉取模型失败: ${e}`
|
||||
}
|
||||
} else {
|
||||
models.value = []
|
||||
}
|
||||
} finally {
|
||||
checking.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(refreshSession)
|
||||
// Re-probe when the tab regains focus (e.g. user came back from /sign-in).
|
||||
// `visibilitychange` covers mobile / tab-switch too; `focus` covers desktop.
|
||||
window.addEventListener('focus', refreshSession)
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') refreshSession()
|
||||
})
|
||||
|
||||
async function onSessionChanged(u: NewApiUser | null) {
|
||||
user.value = u
|
||||
if (u) {
|
||||
try {
|
||||
models.value = await listModels(baseUrl.value, { kind: 'session' })
|
||||
} catch (e) {
|
||||
error.value = `已登录,但拉取模型失败: ${e}`
|
||||
}
|
||||
} else {
|
||||
models.value = []
|
||||
}
|
||||
}
|
||||
|
||||
function onAuthOverridden(a: Auth) {
|
||||
auth.value = a
|
||||
if (a.kind === 'sk') {
|
||||
// refresh user info using the new auth
|
||||
getSelf(baseUrl.value, a)
|
||||
.then((u) => {
|
||||
user.value = u
|
||||
})
|
||||
.catch((e) => {
|
||||
error.value = `sk-key 无效: ${e}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function onGenerated(img: { prompt: string; model: string; urls: string[] }) {
|
||||
galleryRef.value?.add(img)
|
||||
// refresh quota after a generation (best-effort)
|
||||
if (user.value) {
|
||||
probeSession(baseUrl.value)
|
||||
.then((u) => {
|
||||
if (u) user.value = u
|
||||
})
|
||||
.catch(() => {
|
||||
/* ignore */
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function onError(msg: string) {
|
||||
error.value = msg
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-full max-w-5xl mx-auto p-6 space-y-5">
|
||||
<header class="flex items-baseline justify-between">
|
||||
<div>
|
||||
<h1 class="text-2xl font-semibold tracking-tight">newapi-image-gen</h1>
|
||||
<p class="text-xs text-zinc-500 mt-0.5">
|
||||
走 new-api 的 <code class="text-zinc-400">/v1/images/generations</code>,额度扣 new-api 账户
|
||||
</p>
|
||||
</div>
|
||||
<a
|
||||
v-if="user"
|
||||
href="/"
|
||||
class="text-xs text-zinc-500 hover:text-zinc-300"
|
||||
>← 返回 new-api 主页</a>
|
||||
</header>
|
||||
|
||||
<p v-if="error" class="rounded-md border border-rose-800 bg-rose-950/40 px-3 py-2 text-sm text-rose-300">
|
||||
{{ error }}
|
||||
</p>
|
||||
|
||||
<SettingsPanel
|
||||
ref="settingsRef"
|
||||
:user="user"
|
||||
@session-changed="onSessionChanged"
|
||||
@auth-overridden="onAuthOverridden"
|
||||
/>
|
||||
|
||||
<div v-if="checking" class="text-sm text-zinc-500">检查登录态…</div>
|
||||
|
||||
<ImageGenerator
|
||||
v-else-if="user"
|
||||
:base-url="baseUrl"
|
||||
:auth="auth"
|
||||
:models="models"
|
||||
@generated="onGenerated"
|
||||
@error="onError"
|
||||
/>
|
||||
<div v-else class="rounded-xl border border-dashed border-zinc-800 p-6 text-center text-sm text-zinc-500">
|
||||
先在上方登录,登录后会自动出现生图面板。
|
||||
</div>
|
||||
|
||||
<Gallery ref="galleryRef" :base-url="baseUrl" />
|
||||
|
||||
<footer class="pt-4 pb-2 text-center text-xs text-zinc-600">
|
||||
登录走 new-api 自己的 OAuth,会话 cookie 跟 new-api 主站共享;本前端不会碰你的密码或 token。
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user