Commit c5f29f18d386d2dcc564e8f8842257eed2225904

Authored by xingyu
2 parents 4c0275fb 24f0e4dd

Merge remote-tracking branch 'origin/master' into dev

@@ -29,7 +29,7 @@ @@ -29,7 +29,7 @@
29 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 29 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
30 30
31 <properties> 31 <properties>
32 - <revision>1.6.5-snapshot</revision> 32 + <revision>1.6.6-snapshot</revision>
33 <!-- Maven 相关 --> 33 <!-- Maven 相关 -->
34 <java.version>1.8</java.version> 34 <java.version>1.8</java.version>
35 <maven.compiler.source>${java.version}</maven.compiler.source> 35 <maven.compiler.source>${java.version}</maven.compiler.source>
yudao-dependencies/pom.xml
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
15 15
16 <properties> 16 <properties>
17 - <revision>1.6.5-snapshot</revision> 17 + <revision>1.6.6-snapshot</revision>
18 <!-- 统一依赖管理 --> 18 <!-- 统一依赖管理 -->
19 <spring.boot.version>2.7.7</spring.boot.version> 19 <spring.boot.version>2.7.7</spring.boot.version>
20 <!-- Web 相关 --> 20 <!-- Web 相关 -->
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/s3/S3FileClient.java
@@ -9,10 +9,11 @@ import io.minio.*; @@ -9,10 +9,11 @@ import io.minio.*;
9 import java.io.ByteArrayInputStream; 9 import java.io.ByteArrayInputStream;
10 10
11 import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_ALIYUN; 11 import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_ALIYUN;
  12 +import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_TENCENT;
12 13
13 /** 14 /**
14 * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 15 * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务
15 - * 16 + * <p>
16 * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库 17 * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库
17 * 18 *
18 * @author 芋道源码 19 * @author 芋道源码
@@ -78,6 +79,11 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; { @@ -78,6 +79,11 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
78 .replaceAll("-internal", "")// 去除内网 Endpoint 的后缀 79 .replaceAll("-internal", "")// 去除内网 Endpoint 的后缀
79 .replaceAll("https://", ""); 80 .replaceAll("https://", "");
80 } 81 }
  82 + // 腾讯云必须有 region,否则会报错
  83 + if (config.getEndpoint().contains(ENDPOINT_TENCENT)) {
  84 + return StrUtil.subAfter(config.getEndpoint(), ".cos.", false)
  85 + .replaceAll("." + ENDPOINT_TENCENT, ""); // 去除 Endpoint
  86 + }
81 return null; 87 return null;
82 } 88 }
83 89
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/s3/S3FileClientConfig.java
@@ -19,6 +19,7 @@ public class S3FileClientConfig implements FileClientConfig { @@ -19,6 +19,7 @@ public class S3FileClientConfig implements FileClientConfig {
19 19
20 public static final String ENDPOINT_QINIU = "qiniucs.com"; 20 public static final String ENDPOINT_QINIU = "qiniucs.com";
21 public static final String ENDPOINT_ALIYUN = "aliyuncs.com"; 21 public static final String ENDPOINT_ALIYUN = "aliyuncs.com";
  22 + public static final String ENDPOINT_TENCENT = "myqcloud.com";
22 23
23 /** 24 /**
24 * 节点地址 25 * 节点地址
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java
@@ -75,7 +75,7 @@ public class ConfigController { @@ -75,7 +75,7 @@ public class ConfigController {
75 if (config == null) { 75 if (config == null) {
76 return null; 76 return null;
77 } 77 }
78 - if (config.getVisible()) { 78 + if (!config.getVisible()) {
79 throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_VISIBLE); 79 throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_VISIBLE);
80 } 80 }
81 return success(config.getValue()); 81 return success(config.getValue());
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentDAOImpl.java
1 package cn.iocoder.yudao.module.infra.dal.mysql.file; 1 package cn.iocoder.yudao.module.infra.dal.mysql.file;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.file.core.client.db.DBFileContentFrameworkDAO; 4 import cn.iocoder.yudao.framework.file.core.client.db.DBFileContentFrameworkDAO;
4 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO; 5 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO;
5 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 6 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6 import org.springframework.stereotype.Repository; 7 import org.springframework.stereotype.Repository;
7 8
8 import javax.annotation.Resource; 9 import javax.annotation.Resource;
  10 +import java.util.List;
  11 +import java.util.Optional;
9 12
10 @Repository 13 @Repository
11 public class FileContentDAOImpl implements DBFileContentFrameworkDAO { 14 public class FileContentDAOImpl implements DBFileContentFrameworkDAO {
@@ -27,9 +30,11 @@ public class FileContentDAOImpl implements DBFileContentFrameworkDAO { @@ -27,9 +30,11 @@ public class FileContentDAOImpl implements DBFileContentFrameworkDAO {
27 30
28 @Override 31 @Override
29 public byte[] selectContent(Long configId, String path) { 32 public byte[] selectContent(Long configId, String path) {
30 - FileContentDO fileContentDO = fileContentMapper.selectOne(  
31 - buildQuery(configId, path).select(FileContentDO::getContent));  
32 - return fileContentDO != null ? fileContentDO.getContent() : null; 33 + List<FileContentDO> list = fileContentMapper.selectList(
  34 + buildQuery(configId, path).select(FileContentDO::getContent).orderByDesc(FileContentDO::getId));
  35 + return Optional.ofNullable(CollUtil.getFirst(list))
  36 + .map(FileContentDO::getContent)
  37 + .orElse(null);
33 } 38 }
34 39
35 private LambdaQueryWrapper<FileContentDO> buildQuery(Long configId, String path) { 40 private LambdaQueryWrapper<FileContentDO> buildQuery(Long configId, String path) {
yudao-ui-admin-vue3/package.json
1 { 1 {
2 "name": "yudao-ui-admin-vue3", 2 "name": "yudao-ui-admin-vue3",
3 - "version": "1.6.5-snapshot.1901", 3 + "version": "1.6.6-snapshot.1901",
4 "description": "基于vue3、vite4、element-plus、typesScript", 4 "description": "基于vue3、vite4、element-plus、typesScript",
5 "author": "xingyu", 5 "author": "xingyu",
6 "private": false, 6 "private": false,
yudao-ui-admin/package.json
1 { 1 {
2 "name": "yudao-ui-admin", 2 "name": "yudao-ui-admin",
3 - "version": "1.6.5-snapshot", 3 + "version": "1.6.6-snapshot",
4 "description": "芋道管理系统", 4 "description": "芋道管理系统",
5 "author": "芋道", 5 "author": "芋道",
6 "license": "MIT", 6 "license": "MIT",
yudao-ui-admin/src/views/infra/file/index.vue
1 <template> 1 <template>
2 <div class="app-container"> 2 <div class="app-container">
3 - <doc-alert title="上传下载" url="https://doc.iocoder.cn/file/" /> 3 + <doc-alert title="上传下载" url="https://doc.iocoder.cn/file/"/>
4 <!-- 搜索工作栏 --> 4 <!-- 搜索工作栏 -->
5 <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> 5 <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
6 <el-form-item label="文件路径" prop="path"> 6 <el-form-item label="文件路径" prop="path">
7 <el-input v-model="queryParams.path" placeholder="请输入文件路径" clearable @keyup.enter.native="handleQuery"/> 7 <el-input v-model="queryParams.path" placeholder="请输入文件路径" clearable @keyup.enter.native="handleQuery"/>
8 </el-form-item> 8 </el-form-item>
9 <el-form-item label="创建时间" prop="createTime"> 9 <el-form-item label="创建时间" prop="createTime">
10 - <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"  
11 - range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" /> 10 + <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss"
  11 + type="daterange"
  12 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
  13 + :default-time="['00:00:00', '23:59:59']"/>
12 </el-form-item> 14 </el-form-item>
13 <el-form-item> 15 <el-form-item>
14 <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> 16 <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
@@ -35,6 +37,9 @@ @@ -35,6 +37,9 @@
35 <template v-slot="scope"> 37 <template v-slot="scope">
36 <image-preview v-if="scope.row.type&&scope.row.type.indexOf('image/') === 0" :src="scope.row.url" 38 <image-preview v-if="scope.row.type&&scope.row.type.indexOf('image/') === 0" :src="scope.row.url"
37 :width="'100px'"></image-preview> 39 :width="'100px'"></image-preview>
  40 + <video v-else-if="scope.row.type&&scope.row.type.indexOf('video/') === 0" :width="'100px'">
  41 + <source :src="scope.row.url"/>
  42 + </video>
38 <i v-else>无法预览,点击 43 <i v-else>无法预览,点击
39 <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" target="_blank" 44 <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" target="_blank"
40 :href="getFileUrl + scope.row.configId + '/get/' + scope.row.path">下载 45 :href="getFileUrl + scope.row.configId + '/get/' + scope.row.path">下载
@@ -118,7 +123,7 @@ export default { @@ -118,7 +123,7 @@ export default {
118 title: "", // 弹出层标题 123 title: "", // 弹出层标题
119 isUploading: false, // 是否禁用上传 124 isUploading: false, // 是否禁用上传
120 url: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload", // 请求地址 125 url: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload", // 请求地址
121 - headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部 126 + headers: {Authorization: "Bearer " + getAccessToken()}, // 设置上传的请求头部
122 data: {} // 上传的额外数据,用于文件名 127 data: {} // 上传的额外数据,用于文件名
123 }, 128 },
124 }; 129 };
@@ -189,19 +194,20 @@ export default { @@ -189,19 +194,20 @@ export default {
189 /** 删除按钮操作 */ 194 /** 删除按钮操作 */
190 handleDelete(row) { 195 handleDelete(row) {
191 const id = row.id; 196 const id = row.id;
192 - this.$modal.confirm('是否确认删除文件编号为"' + id + '"的数据项?').then(function() { 197 + this.$modal.confirm('是否确认删除文件编号为"' + id + '"的数据项?').then(function () {
193 return deleteFile(id); 198 return deleteFile(id);
194 }).then(() => { 199 }).then(() => {
195 this.getList(); 200 this.getList();
196 this.$modal.msgSuccess("删除成功"); 201 this.$modal.msgSuccess("删除成功");
197 - }).catch(() => {}); 202 + }).catch(() => {
  203 + });
198 }, 204 },
199 // 用户昵称展示 205 // 用户昵称展示
200 sizeFormat(row, column) { 206 sizeFormat(row, column) {
201 - const unitArr = ["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"]; 207 + const unitArr = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
202 const srcSize = parseFloat(row.size); 208 const srcSize = parseFloat(row.size);
203 const index = Math.floor(Math.log(srcSize) / Math.log(1024)); 209 const index = Math.floor(Math.log(srcSize) / Math.log(1024));
204 - let size =srcSize/Math.pow(1024,index); 210 + let size = srcSize / Math.pow(1024, index);
205 size = size.toFixed(2);//保留的小数位数 211 size = size.toFixed(2);//保留的小数位数
206 return size + ' ' + unitArr[index]; 212 return size + ' ' + unitArr[index];
207 }, 213 },