Browse Source

登陆后选择大模型服务类型

李富豪 7 months ago
parent
commit
ad93217554

+ 1 - 1
env/.env.development

@@ -2,4 +2,4 @@
 VITE_ENV = 'development'
 
 # Api地址
-VITE_API_URL = 'http://192.168.3.27:8091'
+VITE_API_URL = 'http://xia0miduo.gicp.net:8091'

+ 16 - 0
src/LocalStorage.ts

@@ -28,6 +28,11 @@ class LocalStorage {
         localStorage.setItem('userInfo', JSON.stringify(info));
     }
 
+    // 存储菜单类型
+    setMenuType = (type: number) => {
+        localStorage.setItem('menuType', String(type));
+    }
+
     // 获取账号密码
     getAccountPassword = () => {
         const infoString = localStorage.getItem('accountPassword');
@@ -64,6 +69,17 @@ class LocalStorage {
         }
     }
 
+    // 获取菜单类型
+    getMenuType = () => {
+        const menuType = localStorage.getItem('menuType');
+
+        if (menuType) {
+            return Number(menuType);
+        } else {
+            return 0;
+        }
+    }
+
     // 清除
     clear = () => {
         /*

+ 87 - 0
src/pages/layout/components/EntryModal.tsx

@@ -0,0 +1,87 @@
+import * as React from 'react';
+import { Button, Card, Col, Modal, Row } from 'antd';
+import { RocketOutlined, CloudServerOutlined } from '@ant-design/icons';
+
+interface Props {
+    open: boolean,
+    onClickConfirm: (type: number) => void,
+};
+
+const EntryModal: React.FC<Props> = (props: Props) => {
+    const {
+        open,
+        onClickConfirm
+    } = props;
+
+    return (
+        <Modal
+            className="model-selector-modal"
+            width={1000}
+            title='请选择大模型服务类型'
+            destroyOnClose={true}
+            closeIcon={false}
+            maskClosable={false}
+            centered={true}
+            open={open}
+            footer={null}
+        >
+            <Row gutter={[32, 32]} justify="center">
+                <Col xs={24} sm={12} md={12} lg={12}>
+                    <Card
+                        hoverable
+                        className="route-option deepseek"
+                        cover={
+                            <div className="logo-container">
+                                <RocketOutlined className="option-icon" />
+                            </div>
+                        }
+                    >
+                        <Card.Meta
+                            title="建科本地化大模型"
+                            description="安全、可控的本地化的大模型服务,创建企业私有的知识库与智能问答"
+                        />
+                        <Button
+                            type="primary"
+                            block
+                            className="select-button"
+                            onClick={() => {
+                                onClickConfirm(1);
+                            }}
+                        >
+                            立即使用
+                        </Button>
+                    </Card>
+                </Col>
+
+                <Col xs={24} sm={12} md={12} lg={12}>
+                    <Card
+                        hoverable
+                        className="route-option zhipu"
+                        cover={
+                            <div className="logo-container">
+                                <CloudServerOutlined className="option-icon" />
+                            </div>
+                        }
+                    >
+                        <Card.Meta
+                            title="线上模型智谱AI"
+                            description="线上的大模型服务,无需本地部署即可使用"
+                        />
+                        <Button
+                            type="primary"
+                            block
+                            className="select-button"
+                            onClick={() => {
+                                onClickConfirm(2);
+                            }}
+                        >
+                            立即使用
+                        </Button>
+                    </Card>
+                </Col>
+            </Row>
+        </Modal>
+    );
+};
+
+export default EntryModal;

+ 0 - 9
src/pages/layout/components/Header.tsx

@@ -3,7 +3,6 @@ import { Layout, MenuProps, Modal, Dropdown, Select } from 'antd';
 import { CaretDownOutlined, PoweroffOutlined } from '@ant-design/icons';
 import logoSrc from '@/assets/public/logo.png';
 import router from '@/router';
-import { debounce, set } from 'lodash';
 
 const { Header: AntdHeader } = Layout;
 
@@ -50,13 +49,6 @@ const Header: React.FC<Props> = (props: Props) => {
     const [open, setOpen] = React.useState(false); // 控制下拉框展开状态
     const onDropdownVisibleChange = (visible: boolean) => {
         setOpen(visible);
-      };
-    const onChange = (value: number) => {
-        // 只调用父组件传递的处理函数
-        onSelectChange(value);
-        if (!open) return; // 确保只在真正选择时触发
-        props.onSelectChange(value);
-        setOpen(false);
     };
 
     return (
@@ -83,7 +75,6 @@ const Header: React.FC<Props> = (props: Props) => {
                     ))}
                 </Select>
             </div>
-
             <Dropdown menu={{ items }}>
                 <div className='header-operation'>
                     <div className='header-operation-picture'>

+ 32 - 29
src/pages/layout/index.tsx

@@ -5,9 +5,10 @@ import { Layout } from 'antd';
 import Header from './components/Header';
 import Nav from './components/Nav';
 import Breadcrumb from './components/Breadcrumb';
+import EntryModal from './components/EntryModal';
 import store from './store';
+import LocalStorage from '@/LocalStorage';
 import './style.less';
-import router from '@/router';
 
 const { Content } = Layout;
 
@@ -44,31 +45,25 @@ const LayoutApp: React.FC = () => {
         init(list);
     }, [matches]);
 
+    const currentMenuType = LocalStorage.getMenuType();
+    const [entryModalOpen, setEntryModalOpen] = React.useState(false);
+
     React.useEffect(() => {
+        if (currentMenuType === 0) {
+            setEntryModalOpen(true);
+        }
         return () => reset();
     }, []);
 
     // 统一管理菜单类型状态
-    const [menuType, setMenuType] = React.useState(() => {
-        const currentPath = window.location.pathname;
-        return currentPath.startsWith('/deepseek') ? 1 : 2;
-    });
-
-    // 监听路由变化,同步菜单类型
-    React.useEffect(() => {
-        const type = location.pathname.startsWith('/deepseek') ? 1 : 2;
-        setMenuType(type);
-    }, [location.pathname]);
+    const [menuType, setMenuType] = React.useState(currentMenuType || (location.pathname.startsWith('/deepseek') ? 1 : 2));
 
     // 处理菜单类型变化
     const handleSelectChange = (value: number) => {
-        const defaultPath = value === 1 
-            ? '/deepseek/questionAnswer' 
-            : '/questionAnswer';
-        
+        setMenuType(value);
+        const defaultPath = value === 1 ? '/deepseek/questionAnswer' : '/questionAnswer';
         // 使用navigate进行路由跳转
         navigate(defaultPath);
-        
         // 同时更新selectedKey
         onChangeSelectedKey(defaultPath, 1);
     };
@@ -78,7 +73,7 @@ const LayoutApp: React.FC = () => {
         const path = location.pathname;
         const type = path.startsWith('/deepseek') ? 1 : 2;
         setMenuType(type);
-        
+
         // 确保selectedKey与当前路由同步
         if (path !== selectedKey) {
             onChangeSelectedKey(path, 1);
@@ -95,19 +90,16 @@ const LayoutApp: React.FC = () => {
                     currentMenuType={menuType}
                 />
             </div>
-
             <Layout>
-                {
-                    <Nav
-                        selectedKey={selectedKey}
-                        onChangeSelectedKey={onChangeSelectedKey}
-                        openKeys={openKeys}
-                        onOpenChange={onOpenChange}
-                        collapsed={collapsed}
-                        onClickCollapsed={onClickCollapsed}
-                        menuType={menuType} // 新增 prop
-                    />
-                }
+                <Nav
+                    selectedKey={selectedKey}
+                    onChangeSelectedKey={onChangeSelectedKey}
+                    openKeys={openKeys}
+                    onOpenChange={onOpenChange}
+                    collapsed={collapsed}
+                    onClickCollapsed={onClickCollapsed}
+                    menuType={menuType}
+                />
                 <Layout>
                     {
                         location.pathname === '/404' ?
@@ -120,6 +112,17 @@ const LayoutApp: React.FC = () => {
                     </Content>
                 </Layout>
             </Layout>
+            {
+                entryModalOpen &&
+                <EntryModal
+                    open={entryModalOpen}
+                    onClickConfirm={(type) => {
+                        handleSelectChange(type);
+                        setEntryModalOpen(false);
+                        LocalStorage.setMenuType(type);
+                    }}
+                />
+            }
         </Layout>
     );
 };

+ 105 - 0
src/pages/layout/style.less

@@ -89,4 +89,109 @@
     padding: 0 20px 20px 20px;
     background: @background-color;
     overflow: auto;
+}
+
+.model-selector-modal {
+    .ant-modal-body {
+        padding: 24px;
+    }
+}
+
+.route-option {
+    border-radius: 8px;
+    overflow: hidden;
+    transition: all 0.3s;
+    height: 480px;
+    display: flex;
+    flex-direction: column;
+
+    .ant-card-cover {
+        display: flex;
+        justify-content: center;
+        padding: 60px 0;
+        background: #f0f5ff;
+        flex: 0 0 auto;
+    }
+
+    .ant-card-body {
+        display: flex;
+        flex-direction: column;
+        height: 100%;
+        padding-bottom: 0;
+    }
+
+    .logo-container {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        width: 100%;
+    }
+
+    .option-icon {
+        font-size: 64px;
+        color: #1890ff;
+    }
+
+    .ant-card-meta {
+        text-align: center;
+        margin-bottom: 0;
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+
+        &-title {
+            font-size: 18px;
+            font-weight: 500;
+            margin-bottom: 8px;
+        }
+
+        &-description {
+            color: #666;
+            padding: 0 16px;
+        }
+    }
+
+    .select-button {
+        margin: 24px 0;
+        height: 48px;
+        font-weight: 500;
+        font-size: 16px;
+        flex: 0 0 auto;
+    }
+
+    &:hover {
+        transform: translateY(-5px);
+        box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08);
+    }
+}
+
+.deepseek {
+    .ant-card-cover {
+        background: #f0f5ff;
+    }
+
+    .option-icon {
+        color: #1890ff;
+    }
+
+    .select-button {
+        background: #1890ff;
+        border-color: #1890ff;
+    }
+}
+
+.zhipu {
+    .ant-card-cover {
+        background: #f9f0ff;
+    }
+
+    .option-icon {
+        color: #722ed1;
+    }
+
+    .select-button {
+        background: #722ed1;
+        border-color: #722ed1;
+    }
 }

+ 2 - 0
src/pages/login/store.tsx

@@ -31,6 +31,8 @@ const useLoginStore = (): LoginStore => {
             try {
                 const res = await apis.login(data);
                 const info = res.data;
+                // 首次登陆,重置菜单类型
+                LocalStorage.setMenuType(0);
                 LocalStorage.setToken(info.token);
                 LocalStorage.setUserInfo({
                     id: info.userId,