Procházet zdrojové kódy

应用审核列表新增查看功能

sunsheng před 5 měsíci
rodič
revize
35d23fd9bd

+ 2 - 1
env/.env.development

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

+ 938 - 0
src/pages/deepseek/audit/components/PreviewModal.tsx

@@ -0,0 +1,938 @@
+import * as React from 'react';
+import { useLocation } from 'react-router-dom';
+import { observer } from 'mobx-react';
+import './style.less';
+import {
+    Button, Input, Form, Divider, Splitter, Select, InputNumber, InputNumberProps,
+    Radio, Switch, Row, Col, Slider, Space, RadioChangeEvent,
+    Spin, message, Typography, Tooltip,
+    Cascader
+} from 'antd';
+import { PlusCircleOutlined, MinusCircleOutlined, ArrowLeftOutlined, InfoCircleOutlined } from '@ant-design/icons';
+import { apis } from '@/apis';
+import router from '@/router';
+import LocalStorage from '@/LocalStorage';
+import Chat from '@/components/chat';
+
+const { TextArea } = Input;
+const FormItem = Form.Item;
+const { Option } = Select;
+const MAX_COUNT = 5;
+const Index = 1;
+interface QuestionAnswerInfoProps {
+  AuditAppId?: string | number,
+  isComponent?: boolean
+}
+const QuestionAnswerInfo: React.FC<QuestionAnswerInfoProps> = ({AuditAppId,isComponent=false}) => {
+
+    const [form] = Form.useForm();
+
+    // top_p
+    const [topPValue, setTopPValue] = React.useState(0.1);
+
+    const TopPDecimalStep: React.FC = () => {
+
+        const onChange: InputNumberProps['onChange'] = (value) => {
+            if (Number.isNaN(value)) {
+                return;
+            }
+            setTopPValue(value as number);
+        };
+
+        return (
+            <Row>
+                <Col span={12}>
+                    <Slider
+                        min={0}
+                        max={1}
+                        onChange={onChange}
+                        // value={typeof topPValue === 'number' ? topPValue : 0}
+                        value={topPValue}
+                        step={0.1}
+                    />
+                </Col>
+                <Col span={4}>
+                    <InputNumber
+                        min={0}
+                        max={1}
+                        className='form-input-number-small'
+                        step={0.01}
+                        value={topPValue}
+                        onChange={onChange}
+                    />
+                </Col>
+            </Row>
+        );
+    };
+    const [tempValue, setTempValue] = React.useState(0.01);
+    // temperature
+    const TempDecimalStep: React.FC = () => {
+        const onChange: InputNumberProps['onChange'] = (value) => {
+            if (Number.isNaN(value)) {
+                return;
+            }
+            setTempValue(value as number);
+        };
+
+        return (
+            <Row>
+                <Col span={12}>
+                    <Slider
+                        min={0}
+                        max={1}
+                        onChange={onChange}
+                        // value={typeof tempValue === 'number' ? tempValue : 0}
+                        value={tempValue}
+                        step={0.01}
+                    />
+                </Col>
+                <Col span={4}>
+                    <InputNumber
+                        min={0}
+                        max={1}
+                        className='form-input-number-small'
+                        step={0.01}
+                        value={tempValue}
+                        onChange={onChange}
+                    />
+                </Col>
+            </Row>
+        );
+    };
+
+    type ModelList = {
+        label: string,
+        value: string,
+    }[];
+
+    type KnowledgeList = {
+        label: string,
+        value: string,
+    }[];
+
+    type AppTypeList = {
+        label: string,
+        value: string,
+        children: {
+            label: string,
+            value: string,
+        }[],
+    }[];
+
+    const [step, setStep] = React.useState(1);
+    const [pageLoading, setPageLoading] = React.useState(false);
+    const [modelList, setModelList] = React.useState<ModelList>([]);
+    const [knowledgeList, setKnowledgeList] = React.useState<KnowledgeList>([]);
+    const [isVisible, setIsVisible] = React.useState(false);
+    const [isVisibleCus, setIsVisibleCus] = React.useState(false);
+    const [isVisibleSlice, setIsVisibleSlice] = React.useState(false);
+    const [isVisibleRerank, setIsVisibleRerank] = React.useState(false);
+    const [isDeepThinkVisible, setIsDeepThinkVisible] = React.useState(false);
+    const [name, setName] = React.useState('');
+    const [appTypeList, setAppTypeList] = React.useState<AppTypeList>([]);
+    const [appVisibleList, setAppVisibleList] = 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 [appId, setAppId] = React.useState<string>('');
+
+    const style: React.CSSProperties = {
+        display: 'flex',
+        flexDirection: 'column',
+        gap: 8,
+        width: 230,
+    };
+
+    const location = useLocation();
+
+    const init = async (id: string) => {
+        await Promise.all([
+            api.fetchKnowlegde(),
+            api.fetchAppType(),
+            // api.fetchModelList(),
+            api.fetchAppProType(),
+            api.fetchAppVisible(id)
+        ])
+        if (id) {
+            await api.fetchDetail(id);
+        }
+    }
+
+    React.useEffect(() => {
+        console.log('isComponent',isComponent)
+        const id = location?.state?.id||AuditAppId;
+        init(id);
+        const uFlag = LocalStorage.getStatusFlag('deepseek:application:update');
+        setUpdateFlag(uFlag);
+        const cFlag = LocalStorage.getStatusFlag('deepseek:application:create');
+        setCreateFlag(cFlag);
+    }, []);
+
+    // 定义一个状态来存储输入框数组
+    const [inputs, setInputs] = React.useState([{ id: 1, value: '' }]);
+
+    // 添加新输入框的函数
+    const addInput = () => {
+        const newId = inputs.length + 1; // 生成新的唯一ID
+        setInputs([...inputs, { id: newId, value: '' }]);
+    };
+
+    // 删除输入框(按id删除+最少数量限制)
+    const delInput = (id: number) => {
+        if (inputs.length <= 1) {
+            message.warning("至少保留1个预设问题");
+            return;
+        }
+        setInputs(inputs.filter(input => input.id !== id));
+    };
+
+    // 处理输入变更的函数
+    const handleChange = (id: number, value: string) => {
+        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);
+    // };
+
+    const onChangeShow = (checked: boolean) => {
+        console.log(`switch to ${checked}`);
+    };
+
+    const onChangeModel = (checked: boolean) => {
+        setIsVisibleRerank(!isVisibleRerank);
+    };
+
+    const onChangeCount = (value: string) => {
+        if (value === 'fixed') {
+            setIsVisibleSlice(!isVisibleSlice);
+        } else {
+            setIsVisibleSlice(false);
+        }
+    };
+
+    // 召回方式
+    const onChangeRecallMethod = (e: RadioChangeEvent) => {
+
+    };
+
+    // 获取应用详情
+    const api = {
+        fetchDetail: async (app_id: string) => {
+            setPageLoading(true);
+            try {
+                const res = await apis.fetchTakaiApplicationDetail(app_id);
+                const sd = res.data.questionlist.map((item: any, index: number) => {
+                    return {
+                        "id": index + 1,
+                        "value": item.question,
+                    }
+                });
+
+                const info = res.data.detail;
+
+                setAppId(info.appId);
+
+                setTopPValue(info.topP as number);
+                setTempValue(info.temperature as number);
+                setName(info.name);
+
+                interface Item2 {
+                    index_type_id: number,
+                    knowledge_id: string
+                }
+
+                interface Item {
+                    show_recall_result: boolean,
+                    recall_method: string,
+                    rerank_status: boolean,
+                    slice_config_type: string,
+                    slice_count: number,
+                    recall_slice_splicing_method: string,
+                    param_desc: string,
+                    rerank_model_name: string,
+                    rerank_index_type_list: [Item2],
+                    recall_index_type_list: [Item2]
+                }
+
+                const data_info: Item = JSON.parse(info.knowledgeInfo);
+
+                if (data_info.param_desc === 'custom') {
+
+                    setIsVisibleCus(!isVisibleCus);    //自定义回答风格
+                }
+                if (data_info.rerank_status === true) {
+                    setIsVisibleRerank(!isVisibleRerank) //模型
+                }
+                //召回切片数量
+                if (data_info.slice_config_type === 'fixed') {
+                    setIsVisibleSlice(!isVisibleSlice);
+                } else {
+                    setIsVisibleSlice(false);
+                }
+
+                if (info.typeId === 41) {
+                    setIsAppPro(true);
+                } else {
+                    setIsAppPro(false);
+                }
+
+                if (info.model === 'Qwen3-30B') {
+                    setIsDeepThinkVisible(true);
+                } else {
+                    setIsDeepThinkVisible(false);
+                }
+
+                console.log(info.knowledgeIds, 'info.knowledgeIds')
+                form.setFieldsValue({
+                    id: info.id,
+                    name: info.name,  //应用名称
+                    desc: info.desc,  //应用描述
+                    prompt: info.prompt, //应用提示语
+                    top_p: info.topP as number, //topP
+                    temperature: info.temperature as number, //温度
+                    knowledge_ids: info.knowledgeIds,
+                    model: info.model,
+                    isDeepThink: info.isDeepThink,
+                    icon_color: info.icon_color,
+                    icon_type: info.icon_type,
+                    questionList: sd, //问题列表
+                    max_token: info.maxToken, //应用最大token
+                    updateDate: info.updateDate, // 更新时间
+                    appProId: info.appProId,// 项目
+                    typeId: info.typeId, //应用类型
+                    visible: info.visible||'0', //是否公开
+                    param_desc: data_info.param_desc, //回答风格
+                    show_recall_result: data_info.show_recall_result, //是否展示召回结果
+                    recall_method: data_info.recall_method, //召回方式
+                    rerank_status: data_info.rerank_status, //开启rerank
+                    rerank_model_name: data_info.rerank_model_name, //模型名称
+                    slice_config_type: data_info.slice_config_type, // 召回切片数量
+                    slice_count: data_info.slice_count, // 切片数量
+                    recall_slice_splicing_method: data_info.recall_slice_splicing_method, // 切片内容
+                    // rerank_status = 1 rerank_index_type_list
+                    // recall_method = 'embedding' || 'mixed'  recall_index_type_list
+                    //recall_index_type_list: info.recall_index_type_list, //知识库id
+                    //rerank_index_type_list: info.rerank_index_type_list, //知识库id
+                })
+                if (sd.length > 0) {
+                    setInputs(sd);
+                }
+            } catch (error) {
+                console.error(error);
+            } finally {
+                setPageLoading(false);
+            }
+        },
+
+        //获取知识库列表
+        fetchKnowlegde: async () => {
+            try {
+                const res = await apis.fetchTakaiKnowledgeList();
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.name,
+                        value: item.knowledgeId,
+                    }
+                });
+                console.log(list, 'list')
+
+
+                setKnowledgeList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+
+        // 获取应用类型
+        fetchAppType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('app_type');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictCode,
+                    }
+                });
+                setAppTypeList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 获取是否公开类型
+        fetchAppVisible: async (id:string) => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('app_visible');
+                console.log('res.data',res.data)
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictValue,
+                    }
+                });
+                setAppVisibleList(list);
+                if(!id){
+                    form.setFieldsValue({
+                        visible: list[0].value
+                    });
+                }
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+
+        // 获取模型列表
+        fetchModelList: async () => {
+            try {
+                const res = await apis.fetchModelList();
+                const list = res.data.data.map((item: any) => {
+                    return {
+                        label: item.modelName,
+                        value: item.modelCode,
+                    }
+                });
+                setModelList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+
+        // 项目级应用下的类型
+        fetchAppProType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('projectTree');
+                const list: AppTypeList = res.data;
+                setAppProjectList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+    }
+
+    const handleRedioClick = (value: string) => {
+        setIsVisibleCus(false);
+        if (value === 'strict') {
+            setTopPValue(0.5);
+            setTempValue(0.01);
+        } else if (value === 'moderate') {
+            setTopPValue(0.7);
+            setTempValue(0.50);
+        } else if (value === 'flexib') {
+            setTopPValue(0.9);
+            setTempValue(0.90);
+        }
+    }
+
+    return (
+        <div className='questionAnswerInfo'>
+            <Spin spinning={pageLoading}>
+                <Form
+                    variant={'underlined'}
+                    form={form}
+                    layout='vertical'
+                    initialValues={{
+                        isDeepThink: false,
+                        max_token: 1024
+                    }}
+                >
+                    <div style={{ display: step === 1 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
+                        <FormItem
+                            label='问答应用名称'
+                            name='name'
+                            rules={[{ required: true, message: '问答应用名称不能为空' }]}
+                        >
+                            <Input placeholder="请输入问答应用名称" disabled={true} className='form-input-large' />
+                        </FormItem>
+                        <FormItem
+                            label='应用类型'
+                            name='typeId'
+                        >
+                            <Select
+                                className='questionAnswerInfo-content-title'
+                                placeholder='请选择问答应用类型'
+                                onChange={handleAppChange}
+                                allowClear={true}
+                                disabled={true}
+                            >
+                                {
+                                    appTypeList.map((item, index) => {
+                                        return <Option value={item.value} key={index}>
+                                            {item.label}
+                                        </Option>
+                                    })
+                                }
+                            </Select>
+                        </FormItem>
+                        <FormItem
+                            label='是否公开'
+                            name='visible'
+                        >
+                            <Select
+                                className='questionAnswerInfo-content-title'
+                                placeholder='请选择是否公开'
+                                allowClear={true}
+                                disabled={true}
+                            >
+                                {
+                                    appVisibleList.map((item, index) => {
+                                        return <Option value={item.value} key={index}>
+                                            {item.label}
+                                        </Option>
+                                    })
+                                }
+                            </Select>
+                        </FormItem>
+                        {
+                            isAppPro &&
+                            <>
+                                <FormItem
+                                    label='项目'
+                                    name='appProId'
+                                    rules={[{ required: true, message: '项目不能为空' }]}
+                                >
+                                    <Cascader
+                                        disabled={true}
+                                        options={appProjectList}
+                                        placeholder="请选择项目"
+                                        showSearch
+                                        className="questionAnswerInfo-content-title"
+                                    />
+                                </FormItem>
+                            </>
+                        }
+
+                        <FormItem
+                            label='问答应用描述'
+                            name='desc'
+                            rules={[{ required: true, message: '问答应用描述不能为空' }]}
+                        >
+                            <TextArea
+                                disabled={true}
+                                showCount
+                                maxLength={500}
+                                placeholder="请输入当前应用的描述"
+                                className='form-textarea-large'
+                            />
+                        </FormItem>
+
+                        <div className='preset-questions'>
+                            <h4>添加预设问题</h4>
+                            <div>
+                                {
+                                    inputs.map(input => (
+                                        <div key={input.id} className='question-item'>
+                                            <label>问题 {input.id}</label>
+                                            <Input
+                                                disabled={true}
+                                                className='question-input'
+                                                type="text"
+                                                value={input.value}
+                                                onChange={e => handleChange(input.id, e.target.value)}
+                                            />
+                                            {/* <div className='question-actions'>
+                                                <PlusCircleOutlined className='question-icon' onClick={addInput} />
+                                                <MinusCircleOutlined className='question-icon' onClick={() => delInput(input.id)} />
+                                            </div> */}
+                                        </div>
+                                    ))}
+                            </div>
+                        </div>
+
+                        <div style={{ display: 'flex', gap: '12px', marginTop: '24px', paddingTop: '24px', borderTop: '1px solid #f0f0f0' }}>
+                            <Button
+                                type='primary'
+                                disabled={false}
+                                onClick={() => {
+                                    form.validateFields(['name', 'desc', 'appProId']).then(async (values) => {
+                                        setStep(2);
+                                        setInputs(inputs);
+                                    }).catch((error) => {
+                                        console.error(error);
+                                    });
+                                }}
+                            >
+                                下一步
+                            </Button>
+                        </div>
+                    </div>
+
+                    <div style={{ display: step === 2 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
+                        <div className='flex-between padding-bottom-16'>
+                            <div>
+                                <Button
+                                    className='btn-back'
+                                    disabled={false}
+                                    icon={<ArrowLeftOutlined />}
+                                    onClick={() => {
+                                        setStep(1);
+                                    }}
+                                >
+                                    上一步
+                                </Button>
+                            </div>
+                        </div>
+                        <div className='section-title'>
+                            Prompt编写与参数配置
+                            <Tooltip
+                                title="Prompt用于对大模型的回复做出一些列指令和约束。这段Prompt不会被用户看到。"
+                                placement="right"
+                                overlayStyle={{ fontSize: '12px' }}
+                            >
+                                <InfoCircleOutlined style={{ marginLeft: '8px', color: '#999', fontSize: '14px' }} />
+                            </Tooltip>
+                        </div>
+                        <Splitter style={{ border: '1px solid #f0f0f0', borderRadius: '6px', height: 550 }}>
+                            <Splitter.Panel defaultSize="45%">
+                                <div className='prompt'>
+                                    <div className='prompt-info'>
+                                        <div className='prompt-info-text'>
+                                            <Typography.Paragraph style={{ fontSize: '12px', lineHeight: '1.6', color: '#999', margin: 0 }}>
+                                                编写Prompt过程中可以引入2项变量:
+                                                <span className='variable-highlight'>{'{{知识}}'}</span>
+                                                代表知识库中检索到的知识内容,
+                                                <span className='variable-highlight'>{'{{用户}}'}</span>
+                                                代表用户输入的内容。您可以在编写Prompt过程中将变量拼接在合适的位置。
+                                                <br />
+                                                插入:
+                                                <span className='variable-highlight'>{'{{知识}}'}</span>,
+                                                插入:
+                                                <span className='variable-highlight'>{'{{用户}}'}</span>。
+                                            </Typography.Paragraph>
+                                        </div>
+                                    </div>
+                                    <Divider style={{ margin: '0' }} />
+                                    <div className='prompt-editor-area'>
+                                        <FormItem name='prompt'
+                                            initialValue={
+                                                `你是一位知识检索助手,你必须并且只能从我发送的众多知识片段中寻找能够解决用户输入问题的最优答案,并且在执行任务的过程中严格执行规定的要求。 \n
+知识片段如下:
+{{知识}}
+
+规定要求:
+- 找到答案就仅使用知识片段中的原文回答用户的提问;- 找不到答案就用自身知识并且告诉用户该信息不是来自文档;
+- 所引用的文本片段中所包含的示意图占位符必须进行返回,占位符格式参考:【示意图序号_编号】
+- 严禁输出任何知识片段中不存在的示意图占位符;
+- 输出的内容必须删除其中包含的任何图注、序号等信息。例如:“进入登录页面(图1.1)”需要从文字中删除图序,回复效果为:“进入登录页面”;“如图所示1.1”,回复效果为:“如图所示”;
+
+格式规范:
+- 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
+- 如果需要用到表格中的数据,以代码块语法输出表格中的数据;
+- 避免使用代码块语法回复信息;
+- 回复的开头语不要输出诸如:“我想”,“我认为”,“think”等相关语义的文本。
+
+严格执行规定要求,不要复述问题,直接开始回答。
+
+用户输入问题:
+{{用户}}`
+                                            }
+                                            rules={[{ required: true, message: '提示词不能为空' }]}>
+                                            <TextArea
+                                                disabled={true}
+                                                placeholder="提示词"
+                                                rows={50}
+                                            />
+                                        </FormItem>
+                                    </div>
+                                </div>
+                            </Splitter.Panel>
+                            <Splitter.Panel defaultSize="25%">
+                                <div className='flex-center-container'>
+                                    <div className='half-width'>
+                                        <div className='flex-center-top'>
+                                            欢迎使用 {name}
+                                        </div>
+                                        <div className='flex-center padding-top-20'>
+                                            <FormItem
+                                                label='引用知识库'
+                                                name='knowledge_ids'
+                                                rules={[{ required: true, message: '知识库不能为空' }]}>
+                                                <Select
+                                                    disabled={true}
+                                                    mode='multiple'
+                                                    maxCount={MAX_COUNT}
+                                                    showSearch={true}
+                                                    // suffixIcon={suffix}
+                                                    // className='questionAnswerInfo-content-title'
+                                                    placeholder='请选择知识库'
+                                                >
+                                                    {
+                                                        knowledgeList.map((item, index) => {
+                                                            return <Option value={item.value} key={index}>
+                                                                {item.label}
+                                                            </Option>
+                                                        })
+                                                    }
+                                                </Select>
+                                            </FormItem>
+                                        </div>
+                                        <div className='flex-center'>
+                                            <FormItem
+                                                label='调用模型'
+                                                name="model"
+                                                rules={[{ required: true, message: '模型不能为空' }]}>
+                                                <Select
+                                                    disabled={true}
+                                                    placeholder='请选择模型'
+                                                    allowClear={true}
+                                                    className='questionAnswerInfo-content-title'
+                                                    onChange={(value) => {
+                                                        if (value === 'Qwen3-30B') {
+                                                            setIsDeepThinkVisible(true);
+                                                        } else {
+                                                            setIsDeepThinkVisible(false);
+                                                        }
+                                                    }}
+                                                >
+                                                    <Option value='Qwen3-30B'>Qwen3-30B</Option>
+                                                    <Option value='Qwen2-72B'>Qwen2-72B</Option>
+                                                </Select>
+
+                                            </FormItem>
+                                        </div>
+                                        <div className='flex-center' style={{
+                                            display: isDeepThinkVisible ? 'flex' : 'none'
+                                        }}>
+                                            <FormItem
+                                                label='深度思考'
+                                                name='isDeepThink'
+                                                rules={[{ required: true, message: '请选择是否深度思考' }]}>
+                                                <Radio.Group buttonStyle="solid" className='form-control-width' disabled={true}>
+                                                    <Radio.Button value='Y'>是</Radio.Button>
+                                                    <Radio.Button value='N'>否</Radio.Button>
+                                                </Radio.Group>
+                                            </FormItem>
+                                        </div>
+                                        <div className='flex-center'>
+                                            <FormItem
+                                                label='max token'
+                                                name='max_token'
+                                                rules={[{ required: true, message: 'max token不能为空' }]}>
+                                                <InputNumber disabled={true}
+                                                    className='questionAnswerInfo-content-title'
+                                                />
+                                            </FormItem>
+                                        </div>
+
+                                        {
+                                            !isVisible &&
+                                            <div className='flex-center'>
+                                                <a onClick={() => {
+                                                    setIsVisible(!isVisible);
+                                                }} className='link-more-settings'>
+                                                    更多设置
+                                                </a>
+                                            </div>
+
+                                        }
+
+                                        {/* {isVisible && */}
+                                        <div style={{ display: isVisible ? 'block' : 'none', paddingTop: '20px' }}>
+                                            {isVisibleCus &&
+                                                <Space style={{ width: '100%' }} direction="vertical">
+                                                    <div className='flex-center'>
+                                                        <FormItem
+                                                            label='Top-p'
+                                                            name='topP'
+                                                            className='form-control-width'
+                                                        >
+                                                            <TopPDecimalStep />
+                                                        </FormItem>
+                                                    </div>
+                                                    <div className='flex-center'>
+                                                        <FormItem
+                                                            label='Temperature'
+                                                            name='temperature'
+                                                            className='form-control-width'
+                                                        >
+                                                            <TempDecimalStep />
+                                                        </FormItem>
+                                                    </div>
+                                                </Space>
+                                            }
+
+                                            <div style={{
+                                                display: 'flex',
+                                                justifyContent: 'center',
+                                                alignItems: 'center'
+                                            }}>
+                                                <FormItem
+                                                    label='回答风格'
+                                                    name='param_desc'
+                                                    rules={[{ required: true, message: '回答风格不能为空' }]}>
+                                                    <Radio.Group buttonStyle="solid" disabled={true}
+                                                        className='form-control-width'>
+                                                        <Radio.Button onClick={() => {
+                                                            handleRedioClick('strict')
+                                                        }} value='strict'>严谨</Radio.Button>
+                                                        <Radio.Button onClick={() => {
+                                                            handleRedioClick('moderate')
+                                                        }} value='moderate'>适中</Radio.Button>
+                                                        <Radio.Button onClick={() => {
+                                                            handleRedioClick('flexib')
+                                                        }} value='flexib'>发散</Radio.Button>
+                                                        <Radio.Button value='custom'
+                                                            onClick={() => {
+                                                                setIsVisibleCus(!isVisibleCus);
+                                                                setTopPValue(0.1);
+                                                                setTempValue(0.01);
+                                                            }}
+                                                        >自定义
+                                                        </Radio.Button>
+                                                    </Radio.Group>
+                                                </FormItem>
+                                            </div>
+                                            <div style={{
+                                                display: 'flex',
+                                                justifyContent: 'center',
+                                                alignItems: 'center'
+                                            }}>
+                                                <FormItem
+                                                    label='展示引用知识'
+                                                    name='show_recall_result'
+                                                    className='form-control-width'>
+                                                    <Switch onChange={onChangeShow} disabled={true} />
+                                                </FormItem>
+                                            </div>
+                                            <div style={{
+                                                display: 'flex',
+                                                justifyContent: 'center',
+                                                alignItems: 'center'
+                                            }}>
+                                                <FormItem
+                                                    label='召回方式'
+                                                    name='recall_method'
+                                                    rules={[{ required: true, message: '召回方式不能为空' }]}>
+
+                                                    <Radio.Group
+                                                        style={style}
+                                                        onChange={onChangeRecallMethod}
+                                                        disabled={true}
+                                                        options={[
+                                                            { value: 'embedding', label: '向量化检索' },
+                                                            { value: 'keyword', label: '关键词检索' },
+                                                            { value: 'mixed', label: '混合检索' },
+                                                        ]}
+                                                    />
+                                                </FormItem>
+                                            </div>
+                                            <div style={{
+                                                display: 'flex',
+                                                justifyContent: 'center',
+                                                alignItems: 'center'
+                                            }}>
+                                                <div className='section-title'>重排方式</div>
+                                            </div>
+                                            <div style={{
+                                                display: 'flex',
+                                                justifyContent: 'center',
+                                                alignItems: 'center'
+                                            }}>
+                                                <FormItem
+                                                    label='Rerank模型'
+                                                    name='rerank_status'
+                                                    valuePropName='checked'
+                                                    className='form-control-width'
+                                                >
+                                                    <Switch onChange={onChangeModel} disabled={true} />
+                                                </FormItem>
+                                            </div>
+                                            {isVisibleRerank &&
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'center',
+                                                    alignItems: 'center'
+                                                }}>
+                                                    <FormItem
+                                                        label='模型选择'
+                                                        name='rerank_model_name'
+                                                    >
+                                                        <Select
+                                                            disabled={true}
+                                                            className='questionAnswerInfo-content-title'
+                                                            placeholder='请选择模型'
+                                                        // defaultValue={'rerank'}
+                                                        >
+                                                            <Option value='rerank'>默认rerank模型</Option>
+                                                        </Select>
+                                                    </FormItem>
+                                                </div>
+                                            }
+                                            <div style={{
+                                                display: 'flex',
+                                                justifyContent: 'center',
+                                                alignItems: 'center'
+                                            }}>
+                                                <FormItem
+                                                    label='召回切片数量'
+                                                    name='slice_config_type'
+                                                    rules={[{ required: true, message: '召回方式不能为空' }]}>
+                                                    <Select
+                                                        disabled={true}
+                                                        className='questionAnswerInfo-content-title'
+                                                        placeholder='请选择'
+                                                        onChange={onChangeCount}>
+                                                        <Option value="fixed">手动设置</Option>
+                                                        <Option value="customized">自动设置</Option>
+                                                    </Select>
+                                                </FormItem>
+                                            </div>
+
+                                            {isVisibleSlice &&
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'center',
+                                                    alignItems: 'center'
+                                                }}>
+                                                    <FormItem
+                                                        label='召回切片数'
+                                                        name='slice_count'
+                                                        rules={[{ required: true, message: '切片数不能为空' }]}>
+                                                        <InputNumber max={1024} changeOnWheel disabled={true}
+                                                            className='questionAnswerInfo-content-title' />
+                                                    </FormItem>
+                                                </div>
+                                            }
+                                            <div style={{
+                                                display: 'flex',
+                                                justifyContent: 'center',
+                                                alignItems: 'center'
+                                            }}>
+                                                <FormItem
+                                                    label='召回切片拼接方式'
+                                                    name='recall_slice_splicing_method'
+                                                >
+                                                    <TextArea
+                                                        disabled={true}
+                                                        rows={4}
+                                                        className='form-textarea-large'
+                                                        placeholder="请输入内容"
+                                                    />
+                                                </FormItem>
+                                            </div>
+                                        </div>
+                                        {/* } */}
+                                    </div>
+                                </div>
+                            </Splitter.Panel>
+                            <Splitter.Panel defaultSize="30%">
+                                <Chat appId={appId} />
+                            </Splitter.Panel>
+                        </Splitter>
+                    </div>
+                </Form>
+            </Spin>
+        </div >
+    );
+};
+
+export default observer(QuestionAnswerInfo);

+ 428 - 0
src/pages/deepseek/audit/components/style.less

@@ -0,0 +1,428 @@
+// 主容器样式
+.questionAnswerInfo {
+  width: 100%;
+  height: 100%;
+  background: #FFFFFF;
+  border-radius: @border-radius-base;
+
+  // 内容区域
+  &-content {
+    width: 100%;
+    height: 100%;
+    background: #FFFFFF;
+    padding: 16px 20px;
+
+    // 标题样式
+    &-title {
+      width: 100%;
+      max-width: 646px;
+      height: 48px;
+    }
+  }
+  .ant-input-underlined[disabled], 
+  .ant-select-selector,
+  .ant-input-number-input, 
+  .ant-input-affix-wrapper >textarea.ant-input{
+    color: rgba(48,49,51,0.88) !important;
+  }
+}
+
+
+
+// 通用布局样式
+.flex {
+  &-center {
+    &-container {
+      width: 100%;
+      height: 100%;
+      background: #f5f5f5;
+    }
+
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    &-top {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      padding-top: 50px;
+      font-size: 16px;
+    }
+  }
+
+  &-between {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  &-end {
+    display: flex;
+    justify-content: flex-end;
+  }
+}
+
+// 按钮样式
+.btn {
+  &-cancel {
+    background: #f5f5f5;
+    border: none;
+    color: #000000;
+    transition: all 0.3s ease;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+
+    &:hover {
+      background: #e8e8e8;
+      color: #000000;
+      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+      transform: translateY(-1px);
+    }
+
+    &:active {
+      background: #dcdcdc;
+      color: #000000;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+      transform: translateY(0);
+    }
+
+    &:focus {
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    }
+  }
+
+  &-back {
+    background: #ffffff;
+    border: 1px solid #f0f0f0;
+    color: #595959;
+    transition: all 0.3s ease;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+
+    &:hover {
+      background: #fafafa;
+      border-color: #40a9ff;
+      color: #40a9ff;
+      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+      transform: translateY(-1px);
+    }
+
+    &:active {
+      background: #f0f0f0;
+      border-color: #1890ff;
+      color: #1890ff;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+      transform: translateY(0);
+    }
+
+    &:focus {
+      border-color: #40a9ff;
+      box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+    }
+  }
+}
+
+// 表单样式
+.form {
+  &-control {
+    &-width {
+      width: 100%;
+      max-width: 646px;
+    }
+
+    &-height {
+      height: 48px;
+    }
+  }
+
+  &-input {
+    &-large {
+      width: 100%;
+      max-width: 646px;
+      padding: 8px;
+    }
+
+    &-number-small {
+      margin: 0 16px;
+      width: 100px;
+    }
+  }
+
+  &-textarea {
+    &-large {
+      height: 120px;
+      resize: none;
+      width: 100%;
+      max-width: 646px;
+    }
+  }
+}
+
+// 文本区域样式
+.textarea {
+  &-full-width {
+    width: 100%;
+  }
+
+  &-fixed-height {
+    height: 300px;
+  }
+}
+
+// 预设问题区域样式
+.preset-questions {
+  margin: 24px 0;
+
+  h4 {
+    margin-bottom: 16px;
+    color: #262626;
+  }
+
+  .question-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
+    flex-wrap: wrap;
+    gap: 12px;
+
+    label {
+      min-width: 60px;
+      color: #595959;
+      flex-shrink: 0;
+    }
+
+    .question-input {
+      flex: 1;
+      min-width: 200px;
+      max-width: 400px;
+      margin: 0;
+    }
+
+    .question-actions {
+      display: flex;
+      gap: 8px;
+      flex-shrink: 0;
+
+      .question-icon {
+        margin: 0;
+        font-size: 18px;
+        color: @primary-color;
+        cursor: pointer;
+        transition: all 0.3s ease;
+
+        &:hover {
+          color: @primary-color;
+          transform: scale(1.1);
+        }
+      }
+    }
+  }
+}
+
+// 问题输入框样式(保留向后兼容)
+.question-input {
+  width: 100%;
+  max-width: 300px;
+  padding-top: 8px;
+  margin-left: 20px;
+}
+
+.link-more-settings {
+  color: @primary-color;
+  cursor: pointer;
+  text-decoration: none;
+
+  &:hover {
+    text-decoration: underline;
+  }
+}
+
+// 标题和链接样式
+.section-title {
+  font-size: 14px;
+  font-weight: 500;
+  color: #262626;
+  margin-bottom: 12px;
+}
+
+// Prompt编辑器布局样式
+.prompt {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  // 滚动条
+  overflow-y: auto;
+
+  // 提示词模板显示区域
+  &-info {
+    padding: 16px 20px 10px 20px;
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+
+    &-text {
+      // 说明文本
+
+      .variable-highlight {
+        color: #1890ff;
+        font-weight: 500;
+        padding: 2px 6px;
+        border-radius: 4px;
+        font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+        margin: 0 2px;
+      }
+    }
+  }
+
+  // 提示词编辑区域
+  &-editor-area {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+
+    .ant-form-item {
+      margin-bottom: 0;
+      height: 100%;
+
+      .ant-form-item-control {
+        height: 100%;
+
+        .ant-form-item-control-input {
+          height: 100%;
+
+          .ant-form-item-control-input-content {
+            height: 100%;
+
+            .ant-input {
+              height: 100%;
+              border: 1px solid #f0f0f0;
+              border-radius: 8px;
+              padding: 16px;
+              font-size: 14px;
+              line-height: 1.6;
+              resize: none;
+
+              &:focus {
+                border-color: #1890ff;
+                box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+              }
+
+              &::placeholder {
+                color: #bfbfbf;
+                font-style: italic;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.half-width {
+  margin: 0 auto;
+  width: 50%;
+  height: 100%;
+}
+
+// 间距样式
+.padding {
+  &-top {
+    &-10 {
+      padding-top: 10px;
+    }
+
+    &-20 {
+      padding-top: 20px;
+    }
+  }
+
+  &-bottom {
+    &-10 {
+      padding-bottom: 10px;
+    }
+
+    &-12 {
+      padding-bottom: 12px;
+    }
+
+    &-16 {
+      padding-bottom: 16px;
+    }
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .questionAnswerInfo {
+    &-content {
+      &-title {
+        max-width: 100%;
+      }
+    }
+  }
+
+  .form {
+    &-control-width,
+    &-input-large,
+    &-textarea-large {
+      max-width: 100%;
+    }
+  }
+
+  .question-input {
+    max-width: 100%;
+    margin-left: 0;
+  }
+
+  .half-width {
+    width: 100%;
+  }
+
+  .preset-questions {
+    .question-item {
+      flex-direction: column;
+      align-items: flex-start;
+      gap: 8px;
+
+      label {
+        min-width: auto;
+      }
+
+      .question-input {
+        width: 100%;
+        max-width: 100%;
+        min-width: auto;
+      }
+
+      .question-actions {
+        align-self: flex-end;
+      }
+    }
+  }
+}
+
+@media (max-width: 480px) {
+  .questionAnswerInfo {
+    &-content {
+      padding: 16px;
+    }
+  }
+
+  .form {
+    &-input-large,
+    &-textarea-large {
+      padding: 6px;
+    }
+  }
+
+  .preset-questions {
+    .question-item {
+      .question-actions {
+        align-self: center;
+        width: 100%;
+        justify-content: center;
+      }
+    }
+  }
+}

+ 28 - 4
src/pages/deepseek/audit/index.tsx

@@ -1,6 +1,6 @@
 import * as React from 'react';
 import { observer } from 'mobx-react';
-import { Table, TableColumnsType, TablePaginationConfig } from 'antd';
+import { Table, TableColumnsType, TablePaginationConfig,Drawer } from 'antd';
 import { StepForwardOutlined } from '@ant-design/icons';
 import dayjs from 'dayjs';
 import store from './store';
@@ -8,13 +8,14 @@ import { Record } from './types';
 import './style.less';
 import LocalStorage from '@/LocalStorage';
 import InfoModal from './components/InfoModal';
-
+import PreviewModal from './components/PreviewModal';
 const KnowledgeLibList: React.FC = () => {
     const {
         state,
         onChangePagination,
         onClickCreate,
         onClickModify,
+        onClickfetchTakaiApplicationDetail,
         infoModalOnClickConfirm,
         infoModalOnClickCancel,
         infoModalOnClickClose,
@@ -33,7 +34,8 @@ const KnowledgeLibList: React.FC = () => {
     const [deleteFlag, setDeleteFlag] = React.useState<boolean>();
     const [detailFlag, setDetailFlag] = React.useState<boolean>();
     const [listFlag, setListFlag] = React.useState<boolean>();
-
+    const [drawerFlag, setDrawerFlag] = React.useState<boolean>(false);
+    const [drawerData, setDrawerData] = React.useState<any>({});
 
     React.useEffect(() => {
         const userInfo = LocalStorage.getUserInfo();
@@ -132,6 +134,17 @@ const KnowledgeLibList: React.FC = () => {
                         >
                             <StepForwardOutlined />审核
                         </a >
+                        <a
+                            style={{ marginRight: 16 }}
+                            onClick={() => {
+                                // onClickfetchTakaiApplicationDetail(record.appId);
+                                setDrawerFlag(true)
+                                setDrawerData(record)
+                            }}
+                            title='审核'
+                        >
+                            查看
+                        </a >
                     </>
                 )
             }
@@ -162,7 +175,7 @@ const KnowledgeLibList: React.FC = () => {
             <div className='knowledgeLibList-table'>
                 <Table
                     scroll={{ x: 'max-content' }}
-                    rowKey={(record) => record.knowledgeId}
+                    rowKey={(record) => record.createTime}
                     loading={listLoading}
                     columns={columns}
                     dataSource={list}
@@ -179,6 +192,17 @@ const KnowledgeLibList: React.FC = () => {
                     onClickClose={infoModalOnClickClose}
                 />
             }
+            {
+                <Drawer
+                    title={drawerData.name}
+                    closable={{ 'aria-label': 'Close Button' }}
+                    onClose={() => { setDrawerFlag(false) }}
+                    width="80%"
+                    open={drawerFlag}
+                >
+                    {drawerFlag&&<PreviewModal isComponent={true} AuditAppId={drawerData.appId} />}
+                </Drawer> 
+            }        
         </div>
     );
 };

+ 17 - 2
src/pages/deepseek/audit/store.ts

@@ -81,8 +81,23 @@ const useKnowledgeLibListStore = (): DocumentLibListStore => {
                 message.error(error.msg);
             }
         },
+        // 获取详情
+        fetchTakaiApplicationDetail: async (appId: string) => {
+            try {
+                const res = await apis.fetchTakaiApplicationDetail(appId);
+                console.log(res, 'resresres');
+                return res;
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+    }
+    // 点击查看出现弹窗
+    const onClickfetchTakaiApplicationDetail = async (appId: string) => {
+        if(appId){
+            await api.fetchTakaiApplicationDetail(appId);
+        }
     }
-
     // 更改分页
     const onChangePagination: DocumentLibListStore['onChangePagination'] = async (pageNumber, pageSize) => {
         actions.setPage({
@@ -135,7 +150,6 @@ const useKnowledgeLibListStore = (): DocumentLibListStore => {
 
     const infoModalOnClickClose: DocumentLibListStore['infoModalOnClickClose'] = () => {
         const initialInfoModalOpen = stateGenerator().infoModalOpen;
-
         actions.setInfoModalOpen(initialInfoModalOpen);
 
     }
@@ -167,6 +181,7 @@ const useKnowledgeLibListStore = (): DocumentLibListStore => {
         onChangePagination,
         onClickCreate,
         onClickModify,
+        onClickfetchTakaiApplicationDetail,
         infoModalOnClickConfirm,
         infoModalOnClickCancel,
         infoModalOnClickClose,

+ 1 - 0
src/pages/deepseek/audit/types.ts

@@ -40,6 +40,7 @@ export type DocumentLibListStore = {
     onChangePagination: (pageNumber: number, pageSize: number) => Promise<any>,
     onClickCreate: () => void,
     onClickModify: (documentId: string) => void,
+    onClickfetchTakaiApplicationDetail: (appId: string) => void,
     infoModalOnClickConfirm: (documentId: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
     infoModalOnClickCancel: (documentId: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
     infoModalOnClickClose:  () => void,