feat(admin): 添加用户管理和Linux.do登录功能
- 新增AdminUser类型定义及用户管理API接口 - 实现用户列表查询、保存和删除功能 - 添加Linux.do第三方登录支持 - 集成Linux.do OAuth认证流程 - 在系统设置中添加Linux.do登录配置选项 - 实现算力点余额调整记录功能 - 优化搜索组件关键词状态管理 - 更新数据库迁移添加credit_logs表 - 完善用户状态和信用等级验证逻辑
This commit is contained in:
@@ -35,8 +35,9 @@ const emptySettings: AdminSettings = {
|
||||
systemPrompt: "",
|
||||
allowCustomChannel: true,
|
||||
},
|
||||
auth: { linuxDo: { enabled: false } },
|
||||
},
|
||||
private: { channels: [], promptSync: { enabled: true, cron: "*/5 * * * *" } },
|
||||
private: { channels: [], promptSync: { enabled: true, cron: "*/5 * * * *" }, auth: { linuxDo: { clientId: "", clientSecret: "", redirectUri: "", minimumTrustLevel: 0 } } },
|
||||
};
|
||||
const emptyChannel: AdminModelChannel = { protocol: "openai", name: "", baseUrl: "", apiKey: "", models: [], weight: 1, enabled: true, remark: "" };
|
||||
|
||||
@@ -61,7 +62,9 @@ export default function AdminSettingsPage() {
|
||||
const [testResults, setTestResults] = useState<Record<string, { status: "success" | "error"; duration?: string; message: string }>>({});
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [linuxDoCallbackUrl, setLinuxDoCallbackUrl] = useState("");
|
||||
const publicModels = Form.useWatch(["public", "modelChannel", "availableModels"], form) || [];
|
||||
const linuxDoRedirectUri = Form.useWatch(["private", "auth", "linuxDo", "redirectUri"], form);
|
||||
const channelModels = useMemo(() => collectChannelModels(channels), [channels]);
|
||||
const channelTableData = useMemo(() => channels.map((channel, index) => ({ ...channel, _index: index, _rowKey: `${index}-${channel.name}-${channel.baseUrl}` })), [channels]);
|
||||
const modelOptions = useMemo(() => uniqueModels([...publicModels, ...channelModels]), [publicModels, channelModels]);
|
||||
@@ -91,6 +94,16 @@ export default function AdminSettingsPage() {
|
||||
void loadSettings();
|
||||
}, [token]);
|
||||
|
||||
useEffect(() => {
|
||||
setLinuxDoCallbackUrl(`${window.location.origin}/api/auth/linux-do/callback`);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!linuxDoCallbackUrl) return;
|
||||
if (linuxDoRedirectUri) return;
|
||||
form.setFieldValue(["private", "auth", "linuxDo", "redirectUri"], linuxDoCallbackUrl);
|
||||
}, [form, linuxDoCallbackUrl, linuxDoRedirectUri]);
|
||||
|
||||
const changeTab = (nextTab: SettingsTabKey) => {
|
||||
setActiveTab(nextTab);
|
||||
};
|
||||
@@ -365,6 +378,46 @@ export default function AdminSettingsPage() {
|
||||
<Form form={form} layout="vertical" initialValues={emptySettings} requiredMark={false}>
|
||||
<Flex vertical gap={12}>
|
||||
<Alert showIcon type="warning" title="当前还没有完整用户体系,所有访问到站点的用户都可以无条件使用后端渠道 API。请不要公网部署,避免私有渠道额度被他人消耗。" />
|
||||
<Card
|
||||
size="small"
|
||||
title={
|
||||
<Space>
|
||||
<img src="/icons/linuxdo.svg" alt="" width={18} height={18} />
|
||||
Linux.do 登录
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Flex vertical gap={14}>
|
||||
<Alert showIcon type="info" message={linuxDoCallbackUrl ? `回调 URL 填 ${linuxDoCallbackUrl}` : "回调 URL 使用当前站点的 /api/auth/linux-do/callback"} />
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} md={6}>
|
||||
<Form.Item name={["public", "auth", "linuxDo", "enabled"]} label="开启 Linux.do 登录" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={9}>
|
||||
<Form.Item name={["private", "auth", "linuxDo", "clientId"]} label="Linux.do Client ID">
|
||||
<Input placeholder="输入 Linux.do OAuth App 的 ID" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={9}>
|
||||
<Form.Item name={["private", "auth", "linuxDo", "clientSecret"]} label="Linux.do Client Secret">
|
||||
<Input.Password placeholder="留空则沿用已保存的密钥" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={18}>
|
||||
<Form.Item name={["private", "auth", "linuxDo", "redirectUri"]} label="回调 URL">
|
||||
<Input placeholder={linuxDoCallbackUrl || "https://your-domain.com/api/auth/linux-do/callback"} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={6}>
|
||||
<Form.Item name={["private", "auth", "linuxDo", "minimumTrustLevel"]} label="最低信任等级">
|
||||
<InputNumber min={0} max={4} precision={0} className="!w-full" placeholder="0" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Flex>
|
||||
</Card>
|
||||
<Card size="small" title="提示词定时同步">
|
||||
<Row gutter={16} align="middle">
|
||||
<Col xs={24} md={8}>
|
||||
@@ -600,6 +653,11 @@ function normalizePublicSetting(setting: Partial<AdminSettings["public"]> = {}):
|
||||
...(setting.modelChannel || {}),
|
||||
availableModels: setting.modelChannel?.availableModels || [],
|
||||
},
|
||||
auth: {
|
||||
linuxDo: {
|
||||
enabled: setting.auth?.linuxDo?.enabled === true,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -610,6 +668,14 @@ function normalizePrivateSetting(setting: Partial<AdminSettings["private"]> = {}
|
||||
enabled: setting.promptSync?.enabled !== false,
|
||||
cron: setting.promptSync?.cron || "*/5 * * * *",
|
||||
},
|
||||
auth: {
|
||||
linuxDo: {
|
||||
clientId: setting.auth?.linuxDo?.clientId || "",
|
||||
clientSecret: setting.auth?.linuxDo?.clientSecret || "",
|
||||
redirectUri: setting.auth?.linuxDo?.redirectUri || "",
|
||||
minimumTrustLevel: Math.max(0, Number(setting.auth?.linuxDo?.minimumTrustLevel) || 0),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user