Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 17 additions & 58 deletions ui/scripts/downLoadIcon.cjs
Original file line number Diff line number Diff line change
@@ -1,64 +1,23 @@
const fs = require('fs')
const path = require('path')

const Axios = require('axios')
const fs = require("fs");
const path = require("path");

async function downloadFile(url) {
try {
const iconPath = path.resolve(__dirname, '../src/assets/fonts/iconfont.js')
const iconDir = path.dirname(iconPath)

// 检查目录是否存在,如果不存在则创建
if (!fs.existsSync(iconDir)) {
console.log(`目录 ${iconDir} 不存在,正在创建...`)
fs.mkdirSync(iconDir, { recursive: true })
console.log('目录创建成功')
}

console.log(`开始下载图标文件到: ${iconPath}`)

const writer = fs.createWriteStream(iconPath)
const response = await Axios({
url: `https:${url}`,
method: 'GET',
responseType: 'stream',
timeout: 30000, // 30秒超时
})

response.data.pipe(writer)

return new Promise((resolve, reject) => {
writer.on('finish', () => {
console.log('图标文件下载成功!')
resolve()
})
writer.on('error', (err) => {
console.error('写入文件时出错:', err.message)
reject(err)
})
})
} catch (error) {
console.error('下载过程中出错:', error.message)
throw error
}
}
const iconPath = path.resolve(__dirname, "../src/assets/fonts/iconfont.js");
const iconDir = path.dirname(iconPath);

async function main() {
const argument = process.argv.splice(2)

if (!argument[0]) {
console.error('错误: 请提供下载URL作为参数')
console.log('使用方法: node downLoadIcon.cjs <url>')
process.exit(1)
}

try {
await downloadFile(argument[0])
console.log('所有操作完成!')
} catch (error) {
console.error('脚本执行失败:', error.message)
process.exit(1)
// 检查目录是否存在,不存在则创建
if (!fs.existsSync(iconDir)) {
fs.mkdirSync(iconDir, { recursive: true });
console.log(`目录 ${iconDir} 已创建`);
}

const response = await fetch(`https:${url}`, {
method: "GET",
// responseType: "stream", // fetch 不支持此参数
}).then((res) => res.text());
fs.writeFileSync(iconPath, response);
console.log("Download Icon Success");
}
let argument = process.argv.splice(2);
downloadFile(argument[0]);

main()
63 changes: 63 additions & 0 deletions ui/src/api/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
DomainListUserResp,
DomainLoginReq,
DomainLoginResp,
DomainOAuthURLResp,
DomainRegisterReq,
DomainSetting,
DomainUpdateSettingReq,
Expand All @@ -32,6 +33,8 @@ import {
GetListAdminUserParams,
GetListUserParams,
GetLoginHistoryParams,
GetUserOauthCallbackParams,
GetUserOauthSignupOrInParams,
WebResp,
} from "./types";

Expand Down Expand Up @@ -401,6 +404,66 @@ export const getLoginHistory = (
...params,
});

/**
* @description 用户 OAuth 回调
*
* @tags User
* @name GetUserOauthCallback
* @summary 用户 OAuth 回调
* @request GET:/api/v1/user/oauth/callback
* @response `200` `(WebResp & {
data?: string,

})` OK
*/

export const getUserOauthCallback = (
query: GetUserOauthCallbackParams,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: string;
}
>({
path: `/api/v1/user/oauth/callback`,
method: "GET",
query: query,
type: ContentType.Json,
format: "json",
...params,
});

/**
* @description 用户 OAuth 登录或注册
*
* @tags User
* @name GetUserOauthSignupOrIn
* @summary 用户 OAuth 登录或注册
* @request GET:/api/v1/user/oauth/signup-or-in
* @response `200` `(WebResp & {
data?: DomainOAuthURLResp,

})` OK
*/

export const getUserOauthSignupOrIn = (
query: GetUserOauthSignupOrInParams,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainOAuthURLResp;
}
>({
path: `/api/v1/user/oauth/signup-or-in`,
method: "GET",
query: query,
type: ContentType.Json,
format: "json",
...params,
});

/**
* @description 注册用户
*
Expand Down
31 changes: 31 additions & 0 deletions ui/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export enum ConstsUserStatus {
UserStatusLocked = "locked",
}

export enum ConstsUserPlatform {
UserPlatformEmail = "email",
UserPlatformDingTalk = "dingtalk",
}

export enum ConstsModelType {
ModelTypeLLM = "llm",
ModelTypeCoder = "coder",
Expand Down Expand Up @@ -312,6 +317,10 @@ export interface DomainModelTokenUsageResp {
total_output?: number;
}

export interface DomainOAuthURLResp {
url?: string;
}

export interface DomainProviderModel {
/** 模型列表 */
models?: DomainModelBasic[];
Expand All @@ -333,6 +342,8 @@ export interface DomainSetting {
created_at?: number;
/** 是否禁用密码登录 */
disable_password_login?: boolean;
/** 是否开启钉钉OAuth */
enable_dingtalk_oauth?: boolean;
/** 是否开启SSO */
enable_sso?: boolean;
/** 是否强制两步验证 */
Expand Down Expand Up @@ -419,8 +430,14 @@ export interface DomainUpdateModelReq {
}

export interface DomainUpdateSettingReq {
/** 钉钉客户端ID */
dingtalk_client_id?: string;
/** 钉钉客户端密钥 */
dingtalk_client_secret?: string;
/** 是否禁用密码登录 */
disable_password_login?: boolean;
/** 是否开启钉钉OAuth */
enable_dingtalk_oauth?: boolean;
/** 是否开启SSO */
enable_sso?: boolean;
/** 是否强制两步验证 */
Expand Down Expand Up @@ -637,3 +654,17 @@ export interface GetLoginHistoryParams {
/** 每页多少条记录 */
size?: number;
}

export interface GetUserOauthCallbackParams {
code: string;
state: string;
}

export interface GetUserOauthSignupOrInParams {
/** 第三方平台 dingtalk */
platform: "email" | "dingtalk";
/** 登录成功后跳转的 URL */
redirect_url?: string;
/** 会话ID */
session_id?: string;
}
2 changes: 1 addition & 1 deletion ui/src/assets/fonts/iconfont.js

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions ui/src/components/form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
'use client';
import { styled, FormLabel } from '@mui/material';

export const StyledFormLabel = styled(FormLabel)(({ theme }) => ({
display: 'block',
color: theme.vars.palette.text.primary,
fontSize: 16,
fontWeight: 500,
fontSize: 14,
fontWeight: 400,
marginBottom: theme.spacing(1),
[theme.breakpoints.down('sm')]: {
fontSize: 14,
Expand Down
7 changes: 6 additions & 1 deletion ui/src/components/markDown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ const MarkDown = ({

const answer = processContent(content);

console.log(answer);

console.log(content);

if (content.length === 0) return null;

return (
Expand Down Expand Up @@ -446,12 +450,13 @@ const MarkDown = ({
...rest
}: React.HTMLAttributes<HTMLElement>) {
const match = /language-(\w+)/.exec(className || '');
console.log(children, rest);
return match ? (
<SyntaxHighlighter
showLineNumbers
{...rest}
language={match[1] || 'bash'}
style={github}
style={anOldHope}
onClick={() => {
if (navigator.clipboard) {
navigator.clipboard.writeText(
Expand Down
62 changes: 45 additions & 17 deletions ui/src/pages/auth/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@ import {
Grid2 as Grid,
InputAdornment,
IconButton,
Divider,
Stack,
} from '@mui/material';
import { Icon } from '@c-x/ui';
import { Icon, message } from '@c-x/ui';

// @ts-ignore
import { AestheticFluidBg } from '@/assets/jsm/AestheticFluidBg.module.js';

import { useSearchParams } from 'react-router-dom';
import { postLogin } from '@/api/User';
import { postLogin, getUserOauthSignupOrIn, getGetSetting } from '@/api/User';

import { useForm, Controller } from 'react-hook-form';
import { styled } from '@mui/material/styles';
import { useRequest } from 'ahooks';

// 样式化组件
const StyledContainer = styled(Container)(({ theme }) => ({
Expand Down Expand Up @@ -111,6 +114,7 @@ const AuthPage = () => {
const [showPassword, setShowPassword] = useState(false);

const [searchParams] = useSearchParams();
const { data: loginSetting = {} } = useRequest(getGetSetting);

const {
control,
Expand All @@ -132,7 +136,8 @@ const AuthPage = () => {
try {
const sessionId = searchParams.get('session_id');
if (!sessionId) {
throw new Error('缺少会话ID参数');
message.error('缺少会话ID参数');
return;
}

// 用户登录
Expand Down Expand Up @@ -245,17 +250,6 @@ const AuthPage = () => {
/>
);

// 渲染错误提示
const renderErrorAlert = () => {
if (!error) return null;

return (
<Grid size={12}>
<Alert severity='error'>{error}</Alert>
</Grid>
);
};

// 渲染登录按钮
const renderLoginButton = () => (
<Grid size={12}>
Expand All @@ -271,6 +265,32 @@ const AuthPage = () => {
</Grid>
);

const onDingdingLogin = () => {
getUserOauthSignupOrIn({
platform: 'dingtalk',
redirect_url: window.location.origin + window.location.pathname,
// @ts-ignore
session_id: searchParams.get('session_id') || null,
}).then((res) => {
if (res.url) {
window.location.href = res.url;
}
});
};

const dingdingLogin = () => {
return (
<Stack justifyContent='center'>
<Divider sx={{ my: 3, fontSize: 12, borderColor: 'divider' }}>
使用其他方式登录
</Divider>
<IconButton sx={{ alignSelf: 'center' }} onClick={onDingdingLogin}>
<Icon type='icon-dingding' sx={{ fontSize: 30 }} />
</IconButton>
</Stack>
);
};

// 渲染登录表单
const renderLoginForm = () => (
<>
Expand All @@ -284,19 +304,27 @@ const AuthPage = () => {
<Box component='form' onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={4}>
<Grid size={12}>{renderUsernameField()}</Grid>

<Grid size={12}>{renderPasswordField()}</Grid>

{renderErrorAlert()}
{renderLoginButton()}
</Grid>
</Box>
</>
);

useEffect(() => {
const redirect_url = searchParams.get('redirect_url');
if (redirect_url) {
window.location.href = redirect_url;
}
}, []);

return (
<StyledContainer id='box'>
<StyledPaper elevation={3}>{renderLoginForm()}</StyledPaper>
<StyledPaper elevation={3}>
{!loginSetting.disable_password_login && renderLoginForm()}
{loginSetting.enable_dingtalk_oauth && dingdingLogin()}
</StyledPaper>
</StyledContainer>
);
};
Expand Down
Loading