feat:新增共享文件功能

This commit is contained in:
czhqwer
2025-03-29 16:56:19 +08:00
parent f7e7db9f84
commit 8bece56908
18 changed files with 411 additions and 18 deletions

View File

@@ -2,6 +2,7 @@ package cn.czh.controller;
import cn.czh.base.Result;
import cn.czh.entity.StorageConfig;
import cn.czh.service.IAuthService;
import cn.czh.service.IStorageConfigService;
import org.springframework.web.bind.annotation.*;
@@ -14,6 +15,8 @@ public class ConfigController {
@Resource
private IStorageConfigService storageConfigService;
@Resource
private IAuthService authService;
@GetMapping
public Result<?> getConfig(String type) {
@@ -31,4 +34,10 @@ public class ConfigController {
storageConfigService.testStorageConfig(config);
return Result.success();
}
@PostMapping("/set-password")
public Result<?> setPassword(@RequestBody String password) {
authService.setMainUserPassword(password);
return Result.success();
}
}

View File

@@ -2,25 +2,30 @@ package cn.czh.controller;
import cn.czh.base.Result;
import cn.czh.entity.StorageConfig;
import cn.czh.service.IAuthService;
import cn.czh.service.IFileService;
import cn.czh.service.IStorageConfigService;
import cn.czh.utils.FileTypeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Enumeration;
@Slf4j
@RestController
@RequestMapping("/file")
public class FileController {
@@ -29,6 +34,13 @@ public class FileController {
private IStorageConfigService storageConfigService;
@Resource
private IFileService fileService;
@Resource
private IAuthService authService;
@Value("${server.port}")
private String serverPort;
private static boolean enableShare = false;
@GetMapping("/preview/{storageType}/**")
public ResponseEntity<?> previewFile(
@@ -76,7 +88,11 @@ public class FileController {
}
@GetMapping("/page")
public Result<?> pageFiles(Integer page, Integer pageSize, String storageType, String fileName) {
public Result<?> pageFiles(HttpServletRequest request, Integer page, Integer pageSize, String storageType, String fileName) {
if (!authService.isMainUser(request.getRemoteAddr())) {
return Result.error("权限不足");
}
if (page == null) {
page = 1;
}
@@ -85,4 +101,83 @@ public class FileController {
}
return Result.success(fileService.pageFiles(page, pageSize, storageType, fileName));
}
@PostMapping("/sharedFile")
public Result<?> listSharedFiles(@RequestParam String fileIdentifier) {
fileService.addSharedFile(fileIdentifier);
return Result.success();
}
@PostMapping("/unShareFile")
public Result<?> unShareFile(HttpServletRequest request, @RequestParam String fileIdentifier) {
if (!authService.isMainUser(request.getRemoteAddr())) {
return Result.error("非主用户不能取消分享");
}
fileService.removeSharedFile(fileIdentifier);
return Result.success();
}
@GetMapping("/sharedFiles")
public Result<?> getSharedFiles(HttpServletRequest request, @RequestHeader("Authorization") String password) {
boolean isMainUser = authService.isMainUser(request.getRemoteAddr());
String mainUserPassword = authService.getMainUserPassword();
if (!isMainUser && !mainUserPassword.equals(password)) {
return Result.error("密码错误");
}
if (!isMainUser && !enableShare) {
return Result.error("分享功能未开启");
}
return Result.success(fileService.listSharedFiles());
}
@PostMapping("/enableShare")
public Result<?> enableShare(HttpServletRequest request, @RequestParam Boolean enable) {
if (!authService.isMainUser(request.getRemoteAddr())) {
return Result.error("非主用户不能修改分享状态");
}
enableShare = enable;
return Result.success();
}
@GetMapping("/getShareStatus")
public Result<?> getShareStatus() {
return Result.success(enableShare);
}
@GetMapping("/shareAddress")
public Result<?> getShareAddress() {
String ip;
try {
ip = getLocalIpAddress();
} catch (Exception e) {
log.error("获取本地IP地址失败{}", e.getMessage(), e);
ip = "localhost";
}
return Result.success("http://" + ip + ":" + serverPort);
}
private String getLocalIpAddress() throws Exception {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
// 跳过回环接口和未启用的接口
if (networkInterface.isLoopback() || !networkInterface.isUp()) {
continue;
}
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
String ip = addr.getHostAddress();
if (ip.startsWith("192.168.") || ip.startsWith("10.") ||
(ip.startsWith("172.") && Integer.parseInt(ip.split("\\.")[1]) >= 16 && Integer.parseInt(ip.split("\\.")[1]) <= 31)) {
return ip;
}
}
}
}
return null;
}
}

View File

@@ -4,6 +4,7 @@ import cn.czh.base.Result;
import cn.czh.dto.req.CreateMultipartUpload;
import cn.czh.entity.StorageConfig;
import cn.czh.entity.UploadFile;
import cn.czh.service.IAuthService;
import cn.czh.service.IStorageService;
import cn.czh.service.StorageServiceFactory;
import cn.czh.utils.FileTypeUtil;
@@ -27,6 +28,8 @@ public class UploadController {
@Resource
private StorageServiceFactory storageServiceFactory;
@Resource
private IAuthService authService;
/**
* 从请求中获取存储类型(示例:从请求头获取)
@@ -83,9 +86,10 @@ public class UploadController {
@PostMapping("/merge")
public Result<?> merge(HttpServletRequest request, String identifier) {
boolean mainUser = authService.isMainUser(request.getRemoteAddr());
String storageType = getStorageTypeFromRequest(request);
IStorageService storageService = storageServiceFactory.getStorageService(storageType);
return Result.success(storageService.merge(identifier));
return Result.success(storageService.merge(identifier, mainUser));
}
@PostMapping
@@ -101,6 +105,8 @@ public class UploadController {
}
}
boolean mainUser = authService.isMainUser(request.getRemoteAddr());
String md5 = SecureUtil.md5(file.getInputStream());
synchronized (md5.intern()) {
String dateFormat = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
@@ -109,7 +115,7 @@ public class UploadController {
dateFormat + "/" + md5 + "." + FileTypeUtil.getFileSuffix(filename);
String storageType = getStorageTypeFromRequest(request);
IStorageService storageService = storageServiceFactory.getStorageService(storageType);
return Result.success(storageService.uploadFile(file, md5, objectName));
return Result.success(storageService.uploadFile(file, md5, objectName, mainUser));
}
}
}

View File

@@ -0,0 +1,15 @@
package cn.czh.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("shared_file")
public class SharedFile {
@TableId(type = IdType.AUTO)
private Long id;
private String fileIdentifier;
private String createTime;
}

View File

@@ -0,0 +1,17 @@
package cn.czh.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("user_config")
public class UserConfig {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private Integer isMainUser; // 0 or 1
private String createTime;
}

View File

@@ -0,0 +1,9 @@
package cn.czh.mapper;
import cn.czh.entity.SharedFile;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ShareFileMapper extends BaseMapper<SharedFile> {
}

View File

@@ -0,0 +1,9 @@
package cn.czh.mapper;
import cn.czh.entity.UserConfig;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserConfigMapper extends BaseMapper<UserConfig> {
}

View File

@@ -0,0 +1,10 @@
package cn.czh.service;
public interface IAuthService {
String getMainUserPassword();
void setMainUserPassword(String password);
boolean isMainUser(String remoteAddress);
}

View File

@@ -3,8 +3,16 @@ package cn.czh.service;
import cn.czh.entity.UploadFile;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.List;
public interface IFileService {
IPage<UploadFile> pageFiles(Integer page, Integer pageSize, String storageType, String fileName);
List<UploadFile> listSharedFiles();
void addSharedFile(String identifier);
void removeSharedFile(String fileIdentifier);
}

View File

@@ -14,7 +14,7 @@ public interface IStorageService {
/**
* 普通文件上传
*/
FileRecordDTO uploadFile(MultipartFile file, String md5, String objectName);
FileRecordDTO uploadFile(MultipartFile file, String md5, String objectName, Boolean admin);
/**
* 获取文件上传进度
@@ -29,7 +29,7 @@ public interface IStorageService {
/**
* 合并分片文件
*/
UploadFile merge(String identifier);
UploadFile merge(String identifier, Boolean admin);
/**
* 根据md5标识获取分片上传任务

View File

@@ -0,0 +1,57 @@
package cn.czh.service.impl;
import cn.czh.entity.UserConfig;
import cn.czh.mapper.UserConfigMapper;
import cn.czh.service.IAuthService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Service
public class AuthServiceImpl implements IAuthService {
@Resource
private UserConfigMapper userConfigMapper;
@Override
public String getMainUserPassword() {
UserConfig user = userConfigMapper.selectOne(
new LambdaQueryWrapper<UserConfig>()
.eq(UserConfig::getIsMainUser, 1)
);
if (user == null) {
return "";
}
return user.getPassword() == null || user.getPassword().trim().isEmpty() ? "" : user.getPassword();
}
@Override
public void setMainUserPassword(String password) {
UserConfig user = userConfigMapper.selectOne(
new LambdaQueryWrapper<UserConfig>()
.eq(UserConfig::getIsMainUser, 1)
);
if (user == null) {
user = new UserConfig();
user.setUsername("admin");
user.setIsMainUser(1);
user.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
user.setPassword(password != null && password.trim().isEmpty() ? null : password);
if (user.getId() == null) {
userConfigMapper.insert(user);
} else {
userConfigMapper.updateById(user);
}
}
@Override
public boolean isMainUser(String remoteAddress) {
return "127.0.0.1".equals(remoteAddress) || "0:0:0:0:0:0:0:1".equals(remoteAddress);
}
}

View File

@@ -1,22 +1,70 @@
package cn.czh.service.impl;
import cn.czh.entity.SharedFile;
import cn.czh.entity.UploadFile;
import cn.czh.mapper.ShareFileMapper;
import cn.czh.mapper.UploadFileMapper;
import cn.czh.service.IFileService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Service
public class FileServiceImpl implements IFileService {
@Resource
private UploadFileMapper uploadFileMapper;
@Resource
private ShareFileMapper shareFileMapper;
@Override
public IPage<UploadFile> pageFiles(Integer page, Integer pageSize, String storageType, String fileName) {
return uploadFileMapper.pageFiles(new Page<>(page, pageSize), storageType, fileName);
}
@Override
public List<UploadFile> listSharedFiles() {
List<SharedFile> sharedFiles = shareFileMapper.selectList(null);
Set<String> files = sharedFiles.stream()
.map(SharedFile::getFileIdentifier)
.collect(Collectors.toSet());
List<UploadFile> uploadFiles = uploadFileMapper.selectList(null);
if (uploadFiles != null) {
return uploadFiles.stream()
.filter(uploadFile -> files.contains(uploadFile.getFileIdentifier()))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
@Override
public void addSharedFile(String identifier) {
SharedFile sharedFile = shareFileMapper.selectOne(
Wrappers.lambdaQuery(SharedFile.class).eq(SharedFile::getFileIdentifier, identifier)
);
if (sharedFile == null) {
sharedFile = new SharedFile();
sharedFile.setFileIdentifier(identifier);
sharedFile.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
shareFileMapper.insert(sharedFile);
}
}
@Override
public void removeSharedFile(String fileIdentifier) {
shareFileMapper.delete(Wrappers.lambdaQuery(SharedFile.class).eq(SharedFile::getFileIdentifier, fileIdentifier));
}
}

View File

@@ -11,6 +11,7 @@ import cn.czh.dto.req.CreateMultipartUpload;
import cn.czh.entity.StorageConfig;
import cn.czh.entity.UploadFile;
import cn.czh.mapper.UploadFileMapper;
import cn.czh.service.IFileService;
import cn.czh.service.IStorageConfigService;
import cn.czh.service.IStorageService;
import cn.hutool.core.date.DatePattern;
@@ -47,6 +48,8 @@ public class LocalStorageService implements IStorageService {
private UploadFileMapper uploadFileMapper;
@Resource
private IStorageConfigService storageConfigService;
@Resource
private IFileService fileService;
private StorageConfig storageConfig;
@@ -75,7 +78,7 @@ public class LocalStorageService implements IStorageService {
@Transactional
@Override
public FileRecordDTO uploadFile(MultipartFile file, String md5, String objectName) {
public FileRecordDTO uploadFile(MultipartFile file, String md5, String objectName, Boolean admin) {
UploadFile uploadFile = getByIdentifier(md5);
if (uploadFile != null) {
FileRecordDTO fileRecord = new FileRecordDTO();
@@ -117,6 +120,10 @@ public class LocalStorageService implements IStorageService {
BeanUtils.copyProperties(uploadFile, fileRecord);
fileRecord.setFileId(uploadFile.getId());
fileRecord.setOriginalName(file.getOriginalFilename());
if (!admin) {
fileService.addSharedFile(md5);
}
return fileRecord;
} catch (IOException e) {
throw new BusinessException("文件上传失败", e);
@@ -178,7 +185,7 @@ public class LocalStorageService implements IStorageService {
@Transactional
@Override
public UploadFile merge(String identifier) {
public UploadFile merge(String identifier, Boolean admin) {
UploadFile uploadFile = getByIdentifier(identifier);
if (uploadFile == null) {
throw new BusinessException("上传任务不存在");
@@ -223,6 +230,10 @@ public class LocalStorageService implements IStorageService {
uploadFile.setDownloadUrl(generateWebUrl(uploadFile.getObjectKey()));
uploadFile.setIsFinish(1);
uploadFileMapper.updateById(uploadFile);
if (!admin) {
fileService.addSharedFile(uploadFile.getFileIdentifier());
}
return uploadFile;
}

View File

@@ -11,6 +11,7 @@ import cn.czh.dto.req.CreateMultipartUpload;
import cn.czh.entity.StorageConfig;
import cn.czh.entity.UploadFile;
import cn.czh.mapper.UploadFileMapper;
import cn.czh.service.IFileService;
import cn.czh.service.IStorageConfigService;
import cn.czh.service.IStorageService;
import cn.czh.utils.ImgUtils;
@@ -61,6 +62,8 @@ public class MinioStorageService implements IStorageService {
private UploadFileMapper uploadFileMapper;
@Resource
private IStorageConfigService storageConfigService;
@Resource
private IFileService fileService;
/**
* 预签名url过期时间: 10分钟
@@ -122,7 +125,7 @@ public class MinioStorageService implements IStorageService {
@Transactional
@Override
public FileRecordDTO uploadFile(MultipartFile file, String md5, String objectName) {
public FileRecordDTO uploadFile(MultipartFile file, String md5, String objectName, Boolean admin) {
UploadFile uploadFile = getByIdentifier(md5);
if (ObjectUtil.isNotNull(uploadFile)) {
@@ -164,6 +167,10 @@ public class MinioStorageService implements IStorageService {
BeanUtils.copyProperties(uploadFile, fileRecord);
fileRecord.setFileId(uploadFile.getId());
fileRecord.setOriginalName(filename);
if (!admin) {
fileService.addSharedFile(md5);
}
return fileRecord;
} catch (Exception e) {
throw new BusinessException("文件上上传失败", e);
@@ -219,7 +226,7 @@ public class MinioStorageService implements IStorageService {
@Transactional
@Override
public UploadFile merge(String identifier) {
public UploadFile merge(String identifier, Boolean admin) {
UploadFile uploadFile = getByIdentifier(identifier);
if (uploadFile == null) {
throw new BusinessException("上传任务不存在");
@@ -244,6 +251,10 @@ public class MinioStorageService implements IStorageService {
uploadFile.setDownloadUrl(getFileDownloadUrl(uploadFile.getObjectKey()));
uploadFile.setIsFinish(1);
uploadFileMapper.updateById(uploadFile);
if (!admin) {
fileService.addSharedFile(uploadFile.getFileIdentifier());
}
return uploadFile;
}

View File

@@ -11,6 +11,7 @@ import cn.czh.dto.req.CreateMultipartUpload;
import cn.czh.entity.StorageConfig;
import cn.czh.entity.UploadFile;
import cn.czh.mapper.UploadFileMapper;
import cn.czh.service.IFileService;
import cn.czh.service.IStorageConfigService;
import cn.czh.service.IStorageService;
import cn.hutool.core.date.DatePattern;
@@ -49,6 +50,8 @@ public class OssStorageService implements IStorageService {
private UploadFileMapper uploadFileMapper;
@Resource
private IStorageConfigService storageConfigService;
@Resource
private IFileService fileService;
private StorageConfig storageConfig;
private OSS ossClient;
@@ -83,7 +86,7 @@ public class OssStorageService implements IStorageService {
*/
@Transactional
@Override
public FileRecordDTO uploadFile(MultipartFile file, String md5, String objectName) {
public FileRecordDTO uploadFile(MultipartFile file, String md5, String objectName, Boolean admin) {
UploadFile uploadFile = getByIdentifier(md5);
if (uploadFile != null) {
FileRecordDTO fileRecord = new FileRecordDTO();
@@ -129,6 +132,10 @@ public class OssStorageService implements IStorageService {
BeanUtils.copyProperties(uploadFile, fileRecord);
fileRecord.setFileId(uploadFile.getId());
fileRecord.setOriginalName(file.getOriginalFilename());
if (!admin) {
fileService.addSharedFile(md5);
}
return fileRecord;
} catch (IOException e) {
throw new BusinessException("文件上传失败", e);
@@ -211,7 +218,7 @@ public class OssStorageService implements IStorageService {
*/
@Transactional
@Override
public UploadFile merge(String identifier) {
public UploadFile merge(String identifier, Boolean admin) {
UploadFile uploadFile = getByIdentifier(identifier);
if (uploadFile == null) {
throw new BusinessException("上传任务不存在");
@@ -243,6 +250,10 @@ public class OssStorageService implements IStorageService {
uploadFile.setDownloadUrl(getFileDownloadUrl(uploadFile.getObjectKey()));
uploadFile.setIsFinish(1);
uploadFileMapper.updateById(uploadFile);
if (!admin) {
fileService.addSharedFile(identifier);
}
return uploadFile;
}

View File

@@ -180,6 +180,55 @@ const testStorageConfig = ({ type, endpoint, accessKey, secretKey, bucket }) =>
});
}
/**
* 获取共享文件列表
* @param {Object} params 参数对象
* @param {string} params.password 密码
* @returns
*/
const getSharedFiles = () => {
return http.get('/file/sharedFiles');
};
/**
* 启用或禁用共享
* @param {Object} params 参数对象
* @param {boolean} params.enable 是否启用
* @returns
*/
const enableShare = ({ enable }) => {
const formData = new FormData();
formData.append('enable', enable);
return http.post("/file/enableShare", formData);
};
/**
* 获取分享状态
* @returns
*/
const getShareStatus = () => {
return http.get("/file/getShareStatus");
}
/**
* 获取分享地址
* @returns
*/
const shareAddress = () => {
return http.get("/file/shareAddress");
}
/**
* 移除共享文件
* @param {string} fileIdentifier
* @returns
*/
const unShareFile = (fileIdentifier) => {
const formData = new FormData();
formData.append('fileIdentifier', fileIdentifier);
return http.post("/file/unShareFile", formData);
}
export {
getUploadProgress,
createMultipartUpload,
@@ -191,5 +240,10 @@ export {
getStorageConfig,
setStorageConfig,
testStorageConfig,
getSharedFiles,
enableShare,
getShareStatus,
shareAddress,
unShareFile,
httpExtra
};

View File

@@ -8,6 +8,16 @@ const http = axios.create({
baseURL: baseUrl
});
// 请求拦截器 - 自动添加 Authorization
http.interceptors.request.use(config => {
// 从 localStorage 获取 password
const password = localStorage.getItem('password');
config.headers['Authorization'] = password ? password : '';
return config;
}, error => {
return Promise.reject(error);
});
// 配置拦截器,返回 response.data
http.interceptors.response.use(response => {
return response.data;
@@ -22,4 +32,14 @@ const httpExtra = axiosExtra.create({
}
});
httpExtra.interceptors.request.use(config => {
const password = localStorage.getItem('password');
if (password) {
config.headers['Authorization'] = password;
}
return config;
}, error => {
return Promise.reject(error);
});
export { http, baseUrl, httpExtra };

View File

@@ -22,7 +22,7 @@
<div class="tab-underline"></div>
</div>
</div>
<div v-if="activeTab !== 'gallery' && !isWipTab" class="upload-content">
<div v-if="activeTab !== 'gallery' && activeTab !== 'shared' && !isWipTab" class="upload-content">
<upload-file :file-list.sync="fileList" :accept="allowedFormats" :max-size="maxUploadSize" width="100%"
height="400px" :storage-type="activeTab" />
</div>
@@ -34,6 +34,7 @@
<p v-else-if="activeTab === 'qiniu'">七牛云功能正在被疯狂调教马上就能和大家见面啦</p>
</div>
</div>
<share-file v-else-if="activeTab === 'shared'" />
<file-gallery v-else />
<settings-modal :show="showSettings" :allowed-formats="allowedFormats" :max-upload-size="maxUploadSize"
@save="saveSettings" @close="closeSettings" />
@@ -49,10 +50,11 @@ import FileGallery from '@/components/FileGallery/FileGallery.vue';
import SettingsModal from '@/components/SettingsModal/SettingsModal.vue';
import StorageConfigModal from '@/components/StorageConfigModal/StorageConfigModal.vue';
import AboutModal from '@/components/AboutModal/AboutModal.vue';
import ShareFile from '@/components/ShareFile/ShareFile.vue';
export default {
name: 'MainPage',
components: { UploadFile, FileGallery, SettingsModal, StorageConfigModal, AboutModal },
components: { UploadFile, FileGallery, SettingsModal, StorageConfigModal, AboutModal, ShareFile },
data() {
return {
fileList: [],
@@ -63,7 +65,8 @@ export default {
{ label: 'OSS', value: 'oss' },
{ label: 'OBS', value: 'obs' },
{ label: 'QiNiu', value: 'qiniu' },
{ label: '已上传文件', value: 'gallery' }
{ label: '已上传文件', value: 'gallery' },
{ label: '共享文件', value: 'shared' },
],
showMenu: false,
showSettings: false,