<template>
|
<div class="app-container document-view">
|
<div class="left">
|
<div>
|
<el-input
|
v-model="search"
|
style="width: 210px"
|
placeholder="输入关键字进行搜索"
|
@change="searchFilter"
|
@clear="searchFilter"
|
clearable
|
prefix-icon="Search"
|
/>
|
<el-button
|
type="primary"
|
@click="openCategoryDia('addOne')"
|
style="margin-left: 10px"
|
>新增分类</el-button
|
>
|
</div>
|
<div ref="containerRef">
|
<el-tree
|
ref="tree"
|
v-loading="treeLoad"
|
:data="categoryList"
|
@node-click="handleNodeClick"
|
:expand-on-click-node="false"
|
default-expand-all
|
:default-expanded-keys="expandedKeys"
|
:draggable="true"
|
:filter-node-method="filterNode"
|
:props="{ children: 'children', label: 'category' }"
|
highlight-current
|
node-key="id"
|
style="
|
height: calc(100vh - 190px);
|
overflow-y: scroll;
|
scrollbar-width: none;
|
margin-top: 10px;
|
"
|
>
|
<template #default="{ node, data }">
|
<div class="custom-tree-node">
|
<span class="tree-node-content">
|
<el-icon class="orange-icon">
|
<component :is="data.children && data.children.length > 0
|
? node.expanded ? 'FolderOpened' : 'Folder' : 'Tickets'" />
|
</el-icon>
|
{{ data.category }}
|
</span>
|
<div>
|
<el-button
|
type="primary"
|
link
|
@click="openCategoryDia('edit', data)"
|
>
|
编辑
|
</el-button>
|
<el-button
|
type="primary"
|
link
|
@click="openCategoryDia('addSub', data)"
|
v-if="node.level < 2"
|
>
|
添加子分类
|
</el-button>
|
<el-button
|
v-if="!node.childNodes.length"
|
style="margin-left: 4px"
|
type="danger"
|
link
|
@click="removeCategory(node, data)"
|
>
|
删除
|
</el-button>
|
</div>
|
</div>
|
</template>
|
</el-tree>
|
</div>
|
</div>
|
<div class="right">
|
<div style="margin-bottom: 10px" v-if="isShowButton">
|
<el-button type="primary" @click="openDocumentDia('add')">
|
新增文档
|
</el-button>
|
<el-button
|
type="danger"
|
@click="handleDelete"
|
style="margin-left: 10px"
|
plain
|
:disabled="selectedRows.length === 0"
|
>
|
删除 ({{ selectedRows.length }})
|
</el-button>
|
</div>
|
<div class="table-container">
|
|
<!-- PIMTable 组件 -->
|
<PIMTable
|
:table-data="documentList"
|
:column="tableColumns"
|
:is-selection="true"
|
:border="true"
|
:table-loading="tableLoading"
|
:page="{
|
current: pagination.currentPage,
|
size: pagination.pageSize,
|
total: pagination.total,
|
layout: 'total, sizes, prev, pager, next, jumper'
|
}"
|
@selection-change="handleSelectionChange"
|
@pagination="handlePagination"
|
/>
|
</div>
|
</div>
|
|
<!-- 分类新增/修改对话框 -->
|
<el-dialog v-model="categoryDia" title="分类" width="400px" @keydown.enter.prevent>
|
<el-form
|
:model="categoryForm"
|
label-width="140px"
|
label-position="top"
|
:rules="categoryRules"
|
ref="categoryFormRef"
|
>
|
<el-row :gutter="30">
|
<el-col :span="24" v-if="categoryOperationType === 'addSub'">
|
<el-form-item label="父分类:" prop="parentName">
|
<el-input
|
v-model="categoryForm.parentName"
|
placeholder="父分类名称"
|
disabled
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="24">
|
<el-form-item label="分类名称:" prop="category">
|
<el-input
|
v-model="categoryForm.category"
|
placeholder="请输入分类名称"
|
clearable
|
@keydown.enter.prevent
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="submitCategoryForm">确认</el-button>
|
<el-button @click="closeCategoryDia">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
<!-- 文档新增/修改对话框 -->
|
<el-dialog
|
v-model="documentDia"
|
:title="documentOperationType === 'add' ? '新增文档' : '编辑文档'"
|
width="600px"
|
@close="closeDocumentDia"
|
@keydown.enter.prevent
|
>
|
<el-form
|
:model="documentForm"
|
label-width="140px"
|
label-position="top"
|
:rules="documentRules"
|
ref="documentFormRef"
|
>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="文档名称:" prop="docName">
|
<el-input v-model="documentForm.docName" placeholder="请输入" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="年度:" prop="year">
|
<el-date-picker
|
v-model="documentForm.year"
|
type="year"
|
value-format="YYYY"
|
format="YYYY"
|
placeholder="选择年度"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="文档编号:" prop="docNumber">
|
<el-input v-model="documentForm.docNumber" placeholder="请输入" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="责任人:" prop="responsiblePerson">
|
<el-input v-model="documentForm.responsiblePerson" placeholder="请输入" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="文档分类:" prop="documentClassificationId">
|
<el-select v-model="documentForm.documentClassificationId" placeholder="请选择文档分类" style="width: 100%">
|
<el-option
|
v-for="item in categoryList"
|
:key="item.id"
|
:label="item.category"
|
:value="item.id"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="文档放置位置:" prop="warehouseGoodsShelvesRowcolId">
|
<el-tree-select
|
v-model="documentForm.warehouseGoodsShelvesRowcolId"
|
:data="locationTree"
|
placeholder="请选择文件放置位置"
|
clearable
|
check-strictly
|
:render-after-expand="false"
|
:props="{ children: 'children', label: 'label', value: 'value' }"
|
style="width: 100%"
|
@change="handleLocationChange"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="文档日期:" prop="docData">
|
<el-date-picker
|
v-model="documentForm.docData"
|
type="date"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
placeholder="选择日期"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="保管期限:" prop="retentionPeriod">
|
<el-select v-model="documentForm.retentionPeriod" placeholder="请选择">
|
<el-option
|
v-for="item in retention_period"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="保密级别:" prop="securityLevel">
|
<el-select v-model="documentForm.securityLevel" placeholder="请选择">
|
<el-option
|
v-for="item in confidentiality_level"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="分数:" prop="copyCount">
|
<el-input v-model="documentForm.copyCount" placeholder="请输入" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="页数:" prop="pageCount">
|
<el-input v-model="documentForm.pageCount" placeholder="请输入" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="文档类别:" prop="docCategory">
|
<el-select v-model="documentForm.docCategory" placeholder="请选择">
|
<el-option
|
v-for="item in document_type"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="文档种类:" prop="docType">
|
<el-select v-model="documentForm.docType" placeholder="请选择">
|
<el-option
|
v-for="item in document_categories"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="紧急程度:" prop="urgencyLevel">
|
<el-select v-model="documentForm.urgencyLevel" placeholder="请选择">
|
<el-option
|
v-for="item in document_urgency"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="文档状态:" prop="docStatus">
|
<el-select v-model="documentForm.docStatus" placeholder="请选择">
|
<el-option
|
v-for="item in document_status"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="24">
|
<el-form-item label="备注:" prop="remark">
|
<el-input
|
v-model="documentForm.remark"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入备注信息"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="submitDocumentForm">确认</el-button>
|
<el-button @click="closeDocumentDia">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
<AttachmentManager ref="attachmentManagerRef" />
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted, getCurrentInstance, toRefs, watch } from "vue";
|
import { ElMessageBox, ElMessage } from "element-plus";
|
import { ArrowRight, Folder, FolderOpened, Tickets, Document } from '@element-plus/icons-vue';
|
import PIMTable from '@/components/PIMTable/PIMTable.vue';
|
import { getToken } from "@/utils/auth";
|
import { getCategoryTree, addCategory, updateCategory, deleteCategory, getDocumentList, addDocument, updateDocument, deleteDocument, getDocumentDetail, searchDocument, getWarehouseStructure } from '@/api/fileManagement/document'
|
import { getWarehouseList } from '@/api/fileManagement/bookshelf'
|
import AttachmentManager from './attachmentManager.vue'
|
import { useDict } from '@/utils/dict'
|
|
const { proxy } = getCurrentInstance();
|
const tree = ref(null);
|
const containerRef = ref(null);
|
|
// 使用字典数据
|
const { confidentiality_level, document_urgency, document_status, document_type, document_categories, retention_period } = useDict('confidentiality_level', 'document_urgency', 'document_status', 'document_type', 'document_categories', 'retention_period')
|
|
// 监听字典数据变化
|
watch([confidentiality_level, document_urgency, document_status, document_type, document_categories, retention_period], () => {
|
// 字典数据已更新
|
}, { immediate: true, deep: true });
|
|
const categoryDia = ref(false);
|
const documentDia = ref(false);
|
const categoryOperationType = ref("");
|
const documentOperationType = ref("");
|
const search = ref("");
|
const currentId = ref("");
|
const currentParentId = ref("");
|
const treeLoad = ref(false);
|
const categoryList = ref([]);
|
const expandedKeys = ref([]);
|
const documentList = ref([]);
|
const isShowButton = ref(false);
|
const selectedRows = ref([]);
|
const selectAll = ref(false);
|
const isIndeterminate = ref(false);
|
const tableLoading = ref(false);
|
const attachmentManagerRef = ref(null);
|
|
// 文件上传配置
|
const upload = reactive({
|
url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
|
headers: { Authorization: "Bearer " + getToken() },
|
});
|
|
// 位置树数据
|
const locationTree = ref([]);
|
|
// 表格列配置
|
const tableColumns = ref([
|
{ label: '文档名称', prop: 'docName', width: '200' },
|
{ label: '文档编号', prop: 'docNumber', width: '120' },
|
{ label: '年度', prop: 'year', width: '80' },
|
{ label: '责任人', prop: 'responsiblePerson', width: '100' },
|
{
|
label: '文档放置位置',
|
prop: 'warehouseGoodsShelvesRowcolId',
|
width: '150',
|
formatData: (params) => {
|
if (params === null || params === undefined || params === '') return '-';
|
return getLocationName(params);
|
}
|
},
|
{ label: '文档日期', prop: 'docData', width: '120' },
|
{
|
label: '保管期限',
|
prop: 'retentionPeriod',
|
width: '100',
|
dataType: 'tag',
|
formatData: (params) => {
|
if (params === null || params === undefined || params === '') return '-';
|
if (!retention_period.value || retention_period.value.length === 0) {
|
return params;
|
}
|
const item = retention_period.value.find(item => item.value == params);
|
return item ? item.label : params;
|
},
|
formatType: (params) => {
|
if (params === null || params === undefined || params === '') return 'info';
|
if (!retention_period.value || retention_period.value.length === 0) {
|
return 'info';
|
}
|
const item = retention_period.value.find(item => item.value == params);
|
const validTypes = ['success', 'warning', 'danger', 'info'];
|
return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
|
}
|
},
|
{
|
label: '保密级别',
|
prop: 'securityLevel',
|
width: '80',
|
dataType: 'tag',
|
formatData: (params) => {
|
if (params === null || params === undefined || params === '') return '-';
|
if (!confidentiality_level.value || confidentiality_level.value.length === 0) {
|
return params;
|
}
|
const item = confidentiality_level.value.find(item => item.value == params);
|
return item ? item.label : params;
|
},
|
formatType: (params) => {
|
if (params === null || params === undefined || params === '') return 'info';
|
if (!confidentiality_level.value || confidentiality_level.value.length === 0) {
|
return 'info';
|
}
|
const item = confidentiality_level.value.find(item => item.value == params);
|
const validTypes = ['success', 'warning', 'danger', 'info'];
|
return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
|
}
|
},
|
{ label: '分数', prop: 'copyCount', width: '80' },
|
{ label: '页数', prop: 'pageCount', width: '80' },
|
{
|
label: '文档类别',
|
prop: 'docCategory',
|
width: '100',
|
dataType: 'tag',
|
formatData: (params) => {
|
if (params === null || params === undefined || params === '') return '-';
|
if (!document_type.value || document_type.value.length === 0) {
|
return params;
|
}
|
const item = document_type.value.find(item => item.value == params);
|
return item ? item.label : params;
|
},
|
formatType: (params) => {
|
if (params === null || params === undefined || params === '') return 'info';
|
if (!document_type.value || document_type.value.length === 0) {
|
return 'info';
|
}
|
const item = document_type.value.find(item => item.value == params);
|
const validTypes = ['success', 'warning', 'danger', 'info'];
|
return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
|
}
|
},
|
{
|
label: '文档种类',
|
prop: 'docType',
|
width: '100',
|
dataType: 'tag',
|
formatData: (params) => {
|
if (params === null || params === undefined || params === '') return '-';
|
if (!document_categories.value || document_categories.value.length === 0) {
|
return params;
|
}
|
const item = document_categories.value.find(item => item.value == params);
|
return item ? item.label : params;
|
},
|
formatType: (params) => {
|
if (params === null || params === undefined || params === '') return 'info';
|
if (!document_categories.value || document_categories.value.length === 0) {
|
return 'info';
|
}
|
const item = document_categories.value.find(item => item.value == params);
|
const validTypes = ['success', 'warning', 'danger', 'info'];
|
return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
|
}
|
},
|
{
|
label: '紧急程度',
|
prop: 'urgencyLevel',
|
width: '100',
|
dataType: 'tag',
|
formatData: (params) => {
|
if (params === null || params === undefined || params === '') return '-';
|
if (!document_urgency.value || document_urgency.value.length === 0) {
|
return params;
|
}
|
const item = document_urgency.value.find(item => item.value == params);
|
return item ? item.label : params;
|
},
|
formatType: (params) => {
|
if (params === null || params === undefined || params === '') return 'info';
|
if (!document_urgency.value || document_urgency.value.length === 0) {
|
return 'info';
|
}
|
const item = document_urgency.value.find(item => item.value == params);
|
const validTypes = ['success', 'warning', 'danger', 'info'];
|
return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
|
}
|
},
|
{
|
label: '文档状态',
|
prop: 'docStatus',
|
width: '100',
|
dataType: 'tag',
|
formatData: (params) => {
|
if (params === null || params === undefined || params === '') return '-';
|
if (!document_status.value || document_status.value.length === 0) {
|
return params;
|
}
|
const item = document_status.value.find(item => item.value == params);
|
return item ? item.label : params;
|
},
|
formatType: (params) => {
|
if (params === null || params === undefined || params === '') return 'info';
|
if (!document_status.value || document_status.value.length === 0) {
|
return 'info';
|
}
|
const item = document_status.value.find(item => item.value == params);
|
const validTypes = ['success', 'warning', 'danger', 'info'];
|
return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
|
}
|
},
|
{
|
dataType: "action",
|
label: "操作",
|
align: "center",
|
fixed: 'right',
|
width: '150',
|
operation: [
|
{
|
name: "编辑",
|
type: "text",
|
clickFun: (row) => {
|
openDocumentDia('edit', row)
|
},
|
},
|
{
|
name: "附件",
|
type: "text",
|
clickFun: (row) => {
|
openAttachment(row)
|
},
|
},
|
],
|
}
|
]);
|
|
// 分类表单
|
const categoryForm = reactive({
|
category: "",
|
parentId: "",
|
parentName: "",
|
});
|
|
const categoryRules = reactive({
|
category: [{ required: true, message: "请输入分类名称", trigger: "blur" }],
|
});
|
|
// 文档表单
|
const documentForm = reactive({
|
id: "",
|
documentClassificationId: "",
|
docName: "",
|
docNumber: "",
|
year: "",
|
responsiblePerson: "",
|
warehouseGoodsShelvesRowcolId: "",
|
docData: "",
|
retentionPeriod: "",
|
securityLevel: "",
|
copyCount: "",
|
pageCount: "",
|
docCategory: "",
|
docType: "",
|
urgencyLevel: "",
|
docStatus: "",
|
remark: "",
|
attachments: [], // 新增附件数组
|
});
|
|
const documentRules = reactive({
|
docName: [{ required: true, message: "请输入文档名称", trigger: "blur" }],
|
docNumber: [{ required: true, message: "请输入文档编号", trigger: "blur" }],
|
year: [{ required: true, message: "请选择年度", trigger: "change" }],
|
documentClassificationId: [{ required: true, message: "请选择文档分类", trigger: "change" }],
|
warehouseGoodsShelvesRowcolId: [{ required: true, message: "请选择文档放置位置", trigger: "change" }],
|
});
|
|
// 分页相关
|
const pagination = reactive({
|
currentPage: 1,
|
pageSize: 10,
|
total: 0,
|
});
|
|
// 初始化分类树数据
|
const initCategoryTree = async() => {
|
try {
|
treeLoad.value = true;
|
const res = await getCategoryTree();
|
if (res.code === 200) {
|
categoryList.value = res.data || [];
|
|
// 设置展开的节点
|
expandedKeys.value = [];
|
categoryList.value.forEach((item) => {
|
if (item.id) {
|
expandedKeys.value.push(item.id);
|
}
|
});
|
} else {
|
ElMessage.error(res.msg || "获取分类树失败");
|
}
|
} catch (error) {
|
ElMessage.error("获取分类树失败,请重试");
|
} finally {
|
treeLoad.value = false;
|
}
|
};
|
|
// 初始化仓库位置数据
|
const initLocationTree = async() => {
|
try {
|
const res = await getWarehouseList();
|
if (res.code === 200) {
|
// 转换数据格式,适配el-tree-select组件
|
locationTree.value = transformWarehouseData(res.data || []);
|
} else {
|
ElMessage.error(res.msg || "获取仓库位置失败");
|
}
|
} catch (error) {
|
ElMessage.error("获取仓库位置失败,请重试");
|
}
|
};
|
|
// 转换仓库数据格式
|
const transformWarehouseData = (data) => {
|
return data.map(item => ({
|
id: item.id,
|
label: item.name || item.warehouseName || item.label,
|
value: item.id,
|
children: item.children ? transformWarehouseData(item.children) : []
|
}));
|
};
|
|
// 根据ID获取位置名称
|
const getLocationName = (locationId) => {
|
if (!locationId || !locationTree.value || locationTree.value.length === 0) {
|
return locationId || '-';
|
}
|
|
const findLocation = (tree, id) => {
|
for (let item of tree) {
|
if (item.value === locationId || item.id === locationId) {
|
return item.label;
|
}
|
if (item.children && item.children.length > 0) {
|
const result = findLocation(item.children, id);
|
if (result) return result;
|
}
|
}
|
return null;
|
};
|
|
const locationName = findLocation(locationTree.value, locationId);
|
return locationName || locationId;
|
};
|
|
// 过滤分类树
|
const searchFilter = () => {
|
if (proxy.$refs.tree) {
|
proxy.$refs.tree.filter(search.value);
|
}
|
};
|
|
// 打开分类弹框
|
const openCategoryDia = (type, data) => {
|
categoryOperationType.value = type;
|
categoryDia.value = true;
|
categoryForm.category = "";
|
categoryForm.parentId ="";
|
categoryForm.parentName = "";
|
|
if (type === "edit") {
|
categoryForm.category = data.category;
|
// 保存当前编辑的分类ID
|
currentId.value = data.id;
|
} else if (type === "addSub") {
|
categoryForm.parentId = data.id;
|
categoryForm.parentName = data.category;
|
}
|
};
|
|
// 打开文档弹框
|
const openDocumentDia = (type, data) => {
|
documentOperationType.value = type;
|
documentDia.value = true;
|
|
if (type === "edit") {
|
// 编辑模式,加载现有数据
|
Object.assign(documentForm, data);
|
documentForm.retentionPeriod = String(documentForm.retentionPeriod)
|
documentForm.securityLevel = String(documentForm.securityLevel)
|
documentForm.docCategory = String(documentForm.docCategory)
|
documentForm.docType = String(documentForm.docType)
|
documentForm.urgencyLevel = String(documentForm.urgencyLevel)
|
documentForm.docStatus = String(documentForm.docStatus)
|
|
// 加载附件信息
|
if (data.attachments) {
|
documentForm.attachments = [...data.attachments];
|
} else {
|
documentForm.attachments = [];
|
}
|
} else {
|
// 新增模式,清空表单
|
Object.keys(documentForm).forEach(key => {
|
documentForm[key] = "";
|
});
|
documentForm.attachments = []; // 新增模式下也清空附件
|
// 设置默认值 - 使用字典数据的第一个选项作为默认值
|
if (document_status.value && document_status.value.length > 0) {
|
documentForm.docStatus = document_status.value[0].value;
|
}
|
if (document_urgency.value && document_urgency.value.length > 0) {
|
documentForm.urgencyLevel = document_urgency.value[0].value;
|
}
|
}
|
};
|
|
// 提交分类表单
|
const submitCategoryForm = () => {
|
proxy.$refs.categoryFormRef.validate(async (valid) => {
|
if (valid) {
|
try {
|
if (categoryOperationType.value === "addSub") {
|
// 添加子分类
|
const res = await addCategory({
|
category: categoryForm.category,
|
parentId: categoryForm.parentId
|
});
|
if (res.code === 200) {
|
ElMessage.success("添加子分类成功");
|
// 重新加载分类树
|
await initCategoryTree();
|
} else {
|
ElMessage.error(res.msg || "添加子分类失败");
|
}
|
} else if (categoryOperationType.value === "edit") {
|
// 编辑分类
|
const res = await updateCategory({
|
id: currentId.value,
|
category: categoryForm.category
|
});
|
if (res.code === 200) {
|
ElMessage.success("编辑分类成功");
|
// 重新加载分类树
|
await initCategoryTree();
|
} else {
|
ElMessage.error(res.msg || "编辑分类失败");
|
}
|
} else {
|
// 新增顶级分类
|
const res = await addCategory({
|
category: categoryForm.category,
|
parentId: null
|
});
|
if (res.code === 200) {
|
ElMessage.success("新增分类成功");
|
// 重新加载分类树
|
await initCategoryTree();
|
} else {
|
ElMessage.error(res.msg || "新增分类失败");
|
}
|
}
|
|
closeCategoryDia();
|
} catch (error) {
|
ElMessage.error("操作失败,请重试");
|
}
|
}
|
});
|
};
|
|
// 关闭分类弹框
|
const closeCategoryDia = () => {
|
proxy.$refs.categoryFormRef.resetFields();
|
categoryForm.parentId = "";
|
categoryForm.parentName = "";
|
categoryDia.value = false;
|
};
|
|
// 删除分类
|
const removeCategory = (node, data) => {
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(async () => {
|
try {
|
const res = await deleteCategory([data.id]);
|
if (res.code === 200) {
|
ElMessage.success("删除成功");
|
// 重新加载分类树
|
await initCategoryTree();
|
} else {
|
ElMessage.error(res.msg || "删除失败");
|
}
|
} catch (error) {
|
ElMessage.error("删除失败,请重试");
|
}
|
})
|
.catch(() => {
|
ElMessage("已取消");
|
});
|
};
|
|
// 选择分类
|
const handleNodeClick = (val, node, el) => {
|
// 判断是否为叶子节点
|
isShowButton.value = true;
|
// 只有叶子节点才执行以下逻辑
|
currentId.value = val.id;
|
currentParentId.value = val.parentId;
|
|
// 清空选择状态
|
selectedRows.value = [];
|
selectAll.value = false;
|
isIndeterminate.value = false;
|
|
// 重置分页
|
pagination.currentPage = 1;
|
pagination.total = 0;
|
|
// 加载文档列表
|
if (isShowButton.value) {
|
loadDocumentList();
|
} else {
|
// 如果不是叶子节点,清空文档列表
|
documentList.value = [];
|
}
|
};
|
|
// 提交文档表单
|
const submitDocumentForm = () => {
|
proxy.$refs.documentFormRef.validate(async (valid) => {
|
if (valid) {
|
try {
|
// 构建提交数据
|
const submitData = {
|
...documentForm,
|
// 设置当前选中的分类ID
|
documentClassificationId: currentId.value || documentForm.documentClassificationId,
|
// 添加附件信息
|
// attachments: documentForm.attachments
|
};
|
|
if (documentOperationType.value === "edit") {
|
// 编辑模式,更新现有数据
|
const res = await updateDocument(submitData);
|
if (res.code === 200) {
|
ElMessage.success("编辑成功");
|
// 重新加载文档列表
|
await loadDocumentList();
|
// 刷新附件列表
|
if (attachmentManagerRef.value && documentForm.id) {
|
attachmentManagerRef.value.loadAttachmentList(documentForm.id);
|
}
|
} else {
|
ElMessage.error(res.msg || "编辑失败");
|
}
|
} else {
|
// 新增模式,添加新数据
|
const res = await addDocument(submitData);
|
if (res.code === 200) {
|
ElMessage.success("新增成功");
|
// 重新加载文档列表
|
await loadDocumentList();
|
// 刷新附件列表
|
if (attachmentManagerRef.value && res.data && res.data.id) {
|
attachmentManagerRef.value.loadAttachmentList(res.data.id);
|
}
|
} else {
|
ElMessage.error(res.msg || "新增失败");
|
}
|
}
|
closeDocumentDia();
|
} catch (error) {
|
ElMessage.error("操作失败,请重试");
|
}
|
}
|
});
|
};
|
|
// 关闭文档弹框
|
const closeDocumentDia = () => {
|
proxy.$refs.documentFormRef.resetFields();
|
documentDia.value = false;
|
// 清空表单数据
|
Object.keys(documentForm).forEach(key => {
|
documentForm[key] = "";
|
});
|
documentForm.attachments = []; // 关闭弹框时也清空附件
|
};
|
|
// 处理位置选择变化
|
const handleLocationChange = (value) => {
|
if (value) {
|
// 检查选择的是否为叶子节点
|
const isLeafNode = checkIfLeafNode(locationTree.value, value);
|
if (!isLeafNode) {
|
ElMessage.warning("请选择最底层的位置(如:柜层)");
|
documentForm.warehouseGoodsShelvesRowcolId = "";
|
return;
|
}
|
}
|
};
|
|
// 检查是否为叶子节点
|
const checkIfLeafNode = (tree, value) => {
|
for (let item of tree) {
|
if (item.value === value || item.id === value) {
|
// 如果没有子节点,则为叶子节点
|
return !item.children || item.children.length === 0;
|
}
|
if (item.children && item.children.length > 0) {
|
const result = checkIfLeafNode(item.children, value);
|
if (result !== null) {
|
return result;
|
}
|
}
|
}
|
return null;
|
};
|
|
// 删除文档
|
const handleDelete = () => {
|
if (selectedRows.value.length > 0) {
|
ElMessageBox.confirm(`确定要删除选中的 ${selectedRows.value.length} 条记录吗?`, "删除提示", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(async () => {
|
try {
|
const selectedIds = selectedRows.value.map(row => row.id);
|
const res = await deleteDocument(selectedIds);
|
if (res.code === 200) {
|
ElMessage.success("删除成功");
|
// 重新加载文档列表
|
await loadDocumentList();
|
} else {
|
ElMessage.error(res.msg || "删除失败");
|
}
|
} catch (error) {
|
ElMessage.error("删除失败,请重试");
|
}
|
})
|
.catch(() => {
|
ElMessage("已取消");
|
});
|
} else {
|
ElMessage.warning("请选择要删除的数据");
|
}
|
};
|
|
// PIMTable 选择变化事件
|
const handleSelectionChange = (selection) => {
|
selectedRows.value = selection;
|
|
// 更新全选状态
|
const selectedCount = selection.length;
|
const totalCount = documentList.value.length;
|
|
if (selectedCount === 0) {
|
selectAll.value = false;
|
isIndeterminate.value = false;
|
} else if (selectedCount === totalCount) {
|
selectAll.value = true;
|
isIndeterminate.value = false;
|
} else {
|
selectAll.value = false;
|
isIndeterminate.value = true;
|
}
|
};
|
|
// 加载文档列表
|
const loadDocumentList = async () => {
|
try {
|
tableLoading.value = true;
|
|
// 构建查询参数
|
const query = {
|
page: pagination.currentPage,
|
size: pagination.pageSize,
|
documentClassificationId:currentId.value
|
};
|
|
const res = await getDocumentList(query);
|
if (res.code === 200) {
|
documentList.value = res.data.records || [];
|
pagination.total = res.data.total || 0;
|
} else {
|
ElMessage.error(res.msg || "获取文档列表失败");
|
documentList.value = [];
|
pagination.total = 0;
|
}
|
|
// 重置选择状态
|
selectedRows.value = [];
|
selectAll.value = false;
|
isIndeterminate.value = false;
|
} catch (error) {
|
ElMessage.error("获取文档列表失败,请重试");
|
documentList.value = [];
|
pagination.total = 0;
|
} finally {
|
tableLoading.value = false;
|
}
|
};
|
|
// 处理分页变化
|
const handlePagination = (current, size) => {
|
pagination.currentPage = current;
|
pagination.pageSize = size;
|
loadDocumentList();
|
};
|
|
// 调用tree过滤方法
|
const filterNode = (value, data, node) => {
|
if (!value) {
|
return true;
|
}
|
let val = value.toLowerCase();
|
return chooseNode(val, data, node);
|
};
|
|
// 过滤父节点 / 子节点
|
const chooseNode = (value, data, node) => {
|
if (data.category && data.category.toLowerCase().indexOf(value) !== -1) {
|
return true;
|
}
|
const level = node.level;
|
if (level === 1) {
|
return false;
|
}
|
let parentData = node.parent;
|
let index = 0;
|
while (index < level - 1) {
|
if (parentData.data.category && parentData.data.category.toLowerCase().indexOf(value) !== -1) {
|
return true;
|
}
|
parentData = parentData.parent;
|
index++;
|
}
|
return false;
|
};
|
|
// 打开附件
|
const openAttachment = (row) => {
|
attachmentManagerRef.value.open([], row.id);
|
};
|
|
onMounted(() => {
|
initCategoryTree();
|
initLocationTree();
|
|
// 不在初始化时加载文档列表,等待用户选择分类后再加载
|
});
|
</script>
|
|
<style scoped>
|
.document-view {
|
display: flex;
|
height: 100%;
|
}
|
|
.left {
|
width: 380px;
|
padding: 16px;
|
background: #ffffff;
|
border-right: 1px solid #e4e7ed;
|
}
|
|
.right {
|
width: calc(100% - 380px);
|
padding: 16px;
|
background: #ffffff;
|
}
|
|
.custom-tree-node {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
font-size: 14px;
|
padding-right: 8px;
|
}
|
|
.tree-node-content {
|
display: flex;
|
align-items: center;
|
height: 100%;
|
}
|
|
.orange-icon {
|
color: orange;
|
font-size: 18px;
|
margin-right: 8px;
|
}
|
|
.table-container {
|
background: #ffffff;
|
border-radius: 8px;
|
overflow: hidden;
|
position: relative;
|
}
|
|
.add-row {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
background-color: #f5f7fa;
|
cursor: pointer;
|
transition: background-color 0.2s ease;
|
padding: 12px 16px;
|
margin-bottom: 16px;
|
border-radius: 6px;
|
border: 1px dashed #d9d9d9;
|
}
|
|
.add-row:hover {
|
background-color: #e4e7ed;
|
border-color: #c0c4cc;
|
}
|
|
.add-icon {
|
color: #909399;
|
font-size: 16px;
|
}
|
|
.add-row span {
|
color: #606266;
|
font-size: 14px;
|
}
|
|
.empty-data {
|
text-align: center;
|
color: #909399;
|
padding: 40px;
|
font-size: 14px;
|
}
|
|
.dialog-footer {
|
text-align: right;
|
}
|
|
.operation-column {
|
position: absolute;
|
right: 0;
|
top: 0;
|
width: 120px;
|
background: #ffffff;
|
border-left: 1px solid #e4e7ed;
|
z-index: 1;
|
box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1);
|
}
|
|
.operation-header {
|
height: 40px;
|
line-height: 40px;
|
text-align: center;
|
background: #fafafa;
|
border-bottom: 1px solid #e4e7ed;
|
font-weight: 500;
|
color: #606266;
|
}
|
|
.operation-cell {
|
height: 40px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border-bottom: 1px solid #e4e7ed;
|
}
|
|
.operation-cell:last-child {
|
border-bottom: none;
|
}
|
|
.attachment-section {
|
width: 100%;
|
}
|
|
.attachment-list {
|
margin-bottom: 10px;
|
}
|
|
.attachment-item {
|
display: flex;
|
align-items: center;
|
padding: 8px 12px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
margin-bottom: 8px;
|
}
|
|
.file-icon {
|
margin-right: 8px;
|
color: #409eff;
|
}
|
|
.file-name {
|
flex: 1;
|
color: #606266;
|
font-size: 14px;
|
}
|
</style>
|