13 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import {useEffect,useState} from 'react'
import BrandLogo from '@/components/BrandLogo'
import {DEFAULT_LOGIN_LOGO_URL} from '@/lib/brand-assets'
import './authorize.css'
export default function AuthorizeClient({account,request}:{account:{id:string;name:string};request:Record<string,string>}){
const [busy,setBusy]=useState(false),[error,setError]=useState(''),[devices,setDevices]=useState<{id:string;deviceName:string;createdAt:string}[]>([])
useEffect(()=>{void fetch('/api/desktop/devices',{cache:'no-store'}).then(r=>r.json()).then(r=>setDevices(r.devices||[])).catch(()=>{})},[])
async function approve(){setBusy(true);setError('');try{const response=await fetch('/api/desktop/authorize',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(request)});const value=await response.json();if(!response.ok)throw new Error(value.error);window.location.assign(value.redirect)}catch(error){setError(error instanceof Error?error.message:'授权未完成,请重试');setBusy(false)}}
function cancel(){const url=new URL(request.redirect_uri);url.searchParams.set('error','access_denied');url.searchParams.set('state',request.state);window.location.assign(url)}
return <main className="client-authorize"><div className="authorize-brand"><BrandLogo src={DEFAULT_LOGIN_LOGO_URL} fallbackSrc={DEFAULT_LOGIN_LOGO_URL} alt="由壹点素材库" width={44} height={44} className="authorize-logo"/><span>由壹点 · 素材库</span></div><h1>授权详情页工作台</h1><p className="authorize-account">使用 <strong>{account.name}</strong> 的账户继续</p><ul><li>查看、继续处理本人项目</li><li>同步草稿、对话和项目文件</li><li>读取管理员开放的模型列表</li></ul><p className="authorize-note">授权只用于当前客户端。你可以随时撤销,客户端不会获取网页登录密码。</p>{error&&<p role="alert">{error}</p>}<div className="authorize-actions"><button disabled={busy} onClick={cancel}>取消</button><button disabled={busy} className="authorize-primary" onClick={()=>void approve()}>{busy?'正在授权…':'授权并返回客户端'}</button></div>{devices.length>0&&<details><summary>已授权的客户端</summary>{devices.map(device=><div className="authorize-device" key={device.id}><span>{device.deviceName}<small>{new Date(device.createdAt).toLocaleDateString('zh-CN')}</small></span><button onClick={async()=>{const r=await fetch('/api/desktop/devices/'+encodeURIComponent(device.id),{method:'DELETE'});if(r.ok)setDevices(v=>v.filter(d=>d.id!==device.id));else setError('撤销未完成,请重试')}}>撤销授权</button></div>)}</details>}</main>
}