| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121 |
- <template>
- <div class="project-search">
- <div class="file-categories">
- <el-button type="primary" @click="createNewFolder">
- <i class="el-icon-plus"></i> 新建目录
- </el-button>
- <p>{{ $route.query.name }}</p>
- <el-tree
- :data="folders"
- :props="defaultProps"
- @node-click="handleNodeClick"
- ref="folderTree"
- :default-expanded-keys="['0']"
- node-key="id"
- highlight-current
- >
- <span class="custom-tree-node" slot-scope="{ node, data }">
- <span class="tree_title">
- <i class="el-icon-folder"></i>
- <span class="folder-name" :title="node.label">{{
- node.label
- }}</span>
- </span>
- <span v-if="data.id !== '001'" :class="getFileCountClass(data.id)"
- >{{ data.document_count }} files</span
- >
- <span
- class="folder-actions"
- v-if="data.id !== 0 && data.id !== '001'"
- >
- <el-tooltip
- class="item"
- effect="dark"
- content="编辑"
- placement="top"
- >
- <i class="el-icon-edit" @click.stop="editFolder(data)"></i>
- </el-tooltip>
- <el-tooltip
- class="item"
- effect="dark"
- content="删除"
- placement="top"
- >
- <i class="el-icon-delete" @click.stop="deleteFolder(data.id)"></i>
- </el-tooltip>
- </span>
- </span>
- </el-tree>
- </div>
- <div class="right">
- <dataSearch
- @bindSetQuery="setQuery"
- @refreshFolders="typeList"
- :currentFolderId="queryForm.doc_type_id"
- ></dataSearch>
- <!-- <dataList
- :queryForm="queryForm"
- :allowEdit="checkAuth('/document/update')"
- :allowDelete="checkAuth('/document/delete')"
- ></dataList> -->
- <div
- class="data-list"
- v-loading="loading"
- element-loading-text="加载中..."
- >
- <div class="batch-actions" style="margin: 10px 0">
- <el-dropdown
- @command="handleBatchCommand"
- :disabled="!selectedRows.length"
- >
- <el-button type="primary" style="color: #fff">
- 批量操作
- <i data-feather="chevron-down" class="el-icon--right icons"></i>
- </el-button>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="analysis">
- <i data-feather="play" class="icons"></i> 批量解析
- </el-dropdown-item>
- <el-dropdown-item command="generateQa">
- <i data-feather="message-square" class="icons"></i> 生成问答对
- </el-dropdown-item>
- <el-dropdown-item command="modifyFolder">
- <i data-feather="folder" class="icons"></i> 批量修改目录
- </el-dropdown-item>
- <el-dropdown-item command="delete">
- <i data-feather="trash-2" class="icons"></i> 批量删除
- </el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- <el-button type="danger" @click="endAnalysis()">
- <i data-feather="stop-circle" class="icons"></i>
- 终止所有任务
- </el-button>
- <el-button type="primary" @click="exportData()">
- <i data-feather="download" class="icons"></i> 导出问答对
- </el-button>
- </div>
- <div class="selection-control" v-if="selectedRows.length > 0">
- <el-alert
- type="info"
- show-icon
- :closable="false"
- style="margin-bottom: 10px"
- >
- <template v-if="!isAllDataSelected">
- <!-- <span>已选择 {{ selectedRows.length }} 项</span> -->
- <span
- type="text"
- style="cursor: pointer; color: #409eff; margin-left: 10px"
- @click="handleSelectAllData"
- >
- 选择全部{{ recordCount }}条数据
- </span>
- </template>
- <template v-else>
- <span>已选择全部{{ recordCount }}条数据</span>
- <span
- type="text"
- style="cursor: pointer; color: #409eff; margin-left: 10px"
- @click="handleCancelAllSelection"
- >
- 取消全选
- </span>
- </template>
- </el-alert>
- </div>
- <el-table
- ref="dataTable"
- :data="dataList"
- style="width: 100%; font-size: 12px"
- header-row-class-name="headerBg"
- empty-text="暂无数据"
- @selection-change="handleSelectionChange"
- @sort-change="handleSortChange"
- :row-key="getRowKey"
- >
- <el-table-column
- type="selection"
- width="55"
- :reserve-selection="true"
- ></el-table-column>
- <el-table-column prop="id" label="ID" align="center" width="80" />
- <el-table-column prop="name" label="文件名称" sortable >
- <template #default="scope">
- <span>{{ scope.row.name }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="type" label="文件类型" align="center" />
- <el-table-column prop="qa_count" label="问答对数" align="center"></el-table-column>
- <el-table-column prop="chunk_num" label="分块数" align="center" />
- <el-table-column
- prop="create_time"
- label="上传时间"
- align="center"
- sortable
- width="140"
- />
- <el-table-column prop="run" label="解析状态" align="center">
- <template #default="scope">
- <el-tooltip
- effect="dark"
- placement="top"
- :disabled="
- ![1, 4, 7].includes(Number(scope.row.run))
- "
- >
- <template #content>
- <div style="padding: 5px">
- <div style="margin-top: 5px; font-size: 12px">
- {{
- Number(scope.row.run) === 7
- ? (scope.row.progress_msg || "正在生成问答对...")
- : (scope.row.progress_msg || "正在解析中...")
- }}
- </div>
- </div>
- </template>
- <div class="status-wrapper">
- <template v-if="Number(scope.row.run) === 1||Number(scope.row.run) === 5">
- <div class="progress-wrapper">
- <el-progress
- type="circle"
- :percentage="Math.floor(scope.row.progress) || 0"
- :width="30"
- :stroke-width="2"
- :format="percentFormat"
- ></el-progress
- ><!-- :status="getProgressStatus(scope.row.progress)" -->
- </div>
- </template>
- <template v-else>
- <el-tag :type="getStatusType(scope.row.run)" size="small">
- {{ getStatusText(scope.row.run) }}
- </el-tag>
- </template>
- </div>
- </el-tooltip>
- </template>
- </el-table-column>
- <el-table-column
- label="操作"
- align="center"
- fixed="right"
- width="180"
- >
- <template #default="scope">
- <div class="operations-container">
- <el-tooltip
- class="item"
- effect="dark"
- content="预览"
- placement="top"
- >
- <el-button
- type="text"
- size="small"
- circle
- icon="el-icon-view"
- v-if="checkAuth('/document/update')"
- style="font-size: 15px"
- @click="getName(scope.row)"
- ></el-button>
- </el-tooltip>
- <el-tooltip
- class="item"
- effect="dark"
- content="修改文件名"
- placement="top"
- >
- <el-button
- type="text"
- size="small"
- circle
- icon="el-icon-edit"
- v-if="checkAuth('/document/update')"
- style="font-size: 15px"
- @click="btnEdit(scope.row)"
- ></el-button>
- </el-tooltip>
- <el-popover
- placement="bottom"
- trigger="click"
- popper-class="operations-popover"
- >
- <template #reference>
- <el-button
- type="text"
- size="small"
- circle
- class="operation-button"
- style="font-size: 15px; margin-left: 10px"
- icon="el-icon-more"
- ></el-button>
- </template>
- <div class="additional-operations">
- <el-tooltip
- class="item"
- effect="dark"
- :content="
- scope.row.run == 1 || scope.row.run == 5
- ? `解析中`
- : '解析'
- "
- placement="top"
- >
- <el-button
- v-if="scope.row.run != 1 && scope.row.run != 5"
- type="text"
- icon="el-icon-caret-right"
- circle
- @click="analysis(scope.row)"
- style="font-size: 15px"
- >
- </el-button>
- <el-button
- v-else
- type="text"
- icon="el-icon-loading"
- circle
- :disabled="true"
- style="font-size: 15px"
- >
- </el-button>
- </el-tooltip>
- <el-tooltip
- class="item"
- effect="dark"
- content="查看问答对"
- placement="top"
- >
- <el-button
- type="text"
- size="small"
- circle
- icon="el-icon-receiving"
- @click="getQa(scope.row.id)"
- style="font-size: 15px"
- ></el-button>
- </el-tooltip>
- <el-tooltip
- class="item"
- effect="dark"
- content="解析方法"
- placement="top"
- >
- <el-button
- type="text"
- size="small"
- circle
- icon="el-icon-tickets"
- v-if="checkAuth('/document/update')"
- style="font-size: 15px"
- @click="Analytical(scope.row)"
- ></el-button>
- </el-tooltip>
- <el-tooltip
- class="item"
- effect="dark"
- content="下载"
- placement="top"
- >
- <el-button
- type="text"
- size="small"
- circle
- icon="el-icon-download"
- @click="btnDown(scope.row)"
- :loading="scope.row.downloading"
- style="font-size: 15px"
- ></el-button>
- </el-tooltip>
- <el-tooltip
- class="item"
- effect="dark"
- content="删除"
- placement="top"
- >
- <el-button
- type="text"
- size="small"
- circle
- icon="el-icon-delete"
- v-if="checkAuth('/document/delete')"
- @click="btnDelete(scope.row.id)"
- style="font-size: 15px"
- ></el-button>
- </el-tooltip>
- </div>
- </el-popover>
- </div>
- </template>
- </el-table-column>
- </el-table>
- <div class="page-info">
- <el-pagination
- :currentPage="queryForm.page"
- :page-size="queryForm.pageSize"
- :total="recordCount"
- :page-count="pageTotal"
- :page-sizes="[10, 20, 50, 100]"
- background
- layout="total,sizes, prev, pager, next"
- @current-change="ChangePage"
- @size-change="handleSizeChange"
- >
- </el-pagination>
- </div>
- <el-dialog
- title="修改名称"
- :visible.sync="dialogVisible"
- width="30%"
- :before-close="handleClose"
- >
- <el-form :model="wordForm" ref="wordRef" :rules="wordRules">
- <el-form-item label="文件名称:" prop="new_name">
- <el-input
- v-model="wordForm.new_name"
- placeholder="请输入文件名称"
- ></el-input>
- </el-form-item>
- </el-form>
- <span slot="footer" class="dialog-footer">
- <el-button @click="handleClose">取 消</el-button>
- <el-button type="primary" @click="submitBuck">确 定</el-button>
- </span>
- </el-dialog>
- <!-- 解析方法 -->
- <el-dialog
- title="解析方法"
- :visible.sync="anaDialogVisible"
- width="30%"
- :before-close="handleAnalClose"
- >
- <el-form
- :model="analForm"
- ref="analRef"
- label-position="top"
- :rules="analRules"
- >
- <el-form-item label="语言选择:" prop="language">
- <el-radio-group v-model="analForm.language">
- <el-radio label="zh">中文</el-radio>
- <el-radio label="en">英文</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="页码范围:" prop="new_name">
- <el-input-number
- v-model="analForm.start_page"
- controls-position="right"
- :min="1"
- ></el-input-number>
- <el-input-number
- v-model="analForm.end_page"
- controls-position="right"
- :min="1"
- style="margin-left: 10px"
- ></el-input-number>
- </el-form-item>
- <el-form-item label="块token数">
- <div class="block">
- <el-slider v-model="analForm.token_num" :max="2048" show-input>
- </el-slider>
- </div>
- </el-form-item>
- </el-form>
- <span slot="footer" class="dialog-footer">
- <el-button type="primary" @click="handleAnalClose">取 消</el-button>
- <el-button type="primary" @click="submitAnal">确 定</el-button>
- </span>
- </el-dialog>
- <el-dialog
- title="新建目录"
- :visible.sync="newFolderDialogVisible"
- width="30%"
- >
- <el-form
- :model="newFolderForm"
- :rules="newFolderRules"
- ref="newFolderFormRef"
- >
- <el-form-item label="文件夹名称" prop="name">
- <el-input v-model="newFolderForm.name"></el-input>
- </el-form-item>
- </el-form>
- <span slot="footer" class="dialog-footer">
- <el-button type="primary" @click="newFolderDialogVisible = false"
- >取 消</el-button
- >
- <el-button type="primary" @click="submitNewFolder">确 定</el-button>
- </span>
- </el-dialog>
- <!-- 批量修改目录 -->
- <el-dialog
- title="批量修改目录"
- :visible.sync="batchModifyFolderDialogVisible"
- width="30%"
- >
- <el-form
- :model="batchModifyFolderForm"
- :rules="batchModifyFolderRules"
- ref="batchModifyFolderFormRef"
- >
- <el-form-item label="选择目录" prop="folderId">
- <el-select
- v-model="batchModifyFolderForm.folderId"
- placeholder="请选择目录"
- >
- <el-option
- v-for="folder in folders.filter((f) => f.id !== 0)"
- :key="folder.id"
- :label="folder.name"
- :value="folder.id"
- >
- </el-option>
- </el-select>
- </el-form-item>
- </el-form>
- <span slot="footer" class="dialog-footer">
- <el-button
- type="primary"
- @click="batchModifyFolderDialogVisible = false"
- >取 消</el-button
- >
- <el-button type="primary" @click="submitBatchModifyFolder"
- >确 定</el-button
- >
- </span>
- </el-dialog>
- <!-- 问答对弹窗 -->
- <el-dialog
- title="问答对"
- :visible.sync="qaDialogVisible"
- width="80%"
- :before-close="handleQaDialogClose"
- >
- <div class="qa-dialog-content">
- <div class="qa-dialog-header">
- <el-tag>文档ID: {{ currentDocumentId }}</el-tag>
- <el-tag type="success" v-if="qaList.length">
- 共 {{ qaList.length }} 个问答对
- </el-tag>
- </div>
- <div class="qa-content" v-loading="qaLoading">
- <div v-if="qaList.length === 0 && !qaLoading" class="empty-state">
- <i class="el-icon-document"></i>
- <p>暂无问答对数据</p>
- </div>
- <div v-else class="qa-list">
- <div
- v-for="(item, index) in qaList"
- :key="index"
- class="qa-item"
- >
- <div class="qa-question">
- <div class="qa-label">问:</div>
- <div class="qa-text">{{ item.question }}</div>
- </div>
- <div class="qa-answer">
- <div class="qa-label">答:</div>
- <div class="qa-text">{{ item.answer }}</div>
- </div>
- <div class="qa-meta" v-if="item.confidence || item.source">
- <el-tag size="mini" v-if="item.confidence">
- 置信度: {{ item.confidence }}
- </el-tag>
- <el-tag size="mini" type="info" v-if="item.source">
- 来源: {{ item.source }}
- </el-tag>
- </div>
- </div>
- </div>
- </div>
- </div>
- <span slot="footer" class="dialog-footer">
- <el-button
- type="primary"
- icon="el-icon-refresh"
- @click="fetchQAData"
- :loading="qaLoading"
- >
- 刷新数据
- </el-button>
- <el-button @click="handleQaDialogClose">关闭</el-button>
- </span>
- </el-dialog>
- </div>
- </div>
- </div>
- </template>
-
- <script>
- import { mapGetters } from "vuex";
- import { dataSearch, dataList } from "./components";
- import {
- getBucketContents,
- deleteFile,
- nameGetUrl,
- renameFile,
- analysis,
- batchAnalysis,
- getRunStatus,
- insertType,
- updateType,
- selectTypeList,
- deleteType,
- Info,
- batchMove,
- selectType0,
- delDocumentList,
- getdocpro,
- analysisPro,
- resultTask,
- endClear,
- generateQa,
- } from "@/api/knowledge";
- import { exportQaToExcel,queryDocumentContent } from "@/api/document";
- import { validateExportParams, logJSON, checkJSONSize } from "@/utils/data-validator";
- export default {
- components: {
- dataSearch,
- dataList,
- },
- computed: {
- ...mapGetters(["roleInfo", "authList"]),
- },
- data() {
- return {
- queryForm: {
- page: 1,
- pageSize: 10,
- bucket_id: "",
- doc_type_id: 0,
- },
- typeForm: {
- page: 1,
- pageSize: 9999,
- kb_id: "",
- },
- folders: [{ id: "001", name: "全部", document_count: 0 }],
- defaultProps: {
- children: "children",
- label: "name",
- },
- // dataList 组件的数据
- loading: false,
- dialogVisible: false,
- currentDataId: 0,
- recordCount: 0,
- pageTotal: 1,
- dataList: [],
- currentData: {},
- wordForm: {
- document_id: "",
- new_name: "",
- },
- wordRules: {
- new_name: [
- { required: true, message: "请输文件名称", trigger: "blur" },
- ],
- },
- anaDialogVisible: false,
- analForm: {
- start_page: 1,
- end_page: 10000,
- token_num: 512,
- language: "en",
- },
- analRules: {},
- selectedRows: [],
- sortColumn: "",
- sortOrder: "",
- analysisStatusCheckers: {},
- newFolderDialogVisible: false,
- newFolderForm: {
- name: "",
- kb_id: "",
- status: 5,
- },
- newFolderRules: {
- name: [
- { required: true, message: "请输入文件夹名称", trigger: "blur" },
- ],
- },
- /* 批量修改目录 */
- batchModifyFolderDialogVisible: false,
- batchModifyFolderForm: {
- folderId: null,
- },
- batchModifyFolderRules: {
- folderId: [
- { required: true, message: "请选择目标目录", trigger: "change" },
- ],
- },
- selectedRows: [], // 已选择的行
- allSelectedRows: new Map(), // 存储所有选中的行
- isAllDataSelected: false, // 是否选中所有数据
- /* 问答对弹窗 */
- qaDialogVisible: false,
- currentDocumentId: null,
- qaList: [],
- qaLoading: false,
- };
- },
- mounted() {
- this.queryForm.bucket_id = this.$route.query.id;
- this.typeForm.kb_id = this.$route.query.id;
- /* this.$nextTick(() => {
- this.initializeTree();
- }); */
- this.typeList();
- /* this.search(); */
- },
- beforeDestroy() {
- Object.values(this.analysisStatusCheckers).forEach(clearTimeout);
- },
- methods: {
- /* 导出 */
- async exportData() {
- try {
- // 显示加载状态
- const loading = this.$loading({
- lock: true,
- text: '正在导出,请稍候...',
- spinner: 'el-icon-loading',
- background: 'rgba(0, 0, 0, 0.7)'
- });
- // 准备导出参数
- const exportParams = {
- kb_id: this.queryForm.bucket_id, // 知识库ID
- doc_type_id: this.queryForm.doc_type_id === 0 ? null : this.queryForm.doc_type_id, // 目录ID,0表示全部
- export_to_local: true,
- };
- // 如果有选中的文档,只导出选中的
- if (this.selectedRows.length > 0) {
- exportParams.document_ids = this.selectedRows.map(row => row.id);
- }
- // 验证和清理导出参数
- const validation = validateExportParams(exportParams);
-
- if (!validation.isValid) {
- loading.close();
- this.$message.error(`参数验证失败: ${validation.errors.join(', ')}`);
- return;
- }
- if (validation.warnings.length > 0) {
- console.warn('参数警告:', validation.warnings);
- }
- // 使用清理后的参数
- const finalParams = validation.cleanedParams;
-
- // 检查JSON数据大小
- const sizeInfo = checkJSONSize(finalParams);
- if (sizeInfo.isLarge) {
- console.warn(`导出数据较大: ${sizeInfo.kb}KB`);
- }
- // 日志输出
- logJSON(finalParams, '最终导出参数');
- // 调用导出接口
- const response = await exportQaToExcel(finalParams);
- console.log(response);
-
- // 检查响应格式
- if (response.status === 200) {
- const { data } = response;
- const { message, data: exportData } = data;
-
- // 如果有下载链接,直接使用浏览器下载
- if (exportData && exportData.download_url) {
- // 直接打开新窗口下载
- const url=process.env.VUE_APP_BASE_API+exportData.download_url
- console.log(url);
- window.open(url, '_blank');
- loading.close();
- this.$message.success(message || '导出成功!');
- } else {
- loading.close();
- this.$message.error('获取下载链接失败');
- }
- } else {
- loading.close();
- this.$message.error('导出请求失败');
- }
- } catch (error) {
- console.error('导出失败:', error);
- this.$message.error('导出失败,请稍后重试');
- if (loading) loading.close();
- }
- },
- // 下载文件的通用方法
- downloadFile(downloadUrl, fileName) {
- try {
- const link = document.createElement('a');
- link.href = downloadUrl;
- link.download = fileName || `问答对导出_${new Date().toISOString().slice(0, 10)}.xlsx`;
- link.target = '_blank'; // 在新窗口打开,避免跨域问题
-
- // 触发下载
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
-
- this.$message.success('文件下载已开始!');
- } catch (error) {
- console.error('下载失败:', error);
- this.$message.error('文件下载失败,请稍后重试');
- }
- },
- /* 查看问答对 */
- getQa(id) {
- this.currentDocumentId = id;
- this.qaDialogVisible = true;
- this.fetchQAData();
- },
-
- /* 获取问答对数据 */
- async fetchQAData() {
- if (!this.currentDocumentId) return;
-
- this.qaLoading = true;
- try {
- const response = await queryDocumentContent({
- document_id: this.currentDocumentId
- });
-
- if (response.status === 200 ) {
- // 根据接口返回的数据结构调整
- this.qaList = response.data[0].qa_pairs || response.result || [];
-
- // 如果接口返回的不是数组格式,进行处理
- if (!Array.isArray(this.qaList)) {
- if (this.qaList.items) {
- this.qaList = this.qaList.items;
- } else if (this.qaList.qa_pairs) {
- this.qaList = this.qaList.qa_pairs;
- console.log(this.qaList);
- } else {
- this.qaList = [];
- }
- }
-
- if (this.qaList.length === 0) {
- this.$message.info('该文档暂无问答对数据');
- }
- } else {
- this.$message.error(response.message || '获取问答对数据失败');
- this.qaList = [];
- }
- } catch (error) {
- console.error('获取问答对数据失败:', error);
- this.$message.error('获取问答对数据失败,请稍后重试');
- this.qaList = [];
- } finally {
- this.qaLoading = false;
- }
- },
-
- /* 关闭问答对弹窗 */
- handleQaDialogClose() {
- this.qaDialogVisible = false;
- this.currentDocumentId = null;
- this.qaList = [];
- },
- // 获取行的唯一标识
- getRowKey(row) {
- return row.id;
- },
- /* 功按钮 */
- handleBatchCommand(command) {
- switch (command) {
- case "analysis":
- this.batchAnalysis();
- break;
- case "generateQa":
- this.batchGenerateQa();
- break;
- case "modifyFolder":
- this.batchModifyFolder();
- break;
- case "delete":
- this.batchDelect();
- break;
- }
- },
- // 批量生成问答对
- batchGenerateQa() {
- if (this.selectedRows.length === 0) {
- this.$message.warning("请选择要生成问答对的文件");
- return;
- }
- const loading = this.$loading({
- lock: true,
- text: '正在生成问答对,请稍候...',
- spinner: 'el-icon-loading',
- background: 'rgba(0, 0, 0, 0.7)'
- });
- const selectedIds = this.selectedRows.map(row => row.id);
- generateQa({
- document_ids: JSON.stringify(selectedIds)
- }).then((res) => {
- console.log('生成问答对响应:', res);
- if (res.status === 200) {
- this.$message.success('问答对生成任务已提交');
- // 更新选中文档的状态
- this.selectedRows.forEach(row => {
- this.$set(row, 'run', 6); // 设置状态为"待生成问答对"
- this.startAnalysisStatusChecker(row); // 开始检查状态
- });
- this.clearSelection(); // 清除选择
- } else {
- this.$message.error(res.data?.message || '生成问答对失败');
- }
- }).catch(error => {
- console.error('生成问答对时出错:', error);
- this.$message.error('生成问答对失败,请稍后重试');
- }).finally(() => {
- loading.close();
- });
- },
- getProgressStatus(progress) {
- // el-progress 只接受 'success'/'exception'/'warning' 这几个值
- if (progress >= 100) {
- return "success";
- }
- // 如果进度小于100,返回undefined,使用默认样式
- return undefined;
- },
- /* 操作栏 */
- handleCommand(command, row) {
- switch (command) {
- case "analysis":
- this.analysis(row);
- break;
- case "analyticalMethod":
- this.Analytical(row);
- break;
- case "download":
- this.btnDown(row);
- break;
- case "delete":
- this.btnDelete(row.id);
- break;
- }
- },
- /* 状态展示 */
- getStatusType(status) {
- const statusMap = {
- 0: "info", // 未解析
- 1: "warning", // 解析中
- 3: "success", // 解析成功,问答对生成成功
- 4: "danger", // 解析失败
- 5: "info", // 待解析
- 6: "warning", // 待生成问答对
- 7: "danger" // 解析成功,问答对生成失败
- };
- return statusMap[status] || "info";
- },
- getStatusText(status) {
- const statusMap = {
- 0: "未解析",
- 1: "解析中",
- 3: "处理成功",
- 4: "解析失败",
- 5: "待解析",
- 6: "待生成问答对",
- 7: "处理失败"
- };
- return statusMap[status] || "未知状态";
- },
- /* 判断类名 */
- getFileCountClass(id) {
- const isSpecialFolder = id === 0 || id === "001";
- console.log(
- `ID: ${id}, Class: ${isSpecialFolder ? "file-counts" : "file-count"}`
- );
- return isSpecialFolder ? "file-counts" : "file-count";
- },
- /* 批量修改目录 */
- batchModifyFolder() {
- if (this.selectedRows.length === 0) {
- this.$message.warning("请选择要修改目录的文件");
- return;
- }
- this.batchModifyFolderDialogVisible = true;
- },
- submitBatchModifyFolder() {
- this.$refs.batchModifyFolderFormRef.validate((valid) => {
- if (valid) {
- const selectedIds = this.selectedRows.map((row) => row.id);
- console.log(selectedIds);
- batchMove({
- ids: JSON.stringify(selectedIds),
- doc_type_id: this.batchModifyFolderForm.folderId,
- })
- .then((res) => {
- if (res.status === 200) {
- this.$message.success("批量修改目录成功");
- this.batchModifyFolderDialogVisible = false;
- this.search(); // Refresh the document list
- this.typeList(); // Refresh the folder list
- this.clearSelection();
- } else {
- this.$message.error("批量修改目录失败");
- }
- })
- .catch((error) => {
- console.error("批量修改目录时出错:", error);
- this.$message.error("批量修改目录时出错");
- });
- }
- });
- },
- editFolder(folder) {
- this.$prompt("请输入新的文件夹名称", "编辑文件夹", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- inputValue: folder.name,
- inputValidator: (value) => {
- if (!value) {
- return "文件夹名称不能为空";
- }
- return true;
- },
- })
- .then(({ value }) => {
- if (value !== folder.name) {
- const updatedFolder = { ...folder, name: value };
- updateType(updatedFolder)
- .then((res) => {
- if (res.status === 200) {
- this.$message.success("更新文件夹成功");
- this.typeList(); // 刷新文件夹列表
- } else {
- this.$message.error("更新文件夹失败");
- }
- })
- .catch((error) => {
- console.error("更新文件夹时出错:", error);
- this.$message.error("更新文件夹时出错");
- });
- }
- })
- .catch(() => {
- // 用户取消操作,不做任何处理
- });
- },
- deleteFolder(folderId) {
- this.$confirm("确定要删除该文件夹吗?删除后无法恢复。", "警告", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning",
- })
- .then(() => {
- deleteType({ id: folderId })
- .then((res) => {
- if (res.status === 200) {
- this.$message.success("删除文件夹成功");
- this.typeList(); // 刷新文件夹列表
- } else {
- this.$message.error("删除文件夹失败");
- }
- })
- .catch((error) => {
- console.error("删除文件夹时出错:", error);
- this.$message.error("删除文件夹时出错");
- });
- })
- .catch(() => {
- // 用户取消删除操作,不做任何处理
- });
- },
- /* 目录初始化 */
- typeList() {
- this.loading = true;
- Promise.all([
- selectTypeList(this.typeForm),
- selectType0({ kb_id: this.typeForm.kb_id, type_id: 0 }),
- ])
- .then(([typeListRes, type0Res]) => {
- if (typeListRes.status === 200 && type0Res.status === 200) {
- const folderList = typeListRes.data.dataList.map((folder) => ({
- ...folder,
- id: folder.id === 0 ? "001" : folder.id.toString(),
- document_count: folder.document_count || 0,
- }));
- // Calculate total documents
- const totalDocuments = folderList.reduce(
- (sum, folder) => sum + folder.document_count,
- 0
- );
- // Get the count of "其他" documents from selectType0 response
- const otherFolderCount = type0Res.data || 0;
- this.folders = [
- {
- id: "001",
- name: "全部",
- document_count: totalDocuments + otherFolderCount,
- },
- ...folderList.filter(
- (folder) => folder.id !== "001" && folder.id !== 0
- ),
- {
- id: 0,
- name: "其他",
- document_count: otherFolderCount,
- },
- ];
- // 直接在这里执行一次性的初始化
- this.$nextTick(() => {
- if (this.$refs.folderTree) {
- this.$refs.folderTree.setCurrentKey("001");
- // 只在这里调用一次 search
- this.queryForm.doc_type_id = "";
- this.search();
- }
- });
- } else {
- this.$message.error("获取文件夹列表败");
- }
- })
- .catch((error) => {
- console.error("获取文件夹列表时出错:", error);
- this.$message.error("获取文件夹列表时出错");
- })
- .finally(() => {
- this.loading = false;
- });
- },
- /* initializeTree() {
- this.$nextTick(() => {
- if (this.$refs.folderTree) {
- this.$refs.folderTree.setCurrentKey(0);
- this.handleNodeClick(this.folders[0]);
- }
- });
- }, */
- createNewFolder() {
- this.newFolderDialogVisible = true;
- },
- /* 新增 */
- submitNewFolder() {
- this.$refs.newFolderFormRef.validate((valid) => {
- if (valid) {
- this.newFolderForm.kb_id = this.$route.query.id;
- insertType(this.newFolderForm).then((res) => {
- if (res.status === 200) {
- this.$message.success("创建文件夹成功");
- this.newFolderDialogVisible = false;
- this.$refs.newFolderFormRef.resetFields();
- this.typeList(); // Refresh folder list
- } else {
- this.$message.error("创建文件夹失败");
- }
- });
- }
- });
- },
- // 移除或简化 initializeTree 方法,因为相关逻辑已经到 typeList 中
- initializeTree() {
- // 可以保留这个方法但不执行 search
- this.$nextTick(() => {
- if (this.$refs.folderTree) {
- this.$refs.folderTree.setCurrentKey("001");
- }
- });
- },
- /* initializeTree() {
- this.$nextTick(() => {
- if (this.$refs.folderTree) {
- this.$refs.folderTree.setCurrentKey("001");
- this.handleNodeClick(this.folders[0]);
- }
- });
- }, */
- checkAuth(path) {
- if (this.roleInfo.is_admin === 1) {
- return true;
- }
- return this.authList.some(
- (auth) => auth.type === 999 && auth.path === path
- );
- },
- setQuery(e) {
- this.queryForm = { ...this.queryForm, ...e };
- this.search();
- },
- handleNodeClick(data) {
- this.queryForm.doc_type_id = data.id === "001" ? "" : data.id;
- this.queryForm.page = 1; // Reset to first page when changing folder
- this.search();
- },
- /*列表事件 */
- /* 排序 */
- handleSortChange({ prop, order }) {
- this.sortColumn = prop;
- this.sortOrder = order;
- this.sortData();
- },
- sortData() {
- const { sortColumn, sortOrder } = this;
- if (!sortColumn || !sortOrder) {
- this.search(); // Reset to original order
- return;
- }
- this.dataList.sort((a, b) => {
- let comparison = 0;
- if (sortColumn === "name") {
- comparison = a.name.localeCompare(b.name, "zh-CN");
- } else if (sortColumn === "create_time") {
- comparison = new Date(a.create_time) - new Date(b.create_time);
- }
- return sortOrder === "ascending" ? comparison : -comparison;
- });
- },
- /* 处理选择变化*/
- handleSelectionChange(selection) {
- if (!this.isAllDataSelected) {
- // 更新当前页选中状态
- this.dataList.forEach((row) => {
- if (selection.find((item) => item.id === row.id)) {
- this.allSelectedRows.set(row.id, row);
- } else {
- this.allSelectedRows.delete(row.id);
- }
- });
- this.selectedRows = Array.from(this.allSelectedRows.values());
- }
- },
- // 选择全部数据
- async handleSelectAllData() {
- try {
- // 构建查询参数,获取所有数据
- const params = {
- ...this.queryForm,
- page: 1,
- page_size: this.recordCount,
- };
- const response = await getBucketContents(params);
- if (response.status === 200) {
- const allData = response.data.documents;
- // 清空之前的选择
- this.allSelectedRows.clear();
- // 将所有数据添加到选中集合
- allData.forEach((item) => {
- this.allSelectedRows.set(item.id, item);
- });
- this.isAllDataSelected = true;
- this.selectedRows = allData;
- // 选中当前页显示的所有行
- this.$nextTick(() => {
- if (this.$refs.dataTable) {
- this.dataList.forEach((row) => {
- this.$refs.dataTable.toggleRowSelection(row, true);
- });
- }
- });
- this.$message.success(`已选中全部${this.recordCount}条数据`);
- }
- } catch (error) {
- console.error("获取全部数据失败:", error);
- this.$message.error("选择全部数据失败");
- }
- },
- // 取消全选
- handleCancelAllSelection() {
- this.clearSelection();
- this.isAllDataSelected = false;
- this.$message.info("已取消全部选择");
- },
- // 修改清除选择方法
- clearSelection() {
- if (this.$refs.dataTable) {
- this.$refs.dataTable.clearSelection();
- }
- this.selectedRows = [];
- this.allSelectedRows.clear();
- this.isAllDataSelected = false;
- },
- // 修改分页方法,保持选中状态
- ChangePage(e) {
- this.queryForm.page = e;
- this.search().then(() => {
- this.$nextTick(() => {
- if (this.$refs.dataTable) {
- this.dataList.forEach((row) => {
- if (this.isAllDataSelected || this.allSelectedRows.has(row.id)) {
- this.$refs.dataTable.toggleRowSelection(row, true);
- }
- });
- }
- });
- });
- },
- batchAnalysis() {
- const selectedIds = this.selectedRows.map((row) => row.id);
- if (selectedIds.length === 0) {
- this.$message.warning("请选择要解析的文件");
- return;
- }
- this.$confirm("确定要批量解析选中的文件吗?", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning",
- })
- .then(() => {
- this.loading = true;
- analysisPro({
- document_ids: JSON.stringify(selectedIds),
- ocr_params: {
- language: this.analForm.language,
- max_retries: 3,
- timeout: [10, 180],
- },
- }) /* { ids: JSON.stringify(selectedIds) } */
- .then((res) => {
- if (res.status === 200) {
- this.$message.success("批量解析任务已提交");
- setTimeout(() => {
- this.updateAnalysisStatus(selectedIds);
- }, 5000);
- this.clearSelection();
- } else {
- this.$message.error("批量解析请求失败");
- }
- })
- .catch((error) => {
- console.error("批量解析错误:", error);
- this.$message.error("批量解析过程中出错误");
- })
- .finally(() => {
- this.loading = false;
- });
- })
- .catch(() => {
- // 取消操作
- });
- },
- /* 批量删除 */
- batchDelect() {
- const selectedIds = this.selectedRows.map((row) => row.id);
- if (selectedIds.length === 0) {
- this.$message.warning("请选择要删除的文件");
- return;
- }
- this.$confirm("确定要批量删除选中的文件吗?", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning",
- })
- .then(() => {
- this.loading = true;
- delDocumentList({ document_ids: JSON.stringify(selectedIds) })
- .then((res) => {
- if (res.status === 200) {
- this.$message.success("批量删除已完成");
- this.search();
- } else {
- this.$message.error("批量删除请求失败");
- }
- })
- .catch((error) => {
- /* console.error("批量删除错误:", error);
- this.$message.error("批量删除过程中出现错误"); */
- })
- .finally(() => {
- this.loading = false;
- });
- })
- .catch(() => {
- // 取消操作
- });
- },
- updateAnalysisStatus(ids) {
- this.dataList.forEach((row) => {
- if (ids.includes(row.id)) {
- row.run = 1; // 设置状态为"解析中"
- this.startAnalysisStatusChecker(row);
- }
- });
- },
- clearSelection() {
- this.$refs.dataTable.clearSelection();
- this.selectedRows = [];
- },
- /* 跳转页面 */
- getName(e) {
- /* this.$router.push({
- path: "/knowledge/category/infoList",
- query: { id: e.id, type: e.type },
- }); */
- let _this = this;
- let a = document.createElement("a");
- a.href = `#/infoList?id=${e.id}&type=${e.type.toLowerCase()}`; // 使用 hash
- a.target = "_blank";
- a.click();
- },
- /*终止 */
- endAnalysis() {
- endClear().then((res) => {
- if (res.status !== 200) return;
- this.search();
- });
- },
- /* 解析 */
- analysis(row) {
- if (row.run == 1 || row.run == 5 || row.run == 6) return;
- // Set the status to "解析中" (1) immediately
- this.$set(row, "run", 1);
- const analysisConfig = {
- document_ids: JSON.stringify([row.id]),
- start_page: row.start_page ?? 0, // 使用空值合并运算符
- end_page: row.end_page ?? 1000, // 使用空值合并运算符
- max_tokens: row.token_num,
- ocr_params: {
- language: this.analForm.language, //en,zh
- max_retries: 3,
- timeout: [10, 180],
- },
- };
- analysisPro(analysisConfig)
- .then((res) => {
- if (res.status === 200) {
- this.$set(row, "progress", 0);
- // Start checking the status immediately after successful API call
- setTimeout(() => {
- this.startAnalysisStatusChecker(row);
- }, 5000);
- } else {
- this.$message.error("解析请求失败");
- this.$set(row, "run", 0);
- }
- })
- .catch((error) => {
- console.error("解析错误:", error);
- this.$message.error("解析过程中出现错误");
- this.$set(row, "run", 0);
- });
- },
- /* 任务监控 */
- startAnalysisStatusChecker(row) {
- // 清除该行已存在的检查器
- if (this.analysisStatusCheckers[row.id]) {
- clearTimeout(this.analysisStatusCheckers[row.id]);
- }
- const checkStatus = () => {
- resultTask(row.id)
- .then((res) => {
- if (res.status === 200) {
- const newStatus = Number(res.data.document_status);
- const newProgress = Number(res.data.progress) === 100 ? 0 : Number(res.data.progress);
- const newProgressMsg = res.data.progress_msg;
- // 更新状态和进度
- this.$set(row, "run", newStatus);
- this.$set(row, "progress", newProgress);
- this.$set(row, "progress_msg", newProgressMsg);
- // 根据不同状态处理
- switch (newStatus) {
- case 3: // 解析成功
- this.$message.success("解析成功");
- delete this.analysisStatusCheckers[row.id];
- this.refreshCurrentList();
- break;
-
- case 4: // 解析失败
- this.$message.error(newProgressMsg || "解析失败");
- delete this.analysisStatusCheckers[row.id];
- break;
-
- case 1: // 解析中
- case 5: // 待解析
- case 6: // 待生成问答对
- case 7: // 解析成功,问答对生成失败
- // 设置检查间隔
- const checkInterval = newStatus === 6 ? 5000 : 15000;
-
- // 更新进度信息
- if (newStatus === 6) {
- this.$set(row, "progress_msg", "正在生成问答对...");
- } else if (newStatus === 7) {
- const progressMsg = res.data.Result?.message || "问答对生成失败";
- this.$set(row, "progress_msg", progressMsg);
- }
-
- // 继续检查状态
- this.analysisStatusCheckers[row.id] = setTimeout(checkStatus, checkInterval);
- break;
- }
- } else {
- this.$message.error("获取解析状态失败");
- delete this.analysisStatusCheckers[row.id];
- }
- })
- .catch((error) => {
- console.error("获取解析状态错误:", error);
- this.$message.error("获取解析状态时出现错误");
- delete this.analysisStatusCheckers[row.id];
- });
- };
- // 立即开始检查
- checkStatus();
- },
- // 修改 refreshCurrentList 方法
- refreshCurrentList() {
- // 保存当前页码和每页显示数量
- const currentPage = this.queryForm.page;
- const currentPageSize = this.queryForm.pageSize;
- // 重新获取数据
- return this.search()
- .then(() => {
- // 恢复之前的页码和每页显示数量
- this.queryForm.page = currentPage;
- this.queryForm.pageSize = currentPageSize;
- })
- .catch((error) => {
- console.error("刷新列表时出错:", error);
- this.$message.error("刷新列表失败,请稍后重试");
- });
- },
- handleAnalClose() {
- this.anaDialogVisible = false;
- },
- /* 确认 */
- submitAnal() {
- this.dataList.map((el) => {
- if (this.analForm.id == el.id) {
- el.language = this.analForm.language;
- el.start_page = this.analForm.start_page;
- el.end_page = this.analForm.end_page;
- el.token_num = this.analForm.token_num;
- }
- });
- this.anaDialogVisible = false;
- },
- /* 解析方法 */
- Analytical(e) {
- this.analForm.id = e.id;
- this.analForm.token_num = e.token_num;
- this.anaDialogVisible = true;
- },
- editWidth() {
- if (this.allowDelete && this.allowEdit) {
- return 200;
- }
- if (this.allowDelete || this.allowEdit) {
- return 120;
- }
- return 100;
- },
- onFocusVal(e) {
- let _this = this;
- _this.currentDataId = e.target.dataset.id;
- },
- onChangeVal(e) {
- let _this = this;
- let par = {
- id: _this.currentDataId,
- val: e,
- };
- },
- btnDelete(e) {
- let _this = this;
- let par = {
- document_id: e,
- };
- _this
- .$confirm("您是否确认删除该记录?", "提示", {
- confirmButtonText: "确认",
- cancelButtonText: "取消",
- type: "warning",
- })
- .then((res) => {
- deleteFile(par).then((res) => {
- if (res.status !== 200) return;
- _this.$message.success(res.data);
- _this.search();
- });
- })
- .catch(() => {});
- },
- searchData() {
- let _this = this;
- _this.dialogVisible = false;
- _this.search();
- },
- /* 关闭 */
- handleClose(done) {
- done();
- },
- /* 修改文件名 */
- btnEdit(e) {
- this.wordForm.new_name = e.name;
- this.wordForm.document_id = e.id;
- this.dialogVisible = true;
- },
- /* 提交 */
- submitBuck() {
- this.$refs.wordRef.validate((valid) => {
- if (valid) {
- renameFile(this.wordForm).then((res) => {
- if (res.status !== 200) return;
- this.search();
- this.dialogVisible = false;
- this.wordForm = {
- new_name: "",
- document_id: "",
- };
- });
- } else {
- this.$message.error("请填写文档名称");
- }
- });
- },
- //下载
- btnDown(e) {
- // Set downloading flag for this specific row
- this.$set(e, "downloading", true);
- nameGetUrl({
- document_id: e.id,
- })
- .then((res) => {
- if (res.status !== 200) {
- this.$message.error("获取下载链接失败");
- return;
- }
- return fetch(res.data.url);
- })
- .then((response) => response.blob())
- .then((blob) => {
- const url = window.URL.createObjectURL(blob);
- const link = document.createElement("a");
- link.href = url;
- link.download = e.name;
- document.body.appendChild(link);
- link.click();
- setTimeout(() => {
- document.body.removeChild(link);
- window.URL.revokeObjectURL(url);
- }, 100);
- })
- .catch((error) => {
- console.error("下载出错:", error);
- this.$message.error("下载失败,请稍后重试");
- })
- .finally(() => {
- // Reset downloading flag when done
- this.$set(e, "downloading", false);
- });
- },
- handleClose() {
- let _this = this;
- _this.currentData = {};
- _this.dialogVisible = false;
- },
- //搜索
- search() {
- let _this = this;
- _this.loading = true;
- return new Promise((resolve, reject) => {
- getBucketContents(_this.queryForm)
- .then((res) => {
- if (res.status !== 200) {
- reject(new Error("Invalid response status"));
- return;
- }
- _this.dataList = res.data.documents.map((el) => ({
- ...el,
- token_num: 512,
- start_page: _this.analForm.start_page,
- end_page: _this.analForm.end_page,
- }));
- // 获取失败状态的文档的失败原因
- const failedDocs = _this.dataList.filter(
- (doc) => Number(doc.run) === 4
- );
- if (failedDocs.length > 0) {
- Promise.all(
- failedDocs.map((doc) =>
- resultTask(doc.id)
- .then((res) => {
- if (res.status === 200) {
- // 找到对应的文档并更新其 progress_msg
- const docIndex = _this.dataList.findIndex(
- (item) => item.id === doc.id
- );
- if (docIndex !== -1) {
- _this.$set(
- _this.dataList[docIndex],
- "progress_msg",
- res.data.progress_msg
- );
- }
- }
- })
- .catch((error) => {
- console.error(
- `获取文档 ${doc.id} 的失败原因时出错:`,
- error
- );
- })
- )
- );
- }
- _this.pageTotal = res.data.pagination.total_count;
- _this.recordCount = res.data.pagination.total_count;
- _this.queryForm.pageSize = res.data.pagination.total_size;
- _this.loading = false;
- // Initialize the analysis status for each row
- _this.dataList.forEach((row) => {
- if (row.run == 1 || row.run == 5 || row.run == 6) {
- _this.startAnalysisStatusChecker(row);
- }
- });
- resolve();
- })
- .catch((error) => {
- _this.loading = false;
- reject(error);
- });
- });
- },
- // 处理每页显示数量变化
- handleSizeChange(val) {
- this.queryForm.pageSize = val;
- this.queryForm.page = 1;
- this.search().then(() => {
- // 恢复选中状态
- this.$nextTick(() => {
- this.dataList.forEach((row) => {
- if (this.pageSelected.has(row.id)) {
- this.$refs.dataTable.toggleRowSelection(row, true);
- }
- });
- });
- });
- },
- // 添加格式化方法
- percentFormat(percentage) {
- return `${percentage}%`;
- },
- },
- };
- </script>
-
- <style lang="scss" scoped>
- .project-search {
- display: flex;
- height: calc(100vh - 100px); // 假设顶部导栏高度为60px
- background-color: #f9fafb;
- .custom-tree-node {
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 8px 0;
- position: relative;
- .el-icon-folder {
- color: #409eff;
- margin-right: 8px;
- }
- .file-count {
- color: #909399;
- font-size: 12px;
- padding: 2px 6px;
- border-radius: 10px;
- transition: opacity 0.3s;
- }
- .file-counts {
- color: #909399;
- font-size: 12px;
- padding: 2px 6px;
- border-radius: 10px;
- transition: opacity 0.3s;
- }
- .folder-actions {
- position: absolute;
- right: 0;
- top: 50%;
- transform: translateY(-50%);
- display: none;
- padding-left: 10px;
- i {
- font-size: 16px;
- margin-left: 8px;
- color: #606266;
- cursor: pointer;
- &:hover {
- color: #409eff;
- }
- }
- }
- &:hover {
- .file-count {
- opacity: 0;
- }
- .folder-actions {
- display: inline-block;
- }
- }
- }
- .el-tree-node__content:hover {
- background-color: #f5f7fa;
- }
- .el-tree-node__content:hover {
- background-color: #f5f7fa;
- }
- .file-categories {
- flex: 0 0 280px;
- padding: 20px;
- background-color: #ffffff;
- box-shadow: 2px 0 10px rgba(0, 0, 0, 0.05);
- overflow-y: auto;
- .el-button {
- width: 100%;
- margin-bottom: 20px;
- }
- .el-tree {
- background-color: transparent;
- }
- }
- .right {
- flex: 1;
- padding: 20px;
- overflow-y: auto;
- min-width: 0;
- }
- .custom-tree-node {
- font-size: 14px;
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 8px 0;
- .el-icon-folder {
- color: #409eff;
- margin-right: 8px;
- }
- .file-count {
- color: #909399;
- font-size: 12px;
- background-color: #f0f2f5;
- padding: 2px 6px;
- border-radius: 10px;
- }
- .tree_title {
- display: flex;
- align-items: center;
- width: 140px;
- .folder-name {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: calc(100% - 24px); // 减去图标的宽度
- }
- }
- }
- }
- .el-tree {
- margin-left: 10px;
- }
- ::v-deep .el-tree-node__expand-icon {
- display: none;
- }
- ::v-deep .el-tag {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- height: auto;
- padding: 5px 10px;
- }
- .batch-actions {
- display: flex;
- gap: 10px;
- .el-dropdown {
- /* margin-right: auto; */
- }
- .icons {
- width: 15px;
- height: 15px;
- vertical-align: middle;
- margin-right: 4px;
- }
- }
- ::v-deep .el-dropdown-menu__item {
- display: flex;
- align-items: center;
- padding: 8px 16px;
- .icons {
- width: 14px;
- height: 14px;
- margin-right: 8px;
- }
- }
- @import "./components/dataList.scss";
- .status-wrapper {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- transition: none !important;
- }
- .progress-wrapper {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- padding: 2px;
- transition: none !important;
- ::v-deep .el-progress {
- line-height: 1;
- transition: none !important;
- .el-progress__text {
- font-size: 12px !important;
- color: inherit;
- transition: none !important;
- }
- .el-progress-circle {
- margin: 0;
- transition: none !important;
- }
- // 禁用 SVG 动画
- svg {
- transition: none !important;
- }
- // 禁用进度条路径动画
- .el-progress-circle__track,
- .el-progress-circle__path {
- transition: none !important;
- }
- }
- }
- // 添加选择提示区域样式
- .selection-control {
- margin-bottom: 10px;
- .el-alert {
- padding: 8px 16px;
- }
- }
- // 添加以下样式来处理表格响应式布局
- ::v-deep .el-table {
- width: 100% !important;
-
- // 设置表格在小屏幕时的行为
- &__body-wrapper {
- overflow-x: auto !important;
- }
-
- // 确保表格单元格内容在空间不足时正确换行
- .cell {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- // 文件名称列允许换行显示
- .el-table__row td:nth-child(3) .cell {
- white-space: normal;
- word-break: break-word;
- }
- }
- // 确保分页区域不会造成横向滚动
- .page-info {
- margin-top: 20px;
- display: flex;
- justify-content: flex-end;
- flex-wrap: wrap;
- }
- /* 问答对弹窗样式 */
- .qa-dialog-content {
- padding: 0;
- }
- .qa-dialog-header {
- margin-bottom: 20px;
- padding-bottom: 12px;
- border-bottom: 1px solid #e8e8e8;
- display: flex;
- gap: 8px;
- align-items: center;
- }
- .qa-content {
- min-height: 300px;
- max-height: 500px;
- overflow-y: auto;
- }
- .empty-state {
- text-align: center;
- padding: 60px 0;
- color: #999;
- }
- .empty-state i {
- font-size: 48px;
- color: #ddd;
- margin-bottom: 16px;
- display: block;
- }
- .empty-state p {
- margin: 0;
- font-size: 16px;
- }
- .qa-list {
- space-y: 20px;
- }
- .qa-item {
- background: #f8f9fa;
- border-radius: 8px;
- padding: 20px;
- margin-bottom: 16px;
- border-left: 4px solid #409eff;
- transition: all 0.3s ease;
- }
- .qa-item:hover {
- box-shadow: 0 2px 12px rgba(64, 158, 255, 0.1);
- }
- .qa-question, .qa-answer {
- display: flex;
- margin-bottom: 12px;
- align-items: flex-start;
- }
- .qa-answer {
- margin-bottom: 16px;
- }
- .qa-label {
- flex-shrink: 0;
- width: 40px;
- font-weight: bold;
- color: #409eff;
- margin-right: 8px;
- }
- .qa-question .qa-label {
- color: #e6a23c;
- }
- .qa-text {
- flex: 1;
- line-height: 1.6;
- color: #333;
- word-break: break-word;
- }
- .qa-meta {
- display: flex;
- gap: 8px;
- padding-top: 8px;
- border-top: 1px solid #eee;
- }
- </style>
-
|