3 Commits

Author SHA1 Message Date
Sh1yu
f99b278e51 1.回收站功能前后端实现
2.文件管理前后端实现
3.样式未调整、功能初步测试通过
2023-10-24 15:41:26 +08:00
Sh1yu
b25e0cd03b 提交文件管理前端页面代码 2023-10-11 15:59:26 +08:00
Sh1yu
8a8cd1b295 回收站前端代码提交 2023-10-11 10:34:33 +08:00
19 changed files with 804 additions and 165 deletions

View File

@@ -2,9 +2,13 @@ package com.zyplayer.doc.data.repository.manage.mapper;
import com.zyplayer.doc.data.repository.manage.entity.WikiPageFile;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zyplayer.doc.data.repository.manage.param.PageFileQueryParam;
import com.zyplayer.doc.data.repository.manage.vo.WikiPageFileInfoVo;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.util.List;
/**
* <p>
* Mapper 接口
@@ -14,7 +18,11 @@ import org.apache.ibatis.annotations.Update;
* @since 2019-03-06
*/
public interface WikiPageFileMapper extends BaseMapper<WikiPageFile> {
@Update("update wiki_page_file set download_num=download_num+1 where id=#{id}")
void addDownloadNum(@Param("id") Long id);
List<WikiPageFileInfoVo> getFileInfosVo(PageFileQueryParam pageFileQueryParam);
Long getFileInfoCount(PageFileQueryParam pageFileQueryParam);
}

View File

@@ -0,0 +1,13 @@
package com.zyplayer.doc.data.repository.manage.param;
import lombok.Data;
@Data
public class PageFileQueryParam {
private String name;
private String status;
private String file;
private String type;
private int pageSize;
private int current;
}

View File

@@ -0,0 +1,25 @@
package com.zyplayer.doc.data.repository.manage.vo;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 文件相关信息
*
* @author sh1yu
* @since 2023-10-17
*/
@Data
public class WikiPageFileInfoVo {
private String id;
private String name;
private String size;
private String uuid;
private String user;
private Date time ;
private String status;
private String type;
private String file;
}

View File

@@ -1,5 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zyplayer.doc.data.repository.manage.mapper.WikiPageFileMapper">
<select id="getFileInfosVo" resultType="com.zyplayer.doc.data.repository.manage.vo.WikiPageFileInfoVo">
SELECT a.id as id,
a.file_name as name,
a.file_size as size,
a.uuid as uuid,
a.create_user_name as user,
a.create_time as time ,
a.del_flag as status,
a.file_source as type,
b.del_flag as file
from wiki_page_file a left JOIN wiki_page b on a.page_id = b.id
where a.del_flag != 2
<if test="name != null and name != ''">
and (
a.file_name like #{name}
)
</if>
<if test="status != null and status != '' and status != 9">
and (
a.del_flag = #{status}
)
</if>
<if test="file != null and file != '' and file != 9">
and (
b.del_flag = #{file}
)
</if>
<if test="type != null and type != '' and type != 0">
and (
a.file_source = #{type}
)
</if>
order by b.id
limit #{pageSize} offset #{current}
</select>
<select id="getFileInfoCount" resultType="java.lang.Long">
SELECT count(*)
from wiki_page_file a left JOIN wiki_page b on a.page_id = b.id
where a.del_flag != 2
<if test="name != null and name != ''">
and (
a.file_name like #{name}
)
</if>
<if test="status != null and status != '' and status != 9">
and (
a.del_flag = #{status}
)
</if>
<if test="file != null and file != '' and file != 9">
and (
b.del_flag = #{file}
)
</if>
<if test="type != null and type != '' and type != 0">
and (
a.file_source = #{type}
)
</if>
</select>
</mapper>

View File

@@ -5,6 +5,9 @@ export default {
pageUpdate: (data) => request({url: '/zyplayer-doc-wiki/page/update', method: 'post', data: Qs.stringify(data)}),
pageChangeParent: (data) => request({url: '/zyplayer-doc-wiki/page/changeParent', method: 'post', data: Qs.stringify(data)}),
pageList: (data) => request({url: '/zyplayer-doc-wiki/page/list', method: 'post', data: Qs.stringify(data)}),
deleted: (data) => request({url: '/zyplayer-doc-wiki/page/deleted', method: 'post', data: Qs.stringify(data)}),
revert: (data) => request({url: '/zyplayer-doc-wiki/page/revert', method: 'post', data: Qs.stringify(data)}),
destroy: (data) => request({url: '/zyplayer-doc-wiki/page/destroy', method: 'post', data: Qs.stringify(data)}),
updatePage: (data) => request({url: '/zyplayer-doc-wiki/page/update', method: 'post', data: Qs.stringify(data)}),
copyPage: (data) => request({url: '/zyplayer-doc-wiki/page/copy', method: 'post', data: Qs.stringify(data)}),
movePage: (data) => request({url: '/zyplayer-doc-wiki/page/move', method: 'post', data: Qs.stringify(data)}),
@@ -26,7 +29,9 @@ export default {
updateSpace: (data) => request({url: '/zyplayer-doc-wiki/space/update', method: 'post', data: Qs.stringify(data)}),
getPageUserAuthList: (data) => request({url: '/zyplayer-doc-wiki/page/auth/list', method: 'post', data: Qs.stringify(data)}),
assignPageUserAuth: (data) => request({url: '/zyplayer-doc-wiki/page/auth/assign', method: 'post', data: Qs.stringify(data)}),
destoryFile: (data) => request({url: '/zyplayer-doc-wiki/page/file/destory', method: 'post', data: Qs.stringify(data)}),
deletePageFile: (data) => request({url: '/zyplayer-doc-wiki/page/file/delete', method: 'post', data: Qs.stringify(data)}),
fileInfoList: (data) => request({url: '/zyplayer-doc-wiki/page/file/list', method: 'post', data: Qs.stringify(data)}),
pageCommentList: (data) => request({url: '/zyplayer-doc-wiki/page/comment/list', method: 'post', data: Qs.stringify(data)}),
updatePageComment: (data) => request({url: '/zyplayer-doc-wiki/page/comment/update', method: 'post', data: Qs.stringify(data)}),
deletePageComment: (data) => request({url: '/zyplayer-doc-wiki/page/comment/delete', method: 'post', data: Qs.stringify(data)}),

View File

@@ -1,5 +1,5 @@
<template>
<div style="padding: 10px;height: 100%;box-sizing: border-box;background: #fafafa;">
<div style="padding: 10px;height: 100%;box-sizing: border-box;background: #fafafa;position: relative">
<div style="margin-bottom: 5px">
<el-select :model-value="choiceSpace" filterable placeholder="选择空间" @change="spaceChangeEvents" style="width: 100%">
<el-option-group label="" v-if="!props.readOnly">
@@ -54,6 +54,20 @@
</template>
</el-tree>
</div>
<div v-if="!props.readOnly" class="sidebar-tool-box">
<span class="sidebar-tool-box-bottom">
<a-divider />
<a-button type="text" @click="routeToFileCtl()">
<template #icon><DatabaseOutlined /></template>
文件管理
</a-button>
<a-divider type="vertical" style="height: 10px; background-color: #7cb305"/>
<a-button type="text" @click="routeToRecycleBin()">
<template #icon><DeleteOutlined /></template>
回收站
</a-button>
</span>
</div>
</div>
</template>
@@ -63,6 +77,9 @@ import {useRouter, useRoute} from "vue-router";
import pageApi from '../../assets/api/page'
import {useStoreDisplay} from "@/store/wikiDisplay";
import {useStorePageData} from "@/store/pageData";
import {DatabaseOutlined,DeleteOutlined} from '@ant-design/icons-vue';
import {useStoreSpaceData} from "@/store/spaceData";
let emit = defineEmits(['doGetPageList', 'spaceChangeEvents', 'setNowPageId'])
let searchKeywords = ref('');
@@ -75,7 +92,9 @@ let router = useRouter();
let defaultProps = ref({children: 'children', label: 'name',});
let wikiPage = ref({});
let wikiPageTreeRef = ref();
let storePage = useStorePageData();
let storeDisplay = useStoreDisplay();
let storeSpace = useStoreSpaceData();
let props = defineProps({
wikiPageList: Array,
spaceOptions: Array,
@@ -139,7 +158,6 @@ const filterPageNode = (value, data) => {
const searchByKeywords = () => {
wikiPageTreeRef.value.filter(searchKeywords.value)
}
let storePage = useStorePageData();
const handleNodeClick = (data) => {
//console.log('点击节点:', data, props.nowPageId)
storeDisplay.showHeader = true
@@ -167,7 +185,29 @@ const handlePageDrop = (draggingNode, dropNode, dropType, ev) => {
emit('doGetPageList', node.id, node)
})
}
const routeToFileCtl = () => {
router.push({
path: '/management/file'
})
}
const routeToRecycleBin = () => {
router.push({
path: '/management/recyclebin',
})
}
defineExpose({searchByKeywords})
</script>
<style scoped>
.sidebar-tool-box{
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
.sidebar-tool-box-bottom{
}
</style>

View File

@@ -1,79 +1,81 @@
<template>
<el-dialog title="设置为模板" v-model="newTemplateDialogVisible" width="600px" :close-on-click-modal="false">
<el-form label-width="100px" :model="templateNewForm">
<el-form-item label="模板标签">
<el-input v-model="templateNewForm.tagName"></el-input>
</el-form-item>
<el-form-item label="是否公开">
<el-switch v-model="templateNewForm.shareStatus" inactive-text="个人模板" :inactive-value="0" active-text="公共模板" :active-value="1"></el-switch>
</el-form-item>
<el-form-item>
<el-button type="primary" v-if="exsit" @click="onNewTemplateSubmit">保存修改</el-button>
<el-button type="primary" v-else @click="onNewTemplateSubmit">立即创建</el-button>
<el-button @click="onNewTemplateCancel">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<a-modal
v-model:open="templateChooseDialogVisible"
title="模板库"
width="100%"
wrapClassName="full-modal"
:confirm-loading="aModalWaiting"
:destroyOnClose=true
:closable=true>
<div>
<el-switch v-model="open" inactive-text="个人模板" :inactive-value="0" active-text="公共模板" :active-value="1" @change="filterByOpen"></el-switch>
<a-divider type="vertical"/>
<el-input v-model="name" style="width: 30%" @change="filterByName"></el-input>
</div>
<a-divider>模板标签</a-divider>
<a-checkable-tag v-for="tag in tags" @click="filterByTags(tag.tagName,tag.show)" v-model:checked="tag.show" style="margin: 5px" size="big">{{tag.tagName}}</a-checkable-tag>
<a-divider/>
<a-list :grid="{gutter:1,column:4,xs:1,sm:1,md:2,lg:2,xl:4,xxl:4}" :data-source="templateList">
<template #renderItem="{item}">
<a-list-item>
<a-card :title="item.name">
<a-tag color="#f50">{{filterShareStatus(item.shareStatus)}}</a-tag>
<a-tag color="#87d068">{{item.tags}}</a-tag>
<br/>
{{item.createUserName}}
<br/>
{{item.createTime}}
<template #actions>
<el-tooltip effect="dark" content="转到原文档" placement="top">
<AimOutlined @click="turnToSource(item)"/>
</el-tooltip>
<el-tooltip effect="dark" content="预览模板" placement="top">
<BorderOutlined @click="showPreview(item)"/>
</el-tooltip>
<el-tooltip effect="dark" content="使用模板" placement="top">
<AlertOutlined @click="chooseTemplate(item)"/>
</el-tooltip>
</template>
</a-card>
</a-list-item>
</template>
</a-list>
<a-pagination simple v-model:current="nowTemplateNum" :total="totalTemplate" style="float: right"
:page-size="8" :hide-on-single-page=true @change="pageUpDown"/>
<template #footer/>
</a-modal>
<a-modal
v-model:open="previewVisible"
title="模板预览"
width="100%"
wrapClassName="full-modal"
:destroyOnClose=true
:closable=true>
<el-row>
<div ref="pageContentRef" class="wiki-page-content">
<div v-html="pageShowDetail" class="markdown-body" v-if="editorType.value === 2" v-highlight></div>
<div v-html="pageShowDetail" class="wang-editor-body" v-else></div>
<div>
<el-dialog title="设置为模板" v-model="newTemplateDialogVisible" width="600px" :close-on-click-modal="false">
<el-form label-width="100px" :model="templateNewForm">
<el-form-item label="模板标签">
<el-input v-model="templateNewForm.tagName"></el-input>
</el-form-item>
<el-form-item label="是否公开">
<el-switch v-model="templateNewForm.shareStatus" inactive-text="个人模板" :inactive-value="0" active-text="公共模板" :active-value="1"></el-switch>
</el-form-item>
<el-form-item>
<el-button type="primary" v-if="exsit" @click="onNewTemplateSubmit">保存修改</el-button>
<el-button type="primary" v-else @click="onNewTemplateSubmit">立即创建</el-button>
<el-button @click="onNewTemplateCancel">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<a-modal
v-model:open="templateChooseDialogVisible"
title="模板库"
width="100%"
wrapClassName="full-modal"
:confirm-loading="aModalWaiting"
:destroyOnClose=true
:closable=true>
<div>
<el-switch v-model="open" inactive-text="个人模板" :inactive-value="0" active-text="公共模板" :active-value="1" @change="filterByOpen"></el-switch>
<a-divider type="vertical"/>
<el-input v-model="name" style="width: 30%" @change="filterByName"></el-input>
</div>
</el-row>
<template #footer/>
</a-modal>
<a-divider>模板标签</a-divider>
<a-checkable-tag v-for="tag in tags" @click="filterByTags(tag.tagName,tag.show)" v-model:checked="tag.show" style="margin: 5px" size="big">{{tag.tagName}}</a-checkable-tag>
<a-divider/>
<a-list :grid="{gutter:1,column:4,xs:1,sm:1,md:2,lg:2,xl:4,xxl:4}" :data-source="templateList">
<template #renderItem="{item}">
<a-list-item>
<a-card :title="item.name">
<a-tag color="#f50">{{filterShareStatus(item.shareStatus)}}</a-tag>
<a-tag color="#87d068">{{item.tags}}</a-tag>
<br/>
{{item.createUserName}}
<br/>
{{item.createTime}}
<template #actions>
<el-tooltip effect="dark" content="转到原文档" placement="top">
<AimOutlined @click="turnToSource(item)"/>
</el-tooltip>
<el-tooltip effect="dark" content="预览模板" placement="top">
<BorderOutlined @click="showPreview(item)"/>
</el-tooltip>
<el-tooltip effect="dark" content="使用模板" placement="top">
<AlertOutlined @click="chooseTemplate(item)"/>
</el-tooltip>
</template>
</a-card>
</a-list-item>
</template>
</a-list>
<a-pagination simple v-model:current="nowTemplateNum" :total="totalTemplate" style="float: right"
:page-size="8" :hide-on-single-page=true @change="pageUpDown"/>
<template #footer/>
</a-modal>
<a-modal
v-model:open="previewVisible"
title="模板预览"
width="100%"
wrapClassName="full-modal"
:destroyOnClose=true
:closable=true>
<el-row>
<div ref="pageContentRef" class="wiki-page-content">
<div v-html="pageShowDetail" class="markdown-body" v-if="editorType.value === 2" v-highlight></div>
<div v-html="pageShowDetail" class="wang-editor-body" v-else></div>
</div>
</el-row>
<template #footer/>
</a-modal>
</div>
</template>
<script setup>

View File

@@ -9,6 +9,8 @@ import Home from './views/home/Home.vue'
import MyInfo from './views/user/MyInfo.vue'
import Show from './views/page/Show.vue'
import Edit from './views/page/Edit.vue'
import FileManagement from './views/management/FileManagement.vue'
import RecycleBinManagement from './views/management/RecycleBinManagement.vue'
import spaceManage from './views/space/Manage.vue'
@@ -30,6 +32,8 @@ let routes = [
{path: '/page/show', name: 'WIKI-页面查看', component: Show},
{path: '/page/edit', name: 'WIKI-编辑内容', component: Edit},
{path: '/space/manage', name: 'WIKI-空间管理', component: spaceManage},
{path: '/management/file', name: 'WIKI-文件管理', component: FileManagement},
{path: '/management/recyclebin', name: 'WIKI-回收站', component: RecycleBinManagement},
],
},
{

View File

@@ -0,0 +1,272 @@
<template>
<div>
<span class="up-query-param-span">
<a-form :model="queryParam" :label-col="{span: 8}" :wrapper-col="{span: 16}">
<a-row :gutter="16">
<a-col :span="5">
<a-form-item label="文件名">
<a-input v-model:value="queryParam.name" placeholder="请输入文件名"/>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item label="文件状态">
<a-select ref="select" v-model:value="queryParam.status">
<a-select-option value="9">全部</a-select-option>
<a-select-option value="1">未删除</a-select-option>
<a-select-option value="2">已删除</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item label="文档状态">
<a-select ref="select" v-model:value="queryParam.file">
<a-select-option value="9">全部</a-select-option>
<a-select-option value="1">未删除</a-select-option>
<a-select-option value="2">已删除</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item label="文件类型">
<a-select ref="select" v-model:value="queryParam.type">
<a-select-option value="0">全部</a-select-option>
<a-select-option value="1">附件</a-select-option>
<a-select-option value="2">文档内含附件</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="4">
<a-button type="primary" @click="query">
<template #icon><SearchOutlined/></template>
查询
</a-button>
</a-col>
</a-row>
</a-form>
</span>
<a-divider/>
<a-button type="primary" danger @click="doDeleteSelected()">
<template #icon>
<DeleteFilled/>
</template>
删除选中文件
</a-button>
<a-radio-group v-model:value="showStyle" size="large" button-style="solid" style="margin-left: 20px">
<a-radio-button value="table">
<TableOutlined/>
列表展示
</a-radio-button>
<a-radio-button value="card">
卡片展示
<ProfileOutlined/>
</a-radio-button>
</a-radio-group>
<a-table v-if="showStyle === 'table'" :columns="columns" :data-source="table"
:scroll="{ x: 1200, y: 'calc(100vh - 280px)' }" :row-selection="rowSelection" :pagination=false
rowKey="id">
<template v-slot:bodyCell="{ column, record ,index}">
<a-tag v-if="column.dataIndex === 'size'" color="#f50">
{{ sizeConvert(record.size) }}
</a-tag>
<a-tag v-if="column.dataIndex === 'status'" color="#f50">
{{ statusDesc(record.status) }}
</a-tag>
<a-tag v-if="column.dataIndex === 'file'" color="#f50">
{{ statusDesc(record.file) }}
</a-tag>
<a-tag v-if="column.dataIndex === 'type'" color="#f50">
{{ typeDesc(record.type) }}
</a-tag>
</template>
</a-table>
<div v-if="showStyle === 'card'">
<span v-for="item in table" @click="mark(item)">
<div v-if="item.type === '1'" :title="item.name">
<a-descriptions title="文件名" bordered size="small"
:column="{ xxl: 1, xl: 1, lg: 1, md: 1, sm: 1, xs: 1 }"
style="width: 250px;height:350px">
<a-descriptions-item label="文件名称">{{item.name}}</a-descriptions-item>
<a-descriptions-item label="文件大小">{{sizeConvert(item.size)}}</a-descriptions-item>
<a-descriptions-item label="文件状态">{{statusDesc(item.status)}}</a-descriptions-item>
<a-descriptions-item label="文件状态">{{statusDesc(item.file)}}</a-descriptions-item>
<a-descriptions-item label="文件类型">{{typeDesc(item.type)}}</a-descriptions-item>
<a-descriptions-item label="上传者">{{item.user}}</a-descriptions-item>
<a-descriptions-item label="上传时间">{{item.time}}</a-descriptions-item>
</a-descriptions>
</div>
<a-tabs v-if="item.type === '2'" v-model:activeKey="activeKey" @mouseenter="showImage()"
@mouseleave="showDetail()">
<a-tab-pane key='1' tab="图片页">
<a-image :width="250" :height="300" :src="buildSrc(item.uuid)"/>
</a-tab-pane>
<a-tab-pane key='2' tab="详情页">
<div style="width: 250px;height:300px;">
<a-descriptions title="图像详情" bordered size="small"
:column="{ xxl: 1, xl: 1, lg: 1, md: 1, sm: 1, xs: 1 }">
<a-descriptions-item label="文件名称">{{item.name}}</a-descriptions-item>
<a-descriptions-item label="文件大小">{{sizeConvert(item.size)}}</a-descriptions-item>
<a-descriptions-item label="文件状态">{{statusDesc(item.status)}}</a-descriptions-item>
<a-descriptions-item label="文件状态">{{statusDesc(item.file)}}</a-descriptions-item>
<a-descriptions-item label="文件类型">{{typeDesc(item.type)}}</a-descriptions-item>
<a-descriptions-item label="上传者">{{item.user}}</a-descriptions-item>
<a-descriptions-item label="上传时间">{{item.time}}</a-descriptions-item>
</a-descriptions>
</div>
</a-tab-pane>
<template #renderTabBar="{ DefaultTabBar, ...props }"></template>
</a-tabs>
<CheckCircleTwoTone v-if="item.choose" twoToneColor="#52c41a" style="margin-right: 200px"/>
<CheckCircleTwoTone v-else twoToneColor="#e5ecf7" style="margin-right: 200px"/>
</span>
</div>
<a-pagination v-model:current="queryParam.current"
:page-size-options="activeKey === 'card'?pageSizeOptionsCard:pageSizeOptions"
:total="queryParam.total" :page-size="queryParam.pageSize" show-size-changer
@showSizeChange="onShowSizeChange" @change="pageQuery">
<template #buildOptionText="props">
<span v-if="props.value !== '50'">{{ props.value }}/</span>
<span v-else>全部</span>
</template>
</a-pagination>
</div>
</template>
<script setup>
import {
AimOutlined,
SearchOutlined,
DeleteFilled,
TableOutlined,
ProfileOutlined,
CheckCircleTwoTone
} from '@ant-design/icons-vue';
import {onMounted, ref} from "vue";
import {mavonEditor} from "mavon-editor";
import pageApi from '../../assets/api/page'
import {ElMessage, ElMessageBox} from "element-plus";
let visible = ref(false)
let showStyle = ref('table')
let activeKey = ref('1')
let pageSizeOptionsCard = ref(['4', '8']);
let pageSizeOptions = ref(['10', '20']);
let deleteQueue = ref([]);
let queryParam = ref({
current: 1,
total: 0,
pageSize: 10,
name: '',
status: '9',
file: '9',
type: '0'
})
let table = ref([]);
let columns = ref([
{title: '文件名称', dataIndex: 'name', width: '500',},
{title: '文件大小', dataIndex: 'size', width: '100',},
{title: '文件状态', dataIndex: 'status', width: '100',},
{title: '文档状态', dataIndex: 'file', width: '100',},
{title: '文档类型', dataIndex: 'type', width: '100',},
{title: '上传者', dataIndex: 'user', width: '150',},
{title: '上传时间', dataIndex: 'time', width: '150',},
])
onMounted(() => {
query()
})
const rowSelection = {
selectedRowKeys: deleteQueue,
onChange: (selectedRowKeys, selectedRows) => {
deleteQueue.value = selectedRowKeys
console.log(selectedRowKeys)
},
onSelect: (record, selected, selectedRows) => {
//console.log(record, selected, selectedRows);
},
onSelectAll: (selected, selectedRows, changeRows) => {
//console.log(selected, selectedRows, changeRows);
},
};
const statusDesc = (status) => {
const statusMap = {
0: '未删除',
1: '已删除',
}
return statusMap[status]
}
const typeDesc = (type) => {
const typeMap = {
1: '附件',
2: '影像',
}
return typeMap[type]
}
const sizeConvert = (size) => {
size = size / 1024 / 1024
return size.toFixed(2) + 'M'
}
const query = () => {
pageApi.fileInfoList(queryParam.value).then((json) => {
table.value = json.data || []
queryParam.value.total = json.total
})
}
const doDeleteSelected = () => {
ElMessageBox.confirm("确认要删除选中的文件吗?删除后不可恢复!", '重要提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
if (showStyle.value === 'card') {
let deleteList = [];
let temp = table
temp = temp.value.filter(item => (item.choose))
temp.forEach(item => {
deleteList.push(item.id)
})
pageApi.destoryFile({arr: deleteList}).then(() => {
query()
})
return
}
pageApi.destoryFile({arr: deleteQueue.value}).then(() => {
query()
})
})
}
const buildSrc = (uuid) => {
return "zyplayer-doc-wiki/common/file?uuid=" + uuid;
};
const showImage = () => {
activeKey.value = '2'
};
const showDetail = () => {
activeKey.value = '1'
};
const pageQuery = () => {
deleteQueue.value = []
query()
};
const onShowSizeChange = (current, size) => {
queryParam.value.pageSize = size;
deleteQueue.value = []
query()
};
const mark = (item) => {
let choosed = item.choose;
if (choosed === undefined) {
choosed = false
}
item.choose = !choosed
};
</script>
<style scoped>
.up-query-param-span {
}
</style>

View File

@@ -0,0 +1,106 @@
<template>
<div>
<a-table :columns="columns" :data-source="table" :pagination=false :scroll="{ y: 'calc(100vh - 170px)' }">
<template v-slot:bodyCell="{ column, record ,index}">
<span v-if="column.key === 'action'">
<a-divider type="vertical"/>
<a-button @click="revertConfirm(record)">
<template #icon><UndoOutlined /></template>
恢复
</a-button>
<a-divider type="vertical"/>
<a-button @click="destroy(record)">
<template #icon><DeleteFilled /></template>
彻底删除
</a-button>
</span>
</template>
</a-table>
<a-pagination v-model:current="queryParam.current"
:page-size-options="pageSizeOptions"
:total="queryParam.total" :page-size="queryParam.pageSize" show-size-changer
@showSizeChange="onShowSizeChange" @change="initDeleted">
<template #buildOptionText="props">
<span v-if="props.value !== '50'">{{ props.value }}/</span>
<span v-else>全部</span>
</template>
</a-pagination>
</div>
</template>
<script setup>
import {UndoOutlined,DeleteFilled,TableOutlined,RightCircleOutlined,} from '@ant-design/icons-vue';
import {onBeforeUnmount, onMounted, ref} from "vue";
import pageApi from '../../assets/api/page'
import {ElMessage, ElMessageBox} from "element-plus";
import {useStoreSpaceData} from "@/store/spaceData";
import {useStorePageData} from "@/store/pageData";
let storeSpace = useStoreSpaceData();
let storePage = useStorePageData();
let table = ref([]);
let pageSizeOptions = ref(['10', '20']);
let columns = ref([
{title: '名称', dataIndex: 'name', width: '40%' ,},
{title: '删除日期', dataIndex: 'updateTime', width: '17%',},
{title: '操作者', dataIndex: 'updateUserName', width: '16%',},
{title: '', key: 'action'},
])
let queryParam = ref({
current: 1,
total: 0,
pageSize: 10,
spaceId: storeSpace.chooseSpaceId
})
onMounted(() => {
initDeleted()
})
const onShowSizeChange = (current, size) => {
queryParam.value.pageSize = size;
initDeleted()
};
const initDeleted = () => {
pageApi.deleted(queryParam.value).then((json) => {
table.value = json.data || []
queryParam.value.total = json.total
})
console.log()
}
const revertConfirm = (record) => {
ElMessageBox.confirm('确定要还原此文档吗(仅此文档,若父级文档不存在还原当前空间根目录)?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
let param = {pageId: record.id}
pageApi.revert(param).then(() => {
ElMessage.success('还原成功!')
doGetPageList()
initDeleted()
})
})
}
const doGetPageList = (parentId, node) => {
let param = {spaceId: storeSpace.chooseSpaceId}
pageApi.pageList(param).then((json) => {
storePage.wikiPageList = json.data || []
})
}
const destroy = (record) => {
ElMessageBox.confirm('确定要物理删除此文档吗?(关联的文件不会被删除仅删除文档)', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
let param = {pageId: record.id}
pageApi.destroy(param).then(() => {
ElMessage.success('删除成功')
doGetPageList()
initDeleted()
})
})
}
</script>
<style scoped>
</style>

View File

@@ -4,6 +4,8 @@ import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zyplayer.doc.core.annotation.AuthMan;
import com.zyplayer.doc.core.enums.PageFileSource;
import com.zyplayer.doc.core.exception.ConfirmException;
@@ -543,5 +545,49 @@ public class WikiPageController {
}
}
}
@PostMapping("/deleted")
public ResponseJson<List<WikiPage>> deletedList(int spaceId,int current ,int pageSize) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("space_id", spaceId);
queryWrapper.eq("del_flag",1);
IPage<WikiPage> page = new Page<>(current, pageSize, false);
wikiPageService.page(page, queryWrapper);
page.setTotal(wikiPageService.count(queryWrapper));
return DocResponseJson.ok(page);
}
@PostMapping("/destroy")
public ResponseJson destroyPage(int pageId) {
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.eq("id", pageId);
updateWrapper.eq("del_flag",1);
updateWrapper.set("del_flag",2);
wikiPageService.update(updateWrapper);
return DocResponseJson.ok();
}
@PostMapping("/revert")
public ResponseJson revertPage(int pageId) {
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.eq("id", pageId);
updateWrapper.eq("del_flag",1);
updateWrapper.set("del_flag",0);
if (!canPageShow(pageId)) {
updateWrapper.set("parent_id",0);
}
wikiPageService.update(updateWrapper);
return DocResponseJson.ok();
}
public boolean canPageShow(long pageId){
WikiPage own = wikiPageService.getById(pageId);
WikiPage parent = wikiPageService.getById(own.getParentId());
if (null==parent||parent.getDelFlag() != 0){
return false;
}
if ( parent.getParentId()!= 0){
canPageShow(parent.getParentId());
}
return true;
}
}

View File

@@ -6,7 +6,9 @@ import com.zyplayer.doc.core.enums.PageFileSource;
import com.zyplayer.doc.core.json.DocResponseJson;
import com.zyplayer.doc.core.json.ResponseJson;
import com.zyplayer.doc.data.repository.manage.entity.WikiPageFile;
import com.zyplayer.doc.data.repository.manage.vo.WikiPageFileInfoVo;
import com.zyplayer.doc.wiki.batch.BatchDocImportManager;
import com.zyplayer.doc.data.repository.manage.param.PageFileQueryParam;
import com.zyplayer.doc.wiki.service.WikiPageFileServiceEx;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -16,7 +18,10 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@@ -32,10 +37,10 @@ import java.util.Map;
@RequestMapping("/zyplayer-doc-wiki/page/file")
@RequiredArgsConstructor
public class WikiPageFileController {
private final WikiPageFileServiceEx wikiPageFileServiceEx;
private final BatchDocImportManager batchDocImportManger;
@PostMapping("/delete")
public ResponseJson<Object> delete(WikiPageFile wikiPageFile) {
String info = wikiPageFileServiceEx.delete(wikiPageFile);
@@ -44,7 +49,31 @@ public class WikiPageFileController {
}
return DocResponseJson.ok();
}
@PostMapping("/list")
public ResponseJson<Object> list(PageFileQueryParam pageFileQueryParam) {
List<WikiPageFileInfoVo> list = wikiPageFileServiceEx.list(pageFileQueryParam);
DocResponseJson<Object> ok = DocResponseJson.ok(list);
ok.setTotal(wikiPageFileServiceEx.total(pageFileQueryParam));
return ok;
}
@PostMapping("/destory")
public ResponseJson<Object> destory( HttpServletRequest request) {
ArrayList<Long> destoryList = new ArrayList<>();
Map<String, String[]> parameterMap = request.getParameterMap();
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
String[] values = entry.getValue();
if (values.length>0){
String value = values[0];
if (null!= value)
destoryList.add(Long.parseLong(value));
}
}
wikiPageFileServiceEx.destory(destoryList);
return DocResponseJson.ok();
}
@PostMapping("/wangEditor/upload")
public Map<String, Object> wangEditorUpload(WikiPageFile wikiPageFile, @RequestParam("files") MultipartFile file) {
Map<String, Object> resultMap = new HashMap<>();
@@ -59,16 +88,17 @@ public class WikiPageFileController {
}
return resultMap;
}
@PostMapping("/import/upload")
public ResponseJson importUpload(WikiPageFile wikiPageFile, @RequestParam("files") MultipartFile file) {
return batchDocImportManger.importBatchDoc(wikiPageFile, file);
}
@PostMapping("/upload")
public ResponseJson upload(WikiPageFile wikiPageFile, @RequestParam("files") MultipartFile file) {
wikiPageFile.setFileSource(PageFileSource.UPLOAD_FILES.getSource());
return wikiPageFileServiceEx.basicUpload(wikiPageFile, file);
}
}

View File

@@ -2,21 +2,25 @@ package com.zyplayer.doc.wiki.service;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zyplayer.doc.core.json.DocResponseJson;
import com.zyplayer.doc.core.json.ResponseJson;
import com.zyplayer.doc.data.config.security.DocUserDetails;
import com.zyplayer.doc.data.config.security.DocUserUtil;
import com.zyplayer.doc.data.repository.manage.entity.UserMessage;
import com.zyplayer.doc.data.repository.manage.entity.WikiPage;
import com.zyplayer.doc.data.repository.manage.entity.WikiPageFile;
import com.zyplayer.doc.data.repository.manage.entity.WikiSpace;
import com.zyplayer.doc.data.repository.manage.mapper.WikiPageFileMapper;
import com.zyplayer.doc.data.repository.manage.vo.WikiPageFileInfoVo;
import com.zyplayer.doc.data.repository.support.consts.DocSysType;
import com.zyplayer.doc.data.repository.support.consts.UserMsgType;
import com.zyplayer.doc.data.service.manage.UserMessageService;
import com.zyplayer.doc.data.service.manage.WikiPageFileService;
import com.zyplayer.doc.data.service.manage.WikiPageService;
import com.zyplayer.doc.data.service.manage.WikiSpaceService;
import com.zyplayer.doc.data.repository.manage.param.PageFileQueryParam;
import com.zyplayer.doc.wiki.service.common.WikiPageAuthService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
@@ -24,6 +28,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -45,6 +50,7 @@ public class WikiPageFileServiceEx {
private final WikiPageService wikiPageService;
private final WikiPageAuthService wikiPageAuthService;
private final UserMessageService userMessageService;
private final WikiPageFileMapper wikiPageFileMapper;
public List<WikiPageFile> list(WikiPageFile wikiPageFile) {
// TODO 检查space是否开放访问
@@ -58,6 +64,22 @@ public class WikiPageFileServiceEx {
return fileList;
}
public List<WikiPageFileInfoVo> list(PageFileQueryParam pageFileQueryParam) {
int offset = 0;
int pageNum = pageFileQueryParam.getCurrent();
if ( pageNum != 0) {
offset = (pageNum - 1) * pageFileQueryParam.getPageSize();
}
pageFileQueryParam.setCurrent(offset);
List<WikiPageFileInfoVo> fileInfosVo = wikiPageFileMapper.getFileInfosVo(pageFileQueryParam);
return fileInfosVo;
}
public Long total(PageFileQueryParam pageFileQueryParam) {
Long total = wikiPageFileMapper.getFileInfoCount(pageFileQueryParam);
return total;
}
public String delete(WikiPageFile wikiPageFile) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
Long id = wikiPageFile.getId();
@@ -84,7 +106,7 @@ public class WikiPageFileServiceEx {
userMessageService.addWikiMessage(userMessage);
return null;
}
public DocResponseJson<Object> basicUpload(WikiPageFile wikiPageFile, MultipartFile file) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
Long pageId = wikiPageFile.getPageId();
@@ -150,4 +172,11 @@ public class WikiPageFileServiceEx {
wikiPageFile.setFileUrl("zyplayer-doc-wiki/common/file?uuid=" + wikiPageFile.getUuid());
return null;
}
public void destory(ArrayList<Long> destoryList) {
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.in("id",destoryList);
updateWrapper.set("del_flag",2);
wikiPageFileService.update(updateWrapper);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,13 +5,13 @@
<link rel="icon" href="./wiki-logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WIKI文档管理系统</title>
<script type="module" crossorigin src="./assets/main-da0e526c.js"></script>
<script type="module" crossorigin src="./assets/main-c2baf885.js"></script>
<link rel="modulepreload" crossorigin href="./assets/highlight.js-1b0b64aa.js">
<link rel="modulepreload" crossorigin href="./assets/vue-650a4d10.js">
<link rel="modulepreload" crossorigin href="./assets/vendor-55144a54.js">
<link rel="modulepreload" crossorigin href="./assets/vant-c4bb6f5f.js">
<link rel="modulepreload" crossorigin href="./assets/vendor-05ab9032.js">
<link rel="modulepreload" crossorigin href="./assets/vant-3a3a3bd1.js">
<link rel="modulepreload" crossorigin href="./assets/wangeditor-564d5916.js">
<link rel="stylesheet" href="./assets/style.cf8016a5.css">
<link rel="stylesheet" href="./assets/style.2aff8dda.css">
</head>
<body>
<div id="app"></div>