Ver Fonte

权限控制

S0025136190 há 7 meses atrás
pai
commit
5a495b094a

+ 40 - 0
src/LocalStorage.ts

@@ -91,6 +91,46 @@ class LocalStorage {
         localStorage.clear();
         this.setAccountPassword(cloneAccountPassword);
     }
+
+    // 存储roles
+    setRoles = (roles: string) => {
+        localStorage.setItem('roles', JSON.stringify(roles));
+    }
+
+    // 存储permissions
+    setPermissions = (permissions: string) => {
+        localStorage.setItem('permissions', JSON.stringify(permissions));
+    }
+
+    // 获取roles
+    getRoles = (): string | null => {
+        const rolesStr = localStorage.getItem('roles');
+        return rolesStr;
+    }
+
+    // 获取permissions
+    getPermissions = (): string | null => {
+        const permissionsStr = localStorage.getItem('permissions');
+        return permissionsStr;
+    }
+
+    getStatusFlag = (permissionsStr: string): boolean => {
+        const permissions = this.getPermissions();
+        if (permissions && (permissions.includes('*:*:*') || permissions.includes(permissionsStr))) {
+            // admin
+            return true;
+        }
+        return false;
+    }
+
+    getStatusRoleFlag = (): boolean => {
+        const roles = this.getRoles();
+        if (roles && (roles.includes('admin') || roles.includes('manager'))) {
+            return true;
+        }else{
+            return false;
+        }
+    }
 }
 
 export default new LocalStorage();

+ 54 - 3
src/apis/index.ts

@@ -1,5 +1,6 @@
 import exp from 'constants';
 import api from './api';
+import audit from '@/pages/takai/audit';
 
 // Api参数类型
 export type LoginApiParams = {
@@ -10,6 +11,9 @@ export type LoginApiParams = {
 export type FetchAppListApiParams = {
     pageNumber: number,
     pageSize: number,
+    userId: string,
+    typeId: any,
+    projectId: any,
 };
 
 export type FetchKnowledgeLibListApiParams = {
@@ -26,6 +30,9 @@ export type CreateOrModifyKnowledgeLibApiParams = {
 export type FetchAppIndexParams = {
     pageNumber: number,
     pageSize: number,
+    userId: string,
+    typeId: any,
+    projectId: any,
 };
 
 export type CreateOrModifyApplicationApiParams = {
@@ -103,6 +110,12 @@ export type addAndModifySliceApiParams = {
     documentId: string,
 };
 
+export type FetchAuditConfigLibListApiParams = {
+    approver: string,
+    pageNumber: number,
+    pageSize: number,
+};
+
 // Api函数类型
 export type LoginApi = (data: LoginApiParams) => Promise<any>;
 export type LogoutApi = () => Promise<any>;
@@ -152,9 +165,15 @@ export type FetchTakaiSliceDetailLibApi = (sliceId: string, knowledgeId: string)
 export type modifyTakaiSliceInfoLibApi = (data: addAndModifySliceApiParams) => Promise<any>;
 export type FetchTakaiChatHistoryListApi = (data: FetchChatHistoryListApiParams) => Promise<any>;
 export type ExportTakaiChatHistoryApi = (id: string) => Promise<any>;
-export type FetchTakaiApplicationListApi = () => Promise<any>;
+export type FetchTakaiApplicationListApi = (userId: string) => Promise<any>;
 export type addTakaiSliceLibApi = (data: addAndModifySliceApiParams) => Promise<any>;
 export type FetchTakaiAppTypeListApi = (dictType: string) => Promise<any>;
+export type FetchUserInfoApi = (userId: string) => Promise<any>;
+export type FetchAuditInfoLibDetailApi = (documentId: string) => Promise<any>;
+export type FetchTakaiAuditConfigLibListApi = (data: FetchAuditConfigLibListApiParams) => Promise<any>;
+export type ModifyTakaiAuditDocumentLibApi = (id: string, data: ModifyDocumentApiParams) => Promise<any>;
+export type AuditTakaiApplicationApi = (appId: string, userId: string) => Promise<any>;
+export type FetchTakaiProjectApi = () => Promise<any>;
 
 // 登录
 const loginApi: LoginApi = async (data) => {
@@ -398,8 +417,8 @@ const exportTakaiChatHistoryApi: ExportTakaiChatHistoryApi = async (id) => {
 };
 
 // 获取takai应用列表 (下拉框)
-const fetchTakaiApplicationListApi: FetchTakaiApplicationListApi = async () => {
-    return api.get('/deepseek/api/application/list');
+const fetchTakaiApplicationListApi: FetchTakaiApplicationListApi = async (userId) => {
+    return api.get('/deepseek/api/application/list/' + userId);
 };
 
 // 新增takai切片
@@ -412,6 +431,32 @@ const fetchTakaiAppTypeListApi: FetchTakaiAppTypeListApi = async (dictType) => {
     return api.get(`/deepseek/api/${dictType}`);
 };
 
+const fetchUserInfoApi: FetchUserInfoApi = async (userId) => {
+    return api.get(`/deepseek/getInfo/${userId}`);
+};
+const fetchAuditInfoLibDetailApi: FetchAuditInfoLibDetailApi = async (documentId) => {
+    return api.get(`/system/info/all/${documentId}`);
+};
+
+
+const fetchTakaiAuditConfigLibListApi: FetchTakaiAuditConfigLibListApi = async (data) => {
+    return api.post('/deepseek/api/app/audit/list', data);
+};
+
+// 修改takai知识审核
+const modifyTakaiAuditDocumentApi: ModifyTakaiAuditDocumentLibApi = async (id, data) => {
+    return api.put(`/deepseek/api/updateDocumentAudit/${id}`, data);
+};
+
+const auditTakaiApplicationApi: AuditTakaiApplicationApi = async (appId, userId) => {
+    return api.put(`/deepseek/api/audit/${appId}/${userId}`);
+};
+
+const fetchTakaiProjectApi: FetchTakaiProjectApi = async () => {
+    return api.get(`/system/project/alllist?pageNum=1&pageSize=1000`);
+};
+
+
 export const apis = {
     login: loginApi,
     logout: logoutApi,
@@ -464,4 +509,10 @@ export const apis = {
     fetchTakaiApplicationList: fetchTakaiApplicationListApi,
     addTakaiSlice: addTakaiSliceApi,
     fetchTakaiAppTypeList: fetchTakaiAppTypeListApi,
+    fetchUserInfo: fetchUserInfoApi,
+    fetchAuditInfoLibDetail: fetchAuditInfoLibDetailApi,
+    fetchTakaiAuditConfigLibList: fetchTakaiAuditConfigLibListApi,
+    modifyTakaiAuditDocumentLibApi: modifyTakaiAuditDocumentApi,
+    auditTakaiApplicationLibApi: auditTakaiApplicationApi,
+    fetchTakaiProjectLibApi: fetchTakaiProjectApi,
 };

+ 4 - 1
src/pages/layout/components/Header.tsx

@@ -3,6 +3,7 @@ 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 LocalStorage from '@/LocalStorage';
 
 const { Header: AntdHeader } = Layout;
 
@@ -54,7 +55,9 @@ const Header: React.FC<Props> = (props: Props) => {
     return (
         <AntdHeader className='header'>
             <div className='header-logo' onClick={() => {
-                router.navigate({ pathname: '/deepseek/questionAnswer' });
+                if(LocalStorage.getStatusFlag('deepseek:application:list')){
+                    router.navigate({ pathname: '/deepseek/questionAnswer' });
+                }
             }}>
                 <img className='header-logo-picture' src={logoSrc} />
                 <div className='header-logo-text'>

+ 24 - 2
src/pages/layout/components/Nav.tsx

@@ -5,10 +5,12 @@ import {
     ReadOutlined,
     FileSearchOutlined,
     MenuFoldOutlined,
-    MenuUnfoldOutlined
+    MenuUnfoldOutlined,
+    StepForwardOutlined
 } from '@ant-design/icons';
 import router from '@/router';
 import { JSX } from 'react/jsx-runtime';
+import LocalStorage from '@/LocalStorage';
 
 const Sider = Layout.Sider;
 
@@ -60,7 +62,27 @@ const Nav: React.FC<Props> = (props: Props) => {
             label: 'DeepSeek数据导出',
             onClick: () => { router.navigate({ pathname: '/deepseek/dataExport' }) }
         },
-    ];
+        {
+            key: '/deepseek/audit',
+            icon: <StepForwardOutlined />,
+            label: '应用审核',
+            onClick: () => { router.navigate({ pathname: '/deepseek/audit' }) }
+        },
+    ].filter(item => {
+        if (item.key === '/deepseek/questionAnswer') {
+            return LocalStorage.getStatusFlag('deepseek:application:list');
+        }
+        if (item.key === '/deepseek/knowledgeLib') {
+            return LocalStorage.getStatusFlag('deepseek:knowledge:list');
+        }
+        if (item.key === '/deepseek/dataExport') {
+            return LocalStorage.getStatusFlag('deepseek:dialog:list');
+        }
+        if (item.key === '/deepseek/audit') {
+            return LocalStorage.getStatusFlag('system:audit:list');
+        }
+        return true; // 其他菜单默认显示
+    });
 
     const zpItems: MenuItem[] = [
         {

+ 21 - 3
src/pages/login/store.tsx

@@ -46,9 +46,27 @@ const useLoginStore = (): LoginStore => {
                 } else {// 不记住密码
                     LocalStorage.setAccountPassword(undefined);
                 }
-                router.navigate({ pathname: '/deepseek/questionAnswer' }, { replace: true });
-                // router.navigate({ pathname: '/' }, { replace: true });
-                message.success('登录成功');
+                // 获取用户详细信息(permissions,role, user)
+                const resUserInfo = await apis.fetchUserInfo(info.userId);
+                if (resUserInfo.code === 200) {
+                    LocalStorage.setPermissions(resUserInfo.permissions);
+                    LocalStorage.setRoles(resUserInfo.roles);
+                    if (!LocalStorage.getStatusFlag('deepseek:application:list') &&
+                        !LocalStorage.getStatusFlag('deepseek:knowledge:list') &&
+                        !LocalStorage.getStatusFlag('deepseek:dialog:list') &&
+                        !LocalStorage.getStatusFlag('system:audit:list')) {
+                        message.error('权限不足,请联系管理员');
+                        LocalStorage.clear();
+                        router.navigate({ pathname: '/login' }, { replace: true });
+                        return;
+                    }
+                    if (LocalStorage.getStatusFlag('deepseek:application:list')) {
+                        router.navigate({ pathname: '/deepseek/questionAnswer' }, { replace: true });
+                    } else {
+                        router.navigate({ pathname: '/404' }, { replace: true });
+                    }
+                    message.success('登录成功');
+                }
             } catch (error: any) {
                 LocalStorage.clear();
                 message.error(error.msg);

+ 188 - 0
src/pages/takai/audit/components/InfoModal.tsx

@@ -0,0 +1,188 @@
+import * as React from 'react';
+import { Modal, Spin, Form, Input, Select, message, Button, Steps, Switch } from 'antd';
+import { apis, ModifyDocumentApiParams } from '@/apis';
+import LocalStorage from '@/LocalStorage';
+import { set } from 'mobx';
+
+const FormItem = Form.Item;
+const { Option } = Select;
+const { TextArea } = Input;
+
+interface Props {
+    id: string,
+    open: boolean,
+    onClickConfirm: (id: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    onClickCancel: (id: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    onClickClose: () => void,
+};
+
+
+
+const InfoModal: React.FC<Props> = (props: Props) => {
+    const {
+        id,
+        open,
+        onClickConfirm,
+        onClickCancel,
+        onClickClose,
+    } = props;
+
+    const [form] = Form.useForm();
+
+    const [loading, setLoading] = React.useState<boolean>(false);
+    const [updateFlag, setUpdateFlag] = React.useState<boolean>();
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+
+    type EmbeddingList = {
+        label: string,
+        value: string,
+    }[];
+
+    interface AuditInfo {
+        title: string,
+        description: string
+        onClick: () => void,
+    }
+
+    const [embeddingList, setEmbeddingList] = React.useState<EmbeddingList>([]);
+    const description = 'This is a description';
+    const [switchFlag, setSwitchFlag] = React.useState<boolean>(false);
+    const [auditInfo, setAuditInfo] = React.useState<AuditInfo[]>([]);
+    const [current, setCurrent] = React.useState<number>(-1);
+    const [refuse, setRefuse] = React.useState<boolean>(false);
+    const [pass, setPass] = React.useState<boolean>(false);
+
+    const onChange = (checked: boolean) => {
+        if (checked) {
+            setSwitchFlag(true);
+        } else {
+            setSwitchFlag(false);
+        }
+    };
+
+    // 获取知识库详情
+    const fetchDetail = async () => {
+        try {
+            const res = await apis.fetchTakaiApplicationDetail(props.id);
+            if (res.code === 200) {
+                const { name, status, comment, nodeOrder } = res.data.detail;
+                form.setFieldsValue({
+                    name: name,
+                    status: status,
+                    comment: '',
+                    nodeOrder: nodeOrder
+                });
+                if (status === 'Y') {
+                    setPass(true);
+                }
+                if (status === 'N') {
+                    setRefuse(true);
+                }
+            }
+
+        } catch (error: any) {
+            message.error(error.msg);
+        }
+    };
+    const init = async () => {
+        setLoading(true);
+        if (props.id) {
+            await fetchDetail();
+        }
+        setLoading(false);
+    };
+
+    React.useEffect(() => {
+        init();
+        const cFlag = LocalStorage.getStatusFlag('deepseek:knowledge:create');
+        setCreateFlag(cFlag);
+        const uFlag = LocalStorage.getStatusFlag('deepseek:knowledge:update');
+        setUpdateFlag(uFlag);
+    }, []);
+
+    // 点击通过
+    const handleClickConfirm = () => {
+        form.validateFields().then(async (values) => {
+            const userInfo = LocalStorage.getUserInfo();
+            const userId = (userInfo?.id ?? '').toString();
+            const data = {
+                ...values,
+                approver: userId,
+                status: 'Y',
+            };
+            console.log(data, 'data');
+            await onClickConfirm(props.id, userId, data);
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+
+    // 点击拒绝
+    const handleClickCancel = () => {
+        form.validateFields().then(async (values) => {
+            const userInfo = LocalStorage.getUserInfo();
+            const userId = (userInfo?.id ?? '').toString();
+            const data = {
+                ...values,
+                approver: userId,
+                status: 'N',
+            };
+            await onClickCancel(props.id, userId, data);
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+
+    return (
+        <Modal
+            width={600}
+            title={'应用审核'}
+            destroyOnClose={true}
+            maskClosable={false}
+            centered={true}
+            open={open}
+            onCancel={onClickClose}
+            // onOk={handleClickConfirm}
+            // onCancel={onClickCancel}
+            footer={[
+                <Button key="submit" type="primary" danger onClick={handleClickCancel} loading={loading}>
+                    拒绝
+                </Button>,
+                <Button key="submit" type="primary" onClick={handleClickConfirm} loading={loading}>
+                    通过
+                </Button>
+            ]}
+        >
+            <Spin spinning={loading}>
+                <Form form={form} layout='vertical'>
+                    <FormItem
+                        label='应用名称'
+                        name='name'
+                    >
+                        <Input disabled={true} />
+                    </FormItem>
+                    <div style={{ width: '100%', height: 0, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
+                        <FormItem
+                            label='审核节点'
+                            name='nodeOrder'
+                            hidden={true}
+                        >
+                            <Input disabled={true} />
+                        </FormItem>
+                    </div>
+                    <FormItem
+                        label='审核意见'
+                        name='comment'
+                    >
+                        <TextArea
+                            maxLength={100}
+                        />
+                    </FormItem>
+                    <div style={{ width: '100%', height: 10 }}></div>
+                </Form>
+            </Spin>
+        </Modal >
+    );
+};
+
+export default InfoModal;

+ 186 - 0
src/pages/takai/audit/index.tsx

@@ -0,0 +1,186 @@
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import { Table, TableColumnsType, TablePaginationConfig } from 'antd';
+import { StepForwardOutlined } from '@ant-design/icons';
+import dayjs from 'dayjs';
+import store from './store';
+import { Record } from './types';
+import './style.less';
+import LocalStorage from '@/LocalStorage';
+import InfoModal from './components/InfoModal';
+
+const KnowledgeLibList: React.FC = () => {
+    const {
+        state,
+        onChangePagination,
+        onClickCreate,
+        onClickModify,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        infoModalOnClickClose,
+        init,
+        reset
+    } = store;
+    const {
+        listLoading,
+        list,
+        infoModalId,
+        infoModalOpen,
+        page
+    } = state;
+
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+    const [deleteFlag, setDeleteFlag] = React.useState<boolean>();
+    const [detailFlag, setDetailFlag] = React.useState<boolean>();
+    const [listFlag, setListFlag] = React.useState<boolean>();
+
+
+    React.useEffect(() => {
+        const userInfo = LocalStorage.getUserInfo();
+        const userId = (userInfo?.id ?? '').toString();
+        init(userId);
+        return () => reset();
+    }, []);
+
+    const columns: TableColumnsType<Record> = [
+        {
+            title: '序号',
+            dataIndex: 'index',
+            width: 80,
+            render: (text, record, index) => {
+                return index + 1;
+            }
+        },
+        {
+            title: '知识名称',
+            dataIndex: 'name',
+            render: (text, record) => {
+                // const previewUrl = `/preview/${record.url}`; // 根据实际字段构造 URL
+                return (
+                    <a
+                        href={record.url}
+                        target="_blank"
+                        rel="noopener noreferrer"
+                        onClick={(e) => {
+                            e.stopPropagation(); // 防止 Table 默认事件干扰
+                        }}
+                    >
+                        {text}
+                    </a>
+                );
+            }
+        },
+        {
+            title: '状态',
+            dataIndex: 'status',
+            render: (text) => {
+                if (text === '1') {
+                    return '待审核';
+                }else if(text === '2'){
+                    return '审核中';
+                }else if(text === '3'){
+                    return '审核通过';
+                }else if(text === '4'){   
+                    return '审核拒绝';
+                }
+            }
+        },
+        {
+            title: '审核人',
+            dataIndex: 'userName',
+            render: (text) => {
+                return `${text}`;
+            }
+        },
+        {
+            title: '审核意见',
+            dataIndex: 'comment',
+            render: (text) => {
+                if(text){
+                    return `${text}`;
+                }else{
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            width: 200,
+            render: (text) => {
+                if (text) {
+                    return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+                } else {
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '操作',
+            dataIndex: 'operation',
+            width: 150,
+            fixed: 'right',
+            render: (text, record) => {
+                return (
+                    <>
+                        <a
+                            style={{ marginRight: 16 }}
+                            onClick={() => {
+                                onClickModify(record.appId);
+                            }}
+                            title='审核'
+                        >
+                            <StepForwardOutlined />审核
+                        </a >
+                    </>
+                )
+            }
+        }
+    ];
+
+    const paginationConfig: TablePaginationConfig = {
+        // 显示数据总量
+        showTotal: (total: number) => {
+            return `共 ${total} 条`;
+        },
+        // 展示分页条数切换
+        showSizeChanger: true,
+        // 指定每页显示条数
+        pageSizeOptions: ['10', '20', '50', '100'],
+        // 快速跳转至某页
+        showQuickJumper: true,
+        current: page.pageNumber,
+        pageSize: page.pageSize,
+        total: page.total,
+        onChange: async (page, pageSize) => {
+            await onChangePagination(page, pageSize);
+        },
+    };
+
+    return (
+        <div className='knowledgeLibList'>
+            <div className='knowledgeLibList-table'>
+                <Table
+                    scroll={{ x: 'max-content' }}
+                    rowKey={(record) => record.knowledgeId}
+                    loading={listLoading}
+                    columns={columns}
+                    dataSource={list}
+                    pagination={paginationConfig}
+                />
+            </div>
+            {
+                infoModalOpen &&
+                <InfoModal
+                    id={infoModalId}
+                    open={infoModalOpen}
+                    onClickConfirm={infoModalOnClickConfirm}
+                    onClickCancel={infoModalOnClickCancel}
+                    onClickClose={infoModalOnClickClose}
+                />
+            }
+        </div>
+    );
+};
+
+export default observer(KnowledgeLibList);

+ 178 - 0
src/pages/takai/audit/store.ts

@@ -0,0 +1,178 @@
+import { makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import { apis, ModifyDocumentApiParams } from '@/apis';
+import { State, ReadonlyState, StateAction, DocumentLibListStore } from './types';
+
+// 定义状态
+const stateGenerator = (): ReadonlyState => ({
+    listLoading: false,
+    list: [],
+    infoModalId: '',
+    infoModalOpen: false,
+    page: {
+        pageNumber: 1,
+        pageSize: 10,
+        total: 0,
+    },
+});
+
+// 修改状态
+const stateActionsGenerator = (state: State): StateAction => {
+    return {
+        setListLoading: (loading) => {
+            state.listLoading = loading;
+        },
+        setList: (list) => {
+            state.list = list;
+        },
+        setInfoModalId: (id) => {
+            state.infoModalId = id;
+        },
+        setInfoModalOpen: (open) => {
+            state.infoModalOpen = open;
+        },
+        setPage: (page) => {
+            state.page = page;
+        },
+    };
+};
+
+// 使用仓库
+const useKnowledgeLibListStore = (): DocumentLibListStore => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    const api = {
+        // 获取审核列表
+        fetchApplicationLibList: async (userId: string) => {
+            actions.setListLoading(true);
+            try {
+                const data = {
+                    pageNumber: state.page.pageNumber,
+                    pageSize: state.page.pageSize,
+                    approver: userId,
+                };
+                const res = await apis.fetchTakaiAuditConfigLibList(data);
+                console.log(res.rows, 'rew.rows');
+                actions.setList(res.rows);
+                actions.setPage({
+                    ...state.page,
+                    total: res.total,
+                });
+            } catch (error: any) {
+                console.error(error);
+            } finally {
+                actions.setListLoading(false);
+            }
+        },
+        
+        // 应用审核
+        modifyDocumentLib: async (documentId: string, userId: string, data: ModifyDocumentApiParams) => {
+            try {
+                const res = await apis.modifyTakaiAuditDocumentLibApi(documentId, data);
+                // 获取审核列表
+                api.fetchApplicationLibList(userId);
+                if(res.data === 1 && res.code === 200){
+                    message.success('修改成功');
+                }else{
+                    message.error('修改失败');
+                }
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+    }
+
+    // 更改分页
+    const onChangePagination: DocumentLibListStore['onChangePagination'] = async (pageNumber, pageSize) => {
+        actions.setPage({
+            ...state.page,
+            pageNumber: pageNumber,
+            pageSize: pageSize,
+        });
+        // 获取知识库列表
+        await api.fetchApplicationLibList('');
+    }
+
+    // 点击创建
+    const onClickCreate: DocumentLibListStore['onClickCreate'] = () => {
+        const initialInfoModalId = stateGenerator().infoModalId;
+
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 点击修改
+    const onClickModify: DocumentLibListStore['onClickModify'] = (documentId) => {
+        actions.setInfoModalId(documentId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 信息弹出层-点击通过
+    const infoModalOnClickConfirm: DocumentLibListStore['infoModalOnClickConfirm'] = async (documentId, userId, data) => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+        if (documentId) {
+            // 审核通过
+            console.log(data, 'datadata');
+            await api.modifyDocumentLib(documentId, userId, data);
+        } 
+    }
+
+    // 信息弹出层-点击拒绝
+    const infoModalOnClickCancel: DocumentLibListStore['infoModalOnClickCancel'] = async(documentId, userId, data) => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+        if (documentId) {
+            // 审核拒绝
+            await api.modifyDocumentLib(documentId, userId, data);
+        } 
+    }
+
+    const infoModalOnClickClose: DocumentLibListStore['infoModalOnClickClose'] = () => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+    }
+
+    
+    // 初始渲染
+    const init: DocumentLibListStore['init'] = async (userId) => {
+        // 获取知识库列表
+        await api.fetchApplicationLibList(userId);
+    }
+
+    // 状态重置
+    const reset: DocumentLibListStore['reset'] = () => {
+        const initialListLoading = stateGenerator().listLoading;
+        const initialList = stateGenerator().list;
+        const initialInfoModalId = stateGenerator().infoModalId;
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+        const initialPage = stateGenerator().page;
+
+        actions.setListLoading(initialListLoading);
+        actions.setList(initialList);
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(initialInfoModalOpen);
+        actions.setPage(initialPage);
+    }
+
+    return {
+        state,
+        onChangePagination,
+        onClickCreate,
+        onClickModify,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        infoModalOnClickClose,
+        init,
+        reset
+    };
+};
+
+export default useKnowledgeLibListStore();

+ 14 - 0
src/pages/takai/audit/style.less

@@ -0,0 +1,14 @@
+.knowledgeLibList {
+  &-operation {
+    padding: 20px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+    margin-bottom: 20px;
+  }
+
+  &-table {
+    padding: 20px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+  }
+}

+ 48 - 0
src/pages/takai/audit/types.ts

@@ -0,0 +1,48 @@
+import { ModifyDocumentApiParams } from '@/apis';
+
+export type Record = {
+    [x: string]: any;
+    documentId: string,
+    knowledgeId: string,
+    name: string,// 知识文件名称
+    createTime: string,// 创建时间
+    updateTime: string,// 更新时间
+};
+
+// 定义状态
+export type State = {
+    listLoading: boolean,
+    list: Record[],
+    infoModalId: string,
+    infoModalOpen: boolean,
+    page: {
+        pageNumber: number,
+        pageSize: number,
+        total: number,
+    },
+};
+
+// 只读状态
+export type ReadonlyState = Readonly<State>;
+
+// 修改状态
+export type StateAction = {
+    setListLoading: (loading: State['listLoading']) => void,
+    setList: (list: State['list']) => void,
+    setInfoModalId: (id: State['infoModalId']) => void,
+    setInfoModalOpen: (open: State['infoModalOpen']) => void,
+    setPage: (page: State['page']) => void,
+};
+
+// 仓库类型
+export type DocumentLibListStore = {
+    state: ReadonlyState,
+    onChangePagination: (pageNumber: number, pageSize: number) => Promise<any>,
+    onClickCreate: () => void,
+    onClickModify: (documentId: string) => void,
+    infoModalOnClickConfirm: (documentId: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    infoModalOnClickCancel: (documentId: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    infoModalOnClickClose:  () => void,
+    init: (userId: string) => Promise<any>,
+    reset: () => void,
+};

+ 4 - 1
src/pages/takai/dataExport/components/Search.tsx

@@ -2,6 +2,7 @@ import * as React from 'react';
 import { Form, Select, Button } from 'antd';
 import { apis } from '@/apis';
 import { Query } from '../types';
+import LocalStorage from '@/LocalStorage';
 
 const FormItem = Form.Item;
 const { Option } = Select;
@@ -28,7 +29,9 @@ const Search: React.FC<Props> = (props: Props) => {
 
     const fetchApplicationList = async () => {
         try {
-            const res = await apis.fetchTakaiApplicationList();
+            const userInfo = LocalStorage.getUserInfo();
+            const userId = (userInfo?.id ?? '').toString();
+            const res = await apis.fetchTakaiApplicationList(userId);
             const list = res.data.map((item: any) => {
                 return {
                     label: item.name,

+ 95 - 63
src/pages/takai/knowledgeLib/detail/index.tsx

@@ -13,6 +13,8 @@ import { Record, RecordKonwledge } from './types';
 import dayjs from 'dayjs';
 import { set } from 'mobx';
 import axios from 'axios';
+import LocalStorage from '@/LocalStorage';
+import { apis, ModifyDocumentApiParams } from '@/apis';
 
 const { Dragger } = Upload;
 
@@ -51,6 +53,12 @@ const KnowledgeLibInfo: React.FC = () => {
     const [fileList, setFileList] = React.useState<any[]>([]);
     const [uploading, setUploading] = React.useState(false);
 
+    const [sListFlag, setSListFlag] = React.useState<boolean>();
+    const [cUpdateFlag, setCUpdateFlag] = React.useState<boolean>();
+    const [detailFlag, setDetailFlag] = React.useState<boolean>();
+    const [deleteFlag, setDeleteFlag] = React.useState<boolean>();
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+
     const props: UploadProps = {
         name: 'files',
         multiple: true,
@@ -154,6 +162,16 @@ const KnowledgeLibInfo: React.FC = () => {
 
     React.useEffect(() => {
         init(params.knowledgeId);
+        const cList = LocalStorage.getStatusFlag('deepseek:slice:list');
+        setSListFlag(cList);
+        const cDetail = LocalStorage.getStatusFlag('deepseek:config:update');
+        setCUpdateFlag(cDetail);
+        const detail = LocalStorage.getStatusFlag('deepseek:document:detail');
+        setDetailFlag(detail);
+        const deleteF = LocalStorage.getStatusFlag('deepseek:document:delete');
+        setDeleteFlag(deleteF);
+        const createF = LocalStorage.getStatusFlag('deepseek:document:create');
+        setCreateFlag(createF);
         return () => reset();
     }, []);
 
@@ -184,7 +202,7 @@ const KnowledgeLibInfo: React.FC = () => {
                 if (text) {
                     const size = (text / 1024 / 1024).toFixed(2);
                     return `${size} M`;
-                }else{
+                } else {
                     return '--'
                 }
             }
@@ -196,7 +214,7 @@ const KnowledgeLibInfo: React.FC = () => {
             render: (text) => {
                 if (text) {
                     return `${text}`;
-                }else{
+                } else {
                     return '--'
                 }
             }
@@ -245,44 +263,54 @@ const KnowledgeLibInfo: React.FC = () => {
             render: (text, record) => {
                 return (
                     <>
-                        <a style={{ marginRight: 16 }}
-                            onClick={() => {
-                                router.navigate({ pathname: '/deepseek/knowledgeLib/slice/' + record.documentId + '/' + params.knowledgeId + '/' + state.knowledgeDetail.embeddingId });
-                            }}>
-                            切片
-                        </a>
-                        <a
-                            style={{ marginRight: 16 }}
-                            onClick={() => {
-                                onClickSettings(record.documentId);
-                            }}
-                        >
-                            配置
-                        </a>
-
-                        <a
-                            style={{ marginRight: 16 }}
-                            onClick={() => {
-                                onClickModify(record.documentId);
-                            }}>
-                            <EditOutlined />
-                        </a>
-
-                        <a
-                            className='text-error'
-                            onClick={() => {
-                                Modal.confirm({
-                                    title: '删除',
-                                    content: `确定删除知识文件:${record.name}吗?`,
-                                    okType: 'danger',
-                                    onOk: async () => {
-                                        await onClickDelete(record.documentId);
-                                    }
-                                });
-                            }}
-                        >
-                            <DeleteOutlined />
-                        </a>
+                        {createFlag &&
+                            <a style={{ marginRight: 16 }}
+                                onClick={() => {
+                                    router.navigate({ pathname: '/deepseek/knowledgeLib/slice/' + record.documentId + '/' + params.knowledgeId + '/' + state.knowledgeDetail.embeddingId });
+                                }}>
+                                切片
+                            </a>
+                        }
+                        {
+                            cUpdateFlag &&
+                            <a
+                                style={{ marginRight: 16 }}
+                                onClick={() => {
+                                    onClickSettings(record.documentId);
+                                }}
+                            >
+                                配置
+                            </a>
+                        }
+                        {
+                            cUpdateFlag &&
+                            <a
+                                style={{ marginRight: 16 }}
+                                onClick={() => {
+                                    onClickModify(record.documentId);
+                                }}>
+                                <EditOutlined />
+                            </a>
+                        }
+                        {
+                            deleteFlag &&
+                            <a
+                                className='text-error'
+                                onClick={() => {
+                                    Modal.confirm({
+                                        title: '删除',
+                                        content: `确定删除知识文件:${record.name}吗?`,
+                                        okType: 'danger',
+                                        onOk: async () => {
+                                            const userInfo = LocalStorage.getUserInfo();
+                                            await onClickDelete(record.documentId);
+                                        }
+                                    });
+                                }}
+                            >
+                                <DeleteOutlined />
+                            </a>
+                        }
                     </>
                 )
             }
@@ -315,26 +343,29 @@ const KnowledgeLibInfo: React.FC = () => {
                     {
                         page.total === 0 &&
                         <>
-                        <div>
+                            <div>
                                 <Button type='primary' icon={<ArrowLeftOutlined />} onClick={() => {
                                     router.navigate(-1);
                                 }}>返回</Button>
                             </div>
-                            <div style={{ marginTop: 20, width: '100%', height: '200px' }}>
-                                <Dragger {...props}>
-                                    <p className="ant-upload-drag-icon">
-                                        <InboxOutlined />
-                                    </p>
-                                    <p >
-                                        点击上传,或拖放文件到此处
-                                    </p >
-                                    <p className="ant-upload-hint">
-                                        支持文件格式txt, pdf, jpg, png, jpeg, doc, docx, ppt, pptx,
-                                        单个文档小于30M,单张图片小于5M,文件总
-                                        大小不得超过125M.
-                                    </p>
-                                </Dragger>
-                            </div>
+                            {
+                                createFlag &&
+                                <div style={{ marginTop: 20, width: '100%', height: '200px' }}>
+                                    <Dragger {...props}>
+                                        <p className="ant-upload-drag-icon">
+                                            <InboxOutlined />
+                                        </p>
+                                        <p >
+                                            点击上传,或拖放文件到此处
+                                        </p >
+                                        <p className="ant-upload-hint">
+                                            支持文件格式md,txt,pdf,jpg,png,jpeg,docx,xlsx,
+                                            pptx,eml,csv,单个文档小雨30M,单张图片小于5M,文件总
+                                            大小不得超过125M.
+                                        </p>
+                                    </Dragger>
+                                </div>
+                            }
                         </>
                     }
                 </div>
@@ -347,14 +378,15 @@ const KnowledgeLibInfo: React.FC = () => {
                                     router.navigate(-1);
                                 }}>返回</Button>
                             </div>
-                            <div>
-                                <Upload {...props}>
-                                    <Button type='primary' icon={<PlusOutlined />}>上传知识文件</Button>
-                                </Upload>
-                            </div>
-                            
+                            {
+                                createFlag &&
+                                <div>
+                                    <Upload {...props}>
+                                        <Button type='primary' icon={<PlusOutlined />}>上传知识文件</Button>
+                                    </Upload>
+                                </div>
+                            }
                         </div>
-                        
 
                         <Table
                             scroll={{ x: 'max-content' }}

+ 71 - 37
src/pages/takai/knowledgeLib/list/index.tsx

@@ -8,6 +8,7 @@ import dayjs from 'dayjs';
 import store from './store';
 import { Record } from './types';
 import './style.less';
+import LocalStorage from '@/LocalStorage';
 
 const KnowledgeLibList: React.FC = () => {
     const {
@@ -29,8 +30,21 @@ const KnowledgeLibList: React.FC = () => {
         page
     } = state;
 
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+    const [deleteFlag, setDeleteFlag] = React.useState<boolean>();
+    const [updateFlag, setUpdateFlag] = React.useState<boolean>();
+    const [listFlag, setListFlag] = React.useState<boolean>();
+
     React.useEffect(() => {
         init();
+        const cFlag = LocalStorage.getStatusFlag('deepseek:knowledge:create');
+        setCreateFlag(cFlag);
+        const dFlag = LocalStorage.getStatusFlag('deepseek:knowledge:delete');
+        setDeleteFlag(dFlag);
+        const tFlag = LocalStorage.getStatusFlag('deepseek:knowledge:update');
+        setUpdateFlag(tFlag);
+        const lFlag = LocalStorage.getStatusFlag('deepseek:knowledge:list');
+        setListFlag(lFlag);
         return () => reset();
     }, []);
 
@@ -47,11 +61,19 @@ const KnowledgeLibList: React.FC = () => {
             title: '知识库名称',
             dataIndex: 'name',
             render: (text, record) => {
-                return (
-                    <Link to={{ pathname: `/deepseek/knowledgeLib/${record.knowledgeId}` }} >
-                        {text}
-                    </Link>
-                )
+                if (createFlag) {
+                    return (
+                        <Link to={{ pathname: `/deepseek/knowledgeLib/${record.knowledgeId}` }} >
+                            {text}
+                        </Link>
+                    )
+                } else {
+                    return (
+                        <>
+                            {text}
+                        </>
+                    )
+                }
             }
         },
         {
@@ -121,29 +143,36 @@ const KnowledgeLibList: React.FC = () => {
             render: (text, record) => {
                 return (
                     <>
-                        <a
-                            style={{ marginRight: 16 }}
-                            onClick={() => {
-                                onClickModify(record.knowledgeId);
-                            }}
-                        >
-                            <EditOutlined />
-                        </a >
-                        <a
-                            className='text-error'
-                            onClick={() => {
-                                Modal.confirm({
-                                    title: '删除',
-                                    content: `确定删除知识库名称${record.name}吗?`,
-                                    okType: 'danger',
-                                    onOk: async () => {
-                                        await onClickDelete(record.knowledgeId);
-                                    }
-                                });
-                            }}
-                        >
-                            <DeleteOutlined />
-                        </a>
+                        {
+                            updateFlag &&
+                            <a
+                                style={{ marginRight: 16 }}
+                                onClick={() => {
+                                    onClickModify(record.knowledgeId);
+                                }}
+                            >
+                                <EditOutlined />
+                            </a >
+                        }
+
+                        {
+                            deleteFlag &&
+                            <a
+                                className='text-error'
+                                onClick={() => {
+                                    Modal.confirm({
+                                        title: '删除',
+                                        content: `确定删除知识库名称${record.name}吗?`,
+                                        okType: 'danger',
+                                        onOk: async () => {
+                                            await onClickDelete(record.knowledgeId);
+                                        }
+                                    });
+                                }}
+                            >
+                                <DeleteOutlined />
+                            </a>
+                        }
                     </>
                 )
             }
@@ -171,15 +200,20 @@ const KnowledgeLibList: React.FC = () => {
 
     return (
         <div className='knowledgeLibList'>
-            <div className='knowledgeLibList-operation'>
-                <Button
-                    type='primary'
-                    icon={<PlusOutlined />}
-                    onClick={onClickCreate}
-                >
-                    创建知识库
-                </Button>
-            </div>
+            {
+                createFlag &&
+                <div className='knowledgeLibList-operation'>
+
+                    <Button
+                        type='primary'
+                        icon={<PlusOutlined />}
+                        onClick={onClickCreate}
+                    >
+                        创建知识库
+                    </Button>
+
+                </div>
+            }
             <div className='knowledgeLibList-table'>
                 <Table
                     scroll={{ x: 'max-content' }}

+ 51 - 27
src/pages/takai/knowledgeLib/slice/index.tsx

@@ -7,6 +7,7 @@ import { apis } from '@/apis';
 import { PaginationConfig } from 'antd/es/pagination';
 import router from '@/router';
 import './style.less';
+import LocalStorage from '@/LocalStorage';
 
 const FormItem = Form.Item;
 const SliceList: React.FC = () => {
@@ -36,6 +37,11 @@ const SliceList: React.FC = () => {
         total: 0,
     });
 
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+    const [deleteFlag, setDeleteFlag] = React.useState<boolean>();
+    const [updateFlag, setUpdateFlag] = React.useState<boolean>();
+    const [listFlag, setListFlag] = React.useState<boolean>();
+
     const appApi = {
         fetchList: async (p0: { searchText: string; }) => {
             setListLoading(true);
@@ -102,6 +108,14 @@ const SliceList: React.FC = () => {
 
     React.useEffect(() => {
         init();
+        const cFlag = LocalStorage.getStatusFlag('deepseek:slice:create');
+        setCreateFlag(cFlag);
+        const dFlag = LocalStorage.getStatusFlag('deepseek:slice:delete');
+        setDeleteFlag(dFlag);
+        const tFlag = LocalStorage.getStatusFlag('deepseek:slice:update');
+        setUpdateFlag(tFlag);
+        const lFlag = LocalStorage.getStatusFlag('deepseek:slice:list');
+        setListFlag(lFlag);
     }, [page.pageSize, page.pageNum])
 
     const paginationConfig: PaginationConfig = {
@@ -150,12 +164,15 @@ const SliceList: React.FC = () => {
                     </Form>
 
                     <div >
-                        <Button style={{ marginRight: 16 }} type='primary' icon={<PlusOutlined />} onClick={() => {
-                            router.navigate({
-                                pathname: '/deepseek/knowledgeLib/slice/detail/' + null + '/' + params.knowledgeId + '/' + params.documentId + '/'
-                                    + params.embeddingId
-                            });
-                        }}>新增切片</Button>
+                        {
+                            createFlag &&
+                            <Button style={{ marginRight: 16 }} type='primary' icon={<PlusOutlined />} onClick={() => {
+                                router.navigate({
+                                    pathname: '/deepseek/knowledgeLib/slice/detail/' + null + '/' + params.knowledgeId + '/' + params.documentId + '/'
+                                        + params.embeddingId
+                                });
+                            }}>新增切片</Button>
+                        }
 
                         <Button type='primary' icon={<ArrowLeftOutlined />} onClick={() => {
                             router.navigate(-1);
@@ -193,27 +210,34 @@ const SliceList: React.FC = () => {
                                             <div style={{ display: 'flex', justifyContent: 'space-between', overflow: 'auto' }}>
 
                                                 <div style={{ overflow: 'auto' }}>
-                                                    <a style={{ marginRight: 20 }} onClick={() => {
-                                                        router.navigate({
-                                                            pathname: '/deepseek/knowledgeLib/slice/detail/' + item.slice_id + '/' + params.knowledgeId + '/' + params.documentId + '/'
-                                                                + params.embeddingId
-                                                        });
-                                                    }}>
-                                                        <SettingOutlined /> 编辑
-                                                    </a>
-                                                    <a className='text-error' onClick={() => {
-                                                        Modal.confirm({
-                                                            title: '删除',
-                                                            content: `确定删除切片: ` + item.slice_id + ` 吗?`,
-                                                            okType: 'danger',
-                                                            onOk: async () => {
-                                                                const knowledgeId = params.knowledgeId || ''; // 提供默认值
-                                                                await deleteSlice(item.slice_id, knowledgeId);
-                                                            }
-                                                        });
-                                                    }}>
-                                                        <DeleteOutlined /> 删除
-                                                    </a>
+                                                    {
+                                                        updateFlag &&
+                                                        <a style={{ marginRight: 20 }} onClick={() => {
+                                                            router.navigate({
+                                                                pathname: '/deepseek/knowledgeLib/slice/detail/' + item.slice_id + '/' + params.knowledgeId + '/' + params.documentId + '/'
+                                                                    + params.embeddingId
+                                                            });
+                                                        }}>
+                                                            <SettingOutlined /> 编辑
+                                                        </a>
+                                                    }
+
+                                                    {
+                                                        deleteFlag &&
+                                                        <a className='text-error' onClick={() => {
+                                                            Modal.confirm({
+                                                                title: '删除',
+                                                                content: `确定删除切片: ` + item.slice_id + ` 吗?`,
+                                                                okType: 'danger',
+                                                                onOk: async () => {
+                                                                    const knowledgeId = params.knowledgeId || ''; // 提供默认值
+                                                                    await deleteSlice(item.slice_id, knowledgeId);
+                                                                }
+                                                            });
+                                                        }}>
+                                                            <DeleteOutlined /> 删除
+                                                        </a>
+                                                    }
                                                 </div>
 
                                                 <div>

+ 165 - 88
src/pages/takai/questionAnswer/info/index.tsx

@@ -10,6 +10,7 @@ import {
 import { PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons';
 import { apis } from '@/apis';
 import router from '@/router';
+import LocalStorage from '@/LocalStorage';
 
 const { TextArea } = Input;
 const FormItem = Form.Item;
@@ -23,6 +24,7 @@ const QuestionAnswerInfo: React.FC = () => {
 
     // top_p
     const [topPValue, setTopPValue] = React.useState(0.1);
+
     const TopPDecimalStep: React.FC = () => {
 
         const onChange: InputNumberProps['onChange'] = (value) => {
@@ -117,6 +119,11 @@ const QuestionAnswerInfo: React.FC = () => {
     const [isVisibleRerank, setIsVisibleRerank] = React.useState(false);
     const [name, setName] = React.useState('');
     const [appTypeList, setAppTypeList] = React.useState<AppTypeList>([]);
+    const [updateFlag, setUpdateFlag] = React.useState<boolean>();
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+    const [appProjectList, setAppProjectList] = React.useState<AppTypeList>([]);
+    const [isAppPro, setIsAppPro] = React.useState<boolean>(false);
+    const [selectedAppProId, setSelectedAppProId] = React.useState<string | undefined>(undefined); // 新增状态变量用于绑定 Select 值
 
     const style: React.CSSProperties = {
         display: 'flex',
@@ -132,6 +139,7 @@ const QuestionAnswerInfo: React.FC = () => {
             api.fetchKnowlegde(),
             api.fetchAppType(),
             // api.fetchModelList(),
+            api.fetchAppProType(),
         ])
         if (id) {
             await api.fetchDetail(id);
@@ -140,7 +148,11 @@ const QuestionAnswerInfo: React.FC = () => {
 
     React.useEffect(() => {
         const id = location?.state?.id;
-        init(id)
+        init(id);
+        const uFlag = LocalStorage.getStatusFlag('deepseek:application:update');
+        setUpdateFlag(uFlag);
+        const cFlag = LocalStorage.getStatusFlag('deepseek:application:create');
+        setCreateFlag(cFlag);
     }, []);
 
     // 定义一个状态来存储输入框数组
@@ -162,6 +174,15 @@ const QuestionAnswerInfo: React.FC = () => {
         setInputs(inputs.map(input => (input.id === id ? { ...input, value } : input)));
     };
 
+    const handleAppChange = (typeId: number) => {
+        if (typeId === 41) { // 根据实际值进行判断
+            setIsAppPro(true);
+        } else {
+            setIsAppPro(false);
+        }
+    };
+
+
     // const onChange: InputNumberProps['onChange'] = (value) => {
     //     console.log('changed', value);
     // };
@@ -241,6 +262,11 @@ const QuestionAnswerInfo: React.FC = () => {
                     setIsVisibleSlice(false);
                 }
 
+                if(info.typeId === 42 || info.typeId === 43){
+                    setIsAppPro(true);
+                }else{
+                    setIsAppPro(false);
+                }
                 form.setFieldsValue({
                     id: info.id,
                     name: info.name,  //应用名称
@@ -255,8 +281,9 @@ const QuestionAnswerInfo: React.FC = () => {
                     questionList: sd, //问题列表
                     max_token: info.maxToken, //应用最大token
                     updateDate: info.updateDate, // 更新时间
-                    typeId: info.typeId, //应用类型
-
+                    appProId: info.typeId, //项目级应用类型
+                    typeId: info.typeId === 42 || info.typeId === 43 ? 41 : info.typeId, //应用类型
+                    
                     param_desc: data_info.param_desc, //回答风格
                     show_recall_result: data_info.show_recall_result, //是否展示召回结果
                     recall_method: data_info.recall_method, //召回方式
@@ -329,6 +356,23 @@ const QuestionAnswerInfo: React.FC = () => {
             }
         },
 
+        // 项目级应用下的类型
+        fetchAppProType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('project_type');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictCode,
+                    }
+                });
+                console.log(list, 'project_type');
+                setAppProjectList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+
     }
 
     const handleRedioClick = (value: string) => {
@@ -367,10 +411,11 @@ const QuestionAnswerInfo: React.FC = () => {
                         <FormItem
                             label='应用类型'
                             name='typeId'
-                            >
+                        >
                             <Select
                                 style={{ width: '300px', height: '48px' }}
-                                placeholder='请选择知识库'
+                                placeholder='请选应用类型'
+                                onChange={handleAppChange}
                             >
                                 {
                                     appTypeList.map((item, index) => {
@@ -381,6 +426,28 @@ const QuestionAnswerInfo: React.FC = () => {
                                 }
                             </Select>
                         </FormItem>
+                                
+                        {
+                            isAppPro &&
+                            <FormItem
+                                label='类型'
+                                name='appProId'
+                                rules={[{ required: true, message: '项目类型不能为空' }]}
+                            >
+                                <Select
+                                    style={{ width: '300px', height: '48px' }}
+                                    placeholder='请选择项目类型'
+                                    value={selectedAppProId}
+                                    onChange={(value) => setSelectedAppProId(value)}
+                                >
+                                    {appProjectList.map((item, index) => (
+                                        <Option value={item.value} key={index}>
+                                            {item.label}
+                                        </Option>
+                                    ))}
+                                </Select>
+                            </FormItem>
+                        }
 
                         <FormItem
                             label='问答应用描述'
@@ -416,7 +483,7 @@ const QuestionAnswerInfo: React.FC = () => {
                         </div>
                         <br />
                         <Button type='primary' onClick={() => {
-                            form.validateFields(['name', 'desc']).then(async (values) => {
+                            form.validateFields(['name', 'desc', 'appProId']).then(async (values) => {
                                 setStep(2);
                                 setInputs(inputs);
                             }).catch((error) => {
@@ -438,91 +505,101 @@ const QuestionAnswerInfo: React.FC = () => {
                                 >
                                     上一步
                                 </Button>
-                                <Button
-                                    type='primary'
-                                    onClick={() => {
-                                        form.validateFields().then(async (values) => {
-                                            const data = values;
-                                            console.log(values, 'values');
-                                            // 问题列表
-                                            const question: string[] = [];
-                                            if (inputs) {
-                                                inputs.map((item, index) => {
-                                                    question.push(item.value);
-                                                });
-                                            }
-                                            console.log(question, 'question');
-                                            interface Item {
-                                                index_type_id: number,
-                                                knowledge_id: string
-                                            }
-                                            const indexTypeList: Item[] = [];
-                                            if (values.knowledge_ids && values.knowledge_ids.length > 0) {
-                                                const index_type: Item = {
-                                                    index_type_id: 0,
-                                                    knowledge_id: values.knowledge_ids
+                                {
+                                    createFlag &&
+                                    <Button
+                                        type='primary'
+                                        onClick={() => {
+                                            form.validateFields().then(async (values) => {
+                                                const data = values;
+                                                console.log(values, 'values');
+                                                // 问题列表
+                                                const question: string[] = [];
+                                                if (inputs) {
+                                                    inputs.map((item, index) => {
+                                                        question.push(item.value);
+                                                    });
+                                                }
+                                                console.log(question, 'question');
+                                                interface Item {
+                                                    index_type_id: number,
+                                                    knowledge_id: string
+                                                }
+                                                const indexTypeList: Item[] = [];
+                                                if (values.knowledge_ids && values.knowledge_ids.length > 0) {
+                                                    const index_type: Item = {
+                                                        index_type_id: 0,
+                                                        knowledge_id: values.knowledge_ids
+                                                    };
+                                                    indexTypeList.push(index_type);
+                                                }
+                                                const userInfo = LocalStorage.getUserInfo();
+                                                const userId = (userInfo?.id ?? '').toString();
+
+                                                const data_info = {
+                                                    param_desc: values.param_desc, //回答风格
+                                                    show_recall_result: values.show_recall_result, //是否展示召回结果
+                                                    recall_method: values.recall_method, //召回方式
+                                                    rerank_status: values.rerank_status, //开启rerank
+                                                    rerank_model_name: values.rerank_model_name, //模型名称
+                                                    slice_config_type: values.slice_config_type, // 召回切片数量
+                                                    slice_count: values.slice_count, // 切片数量
+                                                    recall_slice_splicing_method: values.recall_slice_splicing_method, // 切片内容
+                                                    rerank_index_type_list: values.rerank_status === true ? indexTypeList : [], //知识库id
+                                                    recall_index_type_list: values.recall_method === 'embedding' || 'mixed' ? indexTypeList : []
+                                                    // rerank_status = 1 rerank_index_type_list
+                                                    // recall_method = 'embedding' || 'embedding'  recall_index_type_list
+                                                };
+                                                // const knowledgeIds: string[] = [];
+                                                // knowledgeIds.push(values.knowledge_ids);
+                                                console.log(values.appProId , 'values.appProId ');
+                                                const info = {
+                                                    id: values.id,
+                                                    name: values.name,  //应用名称
+                                                    desc: values.desc,  //应用描述
+                                                    prompt: values.prompt, //应用提示语
+                                                    top_p: topPValue.toString(), //topP
+                                                    temperature: tempValue.toString(), //温度
+                                                    knowledge_ids: values.knowledge_ids,
+                                                    slice_count: values.slice_count,
+                                                    model: values.model,
+                                                    icon_color: values.icon_color,
+                                                    icon_type: values.icon_type,
+                                                    questionList: question,
+                                                    knowledge_info: JSON.stringify(data_info),
+                                                    max_token: values.max_token, //应用最大token
+                                                    typeId:  values.appProId === 42 || values.appProId === 43 ? values.appProId : values.typeId, // 应用类型
+                                                    userId: userId, // 用户id
                                                 };
-                                                indexTypeList.push(index_type);
-                                            }
-
-                                            const data_info = {
-                                                param_desc: values.param_desc, //回答风格
-                                                show_recall_result: values.show_recall_result, //是否展示召回结果
-                                                recall_method: values.recall_method, //召回方式
-                                                rerank_status: values.rerank_status, //开启rerank
-                                                rerank_model_name: values.rerank_model_name, //模型名称
-                                                slice_config_type: values.slice_config_type, // 召回切片数量
-                                                slice_count: values.slice_count, // 切片数量
-                                                recall_slice_splicing_method: values.recall_slice_splicing_method, // 切片内容
-                                                rerank_index_type_list: values.rerank_status === true ? indexTypeList : [], //知识库id
-                                                recall_index_type_list: values.recall_method === 'embedding' || 'mixed' ? indexTypeList : []
-                                                // rerank_status = 1 rerank_index_type_list
-                                                // recall_method = 'embedding' || 'embedding'  recall_index_type_list
-                                            };
-                                            // const knowledgeIds: string[] = [];
-                                            // knowledgeIds.push(values.knowledge_ids);
-                                            const info = {
-                                                id: values.id,
-                                                name: values.name,  //应用名称
-                                                desc: values.desc,  //应用描述
-                                                prompt: values.prompt, //应用提示语
-                                                top_p: topPValue.toString(), //topP
-                                                temperature: tempValue.toString(), //温度
-                                                knowledge_ids: values.knowledge_ids,
-                                                slice_count: values.slice_count,
-                                                model: values.model,
-                                                icon_color: values.icon_color,
-                                                icon_type: values.icon_type,
-                                                questionList: question,
-                                                knowledge_info: JSON.stringify(data_info),
-                                                max_token: values.max_token, //应用最大token
-                                                typeId: values.typeId, // 应用类型
-                                            };
-                                            const id = location?.state?.id;
-                                            let res = null;
-                                            if (id) {
-                                                // 编辑应用
                                                 console.log(info, 'info data');
-                                                res = await apis.modifyTakaiApplicationApi(id, info);
-                                            } else {
-                                                // 创建应用
-                                                res = await await apis.createTakaiApplicationApi(info);
-                                            }
-                                            if (res.code !== 200) {
-                                                message.error(res.data.message);
-                                            } else {
-                                                message.success('操作成功')
+                                                const id = location?.state?.id;
+                                                let res = null;
+                                                if (id) {
+                                                    // 编辑应用
+                                                    res = await apis.modifyTakaiApplicationApi(id, info);
+                                                } else {
+                                                    // 创建应用
+                                                    res = await await apis.createTakaiApplicationApi(info);
+                                                }
+                                                console.log(res, 'create or modify');
+                                                if (res.data === 9) {
+                                                    message.error('没有配置审核人,请联系管理员');
+                                                } else if (res.data === 1) {
+                                                    message.success('操作成功')
+                                                } else {
+                                                    message.error('操作失败');
+                                                }
                                                 router.navigate({ pathname: '/deepseek/questionAnswer' });
-                                            }
-                                        }).catch((error) => {
-                                            console.error(error);
-                                            error.errorFields && error.errorFields.map((item: any) => {
-                                                console.log(item, 'item');
-                                                message.error(`字段 ${item.name} ${item.errors[0]}`);
+                                            }).catch((error) => {
+                                                console.error(error);
+                                                error.errorFields && error.errorFields.map((item: any) => {
+                                                    console.log(item, 'item');
+                                                    message.error(`字段 ${item.name} ${item.errors[0]}`);
+                                                });
                                             });
-                                        });
-                                    }}
-                                >发布应用</Button>
+                                        }}
+                                    >提交应用</Button>
+                                }
                             </div>
                         </div>
                         <Splitter style={{ height: '100%', boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
@@ -553,7 +630,7 @@ const QuestionAnswerInfo: React.FC = () => {
   - 输出的内容必须删除其中包含的任何图注、序号等信息。例如:“进入登录页面(图1.1)”需要从文字中删除图序,回复效果为:“进入登录页面”;“如图所示1.1”,回复效果为:“如图所示”;
 - 格式规范
   - 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
-  - 如果需要用到表格中的数据,以markdown格式输出表格中的数据;
+  - 如果需要用到表格中的数据,以代码块语法输出表格中的数据;
   - 避免使用代码块语法回复信息;
   - 回复的开头语不要输出诸如:“我想”,“我认为”,“think”等相关语义的文本。
 

+ 379 - 48
src/pages/takai/questionAnswer/list/index.tsx

@@ -1,13 +1,19 @@
 import * as React from 'react';
 import { observer } from 'mobx-react';
-import { List, Button, Divider, Flex, Layout, Empty, Image, Modal, Tag } from 'antd';
-import { PlusOutlined, FileOutlined, SettingOutlined, DeleteOutlined } from '@ant-design/icons';
+import { List, Button, Divider, Flex, Layout, Empty, Image, Modal, Tag, message, Tooltip, Select, Form } from 'antd';
+import { PlusOutlined, FileOutlined, SettingOutlined, DeleteOutlined, StepForwardOutlined } from '@ant-design/icons';
 import { apis } from '@/apis';
 import './style.less';
 import { PaginationConfig } from 'antd/es/pagination';
 import router from '@/router';
+import LocalStorage from '@/LocalStorage';
+import { create } from 'domain';
+import audit from '../../audit';
+import { set } from 'mobx';
 
 const { Header, Footer, Sider, Content } = Layout;
+const { Option } = Select;
+const FormItem = Form.Item;
 
 const headerStyle: React.CSSProperties = {
     textAlign: 'center',
@@ -44,12 +50,17 @@ const layoutStyle = {
     maxWidth: 'calc(20% - 8px)',
 };
 const QuestionAnswerList: React.FC = () => {
+    const [form] = Form.useForm();
     interface Item {
         name: string,
         desc: string,
         appId: number,
         createBy: string,
         typeId: string;
+        status: string;
+        comment: string;
+        auditStatus: string;
+        projectName: string;
     };
 
     interface PageInfo {
@@ -63,6 +74,11 @@ const QuestionAnswerList: React.FC = () => {
         value: string,
     }[];
 
+    type ProjectTypeList = {
+        label: string,
+        value: string,
+    }[];
+
     const [listLoading, setListLoading] = React.useState(false);
     const [list, setList] = React.useState<Item[]>([]);
     const [page, setPage] = React.useState<PageInfo>({
@@ -74,16 +90,30 @@ const QuestionAnswerList: React.FC = () => {
     const [knowCount, setKnowCount] = React.useState<string>();
     const { Header, Footer, Sider, Content } = Layout;
     const [appTypeList, setAppTypeList] = React.useState<AppTypeList>([]);
+    const [createFlag, setCreateFlag] = React.useState(false);
+    const [deleteFlag, setDeleteFlag] = React.useState(false);
+    const [updateFlag, setUpdateFlag] = React.useState(false);
+    const [projectList, setProjectList] = React.useState<ProjectTypeList>([]);
+    const [appProjectList, setAppProjectList] = React.useState<AppTypeList>([]);
+    const [showSubPanel, setShowSubPanel] = React.useState(false);
+    const [selectedType, setSelectedType] = React.useState<number | null>(null);
+    const wrapperRef = React.useRef<HTMLDivElement>(null);
+    const selectRef = React.useRef<any>(null);
+    const [levelTypeList, setLevelTypeList] = React.useState<AppTypeList>([]);
 
     const appApi = {
-        fetchList: async () => {
+        fetchList: async (typeId: any, projectId: any) => {
             setListLoading(true);
             try {
+                const userInfo = LocalStorage.getUserInfo();
+                const userId = (userInfo?.id ?? '').toString();
                 const res = await apis.fetchTakaiAppList({
                     pageSize: page.pageSize,
-                    pageNumber: page.pageNumber
+                    pageNumber: page.pageNumber,
+                    userId: userId,
+                    typeId: typeId,
+                    projectId: projectId,
                 })
-                console.log(res.rows, 'fetchTakaiAppList');
                 const list = res.rows.map((item: any) => {
                     return {
                         name: item.name,
@@ -91,20 +121,41 @@ const QuestionAnswerList: React.FC = () => {
                         appId: item.appId,
                         createBy: item.createBy,
                         typeId: item.typeId,
+                        status: item.status,
+                        comment: item.comment,
+                        auditStatus: item.auditStatus,
+                        projectName: item.projectName
+                    }
+                });
+                const c = LocalStorage.getStatusFlag('deepseek:application:create');
+                const u = LocalStorage.getStatusFlag('deepseek:application:delete');
+                const filteredList = list.filter((item: any) => {
+                    // 如果有 createFlag 或 updateFlag 权限,显示所有数据
+                    if (c || u) {
+                        return true;
                     }
+                    // 没有权限时排除 status='5' 的数据
+                    return item.status !== '5';
                 });
-                setList(list);
+                setList(filteredList);
                 setPage({
                     pageNumber: page.pageNumber,
                     pageSize: page.pageSize,
                     total: res.total,
                 });
-                console.log(page, 'res.data.total');
             } catch (error) {
                 console.error(error);
             } finally {
                 setListLoading(false);
             }
+        },
+
+        auditApplication: async (appId: string, userId: string) => {
+            const res = await apis.auditTakaiApplicationLibApi(appId, userId);
+            if (res.data === 9) {
+                message.error('您没有添加审核人');
+            }
+            await appApi.fetchList(null, null);
         }
     };
 
@@ -112,26 +163,26 @@ const QuestionAnswerList: React.FC = () => {
     const delApplication = async (appId: string) => {
         try {
             await apis.deleteTakaiApplicationApi(appId);
-            await appApi.fetchList();
+            await appApi.fetchList(null, null);
         } catch (error) {
             console.error(error);
         }
     }
 
     const indexApi = {
-        fetchIndex: async () => {
+        fetchIndex: async (typeId: any, projectId: any) => {
             try {
+                const userInfo = LocalStorage.getUserInfo();
+                const userId = (userInfo?.id ?? '').toString();
                 const res = await apis.fetchTakaiIndexCount({
                     pageSize: page.pageSize,
-                    pageNumber: page.pageNumber
+                    pageNumber: page.pageNumber,
+                    userId: userId,
+                    typeId: typeId,
+                    projectId: projectId,
                 })
                 setAppCount(res.data.applicationCount);
                 setKnowCount(res.data.knowledgeCount);
-                // setPage({
-                //     pageNumber: page.pageNumber,
-                //     pageSize: page.pageSize,
-                //     total: res.data.total,
-                // });
             } catch (error) {
                 console.error(error);
             } finally {
@@ -158,14 +209,72 @@ const QuestionAnswerList: React.FC = () => {
         },
     };
 
+    // 项目级应用下的类型
+    const appProTypeApi = {
+        fetchAppProType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('project_type');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictCode,
+                    }
+                });
+                setAppProjectList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+    };
+
+    const projectApi = {
+        fetchProject: async () => {
+            try {
+                const res = await apis.fetchTakaiProjectLibApi();
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.projectName,
+                        value: item.projectId,
+                    }
+                });
+                setProjectList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+    };
+
+    // 获取应用类型
+    const levelTypeApi = {
+        fetchLevelAppType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('project_type');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictCode,
+                    }
+                });
+                setLevelTypeList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+    };
 
     const init = async () => {
-        await appApi.fetchList();
-        await indexApi.fetchIndex();
+        await appApi.fetchList(null, null);
+        await indexApi.fetchIndex(null, null);
         await appTypeApi.fetchAppType();
+        await projectApi.fetchProject();
+        await appProTypeApi.fetchAppProType();
+        await levelTypeApi.fetchLevelAppType();
     }
 
     React.useEffect(() => {
+        setCreateFlag(LocalStorage.getStatusFlag('deepseek:application:create'));
+        setDeleteFlag(LocalStorage.getStatusFlag('deepseek:application:delete'));
+        setUpdateFlag(LocalStorage.getStatusFlag('deepseek:application:update'));
         init();
     }, [page.pageSize, page.pageNumber])
 
@@ -192,9 +301,173 @@ const QuestionAnswerList: React.FC = () => {
         },
     };
 
+    // 点击查询
+    const handleClickSearch = async () => {
+        form.validateFields().then(async (values) => {
+            if(values.proTypeId){
+                values.typeId = values.proTypeId;
+            }
+            await indexApi.fetchIndex(values.typeId, values.projectId);
+            await appApi.fetchList(values.typeId, values.projectId);
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+
+    // 点击重置
+    const handleClickReset = async () => {
+        form.resetFields();
+        setShowSubPanel(false);
+        page.pageNumber = 1;
+        page.pageSize = 10;
+        await appApi.fetchList(null, null);
+        await indexApi.fetchIndex(null, null);
+    };
+
+    /** 点击外部关闭面板 */
+    React.useEffect(() => {
+        const handleClickOutside = (event: MouseEvent) => {
+            if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) {
+                setShowSubPanel(false);
+            }
+        };
+
+        document.addEventListener('mousedown', handleClickOutside, true);
+        return () => {
+            document.removeEventListener('mousedown', handleClickOutside, true);
+        };
+    }, []);
+
+
+    const handleAppTypeChange = (value: number) => {
+        console.log(value, 'sssss');
+        if (value === 41) {
+            // 如果是项目级应用,切换面板状态
+            // setShowSubPanel(prev => !prev);
+            setShowSubPanel(true);
+        } else {
+            // 其他选项,隐藏面板
+            setShowSubPanel(false);
+        }
+        setSelectedType(value);
+        form.setFieldsValue({ typeId: value });
+    };
+
+    const handleAppProTypeChange = (value: number) => {
+        console.log(value, 'valuevalue');
+
+        setSelectedType(value);
+        form.setFieldsValue({ typeId: value });
+    };
 
     return (
-        <div>
+        <div >
+            <div >
+                <Form form={form} layout='inline' colon={false}>
+                    <div style={{ display: 'flex', alignItems: 'center', position: 'relative' }} >
+                        {/* 主选择器 */}
+                        <FormItem label="应用类型" name="typeId" style={{ marginBottom: 0 }}>
+                            <Select
+                                ref={selectRef}
+                                style={{ width: 200 }}
+                                placeholder="请选择应用类型"
+                                onChange={handleAppTypeChange}
+                                value={selectedType}
+                                allowClear
+                            >
+                                {appTypeList.map(item => (
+                                    <Option key={item.value} value={item.value}>
+                                        {item.label}
+                                    </Option>
+                                ))}
+                            </Select>
+                        </FormItem>
+
+                        {/* 子选项面板 */}
+                        {showSubPanel && selectedType === 41 && (
+                            // <div 
+                            //     style={{
+                            //         position: 'absolute',
+                            //         left: '68%',
+                            //         top: 35,
+                            //         marginLeft: 10,
+                            //         padding: 12,
+                            //         background: '#fff',
+                            //         border: '1px solid #d9d9d9',
+                            //         borderRadius: 4,
+                            //         boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
+                            //         zIndex: 1000,
+                            //         width: 200
+                            //     }}
+                            // >
+                                <FormItem
+                                    label='类型'
+                                    name='proTypeId'
+                                    rules={[{ required: true, message: '类型不能为空' }]}
+                                >
+                                    <Select
+                                        placeholder='请选择'
+                                        allowClear
+                                        style={{ width: 200 }}
+                                        // onChange={handleAppProTypeChange}
+                                    >
+                                        {
+                                            appProjectList.map((item, index) => {
+                                                return <Option value={item.value} key={index}>
+                                                    {item.label}
+                                                </Option>
+                                            })
+                                        }
+                                    </Select>
+                                </FormItem>
+
+                            // </div>
+                        )}
+                    </div>
+
+                    {/* {
+                            appProjectList.map((subItem, index) => (
+                                <div key={index}>
+                                    {subItem.label}
+                                </div>
+                            ))
+                        } */}
+
+                    <FormItem
+                        label='项目'
+                        name='projectId'
+                    >
+                        <Select
+                            style={{ width: '200px' }}
+                            placeholder='请选择项目'
+                            allowClear
+                        >
+                            {
+                                projectList.map((item, index) => {
+                                    return <Option value={item.value} key={index}>
+                                        {item.label}
+                                    </Option>
+                                })
+                            }
+                        </Select>
+                    </FormItem>
+
+
+
+                    <FormItem>
+                        <Button
+                            style={{ marginRight: 16 }}
+                            type='primary'
+                            onClick={handleClickSearch}
+                        >
+                            查询
+                        </Button>
+                        <Button onClick={handleClickReset}>
+                            重置
+                        </Button>
+                    </FormItem>
+                </Form>
+            </div>
             {
                 list.length
                     ?
@@ -223,11 +496,14 @@ const QuestionAnswerList: React.FC = () => {
                         </div>
                         <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                             <div>所有问答应用</div>
-                            <Button type='primary'
-                                icon={<PlusOutlined />}
-                                onClick={() => {
-                                    router.navigate({ pathname: '/deepseek/questionAnswer/create' });
-                                }}>创建问答应用</Button>
+                            {
+                                createFlag &&
+                                <Button type='primary'
+                                    icon={<PlusOutlined />}
+                                    onClick={() => {
+                                        router.navigate({ pathname: '/deepseek/questionAnswer/create' });
+                                    }}>创建问答应用</Button>
+                            }
                         </div>
                         <div className='applicationList'>
                             <List style={{ height: 400 }}
@@ -257,7 +533,29 @@ const QuestionAnswerList: React.FC = () => {
                                                         {item.name}
                                                     </div>
                                                 </div>
-                                                <div >{item.createBy}</div>
+                                                <div >
+                                                    <>
+                                                        {item.projectName}
+                                                        {
+                                                            (item.status !== null && item.status !== '3') &&
+                                                            < Tag style={{ marginLeft: 16, width: 65, color: '#fff', height: 25, backgroundColor: item.status === '1' ? '#D26900' : item.status === '2' ? '#408080' : item.auditStatus === '4' ? '#CE0000' : item.status === '5' ? '#5151A2' : '' }}>
+                                                                {item.status === '1' ? '待审核' : item.status === '2' ? '审核中' : item.auditStatus === '4' ? '审核拒绝' : item.status === '5' ? '待提交' : '未知'}
+                                                            </Tag>
+                                                        }
+
+                                                        {
+                                                            (item.auditStatus === '4') &&
+                                                            <Tooltip title={item.comment}>
+                                                                {
+                                                                    item.comment !== '' && item.comment !== null && item.comment.length > 10 ?
+                                                                        item.comment.substring(0, 10) + '......' :
+                                                                        item.comment
+                                                                }
+                                                            </Tooltip>
+                                                        }
+
+                                                    </>
+                                                </div>
                                             </div>
                                             <Divider plain></Divider>
                                             <div className='desc'>
@@ -267,23 +565,54 @@ const QuestionAnswerList: React.FC = () => {
                                             </div>
                                             <div style={{ display: 'flex', justifyContent: 'space-between', overflow: 'auto' }}>
                                                 <div style={{ overflow: 'auto' }}>
-                                                    <a style={{ marginRight: 16 }} onClick={() => {
-                                                        router.navigate({ pathname: '/deepseek/questionAnswer/modify' }, { state: { id: item.appId } });
-                                                    }}>
-                                                        <SettingOutlined /> 编辑
-                                                    </a>
-                                                    <a className='text-error' onClick={() => {
-                                                        Modal.confirm({
-                                                            title: '删除',
-                                                            content: `确定删除应用名称: ` + item.name + ` 吗?`,
-                                                            okType: 'danger',
-                                                            onOk: async () => {
-                                                                await delApplication(item.appId.toString());
+                                                    {
+                                                        (item.status === '5' || item.status === '4' || item.status === '3' || item.status === '' || item.status === null) &&
+                                                        <>
+                                                            {
+                                                                updateFlag &&
+                                                                <a style={{ marginRight: 16 }} onClick={() => {
+                                                                    router.navigate({ pathname: '/deepseek/questionAnswer/modify' }, { state: { id: item.appId } });
+                                                                }}>
+                                                                    <SettingOutlined /> 编辑
+                                                                </a>
+                                                            }
+
+                                                            {
+                                                                deleteFlag &&
+                                                                <a className='text-error' onClick={() => {
+                                                                    Modal.confirm({
+                                                                        title: '删除',
+                                                                        content: `确定删除应用名称: ` + item.name + ` 吗?`,
+                                                                        okType: 'danger',
+                                                                        onOk: async () => {
+                                                                            await delApplication(item.appId.toString());
+                                                                        }
+                                                                    });
+                                                                }}>
+                                                                    <DeleteOutlined /> 删除
+                                                                </a>
                                                             }
-                                                        });
-                                                    }}>
-                                                        <DeleteOutlined /> 删除
-                                                    </a>
+
+                                                        </>
+                                                    }
+
+                                                    {
+                                                        createFlag && item.status === '5' &&
+                                                        <a style={{ marginLeft: 16 }} onClick={() => {
+                                                            Modal.confirm({
+                                                                title: '提交审核',
+                                                                content: `确认提交审核应用名称: ` + item.name + `吗?`,
+                                                                okType: 'danger',
+                                                                onOk: async () => {
+                                                                    const userInfo = LocalStorage.getUserInfo();
+                                                                    const userId = (userInfo?.id ?? '').toString();
+                                                                    appApi.auditApplication(item.appId.toString(), userId);
+                                                                }
+                                                            });
+                                                        }}>
+                                                            <StepForwardOutlined /> 提交审核
+                                                        </a>
+                                                    }
                                                 </div>
 
                                                 <div>
@@ -298,7 +627,7 @@ const QuestionAnswerList: React.FC = () => {
                                                     >
                                                         {
                                                             appTypeList
-                                                                .find(item1 => item1.value === item.typeId)?.label || '未分类'
+                                                                .find(item1 => item1.value.toString() === item.typeId)?.label || levelTypeList.find(item2 => item2.value.toString() === item.typeId)?.label || '未分类'
                                                         }
                                                     </Tag>
                                                 </div>
@@ -312,16 +641,18 @@ const QuestionAnswerList: React.FC = () => {
                     </div>
                     :
                     <div>
-                        <Button type='primary'
-                            icon={<PlusOutlined />}
-                            onClick={() => {
-                                router.navigate({ pathname: '/deepseek/questionAnswer/create' });
-                            }}>创建问答应用</Button>
+                        {
+                            createFlag &&
+                            <Button type='primary'
+                                icon={<PlusOutlined />}
+                                onClick={() => {
+                                    router.navigate({ pathname: '/deepseek/questionAnswer/create' });
+                                }}>创建问答应用</Button>
+                        }
                         <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
                     </div>
-
             }
-        </div>
+        </div >
     )
 };
 

+ 9 - 1
src/router.tsx

@@ -30,7 +30,7 @@ const routerList: RouteObject[] = [
         children: [
             {
                 index: true,
-                element: <Navigate to='/deepseek/questionAnswer' />,
+                element: LocalStorage.getStatusFlag('deepseek:application:list') ?  <Navigate to='/deepseek/questionAnswer' /> : <Navigate to='/404' />,
             },
             {   /* 问答应用 */
                 path: '/deepseek/questionAnswer',
@@ -106,6 +106,14 @@ const routerList: RouteObject[] = [
                 },
                 element: lazyLoad(() => import('@/pages/takai/dataExport/index')),
             },
+            {   /* 数据导出 */
+                path: '/deepseek/audit',
+                handle: {
+                    menuLevel: 1,
+                    breadcrumbName: '知识库审核',
+                },
+                element: lazyLoad(() => import('@/pages/takai/audit/index')),
+            },
             {   /* 404 */
                 path: '/404',
                 element: lazyLoad(() => import('@/components/404/index')),