diff --git a/web/berry/.prettierrc b/web/berry/.prettierrc
new file mode 100644
index 00000000..d5fba07c
--- /dev/null
+++ b/web/berry/.prettierrc
@@ -0,0 +1,8 @@
+{
+ "bracketSpacing": true,
+ "printWidth": 140,
+ "singleQuote": true,
+ "trailingComma": "none",
+ "tabWidth": 2,
+ "useTabs": false
+}
diff --git a/web/berry/public/index.html b/web/berry/public/index.html
index 6f232250..abd079e1 100644
--- a/web/berry/public/index.html
+++ b/web/berry/public/index.html
@@ -11,11 +11,6 @@
name="description"
content="OpenAI 接口聚合管理,支持多种渠道包括 Azure,可用于二次分发管理 key,仅单可执行文件,已打包好 Docker 镜像,一键部署,开箱即用"
/>
-
-
diff --git a/web/berry/src/App.js b/web/berry/src/App.js
index fc54c632..d6422a0f 100644
--- a/web/berry/src/App.js
+++ b/web/berry/src/App.js
@@ -1,8 +1,9 @@
-import { useSelector } from 'react-redux';
+import { useEffect } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
import { ThemeProvider } from '@mui/material/styles';
import { CssBaseline, StyledEngineProvider } from '@mui/material';
-
+import { SET_THEME } from 'store/actions';
// routing
import Routes from 'routes';
@@ -20,8 +21,16 @@ import { SnackbarProvider } from 'notistack';
// ==============================|| APP ||============================== //
const App = () => {
+ const dispatch = useDispatch();
const customization = useSelector((state) => state.customization);
+ useEffect(() => {
+ const storedTheme = localStorage.getItem('theme');
+ if (storedTheme) {
+ dispatch({ type: SET_THEME, theme: storedTheme });
+ }
+ }, [dispatch]);
+
return (
diff --git a/web/berry/src/assets/fonts/roboto-500.woff2 b/web/berry/src/assets/fonts/roboto-500.woff2
new file mode 100644
index 00000000..2360b721
Binary files /dev/null and b/web/berry/src/assets/fonts/roboto-500.woff2 differ
diff --git a/web/berry/src/assets/fonts/roboto-700.woff2 b/web/berry/src/assets/fonts/roboto-700.woff2
new file mode 100644
index 00000000..4aeda71b
Binary files /dev/null and b/web/berry/src/assets/fonts/roboto-700.woff2 differ
diff --git a/web/berry/src/assets/fonts/roboto-regular.woff2 b/web/berry/src/assets/fonts/roboto-regular.woff2
new file mode 100644
index 00000000..b65a361a
Binary files /dev/null and b/web/berry/src/assets/fonts/roboto-regular.woff2 differ
diff --git a/web/berry/src/assets/images/icons/lark.svg b/web/berry/src/assets/images/icons/lark.svg
new file mode 100644
index 00000000..239e1bef
--- /dev/null
+++ b/web/berry/src/assets/images/icons/lark.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/web/berry/src/assets/images/logo-white.svg b/web/berry/src/assets/images/logo-white.svg
new file mode 100644
index 00000000..d6289b9a
--- /dev/null
+++ b/web/berry/src/assets/images/logo-white.svg
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/web/berry/src/assets/scss/_themes-vars.module.scss b/web/berry/src/assets/scss/_themes-vars.module.scss
index a470b033..661bb6c6 100644
--- a/web/berry/src/assets/scss/_themes-vars.module.scss
+++ b/web/berry/src/assets/scss/_themes-vars.module.scss
@@ -46,11 +46,16 @@ $grey600: #4b5565;
$grey700: #364152;
$grey900: #121926;
+$tableBackground: #f4f6f8;
+$tableBorderBottom: #f1f3f4;
+
// ==============================|| DARK THEME VARIANTS ||============================== //
// paper & background
$darkBackground: #1a223f; // level 3
$darkPaper: #111936; // level 4
+$darkDivider: rgba(227, 232, 239, 0.2);
+$darkSelectedBack : rgba(124, 77, 255, 0.15);
// dark 800 & 900
$darkLevel1: #29314f; // level 1
@@ -154,4 +159,9 @@ $darkTextSecondary: #8492c4;
darkSecondaryDark: $darkSecondaryDark;
darkSecondary200: $darkSecondary200;
darkSecondary800: $darkSecondary800;
+
+ darkDivider: $darkDivider;
+ darkSelectedBack: $darkSelectedBack;
+ tableBackground: $tableBackground;
+ tableBorderBottom: $tableBorderBottom;
}
diff --git a/web/berry/src/assets/scss/fonts.scss b/web/berry/src/assets/scss/fonts.scss
new file mode 100644
index 00000000..c792aab2
--- /dev/null
+++ b/web/berry/src/assets/scss/fonts.scss
@@ -0,0 +1,32 @@
+
+/* roboto-regular */
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 400;
+ font-display: swap;
+ src: local('Roboto'), url('../fonts/roboto-regular.woff2') format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+ }
+
+ /* roboto-500 */
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 500;
+ font-display: swap;
+ src: local('Roboto'), url('../fonts/roboto-500.woff2') format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+
+
+/* roboto-700 */
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 700;
+ font-display: swap;
+ src: local('Roboto'), url('../fonts/roboto-700.woff2') format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+
\ No newline at end of file
diff --git a/web/berry/src/assets/scss/style.scss b/web/berry/src/assets/scss/style.scss
index 17d566e6..5d2d8975 100644
--- a/web/berry/src/assets/scss/style.scss
+++ b/web/berry/src/assets/scss/style.scss
@@ -1,3 +1,4 @@
+@import 'fonts.scss';
// color variants
@import 'themes-vars.module.scss';
diff --git a/web/berry/src/hooks/useLogin.js b/web/berry/src/hooks/useLogin.js
index 53626577..39d8b407 100644
--- a/web/berry/src/hooks/useLogin.js
+++ b/web/berry/src/hooks/useLogin.js
@@ -48,6 +48,28 @@ const useLogin = () => {
}
};
+ const larkLogin = async (code, state) => {
+ try {
+ const res = await API.get(`/api/oauth/lark?code=${code}&state=${state}`);
+ const { success, message, data } = res.data;
+ if (success) {
+ if (message === 'bind') {
+ showSuccess('绑定成功!');
+ navigate('/panel');
+ } else {
+ dispatch({ type: LOGIN, payload: data });
+ localStorage.setItem('user', JSON.stringify(data));
+ showSuccess('登录成功!');
+ navigate('/panel');
+ }
+ }
+ return { success, message };
+ } catch (err) {
+ // 请求失败,设置错误信息
+ return { success: false, message: '' };
+ }
+ };
+
const wechatLogin = async (code) => {
try {
const res = await API.get(`/api/oauth/wechat?code=${code}`);
@@ -72,7 +94,7 @@ const useLogin = () => {
navigate('/');
};
- return { login, logout, githubLogin, wechatLogin };
+ return { login, logout, githubLogin, wechatLogin, larkLogin };
};
export default useLogin;
diff --git a/web/berry/src/layout/MainLayout/Header/ProfileSection/index.js b/web/berry/src/layout/MainLayout/Header/ProfileSection/index.js
index 3e351254..e1392dc0 100644
--- a/web/berry/src/layout/MainLayout/Header/ProfileSection/index.js
+++ b/web/berry/src/layout/MainLayout/Header/ProfileSection/index.js
@@ -71,8 +71,8 @@ const ProfileSection = () => {
alignItems: 'center',
borderRadius: '27px',
transition: 'all .2s ease-in-out',
- borderColor: theme.palette.primary.light,
- backgroundColor: theme.palette.primary.light,
+ borderColor: theme.typography.menuChip.background,
+ backgroundColor: theme.typography.menuChip.background,
'&[aria-controls="menu-list-grow"], &:hover': {
borderColor: theme.palette.primary.main,
background: `${theme.palette.primary.main}!important`,
diff --git a/web/berry/src/layout/MainLayout/Header/index.js b/web/berry/src/layout/MainLayout/Header/index.js
index 51d40c75..8fd9c950 100644
--- a/web/berry/src/layout/MainLayout/Header/index.js
+++ b/web/berry/src/layout/MainLayout/Header/index.js
@@ -7,6 +7,7 @@ import { Avatar, Box, ButtonBase } from '@mui/material';
// project imports
import LogoSection from '../LogoSection';
import ProfileSection from './ProfileSection';
+import ThemeButton from 'ui-component/ThemeButton';
// assets
import { IconMenu2 } from '@tabler/icons-react';
@@ -37,9 +38,8 @@ const Header = ({ handleLeftDrawerToggle }) => {
sx={{
...theme.typography.commonAvatar,
...theme.typography.mediumAvatar,
+ ...theme.typography.menuButton,
transition: 'all .2s ease-in-out',
- background: theme.palette.secondary.light,
- color: theme.palette.secondary.dark,
'&:hover': {
background: theme.palette.secondary.dark,
color: theme.palette.secondary.light
@@ -55,7 +55,7 @@ const Header = ({ handleLeftDrawerToggle }) => {
-
+
>
);
diff --git a/web/berry/src/layout/MainLayout/Sidebar/MenuCard/index.js b/web/berry/src/layout/MainLayout/Sidebar/MenuCard/index.js
index 16b13231..dadd3eca 100644
--- a/web/berry/src/layout/MainLayout/Sidebar/MenuCard/index.js
+++ b/web/berry/src/layout/MainLayout/Sidebar/MenuCard/index.js
@@ -36,7 +36,7 @@ import { useNavigate } from 'react-router-dom';
// }));
const CardStyle = styled(Card)(({ theme }) => ({
- background: theme.palette.primary.light,
+ background: theme.typography.menuChip.background,
marginBottom: '22px',
overflow: 'hidden',
position: 'relative',
@@ -121,7 +121,6 @@ const MenuCard = () => {
/>
- {/* */}
);
diff --git a/web/berry/src/layout/MainLayout/Sidebar/index.js b/web/berry/src/layout/MainLayout/Sidebar/index.js
index e3c6d12d..10652ba6 100644
--- a/web/berry/src/layout/MainLayout/Sidebar/index.js
+++ b/web/berry/src/layout/MainLayout/Sidebar/index.js
@@ -39,7 +39,13 @@ const Sidebar = ({ drawerOpen, drawerToggle, window }) => {
-
+
@@ -48,7 +54,13 @@ const Sidebar = ({ drawerOpen, drawerToggle, window }) => {
-
+
diff --git a/web/berry/src/layout/MinimalLayout/Header/index.js b/web/berry/src/layout/MinimalLayout/Header/index.js
index 4f61da60..feaeb603 100644
--- a/web/berry/src/layout/MinimalLayout/Header/index.js
+++ b/web/berry/src/layout/MinimalLayout/Header/index.js
@@ -1,10 +1,30 @@
// material-ui
-import { useTheme } from "@mui/material/styles";
-import { Box, Button, Stack } from "@mui/material";
-import LogoSection from "layout/MainLayout/LogoSection";
-import { Link } from "react-router-dom";
-import { useLocation } from "react-router-dom";
-import { useSelector } from "react-redux";
+import { useState } from 'react';
+import { useTheme } from '@mui/material/styles';
+import {
+ Box,
+ Button,
+ Stack,
+ Popper,
+ IconButton,
+ List,
+ ListItemButton,
+ Paper,
+ ListItemText,
+ Typography,
+ Divider,
+ ClickAwayListener
+} from '@mui/material';
+import LogoSection from 'layout/MainLayout/LogoSection';
+import { Link } from 'react-router-dom';
+import { useLocation } from 'react-router-dom';
+import { useSelector } from 'react-redux';
+import ThemeButton from 'ui-component/ThemeButton';
+import ProfileSection from 'layout/MainLayout/Header/ProfileSection';
+import { IconMenu2 } from '@tabler/icons-react';
+import Transitions from 'ui-component/extended/Transitions';
+import MainCard from 'ui-component/cards/MainCard';
+import { useMediaQuery } from '@mui/material';
// ==============================|| MAIN NAVBAR / HEADER ||============================== //
@@ -12,16 +32,26 @@ const Header = () => {
const theme = useTheme();
const { pathname } = useLocation();
const account = useSelector((state) => state.account);
+ const [open, setOpen] = useState(null);
+ const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
+
+ const handleOpenMenu = (event) => {
+ setOpen(open ? null : event.currentTarget);
+ };
+
+ const handleCloseMenu = () => {
+ setOpen(null);
+ };
return (
<>
@@ -31,43 +61,99 @@ const Header = () => {
-
-
-
- {account.user ? (
-
+
+ {isMobile ? (
+ <>
+
+
+
+
+ >
) : (
-
+ <>
+
+
+
+ {account.user ? (
+ <>
+
+
+ >
+ ) : (
+
+ )}
+ >
)}
+
+
+ {({ TransitionProps }) => (
+
+
+
+
+
+
+ 首页} />
+
+
+
+ 关于} />
+
+
+ {account.user ? (
+
+ 控制台
+
+ ) : (
+
+ 登录
+
+ )}
+
+
+
+
+
+ )}
+
>
);
};
diff --git a/web/berry/src/layout/MinimalLayout/index.js b/web/berry/src/layout/MinimalLayout/index.js
index c2919c6d..81047fd1 100644
--- a/web/berry/src/layout/MinimalLayout/index.js
+++ b/web/berry/src/layout/MinimalLayout/index.js
@@ -1,6 +1,6 @@
import { Outlet } from 'react-router-dom';
import { useTheme } from '@mui/material/styles';
-import { AppBar, Box, CssBaseline, Toolbar } from '@mui/material';
+import { AppBar, Box, CssBaseline, Toolbar, Container } from '@mui/material';
import Header from './Header';
import Footer from 'ui-component/Footer';
@@ -22,9 +22,11 @@ const MinimalLayout = () => {
flex: 'none'
}}
>
-
-
-
+
+
+
+
+
diff --git a/web/berry/src/routes/OtherRoutes.js b/web/berry/src/routes/OtherRoutes.js
index 085c4add..58c0b660 100644
--- a/web/berry/src/routes/OtherRoutes.js
+++ b/web/berry/src/routes/OtherRoutes.js
@@ -8,6 +8,7 @@ import MinimalLayout from 'layout/MinimalLayout';
const AuthLogin = Loadable(lazy(() => import('views/Authentication/Auth/Login')));
const AuthRegister = Loadable(lazy(() => import('views/Authentication/Auth/Register')));
const GitHubOAuth = Loadable(lazy(() => import('views/Authentication/Auth/GitHubOAuth')));
+const LarkOAuth = Loadable(lazy(() => import('views/Authentication/Auth/LarkOAuth')));
const ForgetPassword = Loadable(lazy(() => import('views/Authentication/Auth/ForgetPassword')));
const ResetPassword = Loadable(lazy(() => import('views/Authentication/Auth/ResetPassword')));
const Home = Loadable(lazy(() => import('views/Home')));
@@ -48,6 +49,10 @@ const OtherRoutes = {
path: '/oauth/github',
element:
},
+ {
+ path: '/oauth/lark',
+ element:
+ },
{
path: '/404',
element:
diff --git a/web/berry/src/store/actions.js b/web/berry/src/store/actions.js
index 221e8578..f1592d17 100644
--- a/web/berry/src/store/actions.js
+++ b/web/berry/src/store/actions.js
@@ -7,3 +7,4 @@ export const SET_BORDER_RADIUS = '@customization/SET_BORDER_RADIUS';
export const SET_SITE_INFO = '@siteInfo/SET_SITE_INFO';
export const LOGIN = '@account/LOGIN';
export const LOGOUT = '@account/LOGOUT';
+export const SET_THEME = '@customization/SET_THEME';
diff --git a/web/berry/src/store/customizationReducer.js b/web/berry/src/store/customizationReducer.js
index bd8e5f00..0c104025 100644
--- a/web/berry/src/store/customizationReducer.js
+++ b/web/berry/src/store/customizationReducer.js
@@ -9,7 +9,8 @@ export const initialState = {
defaultId: 'default',
fontFamily: config.fontFamily,
borderRadius: config.borderRadius,
- opened: true
+ opened: true,
+ theme: 'light'
};
// ==============================|| CUSTOMIZATION REDUCER ||============================== //
@@ -38,6 +39,11 @@ const customizationReducer = (state = initialState, action) => {
...state,
borderRadius: action.borderRadius
};
+ case actionTypes.SET_THEME:
+ return {
+ ...state,
+ theme: action.theme
+ };
default:
return state;
}
diff --git a/web/berry/src/themes/compStyleOverride.js b/web/berry/src/themes/compStyleOverride.js
index b6e87e01..67a3dd14 100644
--- a/web/berry/src/themes/compStyleOverride.js
+++ b/web/berry/src/themes/compStyleOverride.js
@@ -1,5 +1,5 @@
export default function componentStyleOverrides(theme) {
- const bgColor = theme.colors?.grey50;
+ const bgColor = theme.mode === 'dark' ? theme.backgroundDefault : theme.colors?.grey50;
return {
MuiButton: {
styleOverrides: {
@@ -12,15 +12,7 @@ export default function componentStyleOverrides(theme) {
}
}
},
- MuiMenuItem: {
- styleOverrides: {
- root: {
- '&:hover': {
- backgroundColor: theme.colors?.grey100
- }
- }
- }
- }, //MuiAutocomplete-popper MuiPopover-root
+ //MuiAutocomplete-popper MuiPopover-root
MuiAutocomplete: {
styleOverrides: {
popper: {
@@ -226,12 +218,12 @@ export default function componentStyleOverrides(theme) {
MuiTableCell: {
styleOverrides: {
root: {
- borderBottom: '1px solid rgb(241, 243, 244)',
+ borderBottom: '1px solid ' + theme.tableBorderBottom,
textAlign: 'center'
},
head: {
color: theme.darkTextSecondary,
- backgroundColor: 'rgb(244, 246, 248)'
+ backgroundColor: theme.headBackgroundColor
}
}
},
@@ -239,7 +231,7 @@ export default function componentStyleOverrides(theme) {
styleOverrides: {
root: {
'&:hover': {
- backgroundColor: 'rgb(244, 246, 248)'
+ backgroundColor: theme.headBackgroundColor
}
}
}
@@ -247,10 +239,29 @@ export default function componentStyleOverrides(theme) {
MuiTooltip: {
styleOverrides: {
tooltip: {
- color: theme.paper,
+ color: theme.colors.paper,
background: theme.colors?.grey700
}
}
+ },
+ MuiCssBaseline: {
+ styleOverrides: `
+ .apexcharts-title-text {
+ fill: ${theme.textDark} !important
+ }
+ .apexcharts-text {
+ fill: ${theme.textDark} !important
+ }
+ .apexcharts-legend-text {
+ color: ${theme.textDark} !important
+ }
+ .apexcharts-menu {
+ background: ${theme.backgroundDefault} !important
+ }
+ .apexcharts-gridline, .apexcharts-xaxistooltip-background, .apexcharts-yaxistooltip-background {
+ stroke: ${theme.divider} !important;
+ }
+ `
}
};
}
diff --git a/web/berry/src/themes/index.js b/web/berry/src/themes/index.js
index 6e694aa6..addd61f7 100644
--- a/web/berry/src/themes/index.js
+++ b/web/berry/src/themes/index.js
@@ -15,19 +15,10 @@ import themeTypography from './typography';
export const theme = (customization) => {
const color = colors;
-
+ const options = customization.theme === 'light' ? GetLightOption() : GetDarkOption();
const themeOption = {
colors: color,
- heading: color.grey900,
- paper: color.paper,
- backgroundDefault: color.paper,
- background: color.primaryLight,
- darkTextPrimary: color.grey700,
- darkTextSecondary: color.grey500,
- textDark: color.grey900,
- menuSelected: color.secondaryDark,
- menuSelectedBack: color.secondaryLight,
- divider: color.grey200,
+ ...options,
customization
};
@@ -53,3 +44,49 @@ export const theme = (customization) => {
};
export default theme;
+
+function GetDarkOption() {
+ const color = colors;
+ return {
+ mode: 'dark',
+ heading: color.darkTextTitle,
+ paper: color.darkLevel2,
+ backgroundDefault: color.darkPaper,
+ background: color.darkBackground,
+ darkTextPrimary: color.darkTextPrimary,
+ darkTextSecondary: color.darkTextSecondary,
+ textDark: color.darkTextTitle,
+ menuSelected: color.darkSecondaryMain,
+ menuSelectedBack: color.darkSelectedBack,
+ divider: color.darkDivider,
+ borderColor: color.darkBorderColor,
+ menuButton: color.darkLevel1,
+ menuButtonColor: color.darkSecondaryMain,
+ menuChip: color.darkLevel1,
+ headBackgroundColor: color.darkBackground,
+ tableBorderBottom: color.darkDivider
+ };
+}
+
+function GetLightOption() {
+ const color = colors;
+ return {
+ mode: 'light',
+ heading: color.grey900,
+ paper: color.paper,
+ backgroundDefault: color.paper,
+ background: color.primaryLight,
+ darkTextPrimary: color.grey700,
+ darkTextSecondary: color.grey500,
+ textDark: color.grey900,
+ menuSelected: color.secondaryDark,
+ menuSelectedBack: color.secondaryLight,
+ divider: color.grey200,
+ borderColor: color.grey300,
+ menuButton: color.secondaryLight,
+ menuButtonColor: color.secondaryDark,
+ menuChip: color.primaryLight,
+ headBackgroundColor: color.tableBackground,
+ tableBorderBottom: color.tableBorderBottom
+ };
+}
diff --git a/web/berry/src/themes/palette.js b/web/berry/src/themes/palette.js
index 09768555..70c78782 100644
--- a/web/berry/src/themes/palette.js
+++ b/web/berry/src/themes/palette.js
@@ -5,7 +5,7 @@
export default function themePalette(theme) {
return {
- mode: 'light',
+ mode: theme.mode,
common: {
black: theme.colors?.darkPaper
},
diff --git a/web/berry/src/themes/typography.js b/web/berry/src/themes/typography.js
index 24bfabb9..f20d87a5 100644
--- a/web/berry/src/themes/typography.js
+++ b/web/berry/src/themes/typography.js
@@ -132,6 +132,19 @@ export default function themeTypography(theme) {
width: '44px',
height: '44px',
fontSize: '1.5rem'
+ },
+ menuButton: {
+ color: theme.menuButtonColor,
+ background: theme.menuButton
+ },
+ menuChip: {
+ background: theme.menuChip
+ },
+ CardWrapper: {
+ backgroundColor: theme.mode === 'dark' ? theme.colors.darkLevel2 : theme.colors.primaryDark
+ },
+ SubCard: {
+ border: theme.mode === 'dark' ? '1px solid rgba(227, 232, 239, 0.2)' : '1px solid rgb(227, 232, 239)'
}
};
}
diff --git a/web/berry/src/ui-component/Logo.js b/web/berry/src/ui-component/Logo.js
index a34fe895..52e61f4f 100644
--- a/web/berry/src/ui-component/Logo.js
+++ b/web/berry/src/ui-component/Logo.js
@@ -1,6 +1,8 @@
// material-ui
-import logo from 'assets/images/logo.svg';
+import logoLight from 'assets/images/logo.svg';
+import logoDark from 'assets/images/logo-white.svg';
import { useSelector } from 'react-redux';
+import { useTheme } from '@mui/material/styles';
/**
* if you want to use image instead of
@@ -205,6 +210,13 @@ export default function Profile() {
)}
+ {status.lark_client_id && !inputs.lark_id && (
+
+
+
+ )}
+
+ {' '}
+ 用以支持通过飞书进行登录注册,
+
+ 点击此处
+
+ 管理你的飞书应用
+
+ }
+ >
+
+
+
+ 主页链接填 {inputs.ServerAddress}
+ ,重定向 URL 填 {`${inputs.ServerAddress}/oauth/lark`}
+
+
+
+
+ App ID
+
+
+
+
+
+ App Secret
+
+
+
+
+
+
+
+
{
+
+ 用以推送报警信息,
+
+ 点击此处
+
+ 了解 Message Pusher
+
+ }
+ >
+
+
+
+ Message Pusher 推送地址
+
+
+
+
+
+ Message Pusher 访问凭证
+
+
+
+
+
+
+
+
;
+const checkedIcon = ;
+const filter = createFilterOptions();
const validationSchema = Yup.object().shape({
is_edit: Yup.boolean(),
- name: Yup.string().required("名称 不能为空"),
- remain_quota: Yup.number().min(0, "必须大于等于0"),
+ name: Yup.string().required('名称 不能为空'),
+ remain_quota: Yup.number().min(0, '必须大于等于0'),
expired_time: Yup.number(),
- unlimited_quota: Yup.boolean(),
+ unlimited_quota: Yup.boolean()
});
const originInputs = {
is_edit: false,
- name: "",
+ name: '',
remain_quota: 0,
expired_time: -1,
unlimited_quota: false,
+ subnet: '',
+ models: []
};
const EditModal = ({ open, tokenId, onCancel, onOk }) => {
const theme = useTheme();
const [inputs, setInputs] = useState(originInputs);
+ const [modelOptions, setModelOptions] = useState([]);
const submit = async (values, { setErrors, setStatus, setSubmitting }) => {
setSubmitting(true);
values.remain_quota = parseInt(values.remain_quota);
let res;
+ let models = values.models.join(',');
if (values.is_edit) {
- res = await API.put(`/api/token/`, { ...values, id: parseInt(tokenId) });
+ res = await API.put(`/api/token/`, { ...values, id: parseInt(tokenId), models: models });
} else {
- res = await API.post(`/api/token/`, values);
+ res = await API.post(`/api/token/`, { ...values, models: models });
}
const { success, message } = res.data;
if (success) {
if (values.is_edit) {
- showSuccess("令牌更新成功!");
+ showSuccess('令牌更新成功!');
} else {
- showSuccess("令牌创建成功,请在列表页面点击复制获取令牌!");
+ showSuccess('令牌创建成功,请在列表页面点击复制获取令牌!');
}
setSubmitting(false);
setStatus({ success: true });
@@ -78,61 +91,55 @@ const EditModal = ({ open, tokenId, onCancel, onOk }) => {
const { success, message, data } = res.data;
if (success) {
data.is_edit = true;
+ if (data.models === '') {
+ data.models = [];
+ } else {
+ data.models = data.models.split(',');
+ }
setInputs(data);
} else {
showError(message);
}
};
+ const loadAvailableModels = async () => {
+ let res = await API.get(`/api/user/available_models`);
+ const { success, message, data } = res.data;
+ if (success) {
+ setModelOptions(data);
+ } else {
+ showError(message);
+ }
+ };
useEffect(() => {
if (tokenId) {
loadToken().then();
} else {
- setInputs({...originInputs});
+ setInputs({ ...originInputs });
}
+ loadAvailableModels().then();
}, [tokenId]);
return (
-