school_file_web/src/views/resourceMgt/catalogResourceMgt/index.vue

614 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-row>
<el-col :span="5">
<div class="tree-container">
<div class="top">
<el-button type="" text="plain">全部专题资源</el-button>
<br>
<el-button :class="['btn-audit', isAudit && 'active']" type="" text="plain"
@click="handleAudit">待审核</el-button>
<el-tree ref="treeRef" v-loading="treeLoading" :data="treeData" :props="defaultProps" default-expand-all
@node-click="handleNode" />
</div>
<div class="bottom">
<span>资源空间:639.7MB / 1TB</span>
<el-progress :percentage="55" />
</div>
</div>
</el-col>
<el-col :span="19">
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="课件名称" prop="fileName">
<el-input v-model="queryParams.fileName" placeholder="请输入课件名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="格式" prop="fileSuffix">
<el-select v-model="queryParams.fileSuffix" placeholder="请选择" style="width: 240px"
@keyup.enter="handleQuery">
<el-option v-for="item in formatOptions" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col v-if="isUpload" :span="1.5">
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload"
@click="handleFile">上传课件</el-button>
</el-col>
<el-col :span="1.5">
<el-button v-hasPermi="['system:oss:remove']" type="danger" plain icon="Delete" :disabled="multiple"
@click="handleDelete()">
删除
</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
</el-row>
</template>
<el-table v-if="showTable" v-loading="loading" :data="ossList" :header-cell-class-name="handleHeaderClass"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="课件名" align="center" prop="fileName" width="240" />
<el-table-column label="课件格式" align="center" prop="fileSuffix" />
<el-table-column label="课件大小" align="center" prop="volume" />
<el-table-column label="创建人" align="center" prop="createBy" />
<el-table-column label="创建时间" align="center" prop="createTime">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="350">
<template #default="scope">
<el-tooltip v-if="isAudit" content="审核通过" placement="top">
<el-button link type="primary" icon="CopyDocument"
@click="handleAuditBtn(scope.row, 1)">审核通过</el-button>
</el-tooltip>
<el-tooltip v-if="isAudit" content="审核不通过" placement="top">
<el-button link type="primary" icon="DocumentCopy"
@click="handleAuditBtn(scope.row, 0)">审核不通过</el-button>
</el-tooltip>
<el-tooltip content="预览" placement="top">
<el-button link type="primary" icon="View" @click="handlePreview(scope.row)">预览</el-button>
</el-tooltip>
<el-tooltip v-hasPermi="['system:oss:download']" content="下载" placement="top">
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)">下载</el-button>
</el-tooltip>
<el-tooltip v-if="isTree" content="移动" placement="top">
<el-button link type="primary" icon="CopyDocument" @click="handleMove(scope.row)">移动</el-button>
</el-tooltip>
<el-tooltip v-if="isTree" content="复制" placement="top">
<el-button link type="primary" icon="DocumentCopy" @click="handleCopy(scope.row)">复制</el-button>
</el-tooltip>
<el-tooltip v-if="isTree" content="删除" placement="top">
<el-button v-hasPermi="['system:oss:remove']" link type="primary" icon="Delete"
@click="handleDelete(scope.row)">删除</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
:total="total" @pagination="getList" />
</el-card>
<!-- 添加或修改OSS对象存储对话框 -->
<el-dialog v-model="dialog.visible" :title="dialog.title" width="700px" append-to-body>
<el-form ref="ossFormRef" :model="form" :rules="rules">
<el-form-item prop="file">
<FileMd5Upload v-if="type === 0" v-model="form.file" @onFileName="handleFileName" />
<imageUpload v-if="type === 1" v-model="form.file" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="previewDialog.visible" :title="previewDialog.title" width="900px" append-to-body>
<vue-office-docx v-loading="fileLoading" element-loading-text="加载中..."
v-if="currentFile.fileSuffix == '.doc' || currentFile.fileSuffix == '.docx'" :src="file" />
<vue-office-excel v-loading="fileLoading" element-loading-text="加载中..." :options="options"
style="height: 100vh;width: 100vh;"
v-if="currentFile.fileSuffix == '.xls' || currentFile.fileSuffix == '.xlsx'" :src="file" />
<vue-office-pdf v-loading="fileLoading" element-loading-text="加载中..." v-if="currentFile.fileSuffix == '.pdf'"
:src="file" />
<div v-loading="fileLoading" element-loading-text="加载中..." v-if="currentFile.fileSuffix == '.txt'"
style="white-space: pre-wrap;">{{ txt }}
</div>
<ImagePreview v-loading="fileLoading" element-loading-text="加载中..." style="width: 100%; text-align: center;"
v-if="imgSuffix.includes(currentFile.fileSuffix)" :src="imgUrl" />
</el-dialog>
<el-dialog v-model="treeMoveDialog.visible" :title="treeMoveDialog.title" width="500px" append-to-body>
<el-form ref="treeMoveFormRef" :model="treeMoveForm" :rules="treeMoveRules">
<el-form-item label="移动至" prop="catalogId">
<el-tree-select v-model="treeMoveForm.catalogId" :data="treeData"
:props="{ value: 'catalogId', label: 'catalogName', children: 'children' }" value-key="catalogId"
placeholder="请选择" check-strictly />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitMoveForm">确 定</el-button>
<el-button @click="cancelMove">取 消</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="treeCopyDialog.visible" :title="treeCopyDialog.title" width="500px" append-to-body>
<el-form ref="treeCopyFormRef" :model="treeCopyForm" :rules="treeCopyRules">
<el-form-item label="复制至" prop="catalogId">
<el-tree-select v-model="treeCopyForm.catalogId" :data="treeData"
:props="{ value: 'catalogId', label: 'catalogName', children: 'children' }" value-key="catalogId"
placeholder="请选择" check-strictly />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitCopyForm">确 定</el-button>
<el-button @click="cancelCopy">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</el-col>
</el-row>
</template>
<script setup name="Oss" lang="ts">
import { pageResource, awaitResourceList, preview, previewTxt, delResource, addResource, reviewResource, copyResource, moveResource } from '@/api/system/oss';
import ImagePreview from '@/components/ImagePreview/index.vue';
import FileMd5Upload from '@/components/FileMd5Upload/index.vue';
import { OssForm, OssQuery, OssVO } from '@/api/system/oss/types';
import { listCatalogResource } from "@/api/resource/catalogResource";
import { CatalogTextbookVO } from '@/api/resource/catalogTextbook/types';
//引入VueOfficeDocx组件
import VueOfficeDocx from '@vue-office/docx'
//引入相关样式
import '@vue-office/docx/lib/index.css'
//引入VueOfficeExcel组件
import VueOfficeExcel from '@vue-office/excel'
//引入相关样式
import '@vue-office/excel/lib/index.css'
//引入VueOfficePdf组件
import VueOfficePdf from '@vue-office/pdf'
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const fileSuffix = ['.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf']
const imgSuffix = ['.jpg', '.png', '.jpeg', '.gif', '.bmp']
const formatOptions = [
{
value: '.doc',
label: 'doc',
},
{
value: '.docx',
label: 'docx',
},
{
value: '.xls',
label: 'xls',
},
{
value: '.xlsx',
label: 'xlsx',
},
{
value: '.ppt',
label: 'ppt',
},
{
value: '.pptx',
label: 'pptx',
},
{
value: '.pdf',
label: 'pdf',
},
{
value: '.txt',
label: 'txt',
}
]
const defaultProps = {
children: 'children',
label: 'catalogName',
}
const isUpload = ref(false)
const currentNode = ref<any>({})
const treeData = ref<CatalogTextbookVO[]>([])
const ossList = ref<OssVO[]>([]);
const showTable = ref(true);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const type = ref(0);
const previewListResource = ref(true);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const previewDialog = reactive<DialogOption>({
visible: false,
title: '文件预览'
});
const treeMoveDialog = reactive<DialogOption>({
visible: false,
title: '移动'
});
const treeMoveFormRef = ref()
const treeMoveForm = ref<any>({ id: '', catalogId: '' });
const treeMoveRules = ref({
catalogId: [{ required: true, message: '请选择', trigger: 'blur' }]
})
const treeCopyDialog = reactive<DialogOption>({
visible: false,
title: '复制'
});
const treeCopyFormRef = ref()
const treeCopyForm = ref<any>({ id: '', catalogId: '' });
const treeCopyRules = ref({
catalogId: [{ required: true, message: '请选择', trigger: 'blur' }]
})
const ossFormRef = ref<ElFormInstance>();
const queryFormRef = ref<ElFormInstance>();
const initFormData = {
file: undefined
};
const data = reactive<PageData<OssForm, OssQuery>>({
form: { ...initFormData },
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
ossId: '',
fileName: '',
originalName: '',
fileSuffix: '',
createTime: '',
service: '',
catalogId: '',
},
rules: {
file: [{ required: true, message: '文件不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询OSS对象存储列表 */
const getList = async () => {
loading.value = true;
const res = await proxy?.getConfigKey('sys.oss.previewListResource');
previewListResource.value = res?.data === undefined ? true : res.data === 'true';
let response
if (isAudit.value) {
response = await awaitResourceList(queryParams.value);
} else {
response = await pageResource(queryParams.value);
}
ossList.value = response.rows;
total.value = response.total;
loading.value = false;
showTable.value = true;
};
/** 取消按钮 */
function cancel() {
dialog.visible = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = { ...initFormData };
ossFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
showTable.value = false;
queryFormRef.value?.resetFields();
handleQuery();
}
/** 选择条数 */
function handleSelectionChange(selection: OssVO[]) {
ids.value = selection.map((item) => item.ossId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 设置列的排序为我们自定义的排序 */
const handleHeaderClass = ({ column }: any): any => {
column.order = column.multiOrder;
};
/** 点击表头进行排序 */
const handleHeaderCLick = (column: any) => {
if (column.sortable !== 'custom') {
return;
}
switch (column.multiOrder) {
case 'descending':
column.multiOrder = 'ascending';
break;
case 'ascending':
column.multiOrder = '';
break;
default:
column.multiOrder = 'descending';
break;
}
handleOrderChange(column.property, column.multiOrder);
};
const handleOrderChange = (prop: string, order: string) => {
let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(',') : [];
let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(',') : [];
let propIndex = orderByArr.indexOf(prop);
if (propIndex !== -1) {
if (order) {
//排序里已存在 只修改排序
isAscArr[propIndex] = order;
} else {
//如果order为null 则删除排序字段和属性
isAscArr.splice(propIndex, 1); //删除排序
orderByArr.splice(propIndex, 1); //删除属性
}
} else {
//排序里不存在则新增排序
orderByArr.push(prop);
isAscArr.push(order);
}
//合并排序
queryParams.value.orderByColumn = orderByArr.join(',');
queryParams.value.isAsc = isAscArr.join(',');
getList();
};
/** 文件按钮操作 */
const handleFile = () => {
reset();
type.value = 0;
dialog.visible = true;
dialog.title = '上传文件';
};
const fileName = ref('')
const handleFileName = (val) => {
fileName.value = val
}
/** 提交按钮 */
const submitForm = async () => {
const ossId = form.value.file
const catalogId = currentNode.value.catalogId
await addResource({ ossId, catalogId, fileName: fileName.value })
dialog.visible = false;
getList();
};
const submitMoveForm = () => {
treeMoveFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
treeMoveDialog.visible = false;
const res = await moveResource(treeMoveForm.value)
if (res.code === 200) {
proxy?.$modal.msgSuccess("移动成功")
await getList()
}
}
});
}
const cancelMove = () => {
treeMoveDialog.visible = false
}
const submitCopyForm = () => {
treeCopyFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
treeCopyDialog.visible = false
const res = await copyResource(treeCopyForm.value)
if (res.code === 200) {
proxy?.$modal.msgSuccess("复制成功")
await getList()
}
}
});
}
const cancelCopy = () => {
treeCopyDialog.visible = false
}
// 0审核不通过 1审核通过
const handleAuditBtn = async (row: any, status: number) => {
const id = row?.id
const fileName = row?.fileName
const title = status === 1 ? `是否审核通过${fileName}?` : `是否审核不通过${fileName}?`
await proxy?.$modal.confirm(title).finally(() => loading.value = false)
await reviewResource({ id, status })
proxy?.$modal.msgSuccess(status === 1 ? "审核通过" : '审核不通过');
await getList();
}
/** 下载按钮操作 */
const handleDownload = (row: any) => {
proxy?.download(`/file/resource/download/${row.id}`, {}, `${row.fileName}`);
};
const handleMove = async (row: any) => {
treeMoveDialog.visible = true
treeMoveForm.value.id = row.id
treeMoveForm.value.catalogId = currentNode.value.catalogId
}
const handleCopy = (row: any) => {
treeCopyDialog.visible = true
treeCopyForm.value.id = row.id
treeCopyForm.value.catalogId = currentNode.value.catalogId
}
/** 删除按钮操作 */
const handleDelete = async (row?: any) => {
const delIds = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + delIds + '"的数据项?');
loading.value = true;
await delResource(delIds).finally(() => (loading.value = false));
await getList();
proxy?.$modal.msgSuccess('删除成功');
};
const isAudit = ref(false)
const isTree = ref(false)
const handleAudit = () => {
isAudit.value = true
isTree.value = false
getList()
}
const handleNode = (node: any) => {
console.log(node)
isAudit.value = false
isTree.value = true
isUpload.value = true
currentNode.value = node
queryParams.value.catalogId = node.catalogId
getList()
}
const options = ref({
xls: false, //预览xlsx文件设为false预览xls文件设为true
minColLength: 0, // excel最少渲染多少列如果想实现xlsx文件内容有几列就渲染几列可以将此值设置为0.
minRowLength: 0, // excel最少渲染多少行如果想实现根据xlsx实际函数渲染可以将此值设置为0.
widthOffset: 10, //如果渲染出来的结果感觉单元格宽度不够,可以在默认渲染的列表宽度上再加 Npx宽
heightOffset: 10, //在默认渲染的列表高度上再加 Npx高
beforeTransformData: (workbookData) => { return workbookData }, //底层通过exceljs获取excel文件内容通过该钩子函数可以对获取的excel文件内容进行修改比如某个单元格的数据显示不正确可以在此自行修改每个单元格的value值。
transformData: (workbookData) => { return workbookData }, //将获取到的excel数据进行处理之后且渲染到页面之前可通过transformData对即将渲染的数据及样式进行修改此时每个单元格的text值就是即将渲染到页面上的内容
})
const currentFile = ref()
const file = ref('')
const fileLoading = ref(false)
const txt = ref('')
const imgUrl = ref('')
const handlePreview = async (row: OssVO) => {
file.value = ''
fileLoading.value = true
previewDialog.visible = true
currentFile.value = row
if (row.fileSuffix == '.txt') {
const fileRes = await previewTxt(row.ossId)
console.log(fileRes)
txt.value = fileRes
} else if (imgSuffix.includes(row.fileSuffix)) {
const fileRes = await preview(row.ossId)
let blob = new Blob([fileRes], { type: `image/${row.fileSuffix.substring(1)}` })
imgUrl.value = URL.createObjectURL(blob)
} else if (fileSuffix.includes(row.fileSuffix)) {
const fileRes = await preview(row.ossId)
fileRes.arrayBuffer().then(res => file.value = res)
}
fileLoading.value = false
}
const treeLoading = ref(false)
/** 查询目录-同步教材列表 */
const getlistCatalogResource = async () => {
treeLoading.value = true;
const res = await listCatalogResource();
const data = proxy?.handleTree<CatalogTextbookVO>(res.data, "catalogId", "parentId");
if (data) {
treeData.value = data;
treeLoading.value = false;
}
}
onMounted(() => {
getlistCatalogResource()
getList();
});
</script>
<style lang="scss" scoped>
.tree-container {
margin-top: 10px;
padding-top: 10px;
height: calc(100vh - 120px);
display: flex;
flex-direction: column;
justify-content: space-between;
border: 1px solid #ccc;
.top {
margin: 0 20px;
}
.bottom {
text-align: center;
padding-left: 20px;
padding-right: 20px;
padding-bottom: 30px;
font-size: 18px;
}
.btn-audit {
text-indent: 1em;
}
.active {
background-color: #F5F7FA;
}
}
:deep(.docx-wrapper) {
background-color: #fff;
padding: 0;
}
</style>