feat(file): 添加文件管理功能和相关接口
- 新增文件上传、编辑、删除等基础功能 - 实现文件可见范围控制(公开/私有) - 添加与我相关的文件查询功能 - 集成用户选择组件用于设置文件可见用户 - 实现文件统计展示功能 - 完善文件操作权限验证机制 - 添加文件预览和下载功能 - 优化文件列表分页和搜索功能
This commit is contained in:
@@ -71,8 +71,9 @@ public class SysFileController extends BaseController {
|
|||||||
@Log(title = "文件主信息", businessType = BusinessType.INSERT)
|
@Log(title = "文件主信息", businessType = BusinessType.INSERT)
|
||||||
@RepeatSubmit()
|
@RepeatSubmit()
|
||||||
@PostMapping()
|
@PostMapping()
|
||||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysFileBo bo) {
|
public R<Long> add(@Validated(AddGroup.class) @RequestBody SysFileBo bo) {
|
||||||
return toAjax(iSysFileService.insertByBo(bo));
|
iSysFileService.insertByBo(bo);
|
||||||
|
return R.ok(bo.getFileId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,4 +97,12 @@ public class SysFileController extends BaseController {
|
|||||||
@PathVariable Long[] fileIds) {
|
@PathVariable Long[] fileIds) {
|
||||||
return toAjax(iSysFileService.deleteWithValidByIds(Arrays.asList(fileIds), true));
|
return toAjax(iSysFileService.deleteWithValidByIds(Arrays.asList(fileIds), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询与我相关的文件(私有文件且当前用户在可见用户列表中)
|
||||||
|
*/
|
||||||
|
@GetMapping("/relatedToMe")
|
||||||
|
public TableDataInfo<SysFileVo> relatedToMe(SysFileBo bo, PageQuery pageQuery) {
|
||||||
|
return iSysFileService.queryPageListRelatedToMe(bo, pageQuery);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,4 +46,9 @@ public interface ISysFileService {
|
|||||||
* 校验并批量删除文件主信息信息
|
* 校验并批量删除文件主信息信息
|
||||||
*/
|
*/
|
||||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询与我相关的文件(私有文件且当前用户在可见用户列表中)
|
||||||
|
*/
|
||||||
|
TableDataInfo<SysFileVo> queryPageListRelatedToMe(SysFileBo bo, PageQuery pageQuery);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,22 @@ import com.klp.common.core.domain.PageQuery;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.klp.common.helper.LoginHelper;
|
||||||
import com.klp.common.utils.StringUtils;
|
import com.klp.common.utils.StringUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.klp.system.domain.bo.SysFileBo;
|
import com.klp.system.domain.bo.SysFileBo;
|
||||||
import com.klp.system.domain.vo.SysFileVo;
|
import com.klp.system.domain.vo.SysFileVo;
|
||||||
import com.klp.system.domain.SysFile;
|
import com.klp.system.domain.SysFile;
|
||||||
|
import com.klp.system.domain.SysFileVisibleUser;
|
||||||
import com.klp.system.mapper.SysFileMapper;
|
import com.klp.system.mapper.SysFileMapper;
|
||||||
|
import com.klp.system.mapper.SysFileVisibleUserMapper;
|
||||||
import com.klp.system.service.ISysFileService;
|
import com.klp.system.service.ISysFileService;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件主信息Service业务层处理
|
* 文件主信息Service业务层处理
|
||||||
@@ -30,6 +34,7 @@ import java.util.Collection;
|
|||||||
public class SysFileServiceImpl implements ISysFileService {
|
public class SysFileServiceImpl implements ISysFileService {
|
||||||
|
|
||||||
private final SysFileMapper baseMapper;
|
private final SysFileMapper baseMapper;
|
||||||
|
private final SysFileVisibleUserMapper visibleUserMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询文件主信息
|
* 查询文件主信息
|
||||||
@@ -69,6 +74,7 @@ public class SysFileServiceImpl implements ISysFileService {
|
|||||||
lqw.eq(StringUtils.isNotBlank(bo.getDept()), SysFile::getDept, bo.getDept());
|
lqw.eq(StringUtils.isNotBlank(bo.getDept()), SysFile::getDept, bo.getDept());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getFileType()), SysFile::getFileType, bo.getFileType());
|
lqw.eq(StringUtils.isNotBlank(bo.getFileType()), SysFile::getFileType, bo.getFileType());
|
||||||
lqw.eq(bo.getScopeType() != null, SysFile::getScopeType, bo.getScopeType());
|
lqw.eq(bo.getScopeType() != null, SysFile::getScopeType, bo.getScopeType());
|
||||||
|
lqw.eq(StringUtils.isNotBlank(bo.getCreateBy()), SysFile::getCreateBy, bo.getCreateBy());
|
||||||
return lqw;
|
return lqw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +102,28 @@ public class SysFileServiceImpl implements ISysFileService {
|
|||||||
return baseMapper.updateById(update) > 0;
|
return baseMapper.updateById(update) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询与我相关的文件(私有文件且当前用户在可见用户列表中)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<SysFileVo> queryPageListRelatedToMe(SysFileBo bo, PageQuery pageQuery) {
|
||||||
|
Long currentUserId = LoginHelper.getUserId();
|
||||||
|
// 查询当前用户可见的私有文件ID列表
|
||||||
|
LambdaQueryWrapper<SysFileVisibleUser> vuLqw = Wrappers.lambdaQuery();
|
||||||
|
vuLqw.eq(SysFileVisibleUser::getUserId, currentUserId);
|
||||||
|
List<SysFileVisibleUser> visibleList = visibleUserMapper.selectList(vuLqw);
|
||||||
|
List<Long> fileIds = visibleList.stream().map(SysFileVisibleUser::getFileId).distinct().collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (fileIds.isEmpty()) {
|
||||||
|
return TableDataInfo.build(new Page<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<SysFile> lqw = buildQueryWrapper(bo);
|
||||||
|
lqw.in(SysFile::getFileId, fileIds);
|
||||||
|
Page<SysFileVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||||
|
return TableDataInfo.build(result);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存前的数据校验
|
* 保存前的数据校验
|
||||||
*/
|
*/
|
||||||
|
|||||||
99
klp-ui/src/api/system/file.js
Normal file
99
klp-ui/src/api/system/file.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询文件列表
|
||||||
|
export function listFile(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/file/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询文件详细
|
||||||
|
export function getFile(fileId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/file/' + fileId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增文件
|
||||||
|
export function addFile(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/file',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改文件
|
||||||
|
export function updateFile(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/file',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除文件
|
||||||
|
export function delFile(fileIds) {
|
||||||
|
return request({
|
||||||
|
url: '/system/file/' + fileIds,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出文件列表
|
||||||
|
export function exportFile(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/file/export',
|
||||||
|
method: 'post',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询与我相关的文件
|
||||||
|
export function listRelatedToMe(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/file/relatedToMe',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 文件可见用户关联 ============
|
||||||
|
|
||||||
|
// 查询可见用户列表
|
||||||
|
export function listVisibleUser(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/fileVisibleUser/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增可见用户关联
|
||||||
|
export function addVisibleUser(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/fileVisibleUser',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除可见用户关联
|
||||||
|
export function delVisibleUser(visibleIds) {
|
||||||
|
return request({
|
||||||
|
url: '/system/fileVisibleUser/' + visibleIds,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按文件ID查询可见用户列表
|
||||||
|
export function listVisibleUserByFileId(fileId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/fileVisibleUser/list',
|
||||||
|
method: 'get',
|
||||||
|
params: { fileId: fileId }
|
||||||
|
})
|
||||||
|
}
|
||||||
735
klp-ui/src/views/system/file/index.vue
Normal file
735
klp-ui/src/views/system/file/index.vue
Normal file
@@ -0,0 +1,735 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<!-- 统计卡片 -->
|
||||||
|
<el-row :gutter="16" class="stat-row" v-if="activeTab === 'all'">
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-num">{{ stats.totalFiles }}</div>
|
||||||
|
<div class="stat-label">文件总数</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="stat-card public">
|
||||||
|
<div class="stat-num">{{ stats.publicFiles }}</div>
|
||||||
|
<div class="stat-label">公开文件</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="stat-card private">
|
||||||
|
<div class="stat-num">{{ stats.privateFiles }}</div>
|
||||||
|
<div class="stat-label">私有文件</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-num">{{ stats.myFiles }}</div>
|
||||||
|
<div class="stat-label">我上传的</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- Tab 切换 -->
|
||||||
|
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
||||||
|
<el-tab-pane label="所有文件" name="all"></el-tab-pane>
|
||||||
|
<el-tab-pane label="我的文件" name="my"></el-tab-pane>
|
||||||
|
<el-tab-pane label="共享文件" name="share"></el-tab-pane>
|
||||||
|
<el-tab-pane label="与我相关" name="related"></el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
||||||
|
<el-form-item label="文件名称" prop="fileName">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.fileName"
|
||||||
|
placeholder="请输入文件名称"
|
||||||
|
clearable
|
||||||
|
style="width: 200px"
|
||||||
|
@keyup.enter.native="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单编号" prop="orderNo">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.orderNo"
|
||||||
|
placeholder="请输入订单编号"
|
||||||
|
clearable
|
||||||
|
style="width: 200px"
|
||||||
|
@keyup.enter.native="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属部门" prop="dept">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.dept"
|
||||||
|
placeholder="请输入部门"
|
||||||
|
clearable
|
||||||
|
style="width: 200px"
|
||||||
|
@keyup.enter.native="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="文件类型" prop="fileType">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.fileType"
|
||||||
|
placeholder="请选择文件类型"
|
||||||
|
clearable
|
||||||
|
style="width: 200px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in dict.type.sys_file_type"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="可见范围" prop="scopeType" v-if="activeTab !== 'share' && activeTab !== 'related'">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.scopeType"
|
||||||
|
placeholder="请选择可见范围"
|
||||||
|
clearable
|
||||||
|
style="width: 200px"
|
||||||
|
>
|
||||||
|
<el-option label="公开" :value="1" />
|
||||||
|
<el-option label="私有" :value="2" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="上传时间">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
style="width: 240px"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="-"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="['00:00:00', '23:59:59']"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5" v-if="activeTab === 'my' || activeTab === 'all'">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="el-icon-plus"
|
||||||
|
size="mini"
|
||||||
|
@click="handleAdd"
|
||||||
|
>上传文件</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5" v-if="activeTab === 'my' || activeTab === 'all'">
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
icon="el-icon-delete"
|
||||||
|
size="mini"
|
||||||
|
:disabled="multiple"
|
||||||
|
@click="handleDelete"
|
||||||
|
>删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
plain
|
||||||
|
icon="el-icon-download"
|
||||||
|
size="mini"
|
||||||
|
@click="handleExport"
|
||||||
|
>导出</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 文件列表表格 -->
|
||||||
|
<KLPTable v-loading="loading" :data="fileList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" v-if="activeTab === 'my' || activeTab === 'all'" />
|
||||||
|
<el-table-column label="文件名称" align="center" prop="fileName" :show-overflow-tooltip="true">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-link type="primary" @click="handlePreview(scope.row)">{{ scope.row.fileName }}</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="文件类型" align="center" prop="fileType">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="dict.type.sys_file_type" :value="scope.row.fileType"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="文件大小" align="center" prop="fileSize">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ formatFileSize(scope.row.fileSize) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="订单编号" align="center" prop="orderNo" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="所属部门" align="center" prop="dept" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="可见范围" align="center" prop="scopeType">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag :type="scope.row.scopeType === 1 ? 'success' : 'warning'" size="small">
|
||||||
|
{{ scope.row.scopeType === 1 ? '公开' : '私有' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="上传人" align="center" prop="createBy" />
|
||||||
|
<el-table-column label="上传时间" align="center" prop="createTime" width="160">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="操作" align="center" width="220" class-name="small-padding fixed-width">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-view"
|
||||||
|
@click="handlePreview(scope.row)"
|
||||||
|
>预览</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="canEdit(scope.row)"
|
||||||
|
size="mini"
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-edit"
|
||||||
|
@click="handleUpdate(scope.row)"
|
||||||
|
>编辑</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="canEdit(scope.row)"
|
||||||
|
size="mini"
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
@click="handleDelete(scope.row)"
|
||||||
|
>删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</KLPTable>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-show="total>0"
|
||||||
|
:total="total"
|
||||||
|
:page.sync="queryParams.pageNum"
|
||||||
|
:limit.sync="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 上传/编辑对话框 -->
|
||||||
|
<el-dialog :title="dialogTitle" :visible.sync="open" width="650px" append-to-body @close="handleDialogClose">
|
||||||
|
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||||
|
<el-form-item label="文件名称" prop="fileName">
|
||||||
|
<el-input v-model="form.fileName" placeholder="请输入文件名称" :disabled="isEdit" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="上传文件" v-if="!isEdit">
|
||||||
|
<el-upload
|
||||||
|
ref="upload"
|
||||||
|
:action="uploadUrl"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:file-list="uploadFileList"
|
||||||
|
:before-upload="handleBeforeUpload"
|
||||||
|
:on-success="handleUploadSuccess"
|
||||||
|
:on-error="handleUploadError"
|
||||||
|
:auto-upload="false"
|
||||||
|
:limit="1"
|
||||||
|
class="upload-demo"
|
||||||
|
drag
|
||||||
|
>
|
||||||
|
<i class="el-icon-upload"></i>
|
||||||
|
<div class="el-upload__text">将文件拖到此处,或<em>点击选取</em></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单编号" prop="orderNo">
|
||||||
|
<el-input v-model="form.orderNo" placeholder="请输入订单编号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属部门" prop="dept">
|
||||||
|
<el-input v-model="form.dept" placeholder="请输入所属部门" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="文件类型" prop="fileType">
|
||||||
|
<el-select v-model="form.fileType" placeholder="请选择文件类型" style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="item in dict.type.sys_file_type"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="可见范围" prop="scopeType">
|
||||||
|
<el-radio-group v-model="form.scopeType" @change="handleScopeChange">
|
||||||
|
<el-radio :label="1">公开(所有人可见)</el-radio>
|
||||||
|
<el-radio :label="2">私有(指定用户可见)</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="可见用户" v-if="form.scopeType === 2">
|
||||||
|
<user-select
|
||||||
|
v-model="form.visibleUsers"
|
||||||
|
:multiple="true"
|
||||||
|
placeholder="请选择可见用户"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" :rows="3" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 文件预览对话框 -->
|
||||||
|
<el-dialog :title="previewTitle" :visible.sync="previewVisible" width="80%" append-to-body>
|
||||||
|
<div v-if="previewFile" class="file-preview-container">
|
||||||
|
<el-descriptions :column="2" border>
|
||||||
|
<el-descriptions-item label="文件名称">{{ previewFile.fileName }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="文件类型">
|
||||||
|
<dict-tag :options="dict.type.sys_file_type" :value="previewFile.fileType"/>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="文件大小">{{ formatFileSize(previewFile.fileSize) }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="文件后缀">{{ previewFile.suffix }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="订单编号">{{ previewFile.orderNo || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="所属部门">{{ previewFile.dept || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="可见范围">
|
||||||
|
<el-tag :type="previewFile.scopeType === 1 ? 'success' : 'warning'" size="small">
|
||||||
|
{{ previewFile.scopeType === 1 ? '公开' : '私有' }}
|
||||||
|
</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="上传人">{{ previewFile.createBy }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="上传时间">{{ parseTime(previewFile.createTime) }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="备注" :span="2">{{ previewFile.remark || '-' }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<div v-if="previewFile.filePath" style="margin-top: 16px;">
|
||||||
|
<el-button type="primary" size="small" @click="downloadFile(previewFile)">下载文件</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listFile, getFile, addFile, updateFile, delFile, exportFile, listVisibleUser, addVisibleUser, delVisibleUser, listVisibleUserByFileId, listRelatedToMe } from '@/api/system/file'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
import UserSelect from '@/components/KLPService/UserSelect/index'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SysFile',
|
||||||
|
dicts: ['sys_file_type'],
|
||||||
|
components: {
|
||||||
|
UserSelect
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 当前激活tab
|
||||||
|
activeTab: 'all',
|
||||||
|
// 遮罩层
|
||||||
|
loading: false,
|
||||||
|
// 选中数组
|
||||||
|
ids: [],
|
||||||
|
// 非单个禁用
|
||||||
|
single: true,
|
||||||
|
// 非多个禁用
|
||||||
|
multiple: true,
|
||||||
|
// 显示搜索条件
|
||||||
|
showSearch: true,
|
||||||
|
// 总条数
|
||||||
|
total: 0,
|
||||||
|
// 文件列表
|
||||||
|
fileList: [],
|
||||||
|
// 弹出层标题
|
||||||
|
dialogTitle: '',
|
||||||
|
// 是否显示弹出层
|
||||||
|
open: false,
|
||||||
|
// 是否编辑
|
||||||
|
isEdit: false,
|
||||||
|
// 日期范围
|
||||||
|
dateRange: [],
|
||||||
|
// 查询参数
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
fileName: undefined,
|
||||||
|
orderNo: undefined,
|
||||||
|
dept: undefined,
|
||||||
|
fileType: undefined,
|
||||||
|
scopeType: undefined
|
||||||
|
},
|
||||||
|
// 表单
|
||||||
|
form: {
|
||||||
|
fileId: undefined,
|
||||||
|
fileName: undefined,
|
||||||
|
filePath: undefined,
|
||||||
|
fileSize: undefined,
|
||||||
|
suffix: undefined,
|
||||||
|
orderNo: undefined,
|
||||||
|
dept: undefined,
|
||||||
|
fileType: undefined,
|
||||||
|
scopeType: 1,
|
||||||
|
visibleUsers: [],
|
||||||
|
remark: undefined
|
||||||
|
},
|
||||||
|
// 可见用户原始数据(编辑时回显)
|
||||||
|
originalVisibleUsers: [],
|
||||||
|
// 表单校验
|
||||||
|
rules: {
|
||||||
|
fileName: [
|
||||||
|
{ required: true, message: '文件名称不能为空', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
fileType: [
|
||||||
|
{ required: true, message: '请选择文件类型', trigger: 'change' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// 统计
|
||||||
|
stats: {
|
||||||
|
totalFiles: 0,
|
||||||
|
publicFiles: 0,
|
||||||
|
privateFiles: 0,
|
||||||
|
myFiles: 0
|
||||||
|
},
|
||||||
|
// 上传相关
|
||||||
|
uploadUrl: process.env.VUE_APP_BASE_API + '/system/oss/upload',
|
||||||
|
uploadHeaders: {
|
||||||
|
Authorization: 'Bearer ' + getToken()
|
||||||
|
},
|
||||||
|
uploadFileList: [],
|
||||||
|
// 预览
|
||||||
|
previewVisible: false,
|
||||||
|
previewTitle: '',
|
||||||
|
previewFile: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 切换tab */
|
||||||
|
handleTabClick(tab) {
|
||||||
|
this.resetQuery()
|
||||||
|
},
|
||||||
|
/** 查询文件列表 */
|
||||||
|
getList() {
|
||||||
|
this.loading = true
|
||||||
|
const params = this.addDateRange(this.queryParams, this.dateRange)
|
||||||
|
// 根据tab设置额外参数
|
||||||
|
if (this.activeTab === 'my') {
|
||||||
|
params.createBy = this.$store.getters.name
|
||||||
|
} else if (this.activeTab === 'share') {
|
||||||
|
params.scopeType = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据tab选择不同的API
|
||||||
|
let request
|
||||||
|
if (this.activeTab === 'related') {
|
||||||
|
request = listRelatedToMe(params)
|
||||||
|
} else {
|
||||||
|
request = listFile(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
request.then(response => {
|
||||||
|
this.fileList = response.rows
|
||||||
|
this.total = response.total
|
||||||
|
this.loading = false
|
||||||
|
// 加载统计数据
|
||||||
|
if (this.activeTab === 'all') {
|
||||||
|
this.loadStats()
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 加载统计数据 */
|
||||||
|
loadStats() {
|
||||||
|
// 获取所有公开文件数量
|
||||||
|
listFile({ pageNum: 1, pageSize: 1, scopeType: 1 }).then(r => { this.stats.publicFiles = r.total })
|
||||||
|
// 获取所有私有文件数量
|
||||||
|
listFile({ pageNum: 1, pageSize: 1, scopeType: 2 }).then(r => { this.stats.privateFiles = r.total })
|
||||||
|
// 我上传的
|
||||||
|
listFile({ pageNum: 1, pageSize: 1, createBy: this.$store.getters.name }).then(r => { this.stats.myFiles = r.total })
|
||||||
|
// 总计
|
||||||
|
listFile({ pageNum: 1, pageSize: 1 }).then(r => { this.stats.totalFiles = r.total })
|
||||||
|
},
|
||||||
|
/** 格式化文件大小 */
|
||||||
|
formatFileSize(size) {
|
||||||
|
if (!size) return '0 B'
|
||||||
|
if (size < 1024) return size + ' B'
|
||||||
|
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB'
|
||||||
|
return (size / 1024 / 1024).toFixed(2) + ' MB'
|
||||||
|
},
|
||||||
|
/** 是否可编辑 */
|
||||||
|
canEdit(row) {
|
||||||
|
if (this.activeTab === 'related') return false
|
||||||
|
if (this.activeTab === 'share') return false
|
||||||
|
// 我的文件tab 或 所有文件tab中属于当前用户的
|
||||||
|
return row.createBy === this.$store.getters.name
|
||||||
|
},
|
||||||
|
/** 取消按钮 */
|
||||||
|
cancel() {
|
||||||
|
this.open = false
|
||||||
|
this.reset()
|
||||||
|
},
|
||||||
|
/** 对话框关闭回调 */
|
||||||
|
handleDialogClose() {
|
||||||
|
this.reset()
|
||||||
|
},
|
||||||
|
/** 表单重置 */
|
||||||
|
reset() {
|
||||||
|
this.form = {
|
||||||
|
fileId: undefined,
|
||||||
|
fileName: undefined,
|
||||||
|
filePath: undefined,
|
||||||
|
fileSize: undefined,
|
||||||
|
suffix: undefined,
|
||||||
|
orderNo: undefined,
|
||||||
|
dept: undefined,
|
||||||
|
fileType: undefined,
|
||||||
|
scopeType: 1,
|
||||||
|
visibleUsers: [],
|
||||||
|
remark: undefined
|
||||||
|
}
|
||||||
|
this.uploadFileList = []
|
||||||
|
this.originalVisibleUsers = []
|
||||||
|
this.isEdit = false
|
||||||
|
this.resetForm('form')
|
||||||
|
},
|
||||||
|
/** 可见范围切换 */
|
||||||
|
handleScopeChange(val) {
|
||||||
|
if (val === 1) {
|
||||||
|
this.form.visibleUsers = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 搜索按钮 */
|
||||||
|
handleQuery() {
|
||||||
|
this.queryParams.pageNum = 1
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
/** 重置按钮 */
|
||||||
|
resetQuery() {
|
||||||
|
this.dateRange = []
|
||||||
|
this.resetForm('queryForm')
|
||||||
|
this.queryParams = {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
fileName: undefined,
|
||||||
|
orderNo: undefined,
|
||||||
|
dept: undefined,
|
||||||
|
fileType: undefined,
|
||||||
|
scopeType: undefined
|
||||||
|
}
|
||||||
|
this.handleQuery()
|
||||||
|
},
|
||||||
|
/** 多选框 */
|
||||||
|
handleSelectionChange(selection) {
|
||||||
|
this.ids = selection.map(item => item.fileId)
|
||||||
|
this.single = selection.length !== 1
|
||||||
|
this.multiple = !selection.length
|
||||||
|
},
|
||||||
|
/** 新增/上传 */
|
||||||
|
handleAdd() {
|
||||||
|
this.reset()
|
||||||
|
this.isEdit = false
|
||||||
|
this.open = true
|
||||||
|
this.dialogTitle = '上传文件'
|
||||||
|
},
|
||||||
|
/** 修改 */
|
||||||
|
handleUpdate(row) {
|
||||||
|
this.reset()
|
||||||
|
this.isEdit = true
|
||||||
|
const fileId = row.fileId || this.ids[0]
|
||||||
|
getFile(fileId).then(response => {
|
||||||
|
const data = response.data
|
||||||
|
this.form = {
|
||||||
|
fileId: data.fileId,
|
||||||
|
fileName: data.fileName,
|
||||||
|
filePath: data.filePath,
|
||||||
|
fileSize: data.fileSize,
|
||||||
|
suffix: data.suffix,
|
||||||
|
orderNo: data.orderNo,
|
||||||
|
dept: data.dept,
|
||||||
|
fileType: data.fileType,
|
||||||
|
scopeType: data.scopeType,
|
||||||
|
visibleUsers: [],
|
||||||
|
remark: data.remark
|
||||||
|
}
|
||||||
|
// 如果是私有文件,加载可见用户
|
||||||
|
if (data.scopeType === 2) {
|
||||||
|
listVisibleUserByFileId(fileId).then(res => {
|
||||||
|
const rows = res.rows || []
|
||||||
|
this.form.visibleUsers = rows.map(r => r.userId)
|
||||||
|
this.originalVisibleUsers = [...this.form.visibleUsers]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.open = true
|
||||||
|
this.dialogTitle = '编辑文件'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 上传前校验 */
|
||||||
|
handleBeforeUpload(file) {
|
||||||
|
// 自动设置文件名
|
||||||
|
if (!this.form.fileName) {
|
||||||
|
this.form.fileName = file.name
|
||||||
|
}
|
||||||
|
const ext = file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase()
|
||||||
|
this.form.suffix = ext
|
||||||
|
this.form.fileSize = file.size
|
||||||
|
},
|
||||||
|
/** 上传成功 */
|
||||||
|
handleUploadSuccess(response, file, fileList) {
|
||||||
|
if (response.code === 200) {
|
||||||
|
this.form.filePath = response.data.url
|
||||||
|
this.form.fileName = this.form.fileName || response.data.fileName
|
||||||
|
this.$modal.msgSuccess('文件上传成功')
|
||||||
|
// 自动提交表单
|
||||||
|
this.doSubmit()
|
||||||
|
} else {
|
||||||
|
this.$modal.msgError(response.msg || '上传失败')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 上传失败 */
|
||||||
|
handleUploadError(err, file, fileList) {
|
||||||
|
this.$modal.msgError('文件上传失败')
|
||||||
|
},
|
||||||
|
/** 提交表单 */
|
||||||
|
submitForm() {
|
||||||
|
this.$refs['form'].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
if (this.isEdit) {
|
||||||
|
// 编辑模式直接提交
|
||||||
|
this.doSubmit()
|
||||||
|
} else {
|
||||||
|
// 新增模式,先上传文件
|
||||||
|
if (this.$refs.upload && this.$refs.upload.uploadFiles.length > 0) {
|
||||||
|
this.$refs.upload.submit()
|
||||||
|
} else {
|
||||||
|
this.$modal.msgWarning('请选择要上传的文件')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 执行提交 */
|
||||||
|
doSubmit() {
|
||||||
|
const data = { ...this.form }
|
||||||
|
const visibleUsers = data.visibleUsers
|
||||||
|
delete data.visibleUsers
|
||||||
|
|
||||||
|
if (data.fileId) {
|
||||||
|
// 编辑模式
|
||||||
|
updateFile(data).then(response => {
|
||||||
|
this.saveVisibleUsers(data.fileId, visibleUsers)
|
||||||
|
this.$modal.msgSuccess('修改成功')
|
||||||
|
this.open = false
|
||||||
|
this.getList()
|
||||||
|
}).catch(() => {})
|
||||||
|
} else {
|
||||||
|
// 新增模式
|
||||||
|
addFile(data).then(response => {
|
||||||
|
const newFileId = response.data
|
||||||
|
if (newFileId && visibleUsers && visibleUsers.length > 0) {
|
||||||
|
this.saveVisibleUsers(newFileId, visibleUsers)
|
||||||
|
}
|
||||||
|
this.$modal.msgSuccess('新增成功')
|
||||||
|
this.open = false
|
||||||
|
this.getList()
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 保存可见用户 */
|
||||||
|
saveVisibleUsers(fileId, visibleUsers) {
|
||||||
|
if (!visibleUsers || visibleUsers.length === 0) {
|
||||||
|
// 删除所有可见用户
|
||||||
|
if (this.originalVisibleUsers.length > 0) {
|
||||||
|
delVisibleUser(this.originalVisibleUsers.join(','))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 新增的
|
||||||
|
const toAdd = visibleUsers.filter(u => !this.originalVisibleUsers.includes(u))
|
||||||
|
// 删除的
|
||||||
|
const toDel = this.originalVisibleUsers.filter(u => !visibleUsers.includes(u))
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
if (toDel.length > 0) {
|
||||||
|
// 需要先查出visibleId
|
||||||
|
listVisibleUserByFileId(fileId).then(res => {
|
||||||
|
const rows = res.rows || []
|
||||||
|
const delIds = rows.filter(r => toDel.includes(r.userId)).map(r => r.visibleId)
|
||||||
|
if (delIds.length > 0) {
|
||||||
|
delVisibleUser(delIds.join(','))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 新增
|
||||||
|
toAdd.forEach(userId => {
|
||||||
|
addVisibleUser({ fileId, userId })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 删除 */
|
||||||
|
handleDelete(row) {
|
||||||
|
const fileIds = row.fileId || this.ids.join(',')
|
||||||
|
this.$modal.confirm('是否确认删除所选文件?').then(() => {
|
||||||
|
return delFile(fileIds)
|
||||||
|
}).then(() => {
|
||||||
|
this.getList()
|
||||||
|
this.$modal.msgSuccess('删除成功')
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
/** 导出 */
|
||||||
|
handleExport() {
|
||||||
|
this.download('system/file/export', {
|
||||||
|
...this.queryParams
|
||||||
|
}, `file_${new Date().getTime()}.xlsx`)
|
||||||
|
},
|
||||||
|
/** 预览 */
|
||||||
|
handlePreview(row) {
|
||||||
|
this.previewFile = row
|
||||||
|
this.previewTitle = '文件详情 - ' + row.fileName
|
||||||
|
this.previewVisible = true
|
||||||
|
},
|
||||||
|
/** 下载文件 */
|
||||||
|
downloadFile(row) {
|
||||||
|
if (row.filePath) {
|
||||||
|
window.open(row.filePath, '_blank')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.stat-row {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
border-left: 4px solid #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.public {
|
||||||
|
border-left-color: #67c23a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.private {
|
||||||
|
border-left-color: #e6a23c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-num {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #303133;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #909399;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-preview-container {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-demo {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user