123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- <template>
- <div class="gpu-list">
- <!-- 顶部筛选区域 -->
- <div class="filter-section">
- <el-select
- v-model="selectedBucket"
- placeholder="请选择知识库"
- @change="handleBucketChange"
- >
- <el-option
- v-for="item in buckets"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- />
- </el-select>
- <el-select
- v-model="selectedType"
- placeholder="请选择目录"
- :disabled="!selectedBucket"
- class="ml-15"
- >
- <el-option
- v-for="item in types"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- />
- </el-select>
- <el-button
- type="primary"
- :loading="isSyncing"
- :disabled="!selectedType"
- class="ml-15"
- @click="handleSyncData"
- >
- {{ isSyncing ? "同步中..." : "同步数据" }}
- </el-button>
- </div>
- <el-tabs v-model="activeName" @tab-click="handleClick">
- <!-- 原有的文献列表 tab -->
- <el-tab-pane label="文献列表" name="first">
- <!-- 添加搜索表单 -->
- <div class="search-form">
- <el-form
- :inline="true"
- :model="searchForm"
- class="demo-form-inline"
- label-width="100px"
- ><el-form-item label="名称:">
- <el-input
- v-model="searchForm.name"
- clearable
- placeholder="请输入文献名称"
- ></el-input>
- </el-form-item>
- <el-form-item label="创建时间:">
- <el-date-picker
- v-model="searchForm.createTimeRange"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- value-format="yyyy-MM-dd"
- />
- </el-form-item>
- <!-- <el-form-item label="文本时间:">
- <el-date-picker
- v-model="searchForm.textTimeRange"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- value-format="yyyy-MM-dd"
- />
- </el-form-item> -->
- <el-form-item label="标签:">
- <el-select
- v-model="searchForm.id"
- multiple
- filterable
- remote
- reserve-keyword
- :remote-method="searchFormTags"
- :loading="searchTagsLoading"
- placeholder="请输入标签关键词"
- clearable
- >
- <el-option
- v-for="tag in searchTagOptions"
- :key="tag.id"
- :label="tag.name"
- :value="tag.name"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="handleSearch">搜索</el-button>
- <el-button @click="resetSearch">重置</el-button>
- </el-form-item>
- </el-form>
- </div>
- <div class="batch-operations">
- <el-button
- type="primary"
- @click="handleBatchProcess"
- :loading="isProcessing"
- :disabled="selectedRows.length === 0"
- class="ml-15"
- >
- {{ isProcessing ? "处理中..." : "批量处理文献" }}
- </el-button>
- <el-button
- type="primary"
- @click="handleBatchTag"
- :disabled="selectedRows.length == 0"
- >批量绑定标签</el-button
- >
- </div>
- <!-- 数据表格区域 -->
- <el-table
- v-loading="isLoading"
- :data="gpuList"
- style="width: 100%"
- @selection-change="handleSelectionChange"
- >
- <el-table-column type="selection" width="55" />
- <el-table-column prop="id" label="ID" width="80" />
- <el-table-column prop="name" label="名称">
- <!-- <template #default="{ row }">
- <el-link @click="handleNameClick(row)">{{ row.name }}</el-link>
- </template> -->
- </el-table-column>
- <el-table-column prop="tags" label="已绑定标签">
- <template #default="{ row }">
- <el-tag
- v-for="(item, index) in row.tags"
- :key="index"
- type=""
- :style="index !== 0 ? 'margin-left: 5px;' : ''"
- >
- {{ item }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column prop="type" label="文档类型" width="100" />
- <el-table-column prop="create_time" label="创建时间" width="200" />
- <el-table-column prop="status" label="处理状态" width="100">
- <template #default="{ row }">
- <el-tag :type="getStatusType(row.processing_status)">
- {{ getStatusText(row.processing_status) }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="操作" width="100">
- <template #default="{ row }">
- <el-dropdown trigger="click">
- <el-button
- type="text"
- size="small"
- circle
- class="operation-button"
- style="font-size: 15px; margin-left: 10px"
- icon="el-icon-more"
- ></el-button>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item @click.native="handleNameClick(row)">
- <i class="el-icon-view"></i> 查看
- </el-dropdown-item>
- <el-dropdown-item @click.native="handlePreview(row)">
- <i class="el-icon-tickets"></i> 预览
- </el-dropdown-item>
- <el-dropdown-item @click.native="handleSingleProcess(row)">
- <i class="el-icon-refresh"></i> 处理文献
- </el-dropdown-item>
- <!-- <el-dropdown-item
- @click.native="firstHandleUpload(scope.$index, scope.row)"
- >
- <i class="el-icon-refresh"></i> 批量处理
- </el-dropdown-item> -->
- <!-- <el-dropdown-item
- @click.native="firstHandleDelete(scope.$index, scope.row)"
- >
- <i class="el-icon-delete"></i> 删除
- </el-dropdown-item> -->
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </template>
- </el-table-column>
- </el-table>
- <!-- 分页器 -->
- <el-pagination
- class="pagination"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- :current-page="currentPage"
- :page-sizes="[10, 20, 50, 100]"
- :page-size="pageSize"
- layout="total, sizes, prev, pager, next, jumper"
- :total="total"
- />
- </el-tab-pane>
- <!-- 添加 SOTA详情 tab -->
- <el-tab-pane label="SOTA详情" name="second">
- <el-table :data="sotaDetailsList" style="width: 100%">
- <el-table-column label="Identifier" prop="identifier" />
- <el-table-column label="Device" prop="device" />
- <el-table-column label="Outcomes" prop="outcomes" />
- <el-table-column label="Unit for analysis" prop="unit" />
- <el-table-column label="Mean" prop="mean" />
- <!-- 操作列与原有类似 -->
- </el-table>
- </el-tab-pane>
- <!-- 添加 SOTA汇总表 tab -->
- <el-tab-pane label="SOTA汇总表" name="third">
- <el-table :data="sotaSummaryList" style="width: 100%">
- <el-table-column label="Summary" prop="summary" />
- <el-table-column label="EqMD" prop="eqmd" />
- <el-table-column label="Pain:VAS" prop="painVas" />
- <!-- 操作列与原有类似 -->
- </el-table>
- </el-tab-pane>
- </el-tabs>
- <!-- 添加标签对话框 -->
- <el-dialog
- title="批量绑定标签"
- :visible.sync="tagDialogVisible"
- width="800px"
- >
- <el-form :model="tagForm" label-width="150px">
- <el-form-item label="标签:">
- <el-select
- style="width: 350px"
- v-model="tagForm.tags"
- multiple
- filterable
- remote
- reserve-keyword
- :remote-method="searchTags"
- :loading="tagsLoading"
- placeholder="请输入关键词搜索标签"
- >
- <el-option
- v-for="tag in tagOptions"
- :key="tag.id"
- :label="tag.name"
- :value="tag.id"
- />
- </el-select>
- </el-form-item>
- </el-form>
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="tagDialogVisible = false">取消</el-button>
- <el-button type="primary" @click="submitBatchTag">确定</el-button>
- </span>
- </template>
- </el-dialog>
- </div>
- </template>
- <script>
- import { debounce } from "lodash-es";
- import {
- GET_list,
- GET_sync,
- listBuckets,
- selectTypeList,
- getDetail,
- search_tags,
- edit_tags,
- search,
- process_model_generation,
- } from "@/api/knowledge";
- import axios from "axios";
- // 状态映射表
- const STATUS_MAP = {
- 0: { text: "未处理", type: "info" },
- 1: { text: "处理中", type: "warning" },
- 2: { text: "处理完成", type: "success" },
- 3: { text: "处理失败", type: "danger" },
- };
- export default {
- name: "GpuList",
- data() {
- return {
- gpuList: [],
- currentPage: 1,
- pageSize: 10,
- total: 0,
- isLoading: false,
- isSyncing: false,
- buckets: [],
- types: [],
- selectedBucket: null,
- selectedType: null,
- activeName: "first", // 当前激活的tab
- sotaDetailsList: [], // SOTA详情列表数据
- sotaSummaryList: [], // SOTA汇总表数据
- searchForm: {
- name: "",
- createTimeRange: [],
- textTimeRange: [],
- id: [],
- },
- selectedRows: [], // 选中的行
- tagDialogVisible: false, // 标签对话框显示状态
- tagForm: {
- tags: [], // 选中的标签ID数组
- },
- tagOptions: [], // 标签选项
- tagsLoading: false, // 标签加载状态
- searchTagOptions: [], // 搜索表单的标签选项
- searchTagsLoading: false, // 搜索表单的标签加载状态
- isProcessing: false, // 批量处理的加载状态
- pollingTimers: {}, // 新增:存储每个文献的轮询定时器
- };
- },
- created() {
- // 使用防抖处理数据加载
- this.debouncedFetchGpuList = debounce(this.fetchGpuList, 300);
- },
- mounted() {
- this.initialize();
- },
- methods: {
- // 在中添加单个处理方法
- async handleSingleProcess(row) {
- try {
- await this.$confirm("确认要处理该文献吗?", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning",
- });
- const res = await process_model_generation([row.id]);
- if (res.status === 200) {
- this.$message.success("处理任务已提交");
- await this.fetchGpuList(); // 刷新列表
- } else {
- throw new Error(res.message || "处理失败");
- }
- } catch (error) {
- if (error === "cancel") {
- return;
- }
- this.$message.error(error.message || "处理提交失败");
- console.error("处理错误:", error);
- }
- },
- /* 搜索栏模糊查找 */
- /* 搜索表单的标签搜索 */
- async searchFormTags(query) {
- if (query !== "") {
- this.searchTagsLoading = true;
- try {
- const { data } = await search_tags({ keyword: query });
- this.searchTagOptions = data.data.items;
- } catch (error) {
- this.$message.error("搜索标签失败");
- console.error(error);
- } finally {
- this.searchTagsLoading = false;
- }
- } else {
- this.searchTagOptions = [];
- }
- },
- // 处理表格选择变化
- handleSelectionChange(rows) {
- this.selectedRows = rows;
- },
- // 处理批量标签
- handleBatchTag() {
- this.tagDialogVisible = true;
- },
- /* 批量处理文献 */
- async handleBatchProcess() {
- if (this.selectedRows.length === 0) {
- this.$message.warning("请选择需要处理的文献");
- return;
- }
- try {
- this.isProcessing = true;
- const ids = this.selectedRows.map((row) => row.id);
- // 添加确认对话框
- await this.$confirm("确认要批量处理选中的文献吗?", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning",
- });
- const res = await process_model_generation(ids);
- if (res.status === 200) {
- this.$message.success("批量处理已提交");
- this.selectedRows = []; // 清空选中
- await this.fetchGpuList(); // 刷新列表
- } else {
- throw new Error(res.message || "处理失败");
- }
- } catch (error) {
- if (error === "cancel") {
- return;
- }
- this.$message.error(error.message || "批量处理提交失败");
- console.error("批量处理错误:", error);
- } finally {
- this.isProcessing = false;
- }
- },
- /* 模糊搜索 */
- async searchTags(query) {
- if (query !== "") {
- this.tagsLoading = true;
- try {
- const { data } = await search_tags({
- keyword: query,
- });
- this.tagOptions = data.data.items;
- } catch (error) {
- this.$message.error("搜索标签失败");
- console.error(error);
- } finally {
- this.tagsLoading = false;
- }
- } else {
- this.tagOptions = []; // 当搜索词为空时清空选项
- }
- },
- // 修改提交方法
- async submitBatchTag() {
- try {
- const ids = this.selectedRows.map((row) => row.id);
- // 这里需要添加实际的API调用
- /* await edit_tags({
- ids,
- tagIds: this.tagForm.tags, // 现在传递的是标签ID数组
- }); */
- const idObject = { literature_ids: ids, tag_ids: this.tagForm.tags };
- const response = await axios.post(
- `${process.env.VUE_APP_BASE_API}/literature-tags/relation_tags/`,
- idObject,
- {
- headers: {
- "Content-Type": "application/json",
- },
- }
- );
- if (response.status !== 200) return;
- console.log(this.tagForm.tags);
- this.$message.success("标签更新成功");
- this.tagDialogVisible = false;
- this.fetchGpuList(); // 刷新列表
- } catch (error) {
- this.$message.error("标签更新失败");
- }
- },
- // 处理搜索
- handleSearch() {
- this.currentPage = 1; // 重置页码
- this.fetchGpuList();
- },
- // 重置搜索
- resetSearch() {
- this.searchForm = {
- name: "",
- createTimeRange: [],
- textTimeRange: [],
- id: [],
- };
- this.handleSearch();
- },
- // 初始化数据
- async initialize() {
- try {
- await this.fetchBuckets();
- await this.fetchGpuList();
- } catch (error) {
- this.$message.error("初始化数据失败");
- console.error("初始化失败:", error);
- }
- },
- // 获取状态文本
- getStatusText(status) {
- return STATUS_MAP[status]?.text || "未知状态";
- },
- // 获取状态样式类型
- getStatusType(status) {
- return STATUS_MAP[status]?.type || "info";
- },
- // 获取知识库列表
- async fetchBuckets() {
- try {
- const { data } = await listBuckets();
- this.buckets = data;
- } catch (error) {
- this.$message.error("获取知识库列表失败");
- console.error("获取知识库失败:", error);
- }
- },
- // 处理知识库变更
- async handleBucketChange(val) {
- this.selectedType = null;
- this.types = [];
- if (!val) return;
- try {
- const { data } = await selectTypeList({ kb_id: val });
- this.types = data.dataList;
- this.debouncedFetchGpuList();
- } catch (error) {
- this.$message.error("获取目录列表失败");
- }
- },
- // 同步数据处理
- async handleSyncData() {
- if (!this.selectedType) {
- this.$message.warning("请先选择目录");
- return;
- }
- this.isSyncing = true;
- try {
- await GET_sync({ doc_type_id: this.selectedType });
- this.$message.success("同步成功");
- await this.fetchGpuList();
- } catch (error) {
- this.$message.error("同步失败");
- } finally {
- this.isSyncing = false;
- }
- },
- // 修改 fetchGpuList 方法中的分页处理部分
- async fetchGpuList() {
- this.isLoading = true;
- try {
- const params = {
- page: this.currentPage,
- page_size: this.pageSize,
- doc_type_id: this.selectedType || '',
- keyword: this.searchForm.name,
- tag_names: this.searchForm.id,
- };
- const response = await axios.post(
- `${process.env.VUE_APP_BASE_API}/literature-data/search/`,
- params,
- {
- headers: {
- "Content-Type": "application/json",
- },
- }
- );
- if (response.status !== 200) return;
- // 更新数据和分页信息
- const { list, total, current_page, page_size } = response.data.data;
- this.gpuList = list.map((item) => {
- const nameParts = item.name.split(".");
- const processedItem = {
- ...item,
- name: nameParts[0],
- type: nameParts.length > 1 ? nameParts.pop() : "未知",
- };
- // 检查处理状态,如果是处理中且没有设置轮询,则开始轮询
- if (
- processedItem.processing_status === 1 &&
- !this.pollingTimers[processedItem.id]
- ) {
- this.startPolling(processedItem.id);
- }
- // 如果状态不是处理中,但存在轮询,则停止轮询
- else if (
- processedItem.processing_status !== 1 &&
- this.pollingTimers[processedItem.id]
- ) {
- this.stopPolling(processedItem.id);
- }
- return processedItem;
- });
- // 确保这些值都是数字类型
- this.total = parseInt(total);
- this.currentPage = parseInt(current_page);
- this.pageSize = parseInt(page_size);
- } catch (error) {
- console.error("获取列表数据失败:", error);
- this.$message.error("获取列表数据失败");
- } finally {
- this.isLoading = false;
- }
- },
- // 新增:开始轮询
- startPolling(id) {
- if (this.pollingTimers[id]) return; // 如果已经在轮询,则不重复设置
- this.pollingTimers[id] = setInterval(async () => {
- try {
- const response = await axios.post(
- `${process.env.VUE_APP_BASE_API}/literature-data/search/`,
- {
- page: this.currentPage,
- page_size: this.pageSize,
- doc_type_id: this.selectedType || 36,
- keyword: this.searchForm.name,
- tag_names: this.searchForm.id,
- }
- );
- if (response.status === 200) {
- const item = response.data.data.list.find((item) => item.id === id);
- if (item && item.processing_status !== 1) {
- // 如果状态不再是"处理中",停止轮询
- this.stopPolling(id);
- await this.fetchGpuList(); // 刷新列表
- }
- }
- } catch (error) {
- console.error("轮询检查状态失败:", error);
- this.stopPolling(id); // 发生错误时停止轮询
- }
- }, 30000); // 每分钟检查一次
- },
- // 新增:停止轮询
- stopPolling(id) {
- if (this.pollingTimers[id]) {
- clearInterval(this.pollingTimers[id]);
- delete this.pollingTimers[id];
- }
- },
- // 修改分页处理方法
- handleSizeChange(val) {
- this.pageSize = val;
- this.currentPage = 1; // 切换每页数量时重置为第一页
- this.fetchGpuList(); // 移除防抖,直接调用
- },
- handleCurrentChange(val) {
- this.currentPage = val;
- this.fetchGpuList(); // 移除防抖,直接调用
- },
- /* 预览 */
- handlePreview(row) {
- console.log(row);
- let _this = this;
- let a = document.createElement("a");
- a.href = `#/infoList?id=${row.id}&type=${row.type.toLowerCase()}`; // 使用 hash
- a.target = "_blank";
- a.click();
- },
- // 处理名称点击
- async handleNameClick(row) {
- try {
- /* const res = await getDetail({ id: row.id })
- console.log('详情数据:', res) */
- this.$router.push({
- path: "/knowledge/middPage/index",
- query: {
- id: row.id,
- name: row.name,
- tag: JSON.stringify(row.tags),
- identifier: row.doc_identifier,
- },
- });
- // 这里可以添加详情处理逻辑
- } catch (error) {
- this.$message.error("获取详情失败");
- }
- },
- // Tab切换处理
- handleClick(tab) {
- // 根据tab加载相应数据
- switch (tab.name) {
- case "second":
- this.loadSotaDetails();
- break;
- case "third":
- this.loadSotaSummary();
- break;
- }
- },
- // 加载SOTA详情数据
- async loadSotaDetails() {
- try {
- // 这里调用API获取SOTA详情数据
- const response = await getSotaDetails();
- this.sotaDetailsList = response.data;
- } catch (error) {
- /* this.$message.error("获取SOTA详情失败");
- console.error(error); */
- }
- },
- // 加载SOTA汇总表数据
- async loadSotaSummary() {
- try {
- // 这里调用API获取SOTA汇总数据
- const response = await getSotaSummary();
- this.sotaSummaryList = response.data;
- } catch (error) {
- /* this.$message.error("获取SOTA汇总数据失败");
- console.error(error); */
- }
- },
- },
- // 在组件销毁时清理所有轮询
- beforeDestroy() {
- Object.keys(this.pollingTimers).forEach((id) => {
- this.stopPolling(id);
- });
- },
- };
- </script>
- <style scoped>
- .gpu-list {
- padding: 20px;
- }
- .filter-section {
- margin-bottom: 20px;
- }
- .ml-15 {
- margin-left: 15px;
- }
- .pagination {
- display: flex;
- justify-content: flex-end;
- margin-top: 15px;
- }
- </style>
|