|
|
<template> <div class="app-container category-container" style="height: calc(100vh - 140px);"> <!-- 门类列表 --> <div class="container-main"> <div class="elect-cont-left"> <div class="container-left"> <span class="right-top-line" /> <span class="left-bottom-line" /> <!--门类树状结构--> <div class="tree-scroll"> <el-scrollbar style="height: calc(100vh - 230px);"> <el-tree ref="categroyTree" v-loading="crud.loading" class="arc-tree arc-tree-01" :data="crud.data" :props="defaultProps" node-key="id" :expand-on-click-node="false" highlight-current @node-click="handleNodeClick"> <span slot-scope="{ node, data }" class="custom-tree-node"> <el-tooltip :content="node.label" placement="left" :enterable="false" effect="dark"> <span v-if="data.isType === 0"> {{ data.label }} </span> <span v-if="data.isType === 1" class="iconFolder tree-text"> {{ data.label }} </span> <span v-if="data.isType === 2" class="iconArch tree-text"> {{ data.label }} </span> <span v-if="data.isType === 3" class="iconFile tree-text"> {{ data.label }} </span> </el-tooltip> </span> </el-tree> </el-scrollbar> </div> </div> </div> <div class="elect-cont-right"> <div v-if="selectedCategory.isType === 2" class="container-right"> <span class="right-top-line" /> <span class="left-bottom-line" /> <div class="ai-file-pickUp"> <div class="ai-file-all"> <div class="des-title"> <p>原文列表</p> </div> <el-table ref="table" :data="tableData" style="min-width: 100%" class="archives-table" height="calc(100vh - 220px)" @row-click="clickRowHandler" > <el-table-column type="selection" align="center" width="55" /> <!-- <el-table-column type="index" label="序号" width="55" align="center" /> --> <el-table-column prop="file_name" label="文件名称" show-overflow-tooltip min-width="120" /> <el-table-column prop="file_type" label="格式" min-width="60" align="center"> <template slot-scope="scope"> <div v-if="scope.row.file_type === 'jpg' || scope.row.file_type === 'jpeg' || scope.row.file_type === 'png' || scope.row.file_type === 'bmp'|| scope.row.file_type === 'gif'"> <i class="fileIcon icon-image" /> </div> <div v-else-if="scope.row.file_type === 'xlsx' || scope.row.file_type === 'xls'"> <i class="fileIcon icon-excel" /> </div> <div v-else-if="scope.row.file_type === 'docx' || scope.row.file_type === 'doc'"> <i class="fileIcon icon-word" /> </div> <div v-else-if="scope.row.file_type === 'pdf'"> <i class="fileIcon icon-pdf" /> </div> <div v-else-if="scope.row.file_type === 'ppt' || scope.row.file_type === 'pptx'"> <i class="fileIcon icon-ppt" /> </div> <div v-else-if="scope.row.file_type === 'zip' || scope.row.file_type === 'rar'"> <i class="fileIcon icon-zip" /> </div> <div v-else-if="scope.row.file_type === 'txt'"> <i class="fileIcon icon-txt" /> </div> <div v-else> <i class="fileIcon icon-other" /> </div> </template> </el-table-column> <el-table-column prop="file_status" label="是否标注" width="100" align="center"> <template slot-scope="scope"> <span v-if="scope.row.file_status === 0" class="row-state row-physical ">未标注</span> <span v-else class="row-state row-binding state-active">已标注</span> </template> </el-table-column> <el-table-column prop="file_status" label="操作" align="center" width="80"> <template slot-scope="scope"> <div class="handle-btn"> <el-button class="iconfont icon-huoqu" @click.stop="handlePickUp(scope.row)" /> </div> </template> </el-table-column> </el-table> </div> <div class="pickUp-right"> <div class="pickUp-right-item"> <div class="des-title"> <p>已标注关键词</p> </div> <div v-if="currentRow && currentRow.file_status===1" style="height: calc(100% - 70px); overflow-y: auto;"> <div v-for="(item, index) in keywords" :key="index" class="keywords-list"> <div class="keywords-item"> <div v-if="isEditing[index]" class="keywords-input"> <el-input v-model="keywords[index]" style="width: 320px;" @blur="handleBlur(index)" /> </div> <div v-else class="keywords-text"> <!-- <p>{{ item }}</p> --> <el-tooltip class="item" effect="dark" :content="item" :enterable="false" placement="top"> <p>{{ item }}</p> </el-tooltip> </div> </div> <div class="keywords-handle"> <i class="iconfont icon-shanchu" @click="handleDelete(index)" /> <i class="iconfont icon-bianji" @click="handleEdit(index)" /> </div> </div> </div> <el-empty v-else description="暂无标注的数据" /> </div> <div :key="reloadKey" class="pickUp-Ai"> <div class="des-title"> <p>AI关键词标注</p> <el-button @click="batchAiText">批量标注</el-button> </div> <div v-if="isPickUp " v-loading="aiLoadingPick" style="height: calc(100% - 70px); overflow-y: auto;"> <div v-for="(item, index) in aiPickData" :key="index" class="keywords-list"> <div class="keywords-item ai-item-text"> <el-checkbox v-model="selectedItems[index]" @change="handleCheckboxChange(index)" /> <div class="keywords-text"> <el-tooltip class="item" effect="dark" :content="item" :enterable="false" placement="top"> <p>{{ item }}</p> </el-tooltip> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div></template><script>import crudCategory from '@/api/system/category/category'import CRUD, { presenter, header } from '@crud/crud'const data = [ { 'file_path': '/category//09A6ECD967BCC772DABB2F.txt', 'sequence': '', 'create_time': '2024-02-05 11:43:26', 'file_name': 'A002-WSWJ·XZGL·2024·Y-000201.txt', 'file_type': 'txt', 'document_file_id': '', 'file_dpi': 'null', 'id': '09A6ECD967BCC772DABB2F', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 0, 'file_thumbnail': '', 'file_status': 1 }, { 'file_path': '/category//0EFEF1CB577453482ADE5F.txt', 'sequence': '', 'create_time': '2024-02-05 11:43:26', 'file_name': 'A002-WSWJ·XZGL·2024·Y-000202.txt', 'file_type': 'txt', 'document_file_id': '', 'file_dpi': 'null', 'id': '0EFEF1CB577453482ADE5F', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 0, 'file_thumbnail': '', 'file_status': 0 }, { 'file_path': '/category/AE8B188F0C0314F9BE31B8/82FBCAE96CBC9F50809838/eb824e27-13eb-4f33-adc8-39ca5926d244.txt', 'sequence': '', 'create_time': '2024-3-20 16:16:32', 'file_name': '123.txt', 'file_type': 'txt', 'document_file_id': '', 'file_dpi': '', 'id': '3D49BD844334621851DF24', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 37679, 'file_thumbnail': '', 'file_status': 0 }, { 'file_path': '/category/AE8B188F0C0314F9BE31B8/82FBCAE96CBC9F50809838/4B457990A874D55714FF8C.pdf', 'sequence': '', 'create_time': '2024-3-20 11:36:24', 'file_name': 'DAT 48-2009 基于XML的电子文件封装规范.pdf', 'file_type': 'pdf', 'document_file_id': '', 'file_dpi': '', 'id': '4B457990A874D55714FF8C', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 92308284, 'file_thumbnail': '', 'file_status': 0 }, { 'file_path': '/category//6867E751998B41C3B89FA3.txt', 'sequence': '', 'create_time': '2024-01-25 10:26:44', 'file_name': 'A002-WSWJ·XZGL·2024·Y-000201.txt', 'file_type': 'txt', 'document_file_id': '', 'file_dpi': 'null', 'id': '6867E751998B41C3B89FA3', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 0, 'file_thumbnail': '', 'file_status': 0 }, { 'file_path': '/category//694FD852367CD7465F7142.txt', 'sequence': '', 'create_time': '2024-02-05 13:21:39', 'file_name': 'A002-WSWJ·XZGL·2024·Y-000202.txt', 'file_type': 'txt', 'document_file_id': '', 'file_dpi': 'null', 'id': '694FD852367CD7465F7142', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 0, 'file_thumbnail': '', 'file_status': 0 }, { 'file_path': '/category//6E39B6C1428217A5AAA835.txt', 'sequence': '', 'create_time': '2024-02-05 11:52:33', 'file_name': 'A002-WSWJ·XZGL·2024·Y-000201.txt', 'file_type': 'txt', 'document_file_id': '', 'file_dpi': 'null', 'id': '6E39B6C1428217A5AAA835', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 0, 'file_thumbnail': '', 'file_status': 0 }, { 'file_path': '/category//761753E47A37F7F1C141BB.txt', 'sequence': '', 'create_time': '2024-01-25 10:25:25', 'file_name': 'A002-WSWJ·XZGL·2024·Y-000202.txt', 'file_type': 'txt', 'document_file_id': '', 'file_dpi': 'null', 'id': '761753E47A37F7F1C141BB', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 0, 'file_thumbnail': '', 'file_status': 1 }, { 'file_path': '/category/AE8B188F0C0314F9BE31B8/82FBCAE96CBC9F50809838/95ec71e9-4745-4210-ba28-77c71b95bf06.ofd', 'sequence': '', 'create_time': '2024-3-20 14:20:57', 'file_name': '999.ofd', 'file_type': 'ofd', 'document_file_id': '', 'file_dpi': '', 'id': '7F846C5F6E3D5E50950384', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 29752, 'file_thumbnail': '', 'file_status': 0 }, { 'file_path': '/category//831817367E0C3D2E739787.txt', 'sequence': '', 'create_time': '2024-01-25 10:25:25', 'file_name': 'A002-WSWJ·XZGL·2024·Y-000201.txt', 'file_type': 'txt', 'document_file_id': '', 'file_dpi': 'null', 'id': '831817367E0C3D2E739787', 'archive_id': '0FBCB1FCB6341BFF9709B6', 'document_id': '', 'file_size': 0, 'file_thumbnail': '', 'file_status': 1 }]
export default { name: 'AIKeywords', components: { }, cruds() { return [ CRUD({ title: 'AI关键词提取', url: 'api/category/fondMenu', crudMethod: { ...crudCategory }, optShow: { add: false, edit: false, del: false, download: false, group: false } }) ] }, mixins: [presenter(), header()], data() { return { defaultProps: { children: 'children', label: 'label' }, selectedCategory: {}, tableData: data, selections: [], keywords: [], isEditing: [], aiPickData: [], isPickUp: false, reloadKey: 0, aiLoadingPick: false, currentRow: {}, selectedItems: [] } }, computed: { }, created() { this.isEditing = this.keywords.map(() => false) }, mounted() { }, methods: { // 处理编辑图标点击事件
handleEdit(index) { this.$set(this.isEditing, index, true) }, // 处理输入框失去焦点事件
handleBlur(index) { this.$set(this.isEditing, index, false) }, // 处理删除操作的方法
handleDelete(index) { // 从 keywords 数组中删除指定索引的项
this.keywords.splice(index, 1) // 从 isEditing 数组中删除对应索引的项
this.isEditing.splice(index, 1) }, filterData(data) { return data.filter(node => { if (node.children && node.children.length > 0) { node.children = this.filterData(node.children) // 递归处理子节点
} return node.isType !== 3 // 过滤掉isType为3的节点
}) }, // 逆归实现 获取指定元素
findNode(tree, func) { for (const node of tree) { if (func(node)) return node if (node.children) { const res = this.findNode(node.children, func) if (res) return res } } return null }, // 根据父级展开全部子级
expandAllChildren(node, targetElement) { node.expanded = true // 递归展开当前节点的每个子节点
if (node.childNodes && node.childNodes.length > 0) { for (let i = 0; i < node.childNodes.length; i++) { if (node.childNodes[i].data.id === targetElement.id) { this.$refs.categroyTree.setCurrentKey(node.childNodes[i]) } this.expandAllChildren(node.childNodes[i], targetElement) } } }, // 转换函数,将原始数据转换为el-tree所需格式
transformData(rawData) { return rawData.map(item => { return { label: item.fondName, isType: 0, id: item.fondsId, fondsNo: item.fondsNo, children: item.categoryList.map(category => { return { label: category.cnName, id: category.id, arrangeType: category.arrangeType, isType: category.isType, fondsId: item.fondsId, fondName: item.fondName, fondsNo: item.fondsNo, children: this.transformChildren(category.children, item.fondsId, item.fondName, item.fondsNo) } }) } }) }, // 递归函数,用于处理数据的子节点
transformChildren(children, fondsId, fondName, fondsNo) { return children.map(child => { return { label: child.cnName, id: child.id, isType: child.isType, pid: child.pid, code: child.code, arrangeType: child.arrangeType, fondsId: fondsId, fondName: fondName, fondsNo: fondsNo, children: child.children.length ? this.transformChildren(child.children, fondsId, fondName, fondsNo) : [] } }) }, // 找顶级节点
findTopLevelNode(data, fondsId) { for (let i = 0; i < data.length; i++) { if (data[i].id === fondsId) { return data[i] } } return null }, [CRUD.HOOK.afterRefresh]() { this.crud.data = this.filterData(this.transformData(this.crud.data)) this.$nextTick(() => { let currentKey if (localStorage.getItem('currentArchivesKey') !== null) { currentKey = JSON.parse(localStorage.getItem('currentArchivesKey')) // 删除门类节点后
if (this.$refs.categroyTree.getCurrentKey(currentKey.id) == null) { localStorage.removeItem('currentArchivesKey') } this.topLevelNode = this.findTopLevelNode(this.crud.data, currentKey.fondsId) // 如果找到了顶级节点,则从该节点开始递归查找指定元素
if (this.topLevelNode) { if (currentKey) { // 展开顶级节点的子节点
if (currentKey.isType === 1) { currentKey = this.findNode(this.crud.data[0].children, (node) => { return node.isType !== 1 }) } this.expandAllChildren(this.$refs.categroyTree.getNode(this.topLevelNode), currentKey) } else { this.defaultSetting(currentKey) } } else { this.defaultSetting(currentKey) } } else { this.defaultSetting(currentKey) } if (currentKey && currentKey.id) { this.$nextTick(() => { // 选中节点的门类详情
this.handleNodeClick(currentKey) }) } }) }, defaultSetting(currentKey) { if (this.crud.data[0].isType === 0) { currentKey = this.findNode(this.crud.data[0].children, (node) => { return node.isType !== 1 }) this.expandAllChildren(this.$refs.categroyTree.getNode(this.crud.data[0]), currentKey) } else { currentKey = this.crud.data[0] this.expandAllChildren(this.$refs.categroyTree.getNode(this.crud.data[0]), currentKey) } }, // 选中门类后,设置门类详情数据
handleNodeClick(val) { if (val) { localStorage.setItem('currentArchivesKey', JSON.stringify(val)) this.selectedCategory = val this.$nextTick(() => { }) } }, // table
clickRowHandler(row) { this.isPickUp = false this.$refs.table.clearSelection() this.$refs.table.toggleRowSelection(row) this.selections = [row] this.currentRow = row if (this.currentRow.file_status === 1) { this.keywords = [ '永久', '武汉飞天', '2024' ] } else { this.keywords = [] } }, handlePickUp(row) { this.currentRow = row this.aiPickData = [] this.isPickUp = true this.aiLoadingPick = true setTimeout(() => { this.aiPickData = ['数字人', '多媒体技术在档案信息存贮与检索中的应用中的应用中的应用中的应用', '2023', '30年'] this.aiLoadingPick = false }, 3000) }, // 处理复选框状态变化
handleCheckboxChange(index) { // console.log(`第 ${index} 项的选中状态变为: ${this.selectedItems[index]}`)
const allSelectedItems = this.aiPickData.filter((_, i) => this.selectedItems[i]) console.log('所有选中项:', allSelectedItems) }, batchAiText() { const selected = this.aiPickData.filter((_, index) => this.selectedItems[index]) if (selected.length === 0) { this.$message({ message: '请选择要提取的关键词', type: 'warning', offset: 8 }) return } this.keywords = this.keywords.concat(selected) this.isEditing = this.keywords.map(() => false)
// 移除已提取的关键词
this.aiPickData = this.aiPickData.filter((_, index) => !this.selectedItems[index]) this.selectedItems = this.aiPickData.map(() => false)
// 更新当前行的 file_status 状态
if (this.currentRow) { this.currentRow.file_status = 1 // 找到 tableData 中对应的行并更新状态
const rowIndex = this.tableData.findIndex(row => row.id === this.currentRow.id) if (rowIndex !== -1) { this.$set(this.tableData, rowIndex, { ...this.tableData[rowIndex], file_status: 1 }) } } } }}</script>
<style lang="scss" scoped>.elect-cont-right .container-right { // min-height: calc(100vh - 188px);
}.category-container { .elect-cont-left{ width: 296px !important; }}.openSidebar .category-container .elect-cont-right{ width: calc(100vw - 614px) !important;}.hideSidebar .category-container .elect-cont-right { width: calc(100vw - 412px) !important;}.tree-scroll{ font-size: 14px;}
.ai-file-pickUp{ display: flex; justify-content: space-between;}.ai-file-all{ flex: 1;}.pickUp-right{ width: 400px; margin-left: 20px; .pickUp-right-item, .pickUp-Ai{ height: calc(100% / 2); }}.keywords-text p{ width: 340px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;}.keywords-list{ display: flex; justify-content: space-between; line-height: 40px; border-bottom: 1px solid #e6e8ed; // padding: 0 10px;
}.keywords-handle i{ cursor: pointer;}.ai-item-text{ display: flex; justify-content: flex-start; p{ margin-left: 10px; }}.des-title{ position: relative; .el-button{ position: absolute; right: 0; top: -5px; }}</style>
|