Files
k3GPT/main/ui/kg_select.aps

206 lines
16 KiB
Plaintext
Raw Permalink Normal View History

2025-11-19 19:43:04 +08:00
<div x-data="kg()" x-init="fetchSomething">
<!-- 查询器 四角弧形的矩形容器 -->
<div class="flex rounded-lg bg-white shadow-lg p-4 space-x-4">
<!-- 横向排列的四个元素 -->
<div class="relative flex w-full max-w-md flex-col gap-1 text-neutral-600 dark:text-zinc-200">
<input x-model="demo" type="search" class="w-full rounded border border-zinc-300 bg-zinc-100 py-2 pl-10 pr-2 text-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 disabled:cursor-not-allowed disabled:opacity-75 dark:border-zinc-700 dark:bg-zinc-800/50 dark:focus-visible:outline-sky-600" name="search" placeholder="Search" aria-label="search"/>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true" class="absolute left-2.5 top-1/2 size-5 -translate-y-1/2 text-neutral-600/50 dark:text-zinc-200/50">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
</div>
<button @click="fetchSomething" type="button" class="cursor-pointer whitespace-nowrap rounded bg-sky-700 px-4 py-2 text-sm font-medium tracking-wide text-white transition hover:opacity-75 text-center focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-sky-600 dark:text-white dark:focus-visible:outline-sky-600">查询</button>
<button @click="submitSelected" type="button" class="cursor-pointer whitespace-nowrap rounded bg-sky-700 px-4 py-2 text-sm font-medium tracking-wide text-white transition hover:opacity-75 text-center focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-sky-600 dark:text-white dark:focus-visible:outline-sky-600">确认选中</button>
</div>
<!-- 结果表格-->
<div class="mt-4 overflow-hidden w-full overflow-x-auto rounded border border-zinc-300 dark:border-zinc-700">
<table class="w-full text-left text-sm text-neutral-600 dark:text-zinc-200">
<thead class="border-b border-zinc-300 bg-zinc-100 text-sm text-neutral-900 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-50">
<tr>
<th scope="col" class="p-4">
<label for="checkAll" class="flex items-center cursor-pointer text-neutral-600 dark:text-zinc-200 ">
<div class="relative flex items-center">
<input type="checkbox" x-model="checkAll" id="checkAll" class="before:content[''] peer relative size-4 cursor-pointer appearance-none overflow-hidden rounded border border-zinc-300 bg-zinc-50 before:absolute before:inset-0 checked:border-sky-700 checked:before:bg-sky-700 focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-zinc-500 checked:focus:outline-sky-700 active:outline-offset-0 dark:border-zinc-700 dark:bg-zinc-800 dark:checked:border-sky-600 dark:checked:before:bg-sky-600 dark:focus:outline-zinc-500 dark:checked:focus:outline-sky-600" />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="4" class="pointer-events-none invisible absolute left-1/2 top-1/2 size-3 -translate-x-1/2 -translate-y-1/2 text-white peer-checked:visible dark:text-white">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"/>
</svg>
</div>
</label>
</th>
<th scope="col" class="p-4">知识库</th>
<th scope="col" class="p-4">文档名称</th>
<th scope="col" class="p-4">创建日期</th>
<th scope="col" class="p-4">操作</th>
</tr>
</thead>
<tbody class="divide-y divide-zinc-300 dark:divide-zinc-700">
<template x-for="(item,index) in kItems" :key="item.id">
<tr>
<td class="p-2 px-4">
<label for="user2338" class="flex items-center cursor-pointer text-neutral-600 dark:text-zinc-200 ">
<div class="relative flex items-center">
<input type="checkbox" x-model="selected_doc_list" name="doc_list[]" :value="item.base+'_'+item.path" class="before:content[''] peer relative size-4 cursor-pointer appearance-none overflow-hidden rounded border border-zinc-300 bg-zinc-50 before:absolute before:inset-0 checked:border-sky-700 checked:before:bg-sky-700 focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-zinc-500 checked:focus:outline-sky-700 active:outline-offset-0 dark:border-zinc-700 dark:bg-zinc-800 dark:checked:border-sky-600 dark:checked:before:bg-sky-600 dark:focus:outline-zinc-500 dark:checked:focus:outline-sky-600"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="4" class="pointer-events-none invisible absolute left-1/2 top-1/2 size-3 -translate-x-1/2 -translate-y-1/2 text-white peer-checked:visible dark:text-white">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"/>
</svg>
</div>
</label>
</td>
<td class="p-2" x-text="item.base">知识库</td>
<td class="p-2 max-w-xs"><a x-text="item.f_name" :href="`/api/fd?path=${item.path}&filename=${item.f_name}&base=${item.base}`" target="_blank">文件名称</a></td>
<td class="p-2">
<div class="relative">
<button x-text="item.ct_time.slice(0,10)" type="button" class="peer cursor-pointer rounded bg-zinc-100 px-4 py-2 font-medium tracking-wide text-neutral-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 dark:bg-zinc-800 dark:text-zinc-200 dark:focus-visible:outline-sky-600" aria-describedby="tooltipExample">Hover Me</button>
<div x-text="item.ct_time" id="tooltipExample" class="absolute -top-9 left-1/2 -translate-x-1/2 z-10 whitespace-nowrap rounded bg-zinc-900 px-2 py-1 text-center text-sm text-zinc-50 opacity-0 transition-all ease-out peer-hover:opacity-100 peer-focus:opacity-100 dark:bg-zinc-50 dark:text-neutral-900" role="tooltip">Tooltip top</div>
</div>
</td>
<td class="p-2">
<button @click="remove_fs_file(item.path)" type="button" class="cursor-pointer whitespace-nowrap rounded bg-transparent p-0.5 font-semibold text-sky-700 outline-sky-700 hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 active:opacity-100 active:outline-offset-0 dark:text-sky-600 dark:outline-sky-600">删除</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<!-- 翻页-->
<nav aria-label="pagination">
<ul class="flex flex-shrink-0 items-center gap-2 text-sm font-medium">
<li> 共<span x-text="count" class="font-bold">200</span>条/显示前<span x-text="view_count" class="font-bold"></span>条</li>
<li>
<a href="#" @click="curPage===1 ? pageSlie(1): pageSlie(curPage-1) " class="flex items-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="previous page">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="size-6">
<path fill-rule="evenodd" d="M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" />
</svg>
上一页
</a>
</li>
<li x-show="count/pageSize+1 >=ps+1"><a href="#" x-text="ps+1" @click="pageSlie(ps+1)" :class="curPage===ps+1 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="page 1">1</a></li>
<li x-show="count/pageSize+1 >=ps+2"><a href="#" x-text="ps+2" @click="pageSlie(ps+2)" :class="curPage===ps+2 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:bg-sky-600 dark:text-white" aria-label="page 2">2</a></li>
<li x-show="count/pageSize+1 >=ps+3"><a href="#" x-text="ps+3" @click="pageSlie(ps+3)" :class="curPage===ps+3 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="page 3">3</a></li>
<li x-show="count/pageSize+1 >=ps+4"><a href="#" x-text="ps+4" @click="pageSlie(ps+4)" :class="curPage===ps+4 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="page 4">4</a></li>
<li x-show="count/pageSize+1 >=ps+5"><a href="#" x-text="ps+5" @click="pageSlie(ps+5)" :class="curPage===ps+5 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="page 5">5</a></li>
<li x-show="count/pageSize+1 >=ps+6"><a href="#" x-text="ps+6" @click="pageSlie(ps+6)" :class="curPage===ps+6 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="page 1">6</a></li>
<li x-show="count/pageSize+1 >=ps+7"><a href="#" x-text="ps+7" @click="pageSlie(ps+7)" :class="curPage===ps+7 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:bg-sky-600 dark:text-white" aria-label="page 2">7</a></li>
<li x-show="count/pageSize+1 >=ps+8"><a href="#" x-text="ps+8" @click="pageSlie(ps+8)" :class="curPage===ps+8 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="page 3">8</a></li>
<li x-show="count/pageSize+1 >=ps+9"><a href="#" x-text="ps+9" @click="pageSlie(ps+9)" :class="curPage===ps+9 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="page 4">9</a></li>
<li x-show="count/pageSize+1 >=ps+10"><a href="#" x-text="ps+10" @click="pageSlie(ps+10)" :class="curPage===ps+10 ? 'bg-sky-700 text-white font-bold ' :''" class="flex size-6 items-center justify-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="page 5">10</a></li>
<li>
<a href="#" @click="curPage=== parseInt(count/pageSize)+1 ? pageSlie(parseInt(count/pageSize)+1): pageSlie(curPage+1) " class="flex items-center rounded p-1 text-neutral-600 hover:text-sky-700 dark:text-zinc-200 dark:hover:text-sky-600" aria-label="next page">
下一页
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="size-6">
<path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
</svg>
</a>
</li>
</ul>
</nav>
</div>
<script>
// 定义分割函数
function partition(array, condition) {
return array.reduce((acc, current) => {
// 如果条件为真,则添加到符合的数组中,否则添加到不符合的数组中
acc[condition(current) ? 0 : 1].push(current);
return acc;
}, [[], []]); // 初始化累加器为两个空数组
}
function kg(){
return {
checkAll: false,
demo: '',
fpath: '',
selected_doc_list:[], //选中的文件列表
count: 10,
view_count:10,
pageSize:5,
curPage: 1,
ps:0,
aItems:[],
kItems:[],
submitSelected(){
let base_path = this.selected_doc_list[0];
var b = base_path.indexOf("_");
let base = base_path.slice(0,b);
let path = base_path.slice(b+1);
//分发传播文件选中事件
this.$dispatch('fileselected',{base:base,path:path});
if ("ai_file" in this){ //对话聊天时选择文件
//console.info(this.selected_doc_list);
this.ai_file.base=base;
this.ai_file.path=path;
this.push_item({chat_id:"",req:"你选择了文件: "+this.ai_file.path,rsp:"",rsp_show:false});
}
if ('kagent' in this){
//智能体配置时选择文件
this.kagent.files = this.selected_doc_list.toString(); //转为字符串格式
if ('gen_count' in this){
this.gen_count();
}
this.FileSelecterOpen=false;
}
},
fetchSomething() {
if('people_files' in this && 'gdSelectedTab' in this && this.gdSelectedTab=="my"){
this.fpath = this.people_files;//个人文件夹
}
axios.get('/api/kg_doc?demo='+this.demo+'&fpath='+this.fpath).then(response => {
//非个人文件夹模式
if(!this.fpath){
if (this.kagent.files){
this.selected_doc_list = this.kagent.files.split(",");
}
}
console.log('Select:', this.selected_doc_list);
var all_data = response.data.data;
// 使用定义好的分割函数和条件来分割数组
let [checked, unchecked] = partition(all_data, item => this.selected_doc_list.includes(item.base+'_'+item.path));
console.info(checked);
this.aItems = [...checked, ...unchecked];
this.view_count = this.aItems.length;
this.kItems = this.aItems.slice(0,this.pageSize);
this.curPage = 1;
this.count=response.data.count;
}).catch(error => {
console.error('Error fetching data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
pageSlie(page){
this.ps = Math.floor((page-1)/10)*10;
this.curPage = page;
this.kItems = this.aItems.slice(this.pageSize*(this.curPage-1),this.pageSize*this.curPage);
},
remove_fs_file(file_path){
axios.delete('/api/fs/'+file_path).then(response => {
this.fetchSomething();
}).catch(error => {
console.error('Error fetching data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
}
}
</script>