作者 dong

修改日志管理代码,首页修改指标说明提示修改,

设置-功能按钮,设置-样式修改,知识库跳转,设置-全部字段必填,设置-将智能助手配置放菜单管理下
@@ -15,5 +15,9 @@ export const getLoginfo = (params) => defHttp.get({ url: Api.loginfo, params }, @@ -15,5 +15,9 @@ export const getLoginfo = (params) => defHttp.get({ url: Api.loginfo, params },
15 */ 15 */
16 export const getVisitInfo = (params) => defHttp.get({ url: Api.visitInfo, params }, { isTransformResponse: false }); 16 export const getVisitInfo = (params) => defHttp.get({ url: Api.visitInfo, params }, { isTransformResponse: false });
17 17
18 -export const getStatistics = (params?: { rangeType?: string | null; startTime?: string; endTime?: string }) =>  
19 - defHttp.get({ url: '/airaglog/airagLog/getStatistics', params }); 18 +export const getStatistics = () => defHttp.get({ url: '/airaglog/airagLog/getStatistics' });
  19 +
  20 +export const getButtonStats = (params?: { rangeType?: string | null; startTime?: string; endTime?: string }) =>
  21 + defHttp.get({ url: '/airaglog/airagLog/getButtonStats', params });
  22 +
  23 +export const getQuestionStatistics = () => defHttp.get({ url: '/airaglog/airagLog/getQuestionStatistics' });
@@ -9,20 +9,18 @@ @@ -9,20 +9,18 @@
9 :class="[index + 1 < 4 && '!md:mr-4']" 9 :class="[index + 1 < 4 && '!md:mr-4']"
10 > 10 >
11 <template #action> 11 <template #action>
12 - <a-tooltip title="指标说明"> 12 + <a-tooltip>
13 <Icon :icon="item.icon" :size="20" /> 13 <Icon :icon="item.icon" :size="20" />
14 </a-tooltip> 14 </a-tooltip>
15 </template> 15 </template>
16 <div v-if="type === 'chart'"> 16 <div v-if="type === 'chart'">
17 - <!-- <Trend term="周同比" :percentage="12" v-if="index === 0" />-->  
18 - <!-- <Trend term="日同比" :percentage="11" v-if="index === 0" :type="false" />-->  
19 <div v-if="index === 0" class="p-2 px-4 flex justify-between"> 17 <div v-if="index === 0" class="p-2 px-4 flex justify-between">
20 <span>平均问答次数</span> 18 <span>平均问答次数</span>
21 <span>{{ formatNumber(statistics.averageCount) }}</span> 19 <span>{{ formatNumber(statistics.averageCount) }}</span>
22 </div> 20 </div>
23 - <SingleLine v-if="index === 1" :option="option" :chartData="chartData" :seriesColor="seriesColor" height="50px" /> 21 + <SingleLine v-if="index === 1" :option="option" :chartData="dailyCountsData" :seriesColor="seriesColor" height="50px" />
24 22
25 - <Bar v-if="index === 2" :option="option" :chartData="chartData" :seriesColor="seriesColor" height="50px" /> 23 + <Bar v-if="index === 2" :option="option" :chartData="dailyRejectedCountsData" :seriesColor="seriesColor" height="50px" />
26 24
27 <Trend 25 <Trend
28 v-if="index === 3" 26 v-if="index === 3"
@@ -32,11 +30,11 @@ @@ -32,11 +30,11 @@
32 /> 30 />
33 </div> 31 </div>
34 <div v-else> 32 <div v-else>
35 - <SingleLine :seriesColor="seriesColor" v-if="index === 0" :option="option" :chartData="chartData" height="50px" /> 33 + <SingleLine :seriesColor="seriesColor" v-if="index === 0" :option="option" height="50px" />
36 34
37 - <SingleLine :seriesColor="seriesColor" v-if="index === 1" :option="option" :chartData="chartData" height="50px" /> 35 + <SingleLine :seriesColor="seriesColor" v-if="index === 1" :option="option" :chartData="dailyCountsData" height="50px" />
38 36
39 - <Bar :seriesColor="seriesColor" v-if="index === 2" :option="option" :chartData="chartData" height="50px" /> 37 + <Bar :seriesColor="seriesColor" v-if="index === 2" :option="option" :chartData="dailyRejectedCountsData" height="50px" />
40 38
41 <Progress v-if="index === 3" :percent="78" :show-info="false" /> 39 <Progress v-if="index === 3" :percent="78" :show-info="false" />
42 </div> 40 </div>
@@ -87,34 +85,45 @@ @@ -87,34 +85,45 @@
87 default: 'chart', 85 default: 'chart',
88 }, 86 },
89 }); 87 });
90 - const option = ref({ xAxis: { show: false, boundaryGap: false }, yAxis: { show: false, boundaryGap: false, max: 220 } }); 88 + const dailyCountsData = computed(() => {
  89 + if (!props.statistics.dailyCounts) return [];
  90 + return props.statistics.dailyCounts.map((item) => ({
  91 + name: formatDayLabel(item.date),
  92 + value: item.count,
  93 + }));
  94 + });
91 95
92 - const chartData = ref([  
93 - {  
94 - name: '1月',  
95 - value: 50,  
96 - },  
97 - {  
98 - name: '2月',  
99 - value: 100,  
100 - },  
101 - {  
102 - name: '3月',  
103 - value: 150,  
104 - },  
105 - {  
106 - name: '4月',  
107 - value: 40, 96 + const dailyRejectedCountsData = computed(() => {
  97 + if (!props.statistics.dailyRejectedCounts) return [];
  98 + return props.statistics.dailyRejectedCounts.map((item) => ({
  99 + name: formatDayLabel(item.date),
  100 + value: item.count,
  101 + }));
  102 + });
  103 +
  104 + const formatDayLabel = (dateStr: string) => {
  105 + const date = new Date(dateStr);
  106 + console.log('格式化日期:', dateStr);
  107 + return `${date.getMonth() + 1}/${date.getDate()}`; // 格式: 月/日
  108 + };
  109 + const option = ref({
  110 + xAxis: {
  111 + show: true, // 显示X轴
  112 + type: 'category',
  113 + boundaryGap: false,
108 }, 114 },
109 - {  
110 - name: '5月',  
111 - value: 110, 115 + yAxis: {
  116 + show: true, // 显示Y轴
  117 + boundaryGap: false,
  118 + min: 0, // 设置最小值
112 }, 119 },
113 - {  
114 - name: '6月',  
115 - value: 120, 120 + grid: {
  121 + top: 5,
  122 + bottom: 5,
  123 + left: 5,
  124 + right: 5,
116 }, 125 },
117 - ]); 126 + });
118 const seriesColor = computed(() => { 127 const seriesColor = computed(() => {
119 return getThemeColor.value; 128 return getThemeColor.value;
120 }); 129 });
@@ -14,18 +14,18 @@ @@ -14,18 +14,18 @@
14 <a-range-picker :style="{ width: '256px' }" @change="handleDateChange" :value="dateRange" /> 14 <a-range-picker :style="{ width: '256px' }" @change="handleDateChange" :value="dateRange" />
15 </div> 15 </div>
16 </template> 16 </template>
17 - <a-tab-pane loading="true" tab="每月问答次数" key="1"> 17 + <a-tab-pane loading="true" tab="按钮统计数据" key="1">
18 <a-row> 18 <a-row>
19 <a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24"> 19 <a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
20 <Bar 20 <Bar
21 - :chartData="barData" 21 + :chartData="barChartData"
22 :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }" 22 :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }"
23 height="40vh" 23 height="40vh"
24 :seriesColor="seriesColor" 24 :seriesColor="seriesColor"
25 /> 25 />
26 </a-col> 26 </a-col>
27 <a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24"> 27 <a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
28 - <RankList title="按钮统计榜" :list="buttonStats" /> 28 + <RankList title="按钮统计榜" :list="buttonStatsData" />
29 </a-col> 29 </a-col>
30 </a-row> 30 </a-row>
31 </a-tab-pane> 31 </a-tab-pane>
@@ -49,35 +49,61 @@ @@ -49,35 +49,61 @@
49 </a-card> 49 </a-card>
50 </template> 50 </template>
51 <script lang="ts" setup> 51 <script lang="ts" setup>
52 - import { computed, ref } from 'vue'; 52 + import { computed, onMounted, ref } from 'vue';
53 import Bar from '/@/components/chart/Bar.vue'; 53 import Bar from '/@/components/chart/Bar.vue';
54 import RankList from '/@/components/chart/RankList.vue'; 54 import RankList from '/@/components/chart/RankList.vue';
55 import { useRootSetting } from '/@/hooks/setting/useRootSetting'; 55 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
  56 + import { getButtonStats } from '@/views/dashboard/Analysis/api';
56 57
  58 + // 删除props中的barData和buttonStats
57 defineProps({ 59 defineProps({
58 loading: { 60 loading: {
59 type: Boolean, 61 type: Boolean,
60 }, 62 },
61 - barData: {  
62 - type: Array as () => Array<{ name: string; value: number }>, // 直接定义类型  
63 - default: () => [],  
64 - },  
65 - buttonStats: {  
66 - // 添加按钮统计属性  
67 - type: Array as () => Array<{ name: string; total: number }>,  
68 - default: () => [],  
69 - },  
70 }); 63 });
71 64
72 const activeRange = ref('all'); 65 const activeRange = ref('all');
73 const dateRange = ref<any>(null); 66 const dateRange = ref<any>(null);
  67 + const buttonStatsData = ref<Array<{ name: string; total: number }>>([]); // 存储按钮统计数据
  68 + const loadingStats = ref(false); // 按钮数据加载状态
74 69
75 const emit = defineEmits(['range-change']); 70 const emit = defineEmits(['range-change']);
76 71
  72 + // 获取按钮统计数据
  73 + const fetchButtonStats = async (params?: { rangeType?: string | null; startTime?: string; endTime?: string }) => {
  74 + try {
  75 + loadingStats.value = true;
  76 + const res = await getButtonStats(params);
  77 + buttonStatsData.value = res || [];
  78 + } catch (error) {
  79 + console.error('获取按钮统计数据失败', error);
  80 + buttonStatsData.value = [];
  81 + } finally {
  82 + loadingStats.value = false;
  83 + }
  84 + };
  85 +
  86 + // 将按钮统计数据转换为柱状图格式
  87 + const barChartData = computed(() => {
  88 + return buttonStatsData.value.map((item) => ({
  89 + name: item.name,
  90 + value: item.total,
  91 + }));
  92 + });
  93 +
  94 + // 初始化加载数据
  95 + onMounted(() => {
  96 + fetchButtonStats();
  97 + });
  98 +
77 const changeRange = (rangeType: string) => { 99 const changeRange = (rangeType: string) => {
78 activeRange.value = rangeType; 100 activeRange.value = rangeType;
79 dateRange.value = null; // 清除日期选择 101 dateRange.value = null; // 清除日期选择
80 102
  103 + // 根据范围类型构建参数
  104 + const params = rangeType === 'all' ? null : { rangeType };
  105 + fetchButtonStats(params); // 获取对应范围的按钮数据
  106 +
81 if (rangeType === 'all') { 107 if (rangeType === 'all') {
82 emit('range-change', { rangeType: null }); 108 emit('range-change', { rangeType: null });
83 } else { 109 } else {
@@ -89,16 +115,23 @@ @@ -89,16 +115,23 @@
89 if (dateStrings[0] && dateStrings[1]) { 115 if (dateStrings[0] && dateStrings[1]) {
90 activeRange.value = 'custom'; 116 activeRange.value = 'custom';
91 dateRange.value = dates; 117 dateRange.value = dates;
92 - emit('range-change', { 118 +
  119 + // 构建自定义范围参数
  120 + const params = {
93 rangeType: 'custom', 121 rangeType: 'custom',
94 startTime: dateStrings[0] + ' 00:00:00', 122 startTime: dateStrings[0] + ' 00:00:00',
95 endTime: dateStrings[1] + ' 23:59:59', 123 endTime: dateStrings[1] + ' 23:59:59',
96 - }); 124 + };
  125 +
  126 + fetchButtonStats(params); // 获取自定义范围的按钮数据
  127 + emit('range-change', params);
97 } else { 128 } else {
98 activeRange.value = 'all'; 129 activeRange.value = 'all';
  130 + fetchButtonStats(); // 重置为全部数据
99 emit('range-change', { rangeType: null }); 131 emit('range-change', { rangeType: null });
100 } 132 }
101 }; 133 };
  134 +
102 const { getThemeColor } = useRootSetting(); 135 const { getThemeColor } = useRootSetting();
103 const seriesColor = computed(() => { 136 const seriesColor = computed(() => {
104 return getThemeColor.value; 137 return getThemeColor.value;
1 <template> 1 <template>
2 <div class="p-4"> 2 <div class="p-4">
3 <ChartGroupCard class="enter-y" :loading="loading" type="chart" :statistics="statistics" /> 3 <ChartGroupCard class="enter-y" :loading="loading" type="chart" :statistics="statistics" />
4 - <SaleTabCard class="!my-4 enter-y" :loading="loading" :barData="barData" :buttonStats="buttonStats" @range-change="handleRangeChange" /> 4 + <SaleTabCard class="!my-4 enter-y" :loading="loading" @range-change="handleRangeChange" />
5 <a-row> 5 <a-row>
6 <a-col :span="24"> 6 <a-col :span="24">
7 - <a-card :loading="loading" :bordered="false" title="最近一周访问量统计"> 7 + <a-card :loading="questionLoading" :bordered="false" title="问题输入量统计">
8 <div class="infoArea"> 8 <div class="infoArea">
9 - <HeadInfo title="今日IP" :iconColor="ipColor" :content="loginfo.todayIp" icon="environment" />  
10 - <HeadInfo title="今日访问" :iconColor="visitColor" :content="loginfo.todayVisitCount" icon="team" />  
11 - <HeadInfo title="总访问量" :iconColor="seriesColor" :content="loginfo.totalVisitCount" icon="rise" /> 9 + <HeadInfo title="今日" :iconColor="ipColor" :content="formatNumber(questionStats.todayCount)" icon="environment" />
  10 + <HeadInfo title="本周" :iconColor="ipColor" :content="formatNumber(questionStats.weekCount)" icon="environment" />
  11 + <HeadInfo title="本月" :iconColor="ipColor" :content="formatNumber(questionStats.monthCount)" icon="environment" />
  12 + <HeadInfo title="本年" :iconColor="ipColor" :content="formatNumber(questionStats.yearCount)" icon="environment" />
  13 + <HeadInfo title="总计" :iconColor="seriesColor" :content="formatNumber(questionStats.totalCount)" icon="rise" />
12 </div> 14 </div>
13 <!-- <LineMulti :chartData="lineMultiData" height="33vh" type="line" :option="{ legend: { top: 'bottom' } }" />--> 15 <!-- <LineMulti :chartData="lineMultiData" height="33vh" type="line" :option="{ legend: { top: 'bottom' } }" />-->
14 </a-card> 16 </a-card>
@@ -17,14 +19,15 @@ @@ -17,14 +19,15 @@
17 </div> 19 </div>
18 </template> 20 </template>
19 <script lang="ts" setup> 21 <script lang="ts" setup>
20 - import { computed, onMounted, ref, watch } from 'vue'; 22 + import { onMounted, ref, watch } from 'vue';
21 import ChartGroupCard from '../components/ChartGroupCard.vue'; 23 import ChartGroupCard from '../components/ChartGroupCard.vue';
22 import SaleTabCard from '../components/SaleTabCard.vue'; 24 import SaleTabCard from '../components/SaleTabCard.vue';
23 import HeadInfo from '/@/components/chart/HeadInfo.vue'; 25 import HeadInfo from '/@/components/chart/HeadInfo.vue';
24 - import { getLoginfo, getStatistics, getVisitInfo } from '../api'; 26 + import { getLoginfo, getQuestionStatistics, getStatistics, getVisitInfo } from '../api';
25 import { useRootSetting } from '/@/hooks/setting/useRootSetting'; 27 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
26 28
27 const loading = ref(true); 29 const loading = ref(true);
  30 + const questionLoading = ref(true);
28 const { getThemeColor } = useRootSetting(); 31 const { getThemeColor } = useRootSetting();
29 32
30 // 默认范围类型(全部) 33 // 默认范围类型(全部)
@@ -49,10 +52,40 @@ @@ -49,10 +52,40 @@
49 rejectedCount: 0, 52 rejectedCount: 0,
50 totalCount: 0, 53 totalCount: 0,
51 averageCount: 0, 54 averageCount: 0,
52 - buttonStats: [] as { name: string; total: number }[],  
53 monthlyData: [] as { month: string; count: number }[], 55 monthlyData: [] as { month: string; count: number }[],
  56 + dailyCounts: [] as { date: string; count: number }[],
  57 + dailyRejectedCounts: [] as { date: string; count: number }[],
54 }); 58 });
55 59
  60 + const questionStats = ref({
  61 + todayCount: 0,
  62 + weekCount: 0,
  63 + monthCount: 0,
  64 + yearCount: 0,
  65 + totalCount: 0,
  66 + });
  67 +
  68 + // 获取问题统计数据的方法
  69 + async function fetchQuestionStatistics() {
  70 + try {
  71 + questionLoading.value = true;
  72 + const res = await getQuestionStatistics();
  73 + console.log('问题统计数据:', res);
  74 +
  75 + // 更新数据(根据实际接口返回结构调整)
  76 + questionStats.value = {
  77 + todayCount: res.todayCount ?? 0,
  78 + weekCount: res.weekCount ?? 0,
  79 + monthCount: res.monthCount ?? 0,
  80 + yearCount: res.yearCount ?? 0,
  81 + totalCount: res.totalCount ?? 0,
  82 + };
  83 + } catch (error) {
  84 + console.error('获取问题统计失败', error);
  85 + } finally {
  86 + questionLoading.value = false;
  87 + }
  88 + }
56 // 实时数据获取函数 89 // 实时数据获取函数
57 async function fetchStatistics() { 90 async function fetchStatistics() {
58 try { 91 try {
@@ -72,8 +105,9 @@ @@ -72,8 +105,9 @@
72 rejectedCount: res.rejectedCount || res.data?.rejectedCount || 0, 105 rejectedCount: res.rejectedCount || res.data?.rejectedCount || 0,
73 totalCount: res.totalCount || res.data?.totalCount || 0, 106 totalCount: res.totalCount || res.data?.totalCount || 0,
74 averageCount: res.averageCount || 0, 107 averageCount: res.averageCount || 0,
75 - buttonStats: res.buttonStats || [],  
76 monthlyData: res.monthlyData || res.data?.monthlyData || generateMonthlyData(), 108 monthlyData: res.monthlyData || res.data?.monthlyData || generateMonthlyData(),
  109 + dailyCounts: res.dailyCounts || [],
  110 + dailyRejectedCounts: res.dailyRejectedCounts || [],
77 }; 111 };
78 112
79 console.log('更新后的 statistics:', statistics.value); 113 console.log('更新后的 statistics:', statistics.value);
@@ -90,27 +124,13 @@ @@ -90,27 +124,13 @@
90 })); 124 }));
91 } 125 }
92 126
93 - // 转换按钮统计数据格式  
94 - const buttonStats = computed(() => {  
95 - return statistics.value.buttonStats.map((item) => ({  
96 - name: item.name,  
97 - total: item.total,  
98 - }));  
99 - });  
100 - // 在 setup 中添加转换函数  
101 - const barData = computed(() => {  
102 - if (!statistics.value.monthlyData) return [];  
103 -  
104 - return statistics.value.monthlyData.map((item) => {  
105 - return {  
106 - name: `${item.month}`,  
107 - value: item.count, 127 + const formatNumber = (num: number) => {
  128 + return num.toLocaleString();
108 }; 129 };
109 - });  
110 - });  
111 130
112 onMounted(() => { 131 onMounted(() => {
113 fetchStatistics(); 132 fetchStatistics();
  133 + fetchQuestionStatistics();
114 }); 134 });
115 135
116 setTimeout(() => { 136 setTimeout(() => {
1 import { FormSchema } from '@/components/Form'; 1 import { FormSchema } from '@/components/Form';
2 -import { BasicColumn } from '@/components/Table';  
3 2
4 /** 3 /**
5 * 表单 4 * 表单
@@ -39,7 +39,7 @@ @@ -39,7 +39,7 @@
39 </a-card> 39 </a-card>
40 </a-col> 40 </a-col>
41 <a-col v-if="knowledgeList && knowledgeList.length > 0" :xxl="4" :xl="6" :lg="6" :md="6" :sm="12" :xs="24" v-for="item in knowledgeList"> 41 <a-col v-if="knowledgeList && knowledgeList.length > 0" :xxl="4" :xl="6" :lg="6" :md="6" :sm="12" :xs="24" v-for="item in knowledgeList">
42 - <a-card class="knowledge-card pointer" @click="handleDocClick(item.id)"> 42 + <a-card class="knowledge-card pointer" @click="handleDocClick(item)">
43 <div class="knowledge-header"> 43 <div class="knowledge-header">
44 <div class="flex"> 44 <div class="flex">
45 <img class="header-img" src="./icon/knowledge.png" /> 45 <img class="header-img" src="./icon/knowledge.png" />
@@ -113,6 +113,7 @@ @@ -113,6 +113,7 @@
113 import AiragKnowledgeDocListModal from './components/AiragKnowledgeDocListModal.vue'; 113 import AiragKnowledgeDocListModal from './components/AiragKnowledgeDocListModal.vue';
114 import Icon from '@/components/Icon'; 114 import Icon from '@/components/Icon';
115 import { useMessage } from '@/hooks/web/useMessage'; 115 import { useMessage } from '@/hooks/web/useMessage';
  116 + import { useRouter } from 'vue-router';
116 117
117 export default { 118 export default {
118 name: 'KnowledgeBaseList', 119 name: 'KnowledgeBaseList',
@@ -128,7 +129,7 @@ @@ -128,7 +129,7 @@
128 setup() { 129 setup() {
129 //模型列表 130 //模型列表
130 const knowledgeList = ref([]); 131 const knowledgeList = ref([]);
131 - 132 + const router = useRouter();
132 //注册modal 133 //注册modal
133 const [registerModal, { openModal }] = useModal(); 134 const [registerModal, { openModal }] = useModal();
134 const [docListRegister, { openModal: openDocModal }] = useModal(); 135 const [docListRegister, { openModal: openDocModal }] = useModal();
@@ -246,8 +247,15 @@ @@ -246,8 +247,15 @@
246 * 247 *
247 * @param id 248 * @param id
248 */ 249 */
249 - function handleDocClick(id) {  
250 - openDocModal(true, { id }); 250 + function handleDocClick(item) {
  251 + console.log('测试' + item);
  252 + router.push({
  253 + path: '/super/airag/test/EmbeddingsList',
  254 + query: {
  255 + knowledgeId: item.id,
  256 + knowledgeName: item.name,
  257 + },
  258 + });
251 } 259 }
252 260
253 /** 261 /**
1 <template> 1 <template>
2 <div class="p-2"> 2 <div class="p-2">
3 <BasicModal destroyOnClose @register="registerModal" :canFullscreen="false" width="600px" :title="title" @ok="handleOk" @cancel="handleCancel"> 3 <BasicModal destroyOnClose @register="registerModal" :canFullscreen="false" width="600px" :title="title" @ok="handleOk" @cancel="handleCancel">
4 - <BasicForm @register="registerForm"></BasicForm> 4 + <BasicForm @register="registerForm" />
5 </BasicModal> 5 </BasicModal>
6 </div> 6 </div>
7 </template> 7 </template>
@@ -4,14 +4,13 @@ @@ -4,14 +4,13 @@
4 <div class="p-2"> 4 <div class="p-2">
5 <div class="header"> 5 <div class="header">
6 <a-tag color="#a9c8ff"> 6 <a-tag color="#a9c8ff">
7 - <span>{{hitTextDescData.source}}</span> 7 + <span>{{ hitTextDescData.source }}</span>
8 </a-tag> 8 </a-tag>
9 </div> 9 </div>
10 <div class="content"> 10 <div class="content">
11 <MarkdownViewer :value="hitTextDescData.content" /> 11 <MarkdownViewer :value="hitTextDescData.content" />
12 </div> 12 </div>
13 </div> 13 </div>
14 -  
15 </BasicModal> 14 </BasicModal>
16 </template> 15 </template>
17 16
@@ -32,18 +31,18 @@ @@ -32,18 +31,18 @@
32 }, 31 },
33 emits: ['success', 'register'], 32 emits: ['success', 'register'],
34 setup(props, { emit }) { 33 setup(props, { emit }) {
35 - let hitTextDescData = ref<any>({}) 34 + let hitTextDescData = ref<any>({});
36 35
37 //注册modal 36 //注册modal
38 const [registerModal, { closeModal, setModalProps }] = useModalInner(async (data) => { 37 const [registerModal, { closeModal, setModalProps }] = useModalInner(async (data) => {
39 hitTextDescData.value.source = 'score' + ' ' + data.score.toFixed(2); 38 hitTextDescData.value.source = 'score' + ' ' + data.score.toFixed(2);
40 hitTextDescData.value.content = data.content; 39 hitTextDescData.value.content = data.content;
41 - setModalProps({ header: '300px' }) 40 + setModalProps({ header: '300px' });
42 }); 41 });
43 42
44 return { 43 return {
45 registerModal, 44 registerModal,
46 - hitTextDescData 45 + hitTextDescData,
47 }; 46 };
48 }, 47 },
49 }; 48 };
@@ -16,16 +16,16 @@ @@ -16,16 +16,16 @@
16 </a-layout-sider> 16 </a-layout-sider>
17 <a-layout-content :style="contentStyle"> 17 <a-layout-content :style="contentStyle">
18 <div v-if="selectedKey === 'document'"> 18 <div v-if="selectedKey === 'document'">
19 - <a-input v-model:value="searchText" placeholder="请输入文档名称,回车搜索" class="search-title" @pressEnter="reload"/> 19 + <a-input v-model:value="searchText" placeholder="请输入文档名称,回车搜索" class="search-title" @press-enter="reload" />
20 <a-row :span="24" class="knowledge-row"> 20 <a-row :span="24" class="knowledge-row">
21 <a-col :xxl="4" :xl="6" :lg="6" :md="6" :sm="12" :xs="24"> 21 <a-col :xxl="4" :xl="6" :lg="6" :md="6" :sm="12" :xs="24">
22 <a-card class="add-knowledge-card" :bodyStyle="cardBodyStyle"> 22 <a-card class="add-knowledge-card" :bodyStyle="cardBodyStyle">
23 - <span style="line-height: 18px;font-weight: 500;color:#676f83;font-size: 12px">创建文档</span> 23 + <span style="line-height: 18px; font-weight: 500; color: #676f83; font-size: 12px">创建文档</span>
24 <div class="add-knowledge-doc" @click="handleCreateText"> 24 <div class="add-knowledge-doc" @click="handleCreateText">
25 - <Icon icon="ant-design:form-outlined" size="13"></Icon><span>手动录入</span> 25 + <Icon icon="ant-design:form-outlined" size="13" /><span>手动录入</span>
26 </div> 26 </div>
27 <div class="add-knowledge-doc" @click="handleCreateUpload"> 27 <div class="add-knowledge-doc" @click="handleCreateUpload">
28 - <Icon icon="ant-design:cloud-upload-outlined" size="13"></Icon><span>文件上传</span> 28 + <Icon icon="ant-design:cloud-upload-outlined" size="13" /><span>文件上传</span>
29 </div> 29 </div>
30 <div class="add-knowledge-doc" @click="handleCreateUploadLibrary"> 30 <div class="add-knowledge-doc" @click="handleCreateUploadLibrary">
31 <a-upload 31 <a-upload
@@ -38,7 +38,7 @@ @@ -38,7 +38,7 @@
38 :action="uploadUrl" 38 :action="uploadUrl"
39 @change="handleUploadChange" 39 @change="handleUploadChange"
40 > 40 >
41 - <Icon style="margin-left: 0" icon="ant-design:project-outlined" size="13"></Icon> 41 + <Icon style="margin-left: 0" icon="ant-design:project-outlined" size="13" />
42 <span>文档库上传</span> 42 <span>文档库上传</span>
43 </a-upload> 43 </a-upload>
44 </div> 44 </div>
@@ -48,14 +48,49 @@ @@ -48,14 +48,49 @@
48 <a-card class="knowledge-card pointer" @click="handleEdit(item)"> 48 <a-card class="knowledge-card pointer" @click="handleEdit(item)">
49 <div class="knowledge-header"> 49 <div class="knowledge-header">
50 <div class="header-text flex"> 50 <div class="header-text flex">
51 - <Icon v-if="item.type==='text'" icon="ant-design:file-text-outlined" size="32" color="#00a7d0"></Icon>  
52 - <Icon v-if="item.type==='file' && getFileSuffix(item.metadata) === 'pdf'" icon="ant-design:file-pdf-outlined" size="32" color="rgb(211, 47, 47)"></Icon>  
53 - <Icon v-if="item.type==='file' && getFileSuffix(item.metadata) === 'docx'" icon="ant-design:file-word-outlined" size="32" color="rgb(68, 138, 255)"></Icon>  
54 - <Icon v-if="item.type==='file' && getFileSuffix(item.metadata) === 'pptx'" icon="ant-design:file-ppt-outlined" size="32" color="rgb(245, 124, 0)"></Icon>  
55 - <Icon v-if="item.type==='file' && getFileSuffix(item.metadata) === 'xlsx'" icon="ant-design:file-excel-outlined" size="32" color="rgb(98, 187, 55)"></Icon>  
56 - <Icon v-if="item.type==='file' && getFileSuffix(item.metadata) === 'txt'" icon="ant-design:file-text-outlined" size="32" color="#00a7d0"></Icon>  
57 - <Icon v-if="item.type==='file' && getFileSuffix(item.metadata) === 'md'" icon="ant-design:file-markdown-outlined" size="32" color="#292929"></Icon>  
58 - <Icon v-if="item.type==='file' && getFileSuffix(item.metadata) === ''" icon="ant-design:file-unknown-outlined" size="32" color="#f5f5dc"></Icon> 51 + <Icon v-if="item.type === 'text'" icon="ant-design:file-text-outlined" size="32" color="#00a7d0" />
  52 + <Icon
  53 + v-if="item.type === 'file' && getFileSuffix(item.metadata) === 'pdf'"
  54 + icon="ant-design:file-pdf-outlined"
  55 + size="32"
  56 + color="rgb(211, 47, 47)"
  57 + />
  58 + <Icon
  59 + v-if="item.type === 'file' && getFileSuffix(item.metadata) === 'docx'"
  60 + icon="ant-design:file-word-outlined"
  61 + size="32"
  62 + color="rgb(68, 138, 255)"
  63 + />
  64 + <Icon
  65 + v-if="item.type === 'file' && getFileSuffix(item.metadata) === 'pptx'"
  66 + icon="ant-design:file-ppt-outlined"
  67 + size="32"
  68 + color="rgb(245, 124, 0)"
  69 + />
  70 + <Icon
  71 + v-if="item.type === 'file' && getFileSuffix(item.metadata) === 'xlsx'"
  72 + icon="ant-design:file-excel-outlined"
  73 + size="32"
  74 + color="rgb(98, 187, 55)"
  75 + />
  76 + <Icon
  77 + v-if="item.type === 'file' && getFileSuffix(item.metadata) === 'txt'"
  78 + icon="ant-design:file-text-outlined"
  79 + size="32"
  80 + color="#00a7d0"
  81 + />
  82 + <Icon
  83 + v-if="item.type === 'file' && getFileSuffix(item.metadata) === 'md'"
  84 + icon="ant-design:file-markdown-outlined"
  85 + size="32"
  86 + color="#292929"
  87 + />
  88 + <Icon
  89 + v-if="item.type === 'file' && getFileSuffix(item.metadata) === ''"
  90 + icon="ant-design:file-unknown-outlined"
  91 + size="32"
  92 + color="#f5f5dc"
  93 + />
59 <span class="ellipsis header-title">{{ item.title }}</span> 94 <span class="ellipsis header-title">{{ item.title }}</span>
60 </div> 95 </div>
61 </div> 96 </div>
@@ -65,35 +100,35 @@ @@ -65,35 +100,35 @@
65 <div class="flex" style="justify-content: space-between"> 100 <div class="flex" style="justify-content: space-between">
66 <div class="card-text"> 101 <div class="card-text">
67 状态: 102 状态:
68 - <div v-if="item.status==='complete'" class="card-text-status">  
69 - <Icon icon="ant-design:check-circle-outlined" size="16" color="#56D1A7"></Icon> 103 + <div v-if="item.status === 'complete'" class="card-text-status">
  104 + <Icon icon="ant-design:check-circle-outlined" size="16" color="#56D1A7" />
70 <span class="ml-2">已完成</span> 105 <span class="ml-2">已完成</span>
71 </div> 106 </div>
72 - <div v-else-if="item.status==='building'" class="card-text-status">  
73 - <a-spin v-if="item.loading" :spinning="item.loading" :indicator="indicator"></a-spin> 107 + <div v-else-if="item.status === 'building'" class="card-text-status">
  108 + <a-spin v-if="item.loading" :spinning="item.loading" :indicator="indicator" />
74 <span class="ml-2">构建中</span> 109 <span class="ml-2">构建中</span>
75 </div> 110 </div>
76 - <div v-else-if="item.status==='draft'" class="card-text-status">  
77 - <img src="../icon/draft.png" style="width: 16px;height: 16px" /> 111 + <div v-else-if="item.status === 'draft'" class="card-text-status">
  112 + <img src="../icon/draft.png" style="width: 16px; height: 16px" />
78 <span class="ml-2">草稿</span> 113 <span class="ml-2">草稿</span>
79 </div> 114 </div>
80 </div> 115 </div>
81 <a-dropdown placement="bottomRight" :trigger="['click']"> 116 <a-dropdown placement="bottomRight" :trigger="['click']">
82 <div class="ant-dropdown-link pointer operation" @click.prevent.stop> 117 <div class="ant-dropdown-link pointer operation" @click.prevent.stop>
83 - <Icon icon="ant-design:ellipsis-outlined" size="16"></Icon> 118 + <Icon icon="ant-design:ellipsis-outlined" size="16" />
84 </div> 119 </div>
85 <template #overlay> 120 <template #overlay>
86 <a-menu> 121 <a-menu>
87 <a-menu-item key="vectorization" @click="handleVectorization(item.id)"> 122 <a-menu-item key="vectorization" @click="handleVectorization(item.id)">
88 - <Icon icon="ant-design:retweet-outlined" size="16"></Icon> 123 + <Icon icon="ant-design:retweet-outlined" size="16" />
89 向量化 124 向量化
90 </a-menu-item> 125 </a-menu-item>
91 <a-menu-item key="edit" @click="handleEdit(item)"> 126 <a-menu-item key="edit" @click="handleEdit(item)">
92 - <Icon icon="ant-design:edit-outlined" size="16"></Icon> 127 + <Icon icon="ant-design:edit-outlined" size="16" />
93 编辑 128 编辑
94 </a-menu-item> 129 </a-menu-item>
95 <a-menu-item key="delete" @click="handleDelete(item.id)"> 130 <a-menu-item key="delete" @click="handleDelete(item.id)">
96 - <Icon icon="ant-design:delete-outlined" size="16"></Icon> 131 + <Icon icon="ant-design:delete-outlined" size="16" />
97 删除 132 删除
98 </a-menu-item> 133 </a-menu-item>
99 </a-menu> 134 </a-menu>
@@ -129,13 +164,13 @@ @@ -129,13 +164,13 @@
129 <span>{{ hitShowSearchText }}</span> 164 <span>{{ hitShowSearchText }}</span>
130 </div> 165 </div>
131 <div class="content-card"> 166 <div class="content-card">
132 - <a-row :span="24" class="knowledge-row" v-if="hitTextList.length>0"> 167 + <a-row :span="24" class="knowledge-row" v-if="hitTextList.length > 0">
133 <a-col :xxl="6" :xl="6" :lg="6" :md="6" :sm="12" :xs="24" v-for="item in hitTextList"> 168 <a-col :xxl="6" :xl="6" :lg="6" :md="6" :sm="12" :xs="24" v-for="item in hitTextList">
134 <a-card class="hit-card pointer" style="border-color: #ffffff" @click="hitTextDescClick(item)"> 169 <a-card class="hit-card pointer" style="border-color: #ffffff" @click="hitTextDescClick(item)">
135 <div class="card-title"> 170 <div class="card-title">
136 - <div style="display: flex;">  
137 - <Icon icon="ant-design:appstore-outlined" size="14"></Icon>  
138 - <span style="margin-left: 4px">Chunk-{{item.chunk}}</span> 171 + <div style="display: flex">
  172 + <Icon icon="ant-design:appstore-outlined" size="14" />
  173 + <span style="margin-left: 4px">Chunk-{{ item.chunk }}</span>
139 <span style="margin-left: 10px">{{ item.content.length }} 字符</span> 174 <span style="margin-left: 10px">{{ item.content.length }} 字符</span>
140 </div> 175 </div>
141 <a-tag class="card-title-tag" color="#a9c8ff"> 176 <a-tag class="card-title-tag" color="#a9c8ff">
@@ -146,7 +181,7 @@ @@ -146,7 +181,7 @@
146 {{ item.content }} 181 {{ item.content }}
147 </div> 182 </div>
148 <div class="card-footer"> 183 <div class="card-footer">
149 - {{item.docName}} 184 + {{ item.docName }}
150 </div> 185 </div>
151 </a-card> 186 </a-card>
152 </a-col> 187 </a-col>
@@ -154,9 +189,7 @@ @@ -154,9 +189,7 @@
154 <div v-else-if="notHit"> 189 <div v-else-if="notHit">
155 <a-empty :image-style="{ margin: '0 auto', height: '160px', verticalAlign: 'middle', borderStyle: 'none' }"> 190 <a-empty :image-style="{ margin: '0 auto', height: '160px', verticalAlign: 'middle', borderStyle: 'none' }">
156 <template #description> 191 <template #description>
157 - <div style="margin-top: 26px; font-size: 20px; color: #000; text-align: center !important">  
158 - 没有命中的分段  
159 - </div> 192 + <div style="margin-top: 26px; font-size: 20px; color: #000; text-align: center !important"> 没有命中的分段 </div>
160 </template> 193 </template>
161 </a-empty> 194 </a-empty>
162 </div> 195 </div>
@@ -167,18 +200,18 @@ @@ -167,18 +200,18 @@
167 <ul> 200 <ul>
168 <li> 201 <li>
169 <span>条数:</span> 202 <span>条数:</span>
170 - <a-input-number :min="1" v-model:value="topNumber"></a-input-number> 203 + <a-input-number :min="1" v-model:value="topNumber" />
171 </li> 204 </li>
172 <li> 205 <li>
173 <span>Score阈值:</span> 206 <span>Score阈值:</span>
174 - <a-input-number :min="0" :step="0.01" :max="1" v-model:value="similarity"></a-input-number> 207 + <a-input-number :min="0" :step="0.01" :max="1" v-model:value="similarity" />
175 </li> 208 </li>
176 </ul> 209 </ul>
177 </div> 210 </div>
178 <div class="hit-test-footer"> 211 <div class="hit-test-footer">
179 - <a-input v-model:value="hitText" size="large" placeholder="请输入" style="width: 100%" @pressEnter="hitTestClick"> 212 + <a-input v-model:value="hitText" size="large" placeholder="请输入" style="width: 100%" @press-enter="hitTestClick">
180 <template #suffix> 213 <template #suffix>
181 - <Icon icon="ant-design:send-outlined" style="transform: rotate(-33deg); cursor: pointer" size="22" @click="hitTestClick"></Icon> 214 + <Icon icon="ant-design:send-outlined" style="transform: rotate(-33deg); cursor: pointer" size="22" @click="hitTestClick" />
182 </template> 215 </template>
183 </a-input> 216 </a-input>
184 </div> 217 </div>
@@ -189,9 +222,9 @@ @@ -189,9 +222,9 @@
189 </BasicModal> 222 </BasicModal>
190 223
191 <!-- 手工录入文本 --> 224 <!-- 手工录入文本 -->
192 - <AiragKnowledgeDocTextModal @register="docTextRegister" @success="handleSuccess"></AiragKnowledgeDocTextModal> 225 + <AiragKnowledgeDocTextModal @register="docTextRegister" @success="handleSuccess" />
193 <!-- 文本明细 --> 226 <!-- 文本明细 -->
194 - <AiTextDescModal @register="docTextDescRegister"></AiTextDescModal> 227 + <AiTextDescModal @register="docTextDescRegister" />
195 </div> 228 </div>
196 </template> 229 </template>
197 230
@@ -206,11 +239,11 @@ @@ -206,11 +239,11 @@
206 import AiTextDescModal from './AiTextDescModal.vue'; 239 import AiTextDescModal from './AiTextDescModal.vue';
207 import { useMessage } from '@/hooks/web/useMessage'; 240 import { useMessage } from '@/hooks/web/useMessage';
208 import { LoadingOutlined } from '@ant-design/icons-vue'; 241 import { LoadingOutlined } from '@ant-design/icons-vue';
209 - import {Avatar, message, Modal, Pagination} from 'ant-design-vue'; 242 + import { Avatar, message, Modal, Pagination } from 'ant-design-vue';
210 import { useUserStore } from '@/store/modules/user'; 243 import { useUserStore } from '@/store/modules/user';
211 import { getFileAccessHttpUrl, getHeaders } from '@/utils/common/compUtils'; 244 import { getFileAccessHttpUrl, getHeaders } from '@/utils/common/compUtils';
212 import defaultImg from '/@/assets/images/header.jpg'; 245 import defaultImg from '/@/assets/images/header.jpg';
213 - import Icon from "@/components/Icon"; 246 + import Icon from '@/components/Icon';
214 import { useGlobSetting } from '/@/hooks/setting'; 247 import { useGlobSetting } from '/@/hooks/setting';
215 248
216 export default { 249 export default {
@@ -273,7 +306,7 @@ @@ -273,7 +306,7 @@
273 const headers = getHeaders(); 306 const headers = getHeaders();
274 const globSetting = useGlobSetting(); 307 const globSetting = useGlobSetting();
275 //上传路径 308 //上传路径
276 - const uploadUrl = ref<string>(globSetting.domainUrl+"/airag/knowledge/doc/import/zip"); 309 + const uploadUrl = ref<string>(globSetting.domainUrl + '/airag/knowledge/doc/import/zip');
277 310
278 //菜单项 311 //菜单项
279 const menuItems = ref<any>([ 312 const menuItems = ref<any>([
@@ -325,7 +358,7 @@ @@ -325,7 +358,7 @@
325 const indicator = h(LoadingOutlined, { 358 const indicator = h(LoadingOutlined, {
326 style: { 359 style: {
327 fontSize: '16px', 360 fontSize: '16px',
328 - marginRight: '2px' 361 + marginRight: '2px',
329 }, 362 },
330 spin: true, 363 spin: true,
331 }); 364 });
@@ -336,14 +369,14 @@ @@ -336,14 +369,14 @@
336 * 手工录入文本 369 * 手工录入文本
337 */ 370 */
338 function handleCreateText() { 371 function handleCreateText() {
339 - docTextOpenModal(true, { knowledgeId: knowledgeId.value, type: "text" }); 372 + docTextOpenModal(true, { knowledgeId: knowledgeId.value, type: 'text' });
340 } 373 }
341 374
342 /** 375 /**
343 * 文件上传 376 * 文件上传
344 */ 377 */
345 function handleCreateUpload() { 378 function handleCreateUpload() {
346 - docTextOpenModal(true, { knowledgeId: knowledgeId.value, type: "file" }); 379 + docTextOpenModal(true, { knowledgeId: knowledgeId.value, type: 'file' });
347 } 380 }
348 381
349 /** 382 /**
@@ -377,8 +410,8 @@ @@ -377,8 +410,8 @@
377 cancelText: '取消', 410 cancelText: '取消',
378 onOk: () => { 411 onOk: () => {
379 knowledgeDeleteBatchDoc({ ids: id }, reload); 412 knowledgeDeleteBatchDoc({ ids: id }, reload);
380 - }  
381 - }) 413 + },
  414 + });
382 } 415 }
383 416
384 /** 417 /**
@@ -394,7 +427,7 @@ @@ -394,7 +427,7 @@
394 * 文档新增和编辑成功回调 427 * 文档新增和编辑成功回调
395 */ 428 */
396 function handleSuccess() { 429 function handleSuccess() {
397 - if(!timer.value){ 430 + if (!timer.value) {
398 reload(); 431 reload();
399 } 432 }
400 clearInterval(timer.value); 433 clearInterval(timer.value);
@@ -408,7 +441,7 @@ @@ -408,7 +441,7 @@
408 function triggeringTimer() { 441 function triggeringTimer() {
409 timer.value = setInterval(() => { 442 timer.value = setInterval(() => {
410 reload(); 443 reload();
411 - },5000) 444 + }, 5000);
412 } 445 }
413 446
414 /** 447 /**
@@ -420,7 +453,7 @@ @@ -420,7 +453,7 @@
420 setTimeout(() => { 453 setTimeout(() => {
421 pageNo.value = 1; 454 pageNo.value = 1;
422 pageSize.value = 10; 455 pageSize.value = 10;
423 - searchText.value = ""; 456 + searchText.value = '';
424 457
425 reload(); 458 reload();
426 }); 459 });
@@ -446,7 +479,8 @@ @@ -446,7 +479,8 @@
446 knowId: knowledgeId.value, 479 knowId: knowledgeId.value,
447 topNumber: topNumber.value, 480 topNumber: topNumber.value,
448 similarity: similarity.value, 481 similarity: similarity.value,
449 - }).then((res) => { 482 + })
  483 + .then((res) => {
450 if (res.success) { 484 if (res.success) {
451 if (res.result) { 485 if (res.result) {
452 hitTextList.value = res.result; 486 hitTextList.value = res.result;
@@ -459,7 +493,8 @@ @@ -459,7 +493,8 @@
459 hitText.value = ''; 493 hitText.value = '';
460 notHit.value = hitTextList.value.length == 0; 494 notHit.value = hitTextList.value.length == 0;
461 spinning.value = false; 495 spinning.value = false;
462 - }).catch(()=>{ 496 + })
  497 + .catch(() => {
463 spinning.value = false; 498 spinning.value = false;
464 }); 499 });
465 } 500 }
@@ -491,22 +526,22 @@ @@ -491,22 +526,22 @@
491 knowledgeId: knowledgeId.value, 526 knowledgeId: knowledgeId.value,
492 title: '*' + searchText.value + '*', 527 title: '*' + searchText.value + '*',
493 column: 'createTime', 528 column: 'createTime',
494 - order: 'desc' 529 + order: 'desc',
495 }; 530 };
496 await knowledgeDocList(params).then((res) => { 531 await knowledgeDocList(params).then((res) => {
497 if (res.success) { 532 if (res.success) {
498 //update-begin---author:wangshuai---date:2025-03-21---for:【QQYUN-11636】向量化功能改成异步--- 533 //update-begin---author:wangshuai---date:2025-03-21---for:【QQYUN-11636】向量化功能改成异步---
499 - if(res.result.records){ 534 + if (res.result.records) {
500 let clearTimer = true; 535 let clearTimer = true;
501 for (const item of res.result.records) { 536 for (const item of res.result.records) {
502 - if(item.status && item.status === 'building' ){ 537 + if (item.status && item.status === 'building') {
503 clearTimer = false; 538 clearTimer = false;
504 item.loading = true; 539 item.loading = true;
505 - }else{ 540 + } else {
506 item.loading = false; 541 item.loading = false;
507 } 542 }
508 } 543 }
509 - if(clearTimer){ 544 + if (clearTimer) {
510 clearInterval(timer.value); 545 clearInterval(timer.value);
511 } 546 }
512 } 547 }
@@ -535,7 +570,7 @@ @@ -535,7 +570,7 @@
535 * 获取文件后缀 570 * 获取文件后缀
536 */ 571 */
537 function getFileSuffix(metadata) { 572 function getFileSuffix(metadata) {
538 - if(metadata){ 573 + if (metadata) {
539 let filePath = JSON.parse(metadata).filePath; 574 let filePath = JSON.parse(metadata).filePath;
540 const index = filePath.lastIndexOf('.'); 575 const index = filePath.lastIndexOf('.');
541 return index > 0 ? filePath.substring(index + 1).toLowerCase() : ''; 576 return index > 0 ? filePath.substring(index + 1).toLowerCase() : '';
@@ -562,10 +597,10 @@ @@ -562,10 +597,10 @@
562 function handleUploadChange(info) { 597 function handleUploadChange(info) {
563 let { file } = info; 598 let { file } = info;
564 if (file.status === 'error') { 599 if (file.status === 'error') {
565 - createMessage.error(file.response.message ||`${file.name} 上传失败.`); 600 + createMessage.error(file.response.message || `${file.name} 上传失败.`);
566 } 601 }
567 if (file.status === 'done') { 602 if (file.status === 'done') {
568 - if(!file.response.success){ 603 + if (!file.response.success) {
569 createMessage.warning(file.response.message); 604 createMessage.warning(file.response.message);
570 return; 605 return;
571 } 606 }
@@ -574,10 +609,10 @@ @@ -574,10 +609,10 @@
574 } 609 }
575 } 610 }
576 611
577 - onBeforeMount(()=>{ 612 + onBeforeMount(() => {
578 clearInterval(timer.value); 613 clearInterval(timer.value);
579 timer.value = null; 614 timer.value = null;
580 - }) 615 + });
581 616
582 return { 617 return {
583 registerModal, 618 registerModal,
@@ -615,7 +650,7 @@ @@ -615,7 +650,7 @@
615 handlePageChange, 650 handlePageChange,
616 searchText, 651 searchText,
617 reload, 652 reload,
618 - cardBodyStyle:{ textAlign: 'left', width: '100%' }, 653 + cardBodyStyle: { textAlign: 'left', width: '100%' },
619 getFileSuffix, 654 getFileSuffix,
620 notHit, 655 notHit,
621 indicator, 656 indicator,
@@ -703,7 +738,7 @@ @@ -703,7 +738,7 @@
703 border-radius: 10px; 738 border-radius: 10px;
704 background: #fcfcfd; 739 background: #fcfcfd;
705 border: 1px solid #f0f0f0; 740 border: 1px solid #f0f0f0;
706 - box-shadow: 0 2px 4px rgba(0,0,0,0.1); 741 + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
707 transition: all 0.3s ease; 742 transition: all 0.3s ease;
708 .card-title { 743 .card-title {
709 justify-content: space-between; 744 justify-content: space-between;
@@ -715,7 +750,7 @@ @@ -715,7 +750,7 @@
715 } 750 }
716 } 751 }
717 .hit-card:hover { 752 .hit-card:hover {
718 - box-shadow: 0 6px 12px rgba(0,0,0,0.15) !important; 753 + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15) !important;
719 } 754 }
720 .pointer { 755 .pointer {
721 cursor: pointer; 756 cursor: pointer;
@@ -732,7 +767,7 @@ @@ -732,7 +767,7 @@
732 margin-top: 16px; 767 margin-top: 16px;
733 text-align: left; 768 text-align: left;
734 font-size: 12px; 769 font-size: 12px;
735 - color: #676F83; 770 + color: #676f83;
736 } 771 }
737 772
738 .card-title-tag { 773 .card-title-tag {
@@ -753,7 +788,7 @@ @@ -753,7 +788,7 @@
753 width: calc(100% - 20px); 788 width: calc(100% - 20px);
754 background: #fcfcfd; 789 background: #fcfcfd;
755 border: 1px solid #f0f0f0; 790 border: 1px solid #f0f0f0;
756 - box-shadow: 0 2px 4px rgba(0,0,0,0.1); 791 + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
757 transition: all 0.3s ease; 792 transition: all 0.3s ease;
758 .add-knowledge-card-icon { 793 .add-knowledge-card-icon {
759 padding: 8px; 794 padding: 8px;
@@ -768,7 +803,7 @@ @@ -768,7 +803,7 @@
768 height: 166px; 803 height: 166px;
769 background: #fcfcfd; 804 background: #fcfcfd;
770 border: 1px solid #f0f0f0; 805 border: 1px solid #f0f0f0;
771 - box-shadow: 0 2px 4px rgba(0,0,0,0.1); 806 + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
772 transition: all 0.3s ease; 807 transition: all 0.3s ease;
773 .knowledge-header { 808 .knowledge-header {
774 position: relative; 809 position: relative;
@@ -780,7 +815,7 @@ @@ -780,7 +815,7 @@
780 height: 40px; 815 height: 40px;
781 margin-right: 12px; 816 margin-right: 12px;
782 } 817 }
783 - .header-title{ 818 + .header-title {
784 font-weight: bold; 819 font-weight: bold;
785 color: #354052; 820 color: #354052;
786 margin-left: 4px; 821 margin-left: 4px;
@@ -796,12 +831,14 @@ @@ -796,12 +831,14 @@
796 } 831 }
797 } 832 }
798 833
799 - .add-knowledge-card,.knowledge-card{ 834 + .add-knowledge-card,
  835 + .knowledge-card {
800 transition: box-shadow 0.3s ease; 836 transition: box-shadow 0.3s ease;
801 } 837 }
802 838
803 - .add-knowledge-card:hover,.knowledge-card:hover{  
804 - box-shadow: 0 6px 12px rgba(0,0,0,0.15); 839 + .add-knowledge-card:hover,
  840 + .knowledge-card:hover {
  841 + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
805 } 842 }
806 843
807 .ellipsis { 844 .ellipsis {
@@ -815,21 +852,21 @@ @@ -815,21 +852,21 @@
815 padding: 16px; 852 padding: 16px;
816 } 853 }
817 854
818 - .card-text{ 855 + .card-text {
819 font-size: 12px; 856 font-size: 12px;
820 display: flex; 857 display: flex;
821 margin-top: 10px; 858 margin-top: 10px;
822 align-items: center; 859 align-items: center;
823 } 860 }
824 861
825 - .search-title{ 862 + .search-title {
826 width: 200px; 863 width: 200px;
827 margin-top: 10px; 864 margin-top: 10px;
828 display: block; 865 display: block;
829 margin-left: 20px; 866 margin-left: 20px;
830 } 867 }
831 868
832 - .operation{ 869 + .operation {
833 border: none; 870 border: none;
834 margin-top: 10px; 871 margin-top: 10px;
835 align-items: end; 872 align-items: end;
@@ -839,38 +876,38 @@ @@ -839,38 +876,38 @@
839 position: absolute; 876 position: absolute;
840 } 877 }
841 878
842 - .knowledge-card:hover{  
843 - .operation{ 879 + .knowledge-card:hover {
  880 + .operation {
844 display: block !important; 881 display: block !important;
845 } 882 }
846 } 883 }
847 884
848 - .add-knowledge-doc{ 885 + .add-knowledge-doc {
849 margin-top: 6px; 886 margin-top: 6px;
850 - color:#6F6F83; 887 + color: #6f6f83;
851 font-size: 13px; 888 font-size: 13px;
852 width: 100%; 889 width: 100%;
853 cursor: pointer; 890 cursor: pointer;
854 display: flex; 891 display: flex;
855 - span{ 892 + span {
856 margin-left: 4px; 893 margin-left: 4px;
857 line-height: 28px; 894 line-height: 28px;
858 } 895 }
859 } 896 }
860 - .add-knowledge-doc:hover{ 897 + .add-knowledge-doc:hover {
861 background: #c8ceda33; 898 background: #c8ceda33;
862 } 899 }
863 - .operation{ 900 + .operation {
864 background-color: unset; 901 background-color: unset;
865 border: none; 902 border: none;
866 margin-right: 2px; 903 margin-right: 2px;
867 } 904 }
868 - .operation:hover{ 905 + .operation:hover {
869 color: #000000; 906 color: #000000;
870 - background-color: rgba(0,0,0,0.05); 907 + background-color: rgba(0, 0, 0, 0.05);
871 border: none; 908 border: none;
872 } 909 }
873 - .ant-dropdown-link{ 910 + .ant-dropdown-link {
874 font-size: 14px; 911 font-size: 14px;
875 height: 24px; 912 height: 24px;
876 padding: 0 7px; 913 padding: 0 7px;
@@ -878,18 +915,18 @@ @@ -878,18 +915,18 @@
878 align-content: center; 915 align-content: center;
879 text-align: center; 916 text-align: center;
880 } 917 }
881 - .card-footer{ 918 + .card-footer {
882 margin-top: 4px; 919 margin-top: 4px;
883 font-weight: 400; 920 font-weight: 400;
884 color: #1f2329; 921 color: #1f2329;
885 text-align: left; 922 text-align: left;
886 font-size: 12px; 923 font-size: 12px;
887 } 924 }
888 - .card-text-status{ 925 + .card-text-status {
889 display: flex; 926 display: flex;
890 align-items: center; 927 align-items: center;
891 } 928 }
892 - .ml-2{ 929 + .ml-2 {
893 margin-left: 2px; 930 margin-left: 2px;
894 } 931 }
895 </style> 932 </style>
@@ -36,7 +36,7 @@ export const columns: BasicColumn[] = [ @@ -36,7 +36,7 @@ export const columns: BasicColumn[] = [
36 dataIndex: 'buttonValues', 36 dataIndex: 'buttonValues',
37 }, 37 },
38 { 38 {
39 - title: '按钮code', 39 + title: '按钮标识',
40 align: 'center', 40 align: 'center',
41 dataIndex: 'code', 41 dataIndex: 'code',
42 }, 42 },
@@ -98,7 +98,7 @@ export const formSchema: FormSchema[] = [ @@ -98,7 +98,7 @@ export const formSchema: FormSchema[] = [
98 // componentProps: {}, 98 // componentProps: {},
99 // }, 99 // },
100 { 100 {
101 - label: '按钮code', 101 + label: '按钮标识',
102 field: 'code', 102 field: 'code',
103 component: 'Input', 103 component: 'Input',
104 required: true, 104 required: true,
@@ -59,12 +59,7 @@ export const columns: BasicColumn[] = [ @@ -59,12 +59,7 @@ export const columns: BasicColumn[] = [
59 }, 59 },
60 }, 60 },
61 { 61 {
62 - title: '按钮名称',  
63 - align: 'center',  
64 - dataIndex: 'buttonName',  
65 - },  
66 - {  
67 - title: 'code', 62 + title: '按钮标识',
68 align: 'center', 63 align: 'center',
69 dataIndex: 'code', 64 dataIndex: 'code',
70 }, 65 },
1 <template> 1 <template>
2 <a-card title="智能助手配置" class="config-card"> 2 <a-card title="智能助手配置" class="config-card">
3 - <a-form :model="formState" layout="vertical"> 3 + <a-form :model="formState" layout="vertical" ref="formRef" :rules="rules">
4 <!-- 向量模型 --> 4 <!-- 向量模型 -->
5 - <a-form-item label="向量模型" class="form-item"> 5 + <a-form-item label="向量模型" class="form-item required" name="embeddingId">
6 <a-select 6 <a-select
7 v-model:value="formState.embeddingId" 7 v-model:value="formState.embeddingId"
8 placeholder="请选择向量模型" 8 placeholder="请选择向量模型"
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 </a-form-item> 13 </a-form-item>
14 14
15 <!-- 大语言模型 --> 15 <!-- 大语言模型 -->
16 - <a-form-item label="大语言模型" class="form-item"> 16 + <a-form-item label="大语言模型" class="form-item required" name="llmId">
17 <a-select 17 <a-select
18 v-model:value="formState.llmId" 18 v-model:value="formState.llmId"
19 placeholder="请选择大语言模型" 19 placeholder="请选择大语言模型"
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 </a-form-item> 24 </a-form-item>
25 25
26 <!-- 知识库 --> 26 <!-- 知识库 -->
27 - <a-form-item label="知识库" class="form-item"> 27 + <a-form-item label="知识库" class="form-item required" name="knowledgeId">
28 <a-select 28 <a-select
29 v-model:value="formState.knowledgeId" 29 v-model:value="formState.knowledgeId"
30 placeholder="请选择知识库" 30 placeholder="请选择知识库"
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 </a-form-item> 35 </a-form-item>
36 36
37 <!-- 按钮(多选) --> 37 <!-- 按钮(多选) -->
38 - <a-form-item label="功能按钮" class="form-item"> 38 + <a-form-item label="功能按钮" class="form-item required" name="buttonIds">
39 <a-select 39 <a-select
40 v-model:value="formState.buttonIds" 40 v-model:value="formState.buttonIds"
41 mode="multiple" 41 mode="multiple"
@@ -50,11 +50,11 @@ @@ -50,11 +50,11 @@
50 </a-form-item> 50 </a-form-item>
51 51
52 <!-- 提示词 --> 52 <!-- 提示词 -->
53 - <a-form-item label="提示词" class="form-item"> 53 + <a-form-item label="提示词" class="form-item required" name="prompt">
54 <a-textarea 54 <a-textarea
55 v-model:value="formState.prompt" 55 v-model:value="formState.prompt"
56 placeholder="请输入提示词,例如:你是一个专业的AI助手..." 56 placeholder="请输入提示词,例如:你是一个专业的AI助手..."
57 - :rows="4" 57 + :rows="9"
58 :maxlength="500" 58 :maxlength="500"
59 show-count 59 show-count
60 /> 60 />
@@ -80,7 +80,7 @@ @@ -80,7 +80,7 @@
80 <script lang="ts" setup> 80 <script lang="ts" setup>
81 import { reactive, ref, onMounted } from 'vue'; 81 import { reactive, ref, onMounted } from 'vue';
82 import { getConfigData, saveConfig } from './Chatsetting.api'; 82 import { getConfigData, saveConfig } from './Chatsetting.api';
83 - import { message } from 'ant-design-vue'; 83 + import { FormInstance, message } from 'ant-design-vue';
84 import { SaveOutlined, UndoOutlined } from '@ant-design/icons-vue'; 84 import { SaveOutlined, UndoOutlined } from '@ant-design/icons-vue';
85 85
86 // 表单数据结构 86 // 表单数据结构
@@ -93,6 +93,25 @@ @@ -93,6 +93,25 @@
93 prompt: '', 93 prompt: '',
94 }); 94 });
95 95
  96 + const formRef = ref<FormInstance>(); // 添加表单引用
  97 +
  98 + const rules = reactive({
  99 + embeddingId: [{ required: true, message: '请选择向量模型', trigger: 'change' }],
  100 + llmId: [{ required: true, message: '请选择大语言模型', trigger: 'change' }],
  101 + knowledgeId: [{ required: true, message: '请选择知识库', trigger: 'change' }],
  102 + buttonIds: [
  103 + {
  104 + required: true,
  105 + message: '请至少选择一个按钮',
  106 + trigger: 'change',
  107 + type: 'array',
  108 + },
  109 + ],
  110 + prompt: [
  111 + { required: true, message: '请输入提示词', trigger: 'blur' },
  112 + { max: 500, message: '提示词长度不能超过500个字符', trigger: 'blur' },
  113 + ],
  114 + });
96 // 选项数据 115 // 选项数据
97 const options = reactive({ 116 const options = reactive({
98 embeddingOptions: [], 117 embeddingOptions: [],
@@ -114,7 +133,11 @@ @@ -114,7 +133,11 @@
114 // 填充表单 133 // 填充表单
115 Object.keys(formState).forEach((key) => { 134 Object.keys(formState).forEach((key) => {
116 if (data.airagChatsettingConfig[key] !== undefined) { 135 if (data.airagChatsettingConfig[key] !== undefined) {
  136 + if (key === 'buttonIds') {
  137 + formState[key] = data.airagChatsettingConfig[key] || [];
  138 + } else {
117 formState[key] = data.airagChatsettingConfig[key]; 139 formState[key] = data.airagChatsettingConfig[key];
  140 + }
118 console.log('shuju' + formState[key]); 141 console.log('shuju' + formState[key]);
119 } 142 }
120 }); 143 });
@@ -134,6 +157,12 @@ @@ -134,6 +157,12 @@
134 157
135 // 保存配置 158 // 保存配置
136 const saveConfigData = async () => { 159 const saveConfigData = async () => {
  160 + try {
  161 + await formRef.value?.validateFields();
  162 + } catch (error) {
  163 + message.error('请填写所有必填字段');
  164 + return;
  165 + }
137 const params = { 166 const params = {
138 ...formState, 167 ...formState,
139 id: formState.id || '', 168 id: formState.id || '',
@@ -163,7 +192,7 @@ @@ -163,7 +192,7 @@
163 192
164 // 重置表单 193 // 重置表单
165 const resetForm = () => { 194 const resetForm = () => {
166 - loadConfig(); 195 + formRef.value?.resetFields();
167 }; 196 };
168 197
169 // 初始化加载 198 // 初始化加载
@@ -174,7 +203,7 @@ @@ -174,7 +203,7 @@
174 203
175 <style lang="less" scoped> 204 <style lang="less" scoped>
176 .config-card { 205 .config-card {
177 - max-width: 800px; 206 + max-width: 1800px;
178 margin: 20px auto; 207 margin: 20px auto;
179 box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); 208 box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
180 209
1 <template> 1 <template>
2 <div> 2 <div>
  3 + <div class="knowledge-header" v-if="currentKnowledge">
  4 + <div class="header-container">
  5 + <h2 class="knowledge-title">{{ currentKnowledge.name }} - 文档列表</h2>
  6 + <a-button type="link" @click="goBack" class="back-button"> <Icon icon="ant-design:arrow-left-outlined" /> 返回知识库列表 </a-button>
  7 + </div>
  8 + </div>
3 <!--引用表格--> 9 <!--引用表格-->
4 <BasicTable @register="registerTable" :rowSelection="rowSelection"> 10 <BasicTable @register="registerTable" :rowSelection="rowSelection">
5 <!--插槽:table标题--> 11 <!--插槽:table标题-->
@@ -24,7 +30,7 @@ @@ -24,7 +30,7 @@
24 </a-button> 30 </a-button>
25 </a-dropdown> 31 </a-dropdown>
26 <!-- 高级查询 --> 32 <!-- 高级查询 -->
27 -<!-- <super-query :config="superQueryConfig" @search="handleSuperQuery" />--> 33 + <!-- <super-query :config="superQueryConfig" @search="handleSuperQuery" />-->
28 </template> 34 </template>
29 <!--操作栏--> 35 <!--操作栏-->
30 <template #action="{ record }"> 36 <template #action="{ record }">
@@ -49,10 +55,43 @@ @@ -49,10 +55,43 @@
49 import { useUserStore } from '/@/store/modules/user'; 55 import { useUserStore } from '/@/store/modules/user';
50 import JUploadButton from '@/components/Button/src/JUploadButton.vue'; 56 import JUploadButton from '@/components/Button/src/JUploadButton.vue';
51 import { columns as defaultColumns } from './Test.data'; 57 import { columns as defaultColumns } from './Test.data';
  58 + import { useRoute, useRouter } from 'vue-router';
52 const queryParam = reactive<any>({}); 59 const queryParam = reactive<any>({});
53 const checkedKeys = ref<Array<string | number>>([]); 60 const checkedKeys = ref<Array<string | number>>([]);
54 const userStore = useUserStore(); 61 const userStore = useUserStore();
55 - // 添加知识库名称映射 62 +
  63 + const route = useRoute();
  64 + const router = useRouter();
  65 +
  66 + // 当前知识库信息
  67 + const currentKnowledge = ref<{ id: string; name: string } | null>(null);
  68 +
  69 + // 在onMounted中添加知识库ID处理
  70 + onMounted(() => {
  71 + // 从路由参数获取知识库ID
  72 + const knowledgeId = route.query.knowledgeId as string;
  73 + const knowledgeName = route.query.knowledgeName as string;
  74 +
  75 + console.log('ceshi' + knowledgeId);
  76 + if (knowledgeId && knowledgeName) {
  77 + currentKnowledge.value = {
  78 + id: knowledgeId,
  79 + name: knowledgeName,
  80 + };
  81 +
  82 + // 设置查询参数
  83 + queryParam.knowledgeId = knowledgeId;
  84 + reload();
  85 + }
  86 +
  87 + loadKnowledgeMap();
  88 + });
  89 +
  90 + // 返回知识库列表
  91 + function goBack() {
  92 + router.push('/super/airag/aiknowledge/AiKnowledgeBaseList');
  93 + }
  94 + // 知识库名称映射
56 const knowledgeMap = ref<Record<string, string>>({}); 95 const knowledgeMap = ref<Record<string, string>>({});
57 96
58 // 加载知识库列表 97 // 加载知识库列表
@@ -142,6 +181,9 @@ @@ -142,6 +181,9 @@
142 fixed: 'right', 181 fixed: 'right',
143 }, 182 },
144 beforeFetch: (params) => { 183 beforeFetch: (params) => {
  184 + if (currentKnowledge.value?.id) {
  185 + params.knowledgeId = currentKnowledge.value.id;
  186 + }
145 // 处理知识库查询参数 187 // 处理知识库查询参数
146 if (params.knowledgeId) { 188 if (params.knowledgeId) {
147 // 直接使用对象而不是JSON字符串 189 // 直接使用对象而不是JSON字符串
@@ -269,4 +311,69 @@ @@ -269,4 +311,69 @@
269 :deep(.ant-input-number) { 311 :deep(.ant-input-number) {
270 width: 100%; 312 width: 100%;
271 } 313 }
  314 + .knowledge-header {
  315 + margin-bottom: 16px;
  316 + padding: 16px;
  317 + background: #fff;
  318 + border-radius: 8px;
  319 + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
  320 +
  321 + .header-container {
  322 + display: flex;
  323 + justify-content: space-between;
  324 + align-items: center;
  325 +
  326 + .knowledge-title {
  327 + margin: 0;
  328 + font-size: 18px;
  329 + font-weight: 600;
  330 + color: #1f2329;
  331 + flex: 1;
  332 + white-space: nowrap;
  333 + overflow: hidden;
  334 + text-overflow: ellipsis;
  335 + padding-right: 16px;
  336 + }
  337 +
  338 + .back-button {
  339 + display: flex;
  340 + align-items: center;
  341 + color: #1890ff;
  342 + font-weight: 500;
  343 + padding: 4px 8px;
  344 + transition: all 0.3s;
  345 + flex-shrink: 0;
  346 +
  347 + &:hover {
  348 + color: #40a9ff;
  349 + background: rgba(24, 144, 255, 0.1);
  350 + border-radius: 4px;
  351 + }
  352 +
  353 + i {
  354 + margin-right: 4px;
  355 + font-size: 14px;
  356 + }
  357 + }
  358 + }
  359 + }
  360 +
  361 + @media (max-width: 768px) {
  362 + .knowledge-header {
  363 + .header-container {
  364 + flex-direction: column;
  365 + align-items: flex-start;
  366 +
  367 + .knowledge-title {
  368 + margin-bottom: 12px;
  369 + padding-right: 0;
  370 + width: 100%;
  371 + }
  372 +
  373 + .back-button {
  374 + align-self: flex-end;
  375 + }
  376 + }
  377 + }
  378 + }
272 </style> 379 </style>