generated from kevisual/vite-react-template
feat: 添加远端配置的保存和加载功能,优化仓库卡片显示主题和可见性
This commit is contained in:
@@ -8,10 +8,13 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/comp
|
||||
import { Info } from 'lucide-react';
|
||||
import { configSchema } from './store/schema';
|
||||
import { toast } from 'sonner';
|
||||
import { useLayoutStore } from '../auth/store';
|
||||
import { useShallow } from 'zustand/shallow';
|
||||
import { queryLogin } from '@/modules/query';
|
||||
|
||||
export const ConfigPage = () => {
|
||||
const { config, setConfig, resetConfig } = useConfigStore();
|
||||
|
||||
const layoutStore = useLayoutStore(useShallow(state => ({ me: state.me })))
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const result = configSchema.safeParse(config);
|
||||
@@ -28,6 +31,42 @@ export const ConfigPage = () => {
|
||||
const handleChange = (field: keyof typeof config, value: string | boolean) => {
|
||||
setConfig({ [field]: value });
|
||||
};
|
||||
const saveToRemote = async () => {
|
||||
const _config = config;
|
||||
const res = await queryLogin.post({
|
||||
path: 'config',
|
||||
key: 'update',
|
||||
data: {
|
||||
key: 'cnb_center_config.json',
|
||||
data: _config,
|
||||
}
|
||||
});
|
||||
if (res.code === 200) {
|
||||
toast.success('保存到远端成功')
|
||||
} else {
|
||||
toast.error('保存到远端失败')
|
||||
}
|
||||
}
|
||||
|
||||
const loadFromRemote = async () => {
|
||||
const res = await queryLogin.post({
|
||||
path: 'config',
|
||||
key: 'get',
|
||||
data: {
|
||||
key: 'cnb_center_config.json',
|
||||
}
|
||||
})
|
||||
if (res.code === 404) {
|
||||
toast.error('远端配置不存在')
|
||||
return;
|
||||
}
|
||||
if (res.code === 200) {
|
||||
const config = res.data?.data as typeof config;
|
||||
setConfig(config);
|
||||
toast.success('获取远端配置成功')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
@@ -51,9 +90,9 @@ export const ConfigPage = () => {
|
||||
<TooltipContent>
|
||||
<p>
|
||||
用于访问 CNB API 的密钥。
|
||||
<a
|
||||
href="https://cnb.cool/profile/token"
|
||||
target="_blank"
|
||||
<a
|
||||
href="https://cnb.cool/profile/token"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline ml-1 hover:text-blue-400"
|
||||
>
|
||||
@@ -82,9 +121,9 @@ export const ConfigPage = () => {
|
||||
<TooltipContent>
|
||||
<p>
|
||||
用于身份验证的 Cookie 信息。
|
||||
<a
|
||||
href="https://cnb.cool/kevisual/cnb-live-extension"
|
||||
target="_blank"
|
||||
<a
|
||||
href="https://cnb.cool/kevisual/cnb-live-extension"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline ml-1 hover:text-blue-400"
|
||||
>
|
||||
@@ -103,83 +142,92 @@ export const ConfigPage = () => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="cors-url">跨域地址</Label>
|
||||
<Input
|
||||
id="cors-url"
|
||||
type="url"
|
||||
value={config.CNB_CORS_URL}
|
||||
onChange={(e) => handleChange('CNB_CORS_URL', e.target.value)}
|
||||
placeholder="https://cors.example.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="enable-cors"
|
||||
checked={config.ENABLE_CORS}
|
||||
onCheckedChange={(checked) => handleChange('ENABLE_CORS', checked === true)}
|
||||
/>
|
||||
<Label htmlFor="enable-cors" className="cursor-pointer">
|
||||
启用跨域
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="ai-base-url">AI 基础地址</Label>
|
||||
<Input
|
||||
id="ai-base-url"
|
||||
type="url"
|
||||
value={config.AI_BASE_URL}
|
||||
onChange={(e) => handleChange('AI_BASE_URL', e.target.value)}
|
||||
placeholder="请输入 AI 基础地址"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="ai-model">AI 模型</Label>
|
||||
<Input
|
||||
id="ai-model"
|
||||
type="text"
|
||||
value={config.AI_MODEL}
|
||||
onChange={(e) => handleChange('AI_MODEL', e.target.value)}
|
||||
placeholder="请输入 AI 模型名称"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Label htmlFor="ai-api-key">AI 密钥</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Info className="h-4 w-4 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>
|
||||
如果使用 CNB 的 AI,密钥和 API 密钥一样即可
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="cors-url">跨域地址</Label>
|
||||
<Input
|
||||
id="cors-url"
|
||||
type="url"
|
||||
value={config.CNB_CORS_URL}
|
||||
onChange={(e) => handleChange('CNB_CORS_URL', e.target.value)}
|
||||
placeholder="https://cors.example.com"
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
id="ai-api-key"
|
||||
type="password"
|
||||
value={config.AI_API_KEY}
|
||||
onChange={(e) => handleChange('AI_API_KEY', e.target.value)}
|
||||
placeholder="请输入您的 AI API 密钥"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<Button type="submit">保存配置</Button>
|
||||
<Button type="button" variant="outline" onClick={resetConfig}>
|
||||
重置为默认值
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="enable-cors"
|
||||
checked={config.ENABLE_CORS}
|
||||
onCheckedChange={(checked) => handleChange('ENABLE_CORS', checked === true)}
|
||||
/>
|
||||
<Label htmlFor="enable-cors" className="cursor-pointer">
|
||||
启用跨域
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="ai-base-url">AI 基础地址</Label>
|
||||
<Input
|
||||
id="ai-base-url"
|
||||
type="url"
|
||||
value={config.AI_BASE_URL}
|
||||
onChange={(e) => handleChange('AI_BASE_URL', e.target.value)}
|
||||
placeholder="请输入 AI 基础地址"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="ai-model">AI 模型</Label>
|
||||
<Input
|
||||
id="ai-model"
|
||||
type="text"
|
||||
value={config.AI_MODEL}
|
||||
onChange={(e) => handleChange('AI_MODEL', e.target.value)}
|
||||
placeholder="请输入 AI 模型名称"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Label htmlFor="ai-api-key">AI 密钥</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Info className="h-4 w-4 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>
|
||||
如果使用 CNB 的 AI,密钥和 API 密钥一样即可
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Input
|
||||
id="ai-api-key"
|
||||
type="password"
|
||||
value={config.AI_API_KEY}
|
||||
onChange={(e) => handleChange('AI_API_KEY', e.target.value)}
|
||||
placeholder="请输入您的 AI API 密钥"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<Button type="submit">保存配置</Button>
|
||||
<Button type="button" variant="outline" onClick={resetConfig}>
|
||||
重置为默认值
|
||||
</Button>
|
||||
{layoutStore.me && <>
|
||||
<Button type="button" variant="outline" onClick={loadFromRemote}>
|
||||
获取远端配置
|
||||
</Button>
|
||||
<Button type="button" variant="outline" onClick={saveToRemote}>
|
||||
保存到远端
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user