Compare commits

...

81 Commits

Author SHA1 Message Date
徐大伟
65d879acb4 Merge branch 'feature/REQ-3540' into 'master'
Feature/req 3540

See merge request universal/infrastructure/backend/nanopart!158
2025-04-28 09:00:20 +00:00
xudawei
5039cd9375 Merge branch 'master' into feature/REQ-3540 2025-04-28 16:56:40 +08:00
徐大伟
65970b5107 Merge branch 'feature/REQ-3846' into 'master'
Feature/req 3846

See merge request universal/infrastructure/backend/nanopart!156
2025-04-28 02:44:00 +00:00
xudawei
c33deb72eb Merge branch 'master' into feature/REQ-3846
# Conflicts:
#	doc/doc-api/src/main/java/cn/axzo/nanopart/doc/api/anonymous/DocAnonymousDatabaseApi.java
#	doc/doc-server/src/main/java/cn/axzo/nanopart/doc/dao/IndexNodeDao.java
#	doc/doc-server/src/main/java/cn/axzo/nanopart/doc/file/anonymous/DocAnonymousDatabaseApiController.java
2025-04-28 10:41:54 +08:00
谭杰
7a4f05aca4 Merge branch 'hotfix/20250416' into 'master'
Hotfix/20250416

See merge request universal/infrastructure/backend/nanopart!136
2025-04-17 08:44:58 +00:00
chenwenjian
fd7d79b260 fix: 更新多条步骤数据状态 2025-04-17 14:31:47 +08:00
chenwenjian
5b49d57da9 fix: 返回调整 2025-04-17 10:11:18 +08:00
chenwenjian
e25bda3fa2 fix: 重复数据去重及简易并发控制 2025-04-16 20:23:12 +08:00
xudawei
6ca353c221 feat: (REQ-3846) 根据code批量查询indexNode接口-加上fileKey/fileUrl 2025-04-14 11:03:57 +08:00
xudawei
3cf2f063d0 feat: (REQ-3846) 图文并茂加上createAt 2025-04-11 17:51:27 +08:00
xudawei
3e673fbad4 feat: (REQ-3540) WPS获取文件信息的owner时,没有则取当前登录人 2025-04-11 10:04:20 +08:00
xudawei
e9c6b561fe feat: (REQ-3540) WPS获取文件信息的owner时,没有则取当前登录人 2025-04-10 20:52:45 +08:00
xudawei
d2a2857625 feat: (REQ-3540) WPS获取文件信息的owner时,没有则取当前登录人 2025-04-10 18:08:36 +08:00
xudawei
d368c706f7 feat: (REQ-3540) WPS与OSSFileKey对接,包含创建人为0时处理 2025-04-10 16:30:38 +08:00
xudawei
7dbfd68a30 feat: (REQ-3540) WPS权限枚举添加 2025-04-10 15:15:48 +08:00
xudawei
e06aecc51d feat: (REQ-3846) 获取图片链接排序 2025-04-10 15:07:55 +08:00
xudawei
a44c0f533e feat: (REQ-3540) 根据文件的fileKey预览文件 2025-04-07 19:37:10 +08:00
xudawei
c079f6767a feat: (REQ-3540) 根据文件的fileKey预览文件 2025-04-07 15:37:12 +08:00
谭杰
d4e4c138be Merge branch 'feature/REQ-3540' into 'master'
Revert "REQ-3540: rename element to precise names"

See merge request universal/infrastructure/backend/nanopart!130
2025-04-02 02:53:12 +00:00
xudawei
d7dc42a8f9 Merge branch 'master' into feature/REQ-3540 2025-04-02 10:40:45 +08:00
yanglin
a5a1319316 REQ-3540: 添加字段 2025-04-01 18:32:34 +08:00
yanglin
ef4cfaf2ac REQ-3540: 添加字段 2025-04-01 18:08:08 +08:00
yanglin
59a645c71a REQ-3540: 添加新接口 2025-04-01 16:32:59 +08:00
yanglin
3dd5791854 REQ-3540: 添加新接口 2025-04-01 16:30:10 +08:00
yanglin
7afce22389 REQ-3540: 添加新接口 2025-04-01 16:27:06 +08:00
yanglin
38504f73aa REQ-3540: 添加新接口 2025-04-01 16:14:49 +08:00
yanglin
63c42907b7 REQ-3540: 添加新接口 2025-04-01 15:56:32 +08:00
yanglin
df28fb582d REQ-3540: 修改提示信息 2025-04-01 15:44:52 +08:00
yanglin
9997b11f51 REQ-3540: 修改提示信息 2025-04-01 15:39:51 +08:00
yanglin
9fbed2eaf4 REQ-3540: 修改提示信息 2025-04-01 15:39:44 +08:00
yanglin
6bc47ae13d REQ-3540: 修改提示信息 2025-04-01 15:39:10 +08:00
yanglin
2495f31a7a Merge remote-tracking branch 'origin/feature/REQ-3540' into feature/REQ-3540 2025-04-01 13:50:23 +08:00
yanglin
5c16e55f6a REQ-3540: add comments 2025-04-01 13:50:20 +08:00
xudawei
f0335657ba Merge remote-tracking branch 'origin/feature/REQ-3540' into feature/REQ-3540 2025-04-01 13:45:55 +08:00
xudawei
aa6b0d537d feat: (REQ-3540) fix-checkstyle 2025-04-01 13:45:49 +08:00
yanglin
01e8ee15bf REQ-3540: add comments 2025-04-01 13:43:33 +08:00
xudawei
97446ffb8e Merge remote-tracking branch 'origin/feature/REQ-3540' into feature/REQ-3540 2025-04-01 10:45:38 +08:00
xudawei
6ff07072b9 feat: (REQ-3540) 开通管理根据过期时间更新状态 2025-04-01 10:45:32 +08:00
yanglin
88c3a22c20 REQ-3540: add comments 2025-03-31 18:20:27 +08:00
yanglin
c8995af6d0 Revert "REQ-3540: fix bug"
This reverts commit 8f1ae5aba2.
2025-03-31 18:19:50 +08:00
yanglin
8f1ae5aba2 REQ-3540: fix bug 2025-03-31 18:18:53 +08:00
yanglin
8efeef9431 REQ-3540: 处理文件名冲突的情况 2025-03-31 18:14:51 +08:00
yanglin
8ce7fda35f REQ-3540: 处理文件名冲突的情况 2025-03-31 18:14:37 +08:00
yanglin
942883652f REQ-3540: rename element to precise names 2025-03-31 18:05:48 +08:00
yanglin
5aa151981e REQ-3540: rename element to precise names 2025-03-31 18:02:51 +08:00
yanglin
092215037e REQ-3540: rename element to precise names 2025-03-31 17:59:09 +08:00
yanglin
df62fa31cf Revert "REQ-3540: rename element to precise names"
This reverts commit ee1413586d.
2025-03-31 17:51:56 +08:00
yanglin
ee1413586d REQ-3540: rename element to precise names 2025-03-31 17:51:26 +08:00
yanglin
126032175f REQ-3540: rename element to precise names 2025-03-31 17:12:32 +08:00
yanglin
d0288e5757 REQ-3540: rename element to precise names 2025-03-31 17:12:20 +08:00
yanglin
7a00e9173f REQ-3540: move codes to precise location 2025-03-31 17:07:40 +08:00
yanglin
736cb827f7 REQ-3540: 只有资料库和目录才需要bizCode 2025-03-31 17:02:36 +08:00
yanglin
04db71f324 REQ-3540: rename element to precise names 2025-03-31 16:57:53 +08:00
yanglin
483e23ecf4 REQ-3540: 只有年费类型才有过期时间 2025-03-31 11:51:01 +08:00
yanglin
cb56ef42b2 REQ-3540: 只有年费类型才有过期时间 2025-03-31 11:45:20 +08:00
yanglin
eafa5e9626 REQ-3540: 获取节点信息 2025-03-28 17:26:34 +08:00
yanglin
a7e4c9c6f5 Merge remote-tracking branch 'origin/feature/REQ-3540' into feature/REQ-3540 2025-03-28 17:23:37 +08:00
yanglin
9584032c23 REQ-3540: 获取节点信息 2025-03-28 17:23:34 +08:00
xudawei
1e29852d96 Merge remote-tracking branch 'origin/feature/REQ-3540' into feature/REQ-3540 2025-03-28 16:20:46 +08:00
xudawei
1cba0eebfc feat: (REQ-3540) 校验文件大小优化 2025-03-28 16:20:41 +08:00
yanglin
8d79eca184 REQ-3540: 记录kb 2025-03-28 16:13:53 +08:00
yanglin
938ab42353 REQ-3540: 记录kb 2025-03-28 16:12:20 +08:00
yanglin
df64dcb265 REQ-3540: 复制模版市场 2025-03-28 15:02:59 +08:00
yanglin
5e9cd3a7ed REQ-3540: 复制模版市场 2025-03-28 14:38:38 +08:00
yanglin
2422e2bc43 REQ-3540: 复制模版市场 2025-03-28 14:37:01 +08:00
yanglin
4268e158ef REQ-3540: 添加约束 2025-03-28 11:15:24 +08:00
yanglin
7a41675862 REQ-3540: 扩容校验 2025-03-28 10:34:33 +08:00
yanglin
33b8004b05 REQ-3540: 扩容校验 2025-03-28 09:57:59 +08:00
yanglin
29b41bbc85 REQ-3540: 扩容校验 2025-03-28 09:35:54 +08:00
yanglin
729d04866a REQ-3540: 打开克隆到自己 2025-03-27 16:43:09 +08:00
yanglin
f08f754f71 REQ-3540: 打开克隆到自己 2025-03-27 16:42:45 +08:00
yanglin
ebef16b5c2 REQ-3540: 拷贝匿名空间节点 2025-03-27 15:46:17 +08:00
yanglin
ff7f093d68 REQ-3540: 拷贝匿名空间节点 2025-03-27 14:49:58 +08:00
yanglin
f94c1fa81b REQ-3540: 拷贝匿名空间节点 2025-03-27 14:27:23 +08:00
yanglin
da6f66e10a REQ-3540: 拷贝匿名空间节点 2025-03-27 14:25:59 +08:00
王粒
9fb6aa82e9 Merge branch 'hotfix/20250319' into 'master'
Hotfix/20250319

See merge request universal/infrastructure/backend/nanopart!129
2025-03-20 08:57:32 +00:00
cf5b11d61c feat(REQ-3581) - 补全审批完成后的通知逻辑 2025-03-20 15:58:12 +08:00
45aa2b9515 feat(REQ-3581) - 补全审批完成后的通知逻辑 2025-03-20 14:08:51 +08:00
2e0d4ef253 feat(REQ-3581) - 补全审批完成后的通知逻辑 2025-03-20 14:03:25 +08:00
c5e23cc7cd feat(REQ-3581) - 添加调用消息的通知日志打印 2025-03-20 11:43:17 +08:00
6913a23b25 feat(REQ-3581) - 添加调用消息的通知日志打印 2025-03-19 16:15:08 +08:00
46 changed files with 962 additions and 180 deletions

View File

@ -3,6 +3,8 @@ package cn.axzo.nanopart.doc.api.anonymous;
import javax.validation.Valid; import javax.validation.Valid;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.api.index.request.BatchGetNodeInfoRequest;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -10,9 +12,15 @@ import org.springframework.web.bind.annotation.RequestBody;
import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateDirRequest; import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateDirRequest;
import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest; import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest;
import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousUploadFileRequest; import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousUploadFileRequest;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.api.index.request.CopyNodeRequest; import cn.axzo.nanopart.doc.api.index.request.CopyNodeRequest;
import cn.axzo.nanopart.doc.api.index.request.DeleteNodeRequest;
import cn.axzo.nanopart.doc.api.index.request.GetNodeInfoRequest;
import cn.axzo.nanopart.doc.api.index.request.RenameNodeRequest;
import cn.azxo.framework.common.model.CommonResponse; import cn.azxo.framework.common.model.CommonResponse;
import java.util.Map;
/** /**
* @author yanglin * @author yanglin
*/ */
@ -35,6 +43,14 @@ public interface DocAnonymousDatabaseApi {
@PostMapping("/api/anonymous/createFile") @PostMapping("/api/anonymous/createFile")
CommonResponse<String> createFile(@RequestBody @Valid AnonymousCreateFileRequest request); CommonResponse<String> createFile(@RequestBody @Valid AnonymousCreateFileRequest request);
/**
* 创建新文件
*
* @return 文件编码, 需要由业务存储
*/
@PostMapping("/api/anonymous/createFile2")
CommonResponse<IndexNodeInfo> createFile2(@RequestBody @Valid AnonymousCreateFileRequest request);
/** /**
* 上传文件 * 上传文件
* *
@ -43,6 +59,14 @@ public interface DocAnonymousDatabaseApi {
@PostMapping("/api/anonymous/uploadFile") @PostMapping("/api/anonymous/uploadFile")
CommonResponse<String> uploadFile(@RequestBody @Valid AnonymousUploadFileRequest request); CommonResponse<String> uploadFile(@RequestBody @Valid AnonymousUploadFileRequest request);
/**
* 上传文件
*
* @return 文件编码, 需要由业务存储
*/
@PostMapping("/api/anonymous/uploadFile2")
CommonResponse<IndexNodeInfo> uploadFile2(@RequestBody @Valid AnonymousUploadFileRequest request);
/** /**
* 拷贝节点 (文件) * 拷贝节点 (文件)
* *
@ -51,4 +75,28 @@ public interface DocAnonymousDatabaseApi {
@PostMapping("/api/anonymous/copy") @PostMapping("/api/anonymous/copy")
CommonResponse<String> copy(@RequestBody @Valid CopyNodeRequest request); CommonResponse<String> copy(@RequestBody @Valid CopyNodeRequest request);
/**
* 删除节点 (文件)
*/
@PostMapping("/api/anonymous/delete")
CommonResponse<Void> delete(@RequestBody @Valid DeleteNodeRequest request);
/**
* 重命名节点 (文件)
*/
@PostMapping("/api/anonymous/rename")
CommonResponse<Void> rename(@RequestBody @Valid RenameNodeRequest request);
/**
* 获取节点信息
*/
@PostMapping("/api/anonymous/getNodeInfo")
CommonResponse<IndexNodeInfo> getNodeInfo(@RequestBody @Valid GetNodeInfoRequest request);
/**
* 批量获取节点信息集合
*/
@PostMapping("/api/anonymous/batchGetNodeInfo")
CommonResponse<Map<String, IndexNodeInfo>> batchGetNodeInfo(@RequestBody @Valid BatchGetNodeInfoRequest request);
} }

View File

@ -38,6 +38,7 @@ abstract class NodeCreateAnonymous implements NodeCreate, IndexNodeScope {
/** /**
* 业务编码 * 业务编码
*/ */
@NotBlank(message = "bizCode不能为空")
private String bizCode; private String bizCode;
/** /**

View File

@ -55,6 +55,11 @@ public class SearchNodeBizAttributesResponse {
*/ */
private Long createAtTime; private Long createAtTime;
/**
* 创建时间
*/
private String createAt;
@Override @Override
public int compareTo(DrawMaterial o) { public int compareTo(DrawMaterial o) {
Long first = this.getCreateAtTime(); Long first = this.getCreateAtTime();
@ -106,6 +111,11 @@ public class SearchNodeBizAttributesResponse {
*/ */
private Long createAtTime; private Long createAtTime;
/**
* 创建时间
*/
private String createAt;
@Override @Override
public int compareTo(Content o) { public int compareTo(Content o) {
Long first = this.getCreateAtTime(); Long first = this.getCreateAtTime();

View File

@ -89,6 +89,11 @@ public class IndexNodeInfo implements NodeValue, ValueContainer<IndexNodeInfo> {
*/ */
private String icon; private String icon;
/**
* 文件的大小(bytes), 只有文件才存这个字段
*/
private Integer size;
/** /**
* 状态. VALID: 有效的 * 状态. VALID: 有效的
*/ */
@ -125,6 +130,10 @@ public class IndexNodeInfo implements NodeValue, ValueContainer<IndexNodeInfo> {
private IndexNodeAttributes attributes; private IndexNodeAttributes attributes;
private String ossFileKey;
private String ossFileUrl;
public Path path() { public Path path() {
return Path.wrap(path); return Path.wrap(path);
} }
@ -145,6 +154,12 @@ public class IndexNodeInfo implements NodeValue, ValueContainer<IndexNodeInfo> {
return fileTemplateNodeInfo; return fileTemplateNodeInfo;
} }
@JsonIgnore
@JSONField(serialize = false, deserialize = false)
public FileAttributes getOrCreateFileAttributes() {
return getOrCreateAttributes().getOrCreateFileAttributes();
}
@Override @Override
public Long id() { public Long id() {
return id; return id;

View File

@ -4,7 +4,6 @@ package cn.axzo.nanopart.doc.api.domain;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import cn.axzo.nanopart.doc.api.enums.FileFormat; import cn.axzo.nanopart.doc.api.enums.FileFormat;
import cn.axzo.nanopart.doc.api.util.BizAssertions;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -41,13 +40,6 @@ public class OssFile {
return ossFile; return ossFile;
} }
public void validate() {
BizAssertions.assertNotNull(format, "format不能为空");
BizAssertions.assertTrue(size > 0, "size必须大于0");
BizAssertions.assertNotBlank(ossFileKey, "ossFileKey不能为空");
BizAssertions.assertNotBlank(extension, "后缀不能为空");
}
@Override @Override
public String toString() { public String toString() {
return JSON.toJSONString(this); return JSON.toJSONString(this);

View File

@ -26,6 +26,10 @@ public enum DatabaseScope {
private final Boolean childNameDuplicatable; private final Boolean childNameDuplicatable;
private final Boolean limitChildrenCount; private final Boolean limitChildrenCount;
public boolean isFeeAware() {
return databaseType != DatabaseType.NONE;
}
public Integer getWorkspaceType() { public Integer getWorkspaceType() {
if (this == ENT_DATABASE) if (this == ENT_DATABASE)
return 1; return 1;

View File

@ -17,7 +17,7 @@ public enum FileFormat {
EXCEL(true, "Excel", "xlsx"), EXCEL(true, "Excel", "xlsx"),
WORD(true, "Word", "docx"), WORD(true, "Word", "docx"),
PDF(false, "PDF", "pdf"), PDF(false, "PDF", "pdf"),
PPT(false, "PPT", "pptx"); PPT(true, "PPT", "pptx");
private final boolean creatable; private final boolean creatable;
private final String readableName; private final String readableName;

View File

@ -0,0 +1,81 @@
package cn.axzo.nanopart.doc.api.enums;
import cn.axzo.nanopart.doc.api.wps.response.WpsPermissionResponse;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author xudawei
*/
@Getter
@Accessors(fluent = true)
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum WpsPermissionStatusEnum {
EDIT("edit", "编辑"),
PREVIEW("preview", "预览"),
;
private final String code;
private final String desc;
private static final Map<String, WpsPermissionStatusEnum> map = Stream.of(WpsPermissionStatusEnum.values()).collect(Collectors.toMap(key -> key.code, key -> key));
public static WpsPermissionStatusEnum getByCode(String code) {
return map.get(code);
}
public static void main(String[] args) {
WpsPermissionStatusEnum preview = WpsPermissionStatusEnum.getByCode("preview");
System.out.println("preview = " + preview);
}
/**
* 预览
* @param personId
* @return
*/
public static WpsPermissionResponse preview(String personId) {
return WpsPermissionResponse.builder()
.personId(personId)
.read(1)
.update(0)
.download(0)
.rename(0)
.history(0)
.copy(1)
.print(0)
.saveas(0)
.comment(0)
.build();
}
/**
* 编辑
*/
public static WpsPermissionResponse edit(String personId) {
return WpsPermissionResponse.builder()
.personId(personId)
.read(1)
.update(1)
.download(0)
.rename(0)
.history(0)
.copy(1)
.print(0)
.saveas(0)
.comment(0)
.build();
}
}

View File

@ -0,0 +1,25 @@
package cn.axzo.nanopart.doc.api.file;
import javax.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.api.index.request.GetNodeInfoRequest;
import cn.azxo.framework.common.model.CommonResponse;
/**
* @author yanglin
*/
@FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
public interface IndexNodeApi {
/**
* 获取节点信息
*/
@PostMapping("/api/indexNode/getNodeInfo")
CommonResponse<IndexNodeInfo> getNodeInfo(@RequestBody @Valid GetNodeInfoRequest request);
}

View File

@ -1,9 +1,11 @@
package cn.axzo.nanopart.doc.api.filedb.response; package cn.axzo.nanopart.doc.api.filedb.response;
import cn.axzo.nanopart.doc.api.enums.DatabaseType; import java.math.BigDecimal;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import cn.axzo.nanopart.doc.api.enums.DatabaseType;
import cn.axzo.nanopart.doc.api.enums.FileDatabaseState; import cn.axzo.nanopart.doc.api.enums.FileDatabaseState;
import cn.axzo.nanopart.doc.api.templatedb.domain.TemplateDatabaseInfo; import cn.axzo.nanopart.doc.api.templatedb.domain.TemplateDatabaseInfo;
import lombok.Getter; import lombok.Getter;
@ -79,7 +81,7 @@ public class FileDatabaseInfoResponse {
/** /**
* 已使用的容量, 单位GB * 已使用的容量, 单位GB
*/ */
private Integer usedCapacity; private BigDecimal usedCapacity;
/** /**
* 资料库信息 * 资料库信息

View File

@ -0,0 +1,32 @@
package cn.axzo.nanopart.doc.api.index.request;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* @author xudawei@axzo.cn
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BatchGetNodeInfoRequest {
/**
* 节点编码集合
*/
@NotEmpty(message = "节点编码集合不能为空")
private List<String> codes;
/**
* 是否需要fileUrltrue:需要,false:不需要
* 默认false
*/
private Boolean needFileUrl = false;
}

View File

@ -0,0 +1,21 @@
package cn.axzo.nanopart.doc.api.index.request;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* @author yanglin
*/
@Setter
@Getter
public class GetNodeInfoRequest {
/**
* 节点编码
*/
@NotBlank(message = "节点编码不能为空")
private String code;
}

View File

@ -33,4 +33,19 @@ public class Constants {
*/ */
public static final String WPS_UPLOAD_PREPARE_SHA1 = "sha1"; public static final String WPS_UPLOAD_PREPARE_SHA1 = "sha1";
/**
* http开头
*/
public static final String WPS_HTTP_START = "http://";
/**
* https开头
*/
public static final String WPS_HTTPS_START = "https://";
/**
* wps默认用户Id
*/
public static final String WPS_DEFAULT_USER_ID = "0";
} }

View File

@ -22,4 +22,9 @@ public class WpsFetchFileRequest {
*/ */
private String docCode; private String docCode;
/**
* 用户Id
*/
private String personId;
} }

View File

@ -1,6 +1,7 @@
package cn.axzo.nanopart.doc.api.wps.request; package cn.axzo.nanopart.doc.api.wps.request;
import cn.axzo.nanopart.doc.api.enums.WpsPermissionStatusEnum;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -27,4 +28,9 @@ public class WpsPermissionRequest {
*/ */
private String personId; private String personId;
/**
* 权限状态
*/
private WpsPermissionStatusEnum wpsPermissionStatus;
} }

View File

@ -67,22 +67,4 @@ public class WpsPermissionResponse {
*/ */
private Integer comment; private Integer comment;
/**
* 预览文档权限
*/
public static WpsPermissionResponse preview(String personId) {
return WpsPermissionResponse.builder()
.personId(personId)
.read(1)
.update(0)
.download(0)
.rename(0)
.history(0)
.copy(0)
.print(0)
.saveas(0)
.comment(0)
.build();
}
} }

View File

@ -1,6 +1,7 @@
package cn.axzo.nanopart.doc.dao; package cn.axzo.nanopart.doc.dao;
import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@ -19,9 +20,10 @@ import cn.axzo.nanopart.doc.mapper.FileDatabaseMapper;
@Repository @Repository
public class FileDatabaseDao extends ServiceImpl<FileDatabaseMapper, FileDatabase> { public class FileDatabaseDao extends ServiceImpl<FileDatabaseMapper, FileDatabase> {
public FileDatabase findForUpdateOrNull(DatabaseScope scope, String scopeUniqueCode) { public FileDatabase findForUpdateOrNull(DatabaseScope scope, String templateDatabaseCode, String scopeUniqueCode) {
return lambdaQuery() // return lambdaQuery() //
.eq(FileDatabase::getScope, scope) // .eq(FileDatabase::getScope, scope) //
.eq(FileDatabase::getTemplateDatabaseCode, templateDatabaseCode) //
.eq(FileDatabase::getScopeUniqueCode, scopeUniqueCode) // .eq(FileDatabase::getScopeUniqueCode, scopeUniqueCode) //
.last("FOR UPDATE") // .last("FOR UPDATE") //
.one(); .one();
@ -61,10 +63,11 @@ public class FileDatabaseDao extends ServiceImpl<FileDatabaseMapper, FileDatabas
.remove(); .remove();
} }
public void updateUsedCapacity(String code, int usedFileSize) { public void updateUsedCapacity(String code, int usedFileSizeKb, BigDecimal usedFileSizeGb) {
lambdaUpdate() // lambdaUpdate() //
.eq(FileDatabase::getCode, code) // .eq(FileDatabase::getCode, code) //
.set(FileDatabase::getUsedCapacity, usedFileSize) // .set(FileDatabase::getUsedCapacity, usedFileSizeGb) //
.set(FileDatabase::getUsedCapacityKb, usedFileSizeKb) //
.update(); .update();
} }
@ -82,4 +85,13 @@ public class FileDatabaseDao extends ServiceImpl<FileDatabaseMapper, FileDatabas
.update(); .update();
} }
public void expire() {
lambdaUpdate() //
.eq(FileDatabase::getState, FileDatabaseState.ACTIVATED) //
.isNotNull(FileDatabase::getExpireDate)
.le(FileDatabase::getExpireDate, new Date()) //
.set(FileDatabase::getState, FileDatabaseState.EXPIRED)
.update();
}
} }

View File

@ -1,10 +1,13 @@
package cn.axzo.nanopart.doc.dao; package cn.axzo.nanopart.doc.dao;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope; import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@ -14,6 +17,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope; import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope; import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import cn.axzo.nanopart.doc.api.enums.IndexNodeState; import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType; import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.util.BizAssertions; import cn.axzo.nanopart.doc.api.util.BizAssertions;
@ -53,6 +57,15 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
.one(); .one();
} }
public List<IndexNode> findByCodes(List<String> codes) {
if (CollectionUtils.isEmpty(codes)) {
return Lists.newArrayList();
}
return lambdaQuery() //
.in(IndexNode::getCode, codes) //
.list();
}
public void updatePath(String code, String path) { public void updatePath(String code, String path) {
lambdaUpdate() // lambdaUpdate() //
.eq(IndexNode::getCode, code) // .eq(IndexNode::getCode, code) //
@ -92,10 +105,11 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
.update(); .update();
} }
public List<IndexNode> collectValidSubtreeNodes(IndexNode indexNode) { public List<IndexNode> collectValidSubtreeNodes(IndexNode indexNode, IndexNodeType... nodeTypes) {
return lambdaQuery() // return lambdaQuery() //
.likeRight(IndexNode::getPath, indexNode.getPath()) // .likeRight(IndexNode::getPath, indexNode.getPath()) //
.eq(IndexNode::getState, IndexNodeState.VALID) // .eq(IndexNode::getState, IndexNodeState.VALID) //
.in(nodeTypes.length > 0, IndexNode::getNodeType, Arrays.asList(nodeTypes)) //
.list(); .list();
} }

View File

@ -3,6 +3,7 @@ package cn.axzo.nanopart.doc.dao;
import java.util.List; import java.util.List;
import cn.axzo.nanopart.doc.api.util.BizAssertions;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@ -18,6 +19,12 @@ import cn.axzo.nanopart.doc.mapper.TemplateDatabaseMapper;
@Repository @Repository
public class TemplateDatabaseDao extends ServiceImpl<TemplateDatabaseMapper, TemplateDatabase> { public class TemplateDatabaseDao extends ServiceImpl<TemplateDatabaseMapper, TemplateDatabase> {
public TemplateDatabase getOrThrow(String code) {
TemplateDatabase templateDb = findOrNull(code);
BizAssertions.assertNotNull(templateDb, "找不到资料库: {}", code);
return templateDb;
}
public TemplateDatabase findOrNull(String code) { public TemplateDatabase findOrNull(String code) {
return lambdaQuery().eq(TemplateDatabase::getCode, code).one(); return lambdaQuery().eq(TemplateDatabase::getCode, code).one();
} }

View File

@ -1,6 +1,7 @@
package cn.axzo.nanopart.doc.entity; package cn.axzo.nanopart.doc.entity;
import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@ -76,7 +77,12 @@ public class FileDatabase extends BaseEntity<FileDatabase> implements IndexNodeS
/** /**
* 已使用的容量, 单位GB * 已使用的容量, 单位GB
*/ */
private Integer usedCapacity; private BigDecimal usedCapacity;
/**
* 已使用的容量, 单位kb
*/
private Integer usedCapacityKb;
public boolean isActivated() { public boolean isActivated() {
return state == FileDatabaseState.ACTIVATED; return state == FileDatabaseState.ACTIVATED;

View File

@ -1,6 +1,8 @@
package cn.axzo.nanopart.doc.entity; package cn.axzo.nanopart.doc.entity;
import cn.axzo.nanopart.doc.api.enums.FileFeeType;
import cn.axzo.nanopart.doc.api.enums.FileTemplateFeeType;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -56,6 +58,10 @@ public class TemplateDatabase extends BaseEntity<TemplateDatabase> implements In
@TableField(typeHandler = FastjsonTypeHandler.class) @TableField(typeHandler = FastjsonTypeHandler.class)
private DatabaseAccessConfig accessConfig; private DatabaseAccessConfig accessConfig;
public FileTemplateFeeType getFeeType() {
return feeConfig == null ? null : feeConfig.getFeeType();
}
@Override @Override
public String indexNodeCode() { public String indexNodeCode() {
return code; return code;

View File

@ -25,7 +25,6 @@ public class BizCodeGenerator {
.append(create.nodeScope().scope() == DatabaseScope.ENT_DATABASE ? "ent" : "pro") // .append(create.nodeScope().scope() == DatabaseScope.ENT_DATABASE ? "ent" : "pro") //
.append(nodeType == IndexNodeType.DATABASE ? "space" : "folder") // .append(nodeType == IndexNodeType.DATABASE ? "space" : "folder") //
.append(create.nodeScope().context() == IndexNodeContext.TEMPLATE_DATABASE ? "oms" : workspaceId) // .append(create.nodeScope().context() == IndexNodeContext.TEMPLATE_DATABASE ? "oms" : workspaceId) //
.append("") //
.build(); .build();
create.setBizCode(bizCode); create.setBizCode(bizCode);
} }

View File

@ -1,16 +1,35 @@
package cn.axzo.nanopart.doc.file.anonymous; package cn.axzo.nanopart.doc.file.anonymous;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.function.Function;
import java.util.stream.Collectors;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.api.index.request.BatchGetNodeInfoRequest;
import cn.axzo.nanopart.doc.integration.OssClient;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.hutool.core.bean.BeanUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi; import cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi;
import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateDirRequest; import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateDirRequest;
import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest; import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest;
import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousUploadFileRequest; import cn.axzo.nanopart.doc.api.anonymous.request.AnonymousUploadFileRequest;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.api.domain.OssFile; import cn.axzo.nanopart.doc.api.domain.OssFile;
import cn.axzo.nanopart.doc.api.index.request.CopyNodeRequest; import cn.axzo.nanopart.doc.api.index.request.CopyNodeRequest;
import cn.axzo.nanopart.doc.api.index.request.DeleteNodeRequest;
import cn.axzo.nanopart.doc.api.index.request.GetNodeInfoRequest;
import cn.axzo.nanopart.doc.api.index.request.RenameNodeRequest;
import cn.axzo.nanopart.doc.entity.IndexNode; import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.file.index.IndexManager; import cn.axzo.nanopart.doc.file.index.IndexManager;
import cn.axzo.nanopart.doc.utils.AsyncUtils; import cn.axzo.nanopart.doc.utils.AsyncUtils;
@ -28,6 +47,7 @@ public class DocAnonymousDatabaseApiController implements DocAnonymousDatabaseAp
private final IndexManager indexManager; private final IndexManager indexManager;
private final AsyncUtils asyncUtils; private final AsyncUtils asyncUtils;
private final OssClient ossClient;
@Override @Override
public CommonResponse<String> createDir(AnonymousCreateDirRequest request) { public CommonResponse<String> createDir(AnonymousCreateDirRequest request) {
@ -42,13 +62,26 @@ public class DocAnonymousDatabaseApiController implements DocAnonymousDatabaseAp
return CommonResponse.success(indexManager.createFile(request, ossFile).getCode()); return CommonResponse.success(indexManager.createFile(request, ossFile).getCode());
} }
@Override
public CommonResponse<IndexNodeInfo> createFile2(AnonymousCreateFileRequest request) {
OssFile ossFile = indexManager.prepareEmptyOssFile(request, request.getFormat());
IndexNode fileNode = indexManager.createFile(request, ossFile);
return CommonResponse.success(BeanMapper.map(fileNode, IndexNodeInfo.class));
}
@Override @Override
public CommonResponse<String> uploadFile(AnonymousUploadFileRequest request) { public CommonResponse<String> uploadFile(AnonymousUploadFileRequest request) {
log.info("upload file request:{}", request); log.info("upload file request:{}", request);
request.getOssFile().validate();
return CommonResponse.success(indexManager.uploadFile(request, request.getOssFile()).getCode()); return CommonResponse.success(indexManager.uploadFile(request, request.getOssFile()).getCode());
} }
@Override
public CommonResponse<IndexNodeInfo> uploadFile2(AnonymousUploadFileRequest request) {
log.info("upload file2 request:{}", request);
IndexNode fileNode = indexManager.uploadFile(request, request.getOssFile());
return CommonResponse.success(BeanMapper.map(fileNode, IndexNodeInfo.class));
}
@Override @Override
public CommonResponse<String> copy(CopyNodeRequest request) { public CommonResponse<String> copy(CopyNodeRequest request) {
log.info("copy request:{}", request); log.info("copy request:{}", request);
@ -56,4 +89,66 @@ public class DocAnonymousDatabaseApiController implements DocAnonymousDatabaseAp
return CommonResponse.success(asyncUtils.getOrTimeout(future, 60, "克隆").getCode()); return CommonResponse.success(asyncUtils.getOrTimeout(future, 60, "克隆").getCode());
} }
@Override
public CommonResponse<Void> delete(DeleteNodeRequest request) {
log.info("delete request:{}", request);
indexManager.delete(request.getCode());
return CommonResponse.success();
}
@Override
public CommonResponse<Void> rename(RenameNodeRequest request) {
log.info("rename request:{}", request);
indexManager.rename(request.getCode(), request.getNewName());
return CommonResponse.success();
}
@Override
public CommonResponse<IndexNodeInfo> getNodeInfo(GetNodeInfoRequest request) {
IndexNode indexNode = indexManager.getOrThrow(request.getCode());
return CommonResponse.success(BeanMapper.copyBean(indexNode, IndexNodeInfo.class));
}
/**
* 批量获取节点信息集合
*/
@Override
public CommonResponse<Map<String, IndexNodeInfo>> batchGetNodeInfo(BatchGetNodeInfoRequest request) {
if (Objects.isNull(request) || CollectionUtils.isEmpty(request.getCodes())) {
return CommonResponse.success(Collections.emptyMap());
}
List<IndexNode> indexNodes = indexManager.findByCodes(request.getCodes());
if (CollectionUtils.isEmpty(indexNodes)) {
return CommonResponse.success(Collections.emptyMap());
}
List<IndexNodeInfo> indexNodeInfos = BeanUtil.copyToList(indexNodes, IndexNodeInfo.class);
//填充对象中的fileKey/fileUrl
this.fillFileKeyUrl(request, indexNodeInfos);
Map<String, IndexNodeInfo> nodeInfoMap = indexNodeInfos.stream()
.collect(Collectors.toMap(item -> item.getCode(), Function.identity(), (x, y) -> x));
return CommonResponse.success(nodeInfoMap);
}
/**
* 填充对象中的fileKey/fileUrl
*/
private void fillFileKeyUrl(BatchGetNodeInfoRequest request, List<IndexNodeInfo> indexNodeInfos) {
if (request.getNeedFileUrl()) {
Set<String> fileKeys = indexNodeInfos.stream().filter(item -> StringUtils.hasText(item.getOrCreateFileAttributes().getOssFileKey()))
.map(item -> item.getOrCreateFileAttributes().getOssFileKey())
.collect(Collectors.toSet());
if (CollectionUtils.isNotEmpty(fileKeys)) {
List<ApiSignUrlDownloadResponse> urlResponses = ossClient.batchGetOssUrl(fileKeys);
Map<String, String> fileKeyAndUrlMap = urlResponses.stream().collect(Collectors.toMap(key -> key.getFileKey(), value -> value.getSignUrl(), (x, y) -> x));
indexNodeInfos.stream().filter(item -> StringUtils.hasText(item.getOrCreateFileAttributes().getOssFileKey()))
.forEach(item -> {
item.setOssFileKey(item.getOrCreateFileAttributes().getOssFileKey());
item.setOssFileUrl(fileKeyAndUrlMap.get(item.getOssFileKey()));
});
}
}
}
} }

View File

@ -1,17 +1,10 @@
package cn.axzo.nanopart.doc.file.filedb; package cn.axzo.nanopart.doc.file.filedb;
import java.util.Date;
import org.springframework.stereotype.Component;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob; import com.xxl.job.core.handler.annotation.XxlJob;
import cn.axzo.nanopart.doc.api.enums.FileDatabaseState;
import cn.axzo.nanopart.doc.dao.FileDatabaseDao;
import cn.axzo.nanopart.doc.entity.FileDatabase;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/** /**
* @author yanglin * @author yanglin
@ -21,14 +14,11 @@ import lombok.RequiredArgsConstructor;
@SuppressWarnings({ "unused", "used by job" }) @SuppressWarnings({ "unused", "used by job" })
public class FileDatabaseExpireJob { public class FileDatabaseExpireJob {
private final FileDatabaseDao fileDatabaseDao; private final FileDatabaseService fileDatabaseService;
@XxlJob("fileDatabaseExpireJob") @XxlJob("fileDatabaseExpireJob")
public ReturnT<String> exec(String paramStr) { public ReturnT<String> exec(String paramStr) {
fileDatabaseDao.lambdaUpdate() // fileDatabaseService.expire();
.eq(FileDatabase::getState, FileDatabaseState.ACTIVATED) //
.le(FileDatabase::getExpireDate, new Date()) //
.update();
return ReturnT.SUCCESS; return ReturnT.SUCCESS;
} }

View File

@ -3,6 +3,8 @@ package cn.axzo.nanopart.doc.file.filedb;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -26,10 +28,13 @@ import cn.axzo.apollo.workspace.api.workspace.res.SimpleWorkspaceRes;
import cn.axzo.apollo.workspace.common.enums.WorkspaceTypeEnum; import cn.axzo.apollo.workspace.common.enums.WorkspaceTypeEnum;
import cn.axzo.maokai.api.vo.response.tree.ValueNode; import cn.axzo.maokai.api.vo.response.tree.ValueNode;
import cn.axzo.maokai.api.vo.response.tree.WalkingDecision; import cn.axzo.maokai.api.vo.response.tree.WalkingDecision;
import cn.axzo.nanopart.doc.api.domain.DatabaseFeeConfig;
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope; import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
import cn.axzo.nanopart.doc.api.enums.DatabaseScope; import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
import cn.axzo.nanopart.doc.api.enums.DatabaseType; import cn.axzo.nanopart.doc.api.enums.DatabaseType;
import cn.axzo.nanopart.doc.api.enums.FileDatabaseState; import cn.axzo.nanopart.doc.api.enums.FileDatabaseState;
import cn.axzo.nanopart.doc.api.enums.FileTemplateFeeType;
import cn.axzo.nanopart.doc.api.enums.IndexNodeContext;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType; import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseAbortRequest; import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseAbortRequest;
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseActiveRequest; import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseActiveRequest;
@ -88,26 +93,26 @@ public class FileDatabaseService {
private FileDatabase addWorkspace0(FileDatabaseAddWorkspaceRequest request) { private FileDatabase addWorkspace0(FileDatabaseAddWorkspaceRequest request) {
String scopeUniqueCode = String.valueOf(request.getWorkspaceId()); String scopeUniqueCode = String.valueOf(request.getWorkspaceId());
TemplateDatabase templateDatabase = templateDatabaseQueryService.getOrThrow(request.getTemplateDatabaseCode()); TemplateDatabase templateDb = templateDatabaseQueryService.getOrThrow(request.getTemplateDatabaseCode());
FileDatabase savedDb = fileDatabaseDao.findForUpdateOrNull(templateDatabase.getScope(), scopeUniqueCode); FileDatabase savedDb = fileDatabaseDao.findForUpdateOrNull(templateDb.getScope(), templateDb.getCode(),
scopeUniqueCode);
if (savedDb != null) if (savedDb != null)
throw new FileDatabaseExistsException("无法重复创建, 请刷新页面查询已创建的记录"); throw new FileDatabaseExistsException("无法重复创建, 请刷新页面查询已创建的记录");
SimpleWorkspaceRes workspace = RpcExternalUtil.rpcApolloProcessor( SimpleWorkspaceRes workspace = RpcExternalUtil.rpcApolloProcessor(
() -> workspaceApi.getOne(request.getWorkspaceId()), "查询租户", request.getWorkspaceId()); () -> workspaceApi.getOne(request.getWorkspaceId()), "查询租户", request.getWorkspaceId());
BizAssertions.assertNotNull(workspace, "找不到对应的租户"); BizAssertions.assertNotNull(workspace, "找不到对应的租户");
BizAssertions.assertEquals(workspace.getType(), templateDatabase.getScope().getWorkspaceType(), BizAssertions.assertEquals(workspace.getType(), templateDb.getScope().getWorkspaceType(), "请求租户类型和资料库的租户类型不匹配");
"请求租户类型和资料库的租户类型不匹配");
FileDatabase db = new FileDatabase(); FileDatabase db = new FileDatabase();
db.setCode(UUIDUtil.uuidString()); db.setCode(UUIDUtil.uuidString());
db.setTemplateDatabaseCode(templateDatabase.getCode()); db.setTemplateDatabaseCode(templateDb.getCode());
db.setScope(templateDatabase.getScope()); db.setScope(templateDb.getScope());
db.setScopeUniqueCode(scopeUniqueCode); db.setScopeUniqueCode(scopeUniqueCode);
db.setWorkspaceId(request.getWorkspaceId()); db.setWorkspaceId(request.getWorkspaceId());
db.setState(FileDatabaseState.ACTIVATING); db.setState(FileDatabaseState.ACTIVATING);
if (request.getExpiredDateMs() != null) if (templateDb.getFeeType() == FileTemplateFeeType.ANNUAL && request.getExpiredDateMs() != null)
db.setExpireDate(new Date(request.getExpiredDateMs())); db.setExpireDate(new Date(request.getExpiredDateMs()));
db.setAllowedCapacity(request.getAllowedCapacity()); db.setAllowedCapacity(request.getAllowedCapacity());
db.setUsedCapacity(0); db.setUsedCapacity(BigDecimal.ZERO);
db.setCreateAt(new Date()); db.setCreateAt(new Date());
db.setUpdateAt(new Date()); db.setUpdateAt(new Date());
fileDatabaseDao.save(db); fileDatabaseDao.save(db);
@ -140,7 +145,8 @@ public class FileDatabaseService {
public WalkingDecision visit(ValueNode<IndexNode> node) { public WalkingDecision visit(ValueNode<IndexNode> node) {
WalkingDecision walkingDecision = super.visit(node); WalkingDecision walkingDecision = super.visit(node);
IndexNode indexNode = node.getValue(); IndexNode indexNode = node.getValue();
BizCodeGenerator.gen(indexNode, indexNode.getNodeType(), db.getWorkspaceId()); if (indexNode.isDatabase() || indexNode.isDirectory())
BizCodeGenerator.gen(indexNode, indexNode.getNodeType(), db.getWorkspaceId());
return walkingDecision; return walkingDecision;
} }
}); });
@ -167,14 +173,16 @@ public class FileDatabaseService {
@BizTransactional @BizTransactional
public void fileSizeChanged(String indexNodeCode) { public void fileSizeChanged(String indexNodeCode) {
IndexNode indexNode = indexManager.findOrNull(indexNodeCode); IndexNode indexNode = indexManager.findOrNull(indexNodeCode);
if (indexNode == null || !indexNode.isFile()) if (indexNode == null || !indexNode.isFile() || indexNode.context() != IndexNodeContext.FILE_DATABASE)
return; return;
FileDatabase db = fileDatabaseDao.findForUpdateOrNull(indexNode.scopeCode()); FileDatabase db = fileDatabaseDao.findForUpdateOrNull(indexNode.scopeCode());
if (db == null) if (db == null)
return; return;
int usedFileSize = indexQueryService.getUsedFileSize(db); int sizeByte = indexQueryService.getUsedFileSize(db);
fileDatabaseDao.updateUsedCapacity(db.getCode(), usedFileSize); BigDecimal sizeGb = BigDecimal.valueOf(sizeByte) //
if (db.isActivated() && db.getAllowedCapacity() <= usedFileSize) .divide(BigDecimal.valueOf(1024 * 1024 * 1024), 2, RoundingMode.HALF_UP);
fileDatabaseDao.updateUsedCapacity(db.getCode(), sizeByte, sizeGb);
if (db.isActivated() && isCapacityExhausted(db.getAllowedCapacity(), sizeGb))
fileDatabaseDao.updateState(db.getCode(), FileDatabaseState.CAPACITY_EXHAUSTED); fileDatabaseDao.updateState(db.getCode(), FileDatabaseState.CAPACITY_EXHAUSTED);
} }
@ -184,21 +192,31 @@ public class FileDatabaseService {
FileDatabase db = fileDatabaseDao.getForUpdateOrThrow(request.getCode()); FileDatabase db = fileDatabaseDao.getForUpdateOrThrow(request.getCode());
updateCapacity(request) // updateCapacity(request) //
.set(FileDatabase::getState, // .set(FileDatabase::getState, //
request.getAllowedCapacity() <= db.getUsedCapacity() // isCapacityExhausted(request.getAllowedCapacity(), db.getUsedCapacity()) //
? FileDatabaseState.CAPACITY_EXHAUSTED // ? FileDatabaseState.CAPACITY_EXHAUSTED //
: FileDatabaseState.ACTIVATED) // : FileDatabaseState.ACTIVATED) //
.update(); .update();
} }
private boolean isCapacityExhausted(Integer allowedCapacity, BigDecimal usedCapacity) {
return BigDecimal.valueOf(allowedCapacity).compareTo(usedCapacity) <= 0;
}
@BizTransactional @BizTransactional
public void expandCapacity(FileDatabaseExpandCapacityRequest request) { public void expandCapacity(FileDatabaseExpandCapacityRequest request) {
docLogDao.logRequest("expandCapacity", request.getCode(), request); docLogDao.logRequest("expandCapacity", request.getCode(), request);
FileDatabase db = fileDatabaseDao.getForUpdateOrThrow(request.getCode()); FileDatabase db = fileDatabaseDao.getForUpdateOrThrow(request.getCode());
BizAssertions.assertTrue(db.isActivated(), "只有激活状态的资料库才能扩容"); BizAssertions.assertTrue(db.isActivated(), "只有激活状态的资料库才能扩容");
DatabaseFeeConfig feeConfig = templateDatabaseQueryService.getOrThrow(
db.getTemplateDatabaseCode()).getFeeConfig();
if (feeConfig != null)
BizAssertions.assertTrue(feeConfig.getExtendable(), "资料库不支持扩容");
updateCapacity(request).update(); updateCapacity(request).update();
} }
private LambdaUpdateChainWrapper<FileDatabase> updateCapacity(FileDatabaseActiveRequest request) { private LambdaUpdateChainWrapper<FileDatabase> updateCapacity(FileDatabaseActiveRequest request) {
FileDatabase db = fileDatabaseDao.getOrThrow(request.getCode());
TemplateDatabase templateDb = templateDatabaseQueryService.getOrThrow(db.getTemplateDatabaseCode());
Date expireDate = null; Date expireDate = null;
if (request.getExpiredDateMs() != null && request.getExpiredDateMs() > 0) if (request.getExpiredDateMs() != null && request.getExpiredDateMs() > 0)
expireDate = new Date(request.getExpiredDateMs()); expireDate = new Date(request.getExpiredDateMs());
@ -206,7 +224,8 @@ public class FileDatabaseService {
.eq(FileDatabase::getCode, request.getCode()) // .eq(FileDatabase::getCode, request.getCode()) //
.set(FileDatabase::getAllowedCapacity, request.getAllowedCapacity()) // .set(FileDatabase::getAllowedCapacity, request.getAllowedCapacity()) //
.set(FileDatabase::getPurchaseDate, new Date()) // .set(FileDatabase::getPurchaseDate, new Date()) //
.set(expireDate != null, FileDatabase::getExpireDate, expireDate); .set(templateDb.getFeeType() == FileTemplateFeeType.ANNUAL && expireDate != null,
FileDatabase::getExpireDate, expireDate);
} }
@BizTransactional @BizTransactional
@ -294,4 +313,8 @@ public class FileDatabaseService {
.collect(toList()); .collect(toList());
return Page.toPage(request.getPage(), request.getPageSize(), page.getTotal(), records); return Page.toPage(request.getPage(), request.getPageSize(), page.getTotal(), records);
} }
public void expire() {
this.fileDatabaseDao.expire();
}
} }

View File

@ -67,7 +67,6 @@ public class FileTemplateApiController implements FileTemplateApi {
@Override @Override
public CommonResponse<String> uploadFile(FileTemplateUploadFileRequest request) { public CommonResponse<String> uploadFile(FileTemplateUploadFileRequest request) {
log.info("upload file request:{}", request); log.info("upload file request:{}", request);
request.getOssFile().validate();
return CommonResponse.success(fileTemplateManager.uploadFile(request)); return CommonResponse.success(fileTemplateManager.uploadFile(request));
} }

View File

@ -1,13 +1,16 @@
package cn.axzo.nanopart.doc.file.filetemplate; package cn.axzo.nanopart.doc.file.filetemplate;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import cn.axzo.nanopart.doc.api.domain.OssFile; import cn.axzo.nanopart.doc.api.domain.OssFile;
import cn.axzo.nanopart.doc.api.enums.FileTemplateState; import cn.axzo.nanopart.doc.api.enums.FileTemplateState;
import cn.axzo.nanopart.doc.api.enums.IndexNodeContext;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType; import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.filetemplate.request.FileTemplateCreateDirRequest; import cn.axzo.nanopart.doc.api.filetemplate.request.FileTemplateCreateDirRequest;
import cn.axzo.nanopart.doc.api.filetemplate.request.FileTemplateCreateFileRequest; import cn.axzo.nanopart.doc.api.filetemplate.request.FileTemplateCreateFileRequest;
@ -18,6 +21,7 @@ import cn.axzo.nanopart.doc.dao.FileTemplateDao;
import cn.axzo.nanopart.doc.entity.FileTemplate; import cn.axzo.nanopart.doc.entity.FileTemplate;
import cn.axzo.nanopart.doc.entity.IndexNode; import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.file.index.IndexManager; import cn.axzo.nanopart.doc.file.index.IndexManager;
import cn.axzo.nanopart.doc.file.index.SubtreeCopyEventTransactional;
import cn.axzo.nanopart.doc.file.index.domain.IndexNodes; import cn.axzo.nanopart.doc.file.index.domain.IndexNodes;
import cn.axzo.nanopart.doc.utils.BizTransactional; import cn.axzo.nanopart.doc.utils.BizTransactional;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -27,11 +31,11 @@ import lombok.RequiredArgsConstructor;
*/ */
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class FileTemplateManager { public class FileTemplateManager implements ApplicationListener<SubtreeCopyEventTransactional> {
private final IndexManager indexManager; private final IndexManager indexManager;
private final FileTemplateDao fileTemplateDao; private final FileTemplateDao fileTemplateDao;
private final TransactionTemplate transactionTemplate; private final TransactionTemplate transaction;
public String createDir(FileTemplateCreateDirRequest request) { public String createDir(FileTemplateCreateDirRequest request) {
return indexManager.createDir(request).getCode(); return indexManager.createDir(request).getCode();
@ -39,7 +43,7 @@ public class FileTemplateManager {
public String createFile(FileTemplateCreateFileRequest request) { public String createFile(FileTemplateCreateFileRequest request) {
OssFile ossFile = indexManager.prepareEmptyOssFile(request, request.getFormat()); OssFile ossFile = indexManager.prepareEmptyOssFile(request, request.getFormat());
return transactionTemplate.execute(unused -> createFileTemplate(indexManager.createFile(request, ossFile))); return transaction.execute(unused -> createFileTemplate(indexManager.createFile(request, ossFile)));
} }
@BizTransactional @BizTransactional
@ -48,11 +52,16 @@ public class FileTemplateManager {
} }
private String createFileTemplate(IndexNode fileNode) { private String createFileTemplate(IndexNode fileNode) {
FileTemplate fileTemplate = buildFileTemplate(fileNode);
fileTemplateDao.save(fileTemplate);
return fileNode.getCode();
}
private static FileTemplate buildFileTemplate(IndexNode fileNode) {
FileTemplate fileTemplate = new FileTemplate(); FileTemplate fileTemplate = new FileTemplate();
fileTemplate.setCode(fileNode.getCode()); fileTemplate.setCode(fileNode.getCode());
fileTemplate.setState(FileTemplateState.UNPUBLISH); fileTemplate.setState(FileTemplateState.UNPUBLISH);
fileTemplateDao.save(fileTemplate); return fileTemplate;
return fileNode.getCode();
} }
@BizTransactional @BizTransactional
@ -81,4 +90,16 @@ public class FileTemplateManager {
.set(request.getState() != null, FileTemplate::getState, request.getState()) // .set(request.getState() != null, FileTemplate::getState, request.getState()) //
.update(); .update();
} }
@Override
public void onApplicationEvent(SubtreeCopyEventTransactional event) {
if (event.getCopiedRoot().getContext() != IndexNodeContext.FILE_TEMPLATE)
return;
ArrayList<FileTemplate> fileTemplates = new ArrayList<>();
for (IndexNode fileNode : indexManager.collectValidSubtreeNodes(event.getCopiedRoot(), IndexNodeType.FILE))
fileTemplates.add(buildFileTemplate(fileNode));
if (!fileTemplates.isEmpty())
fileTemplateDao.saveBatch(fileTemplates);
}
} }

View File

@ -8,6 +8,7 @@ import java.util.concurrent.Future;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
@ -52,16 +53,17 @@ public class IndexManager {
private final FileBroadcaster fileBroadcaster; private final FileBroadcaster fileBroadcaster;
private final TransactionTemplate transaction; private final TransactionTemplate transaction;
private final DocLogDao docLogDao; private final DocLogDao docLogDao;
private final ApplicationContext applicationContext;
@BizTransactional @BizTransactional
public IndexNode createDatabase(NodeCreate create) { public IndexNode createDatabase(NodeCreate create) {
ensureChildNameNotUsed(create, IndexNodeType.DATABASE, true); indexSupport.ensureChildNameNotUsed(create, IndexNodeType.DATABASE, true);
return indexSupport.createNode(create, IndexNodeType.DATABASE); return indexSupport.createNode(create, IndexNodeType.DATABASE);
} }
@BizTransactional @BizTransactional
public IndexNode createDir(NodeCreate create) { public IndexNode createDir(NodeCreate create) {
ensureChildNameNotUsed(create, IndexNodeType.DIRECTORY, true); indexSupport.ensureChildNameNotUsed(create, IndexNodeType.DIRECTORY, true);
return indexSupport.createNode(create, IndexNodeType.DIRECTORY); return indexSupport.createNode(create, IndexNodeType.DIRECTORY);
} }
@ -69,7 +71,7 @@ public class IndexManager {
BizAssertions.assertTrue(format.creatable(), "无法创建: {}", format.readableName()); BizAssertions.assertTrue(format.creatable(), "无法创建: {}", format.readableName());
BizAssertions.assertFalse(TransactionSynchronizationManager.isActualTransactionActive(), "不能在事务中使用"); BizAssertions.assertFalse(TransactionSynchronizationManager.isActualTransactionActive(), "不能在事务中使用");
// check without lock // check without lock
ensureChildNameNotUsed(create, IndexNodeType.FILE, false); indexSupport.ensureChildNameNotUsed(create, IndexNodeType.FILE, false);
String fullFileName = String.format("%s.%s", create.name(), format.createFileExtension()); String fullFileName = String.format("%s.%s", create.name(), format.createFileExtension());
String emptyOssFileKey = format == FileFormat.WORD // String emptyOssFileKey = format == FileFormat.WORD //
? docProps.getCreateFileOssFileKeyWord() // ? docProps.getCreateFileOssFileKeyWord() //
@ -83,9 +85,10 @@ public class IndexManager {
@BizTransactional @BizTransactional
public IndexNode uploadFile(NodeCreate node, OssFile ossFile) { public IndexNode uploadFile(NodeCreate node, OssFile ossFile) {
BizAssertions.assertNotNull(ossFile.getFormat(), "format不能为空"); BizAssertions.assertNotNull(ossFile.getFormat(), "format不能为空");
BizAssertions.assertTrue(ossFile.getSize() > 0, "size必须大于0");
BizAssertions.assertNotBlank(ossFile.getOssFileKey(), "oosFileKey不能为空"); BizAssertions.assertNotBlank(ossFile.getOssFileKey(), "oosFileKey不能为空");
BizAssertions.assertNotBlank(ossFile.getExtension(), "extension不能为空"); BizAssertions.assertNotBlank(ossFile.getExtension(), "extension不能为空");
if (node.nodeScope().scope().isFeeAware())
BizAssertions.assertTrue(ossFile.getSize() >= 0, "size必须大于等于0");
IndexNode fileNode = createFile(node, ossFile); IndexNode fileNode = createFile(node, ossFile);
updateFileSize(fileNode, ossFile.getSize()); updateFileSize(fileNode, ossFile.getSize());
return fileNode; return fileNode;
@ -93,7 +96,7 @@ public class IndexManager {
@BizTransactional @BizTransactional
public void updateFileSize(IndexNode fileNode, int size) { public void updateFileSize(IndexNode fileNode, int size) {
if (fileNode == null || !fileNode.isFile()) if (fileNode == null || !fileNode.isFile() || size < 0)
return; return;
indexNodeDao.updateFileSize(fileNode.getCode(), size); indexNodeDao.updateFileSize(fileNode.getCode(), size);
fileBroadcaster.fireFileSizeChanged(fileNode.getCode()); fileBroadcaster.fireFileSizeChanged(fileNode.getCode());
@ -105,7 +108,7 @@ public class IndexManager {
return transaction.execute(unused -> { return transaction.execute(unused -> {
try { try {
// check with lock // check with lock
ensureChildNameNotUsed(create, IndexNodeType.FILE, true); indexSupport.ensureChildNameNotUsed(create, IndexNodeType.FILE, true);
} }
catch (NameUsedException e) { catch (NameUsedException e) {
deleteOssFile.set(true); deleteOssFile.set(true);
@ -128,14 +131,6 @@ public class IndexManager {
} }
} }
private void ensureChildNameNotUsed(NodeCreate create, IndexNodeType nodeType, boolean withLock) {
if (indexSupport.childrenNameDuplicatable(create))
return;
if (withLock)
indexSupport.lockParentAndReleaseOnCommit(create);
indexSupport.ensureChildNameNotUsed(create, nodeType, create.name());
}
@BizTransactional @BizTransactional
public void rename(String code, String newName) { public void rename(String code, String newName) {
IndexNode indexNode = getOrThrow(code); IndexNode indexNode = getOrThrow(code);
@ -158,7 +153,7 @@ public class IndexManager {
public List<IndexNode> delete(String code) { public List<IndexNode> delete(String code) {
IndexNode indexNode = getOrThrow(code); IndexNode indexNode = getOrThrow(code);
docLogDao.log("indexNode:delete", code); docLogDao.log("indexNode:delete", code);
List<IndexNode> subtree = indexNodeDao.collectValidSubtreeNodes(indexNode); List<IndexNode> subtree = collectValidSubtreeNodes(indexNode);
indexNodeDao.stateDeleteSubtree(indexNode); indexNodeDao.stateDeleteSubtree(indexNode);
return subtree; return subtree;
} }
@ -176,7 +171,7 @@ public class IndexManager {
IndexNode srcNode = getOrThrow(srcCode); IndexNode srcNode = getOrThrow(srcCode);
BizAssertions.assertTrue(indexNodeDao.validSubtreeFileCount(srcNode) <= docProps.getIndexNodeMaxCopyFileSize(), BizAssertions.assertTrue(indexNodeDao.validSubtreeFileCount(srcNode) <= docProps.getIndexNodeMaxCopyFileSize(),
"拷贝文件数超过限制: {}", docProps.getIndexNodeMaxCopyFileSize()); "拷贝文件数超过限制: {}", docProps.getIndexNodeMaxCopyFileSize());
IndexNode destParentNode = determineDestParentNode(srcNode, destParentCode, "克隆"); IndexNode destParentNode = determineDestParentNode(srcNode, destParentCode, Op.COPY);
return async(() -> { return async(() -> {
// don't inline in transaction // don't inline in transaction
CopyFileVisitor copyNodeVisitor = new CopyFileVisitor(copySubtreeOssFiles(srcNode)); CopyFileVisitor copyNodeVisitor = new CopyFileVisitor(copySubtreeOssFiles(srcNode));
@ -193,7 +188,7 @@ public class IndexManager {
*/ */
public Future<IndexNode> asyncMove(String srcCode, @Nullable String destParentCode) { public Future<IndexNode> asyncMove(String srcCode, @Nullable String destParentCode) {
IndexNode srcNode = getOrThrow(srcCode); IndexNode srcNode = getOrThrow(srcCode);
IndexNode destParentNode = determineDestParentNode(srcNode, destParentCode, "移动"); IndexNode destParentNode = determineDestParentNode(srcNode, destParentCode, Op.MOVE);
return async(() -> transaction.execute(unused -> { return async(() -> transaction.execute(unused -> {
docLogDao.log("indexNode:asyncMove", srcCode, "srcCode", srcCode, "destParentCode", destParentCode); docLogDao.log("indexNode:asyncMove", srcCode, "srcCode", srcCode, "destParentCode", destParentCode);
if (docProps.isLockSubtreeWhenMove()) if (docProps.isLockSubtreeWhenMove())
@ -204,18 +199,20 @@ public class IndexManager {
})); }));
} }
private IndexNode determineDestParentNode(IndexNode srcNode, String destParentCode, String op) { private IndexNode determineDestParentNode(IndexNode srcNode, String destParentCode, Op op) {
IndexNode parent = StringUtils.isBlank(destParentCode) ? null : getOrThrow(destParentCode); IndexNode parent = StringUtils.isBlank(destParentCode) ? null : getOrThrow(destParentCode);
if (parent == null) if (parent == null)
return null; return null;
BizAssertions.assertFalse(srcNode.isDirectory() && parent.isFile(), "不能{}文件夹到文件下", op); BizAssertions.assertFalse(srcNode.isDirectory() && parent.isFile(), "不能{}文件夹到文件下", op);
BizAssertions.assertFalse(srcNode.isSameNodeWith(parent), "不能{}到同一节点下", op);
BizAssertions.assertFalse(srcNode.isParentOf(parent), "不能{}到子节点下", op); BizAssertions.assertFalse(srcNode.isParentOf(parent), "不能{}到子节点下", op);
if (op == Op.MOVE)
BizAssertions.assertFalse(srcNode.isSameNodeWith(parent), "不能{}到同一节点下", op);
List<IndexNode> subtreeNodes = indexSupport.collectValidSubtreeAsValueRoot(srcNode); List<IndexNode> subtreeNodes = indexSupport.collectValidSubtreeAsValueRoot(srcNode);
int subtreeMaxDepth = IndexNodeTreeUtils.build(subtreeNodes).getChildren().stream() // int subtreeMaxDepth = IndexNodeTreeUtils.build(subtreeNodes).getValueNodes().stream() //
.mapToInt(Node::getLevel) // .mapToInt(Node::getLevel) //
.max() // .max() //
.orElse(0); .orElse(0);
// 这里不加1, 因为root node其实不是真实的值节点, 不用算在内
indexSupport.validateDepthWhenAddChild(parent.path().depth() + subtreeMaxDepth); indexSupport.validateDepthWhenAddChild(parent.path().depth() + subtreeMaxDepth);
return parent; return parent;
} }
@ -226,7 +223,9 @@ public class IndexManager {
RootNode<IndexNode> srcRoot = TreeUtils.transform(subtreeNodes, IndexNode.class, true); RootNode<IndexNode> srcRoot = TreeUtils.transform(subtreeNodes, IndexNode.class, true);
srcRoot.walkDown(copyNodeVisitor); srcRoot.walkDown(copyNodeVisitor);
indexNodeDao.saveBatch(TreeUtils.collectValues(srcRoot)); indexNodeDao.saveBatch(TreeUtils.collectValues(srcRoot));
return connectNodes(srcRoot, destParent); IndexNode copiedRoot = connectNodes(srcRoot, destParent);
applicationContext.publishEvent(new SubtreeCopyEventTransactional(this, src, copiedRoot));
return copiedRoot;
} }
/** /**
@ -244,6 +243,10 @@ public class IndexManager {
return indexNodeDao.findOrNull(rootNode.getCode()); return indexNodeDao.findOrNull(rootNode.getCode());
} }
public List<IndexNode> collectValidSubtreeNodes(IndexNode indexNode, IndexNodeType... nodeTypes) {
return indexNodeDao.collectValidSubtreeNodes(indexNode, nodeTypes);
}
public IndexNode findOrNull(String code) { public IndexNode findOrNull(String code) {
if (StringUtils.isBlank(code)) if (StringUtils.isBlank(code))
return null; return null;
@ -254,6 +257,10 @@ public class IndexManager {
return indexNodeDao.getOrThrow(code); return indexNodeDao.getOrThrow(code);
} }
public List<IndexNode> findByCodes(List<String> codes) {
return indexNodeDao.findByCodes(codes);
}
public void updateBizInfo(String code, String bizCode, String description, String icon) { public void updateBizInfo(String code, String bizCode, String description, String icon) {
if (StringUtils.isBlank(bizCode) && StringUtils.isBlank(description) && StringUtils.isBlank(icon)) if (StringUtils.isBlank(bizCode) && StringUtils.isBlank(description) && StringUtils.isBlank(icon))
return; return;
@ -276,4 +283,14 @@ public class IndexManager {
}); });
} }
@RequiredArgsConstructor
private enum Op {
MOVE("移动"), COPY("克隆");
private final String name;
@Override
public String toString() {
return name;
}
}
} }

View File

@ -0,0 +1,31 @@
package cn.axzo.nanopart.doc.file.index;
import org.springframework.web.bind.annotation.RestController;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
import cn.axzo.nanopart.doc.api.file.IndexNodeApi;
import cn.axzo.nanopart.doc.api.index.request.GetNodeInfoRequest;
import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.azxo.framework.common.model.CommonResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* @author yanglin
*/
@Slf4j
@RestController
@RequiredArgsConstructor
public class IndexNodeApiController implements IndexNodeApi {
private final IndexManager indexManager;
@Override
public CommonResponse<IndexNodeInfo> getNodeInfo(GetNodeInfoRequest request) {
IndexNode indexNode = indexManager.getOrThrow(request.getCode());
return CommonResponse.success(BeanMapper.copyBean(indexNode, IndexNodeInfo.class));
}
}

View File

@ -100,8 +100,8 @@ public class IndexSupport {
"创建失败, 子节点数量不能超过 {}", docProps.getIndexNodeMaxChildrenSize()); "创建失败, 子节点数量不能超过 {}", docProps.getIndexNodeMaxChildrenSize());
} }
public void validateDepthWhenAddChild(int pendingDepth) { public void validateDepthWhenAddChild(int targetDepth) {
BizAssertions.assertTrue(pendingDepth >= docProps.getIndexNodeMaxDepth(), // BizAssertions.assertTrue(targetDepth <= docProps.getIndexNodeMaxDepth(), //
"节点深度超过限制{}, 无法再创建新节点", docProps.getIndexNodeMaxDepth()); "节点深度超过限制{}, 无法再创建新节点", docProps.getIndexNodeMaxDepth());
} }
@ -134,6 +134,14 @@ public class IndexSupport {
indexNodeDao.rename(rename.getCode(), newName); indexNodeDao.rename(rename.getCode(), newName);
} }
void ensureChildNameNotUsed(NodeCreate create, IndexNodeType nodeType, boolean withLock) {
if (childrenNameDuplicatable(create))
return;
if (withLock)
lockParentAndReleaseOnCommit(create);
ensureChildNameNotUsed(create, nodeType, create.name());
}
void ensureChildNameNotUsed(IndexNodeParentScope parentScope, IndexNodeType nodeType, String childName) { void ensureChildNameNotUsed(IndexNodeParentScope parentScope, IndexNodeType nodeType, String childName) {
IndexNode child = indexNodeDao.findValidChildByName(parentScope, nodeType, childName); IndexNode child = indexNodeDao.findValidChildByName(parentScope, nodeType, childName);
// don't use BizAssertions.assertNull // don't use BizAssertions.assertNull

View File

@ -0,0 +1,24 @@
package cn.axzo.nanopart.doc.file.index;
import org.springframework.context.ApplicationEvent;
import cn.axzo.nanopart.doc.entity.IndexNode;
import lombok.Getter;
/**
* @author yanglin
*/
@Getter
public class SubtreeCopyEventTransactional extends ApplicationEvent {
private final IndexNode srcNode;
private final IndexNode copiedRoot;
public SubtreeCopyEventTransactional(Object source, IndexNode srcNode, IndexNode copiedRoot) {
super(source);
this.srcNode = srcNode;
this.copiedRoot = copiedRoot;
}
}

View File

@ -29,6 +29,12 @@ public class IndexNodes {
.collect(toList()); .collect(toList());
} }
public List<IndexNode> collectNodes(IndexNodeType nodeType) {
return indexNodes.stream() //
.filter(node -> node.getNodeType() == nodeType) //
.collect(toList());
}
public IndexNode findOrNull(String code) { public IndexNode findOrNull(String code) {
return indexNodes.stream() // return indexNodes.stream() //
.filter(node -> node.getCode().equals(code)) // .filter(node -> node.getCode().equals(code)) //

View File

@ -78,7 +78,6 @@ public class TemplateDatabaseApiController implements TemplateDatabaseApi {
@Override @Override
public CommonResponse<String> uploadFile(TemplateDatabaseUploadFileRequest request) { public CommonResponse<String> uploadFile(TemplateDatabaseUploadFileRequest request) {
log.info("upload file request:{}", request); log.info("upload file request:{}", request);
request.getOssFile().validate();
return CommonResponse.success(templateDatabaseManager.updateFile(request)); return CommonResponse.success(templateDatabaseManager.updateFile(request));
} }

View File

@ -4,11 +4,13 @@ package cn.axzo.nanopart.doc.file.templatedb;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import cn.axzo.nanopart.doc.api.domain.OssFile; import cn.axzo.nanopart.doc.api.domain.OssFile;
import cn.axzo.nanopart.doc.api.enums.IndexNodeContext;
import cn.axzo.nanopart.doc.api.enums.IndexNodeType; import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
import cn.axzo.nanopart.doc.api.index.request.DeleteNodeRequest; import cn.axzo.nanopart.doc.api.index.request.DeleteNodeRequest;
import cn.axzo.nanopart.doc.api.templatedb.reqeust.NodeCreateTemplateDatabase; import cn.axzo.nanopart.doc.api.templatedb.reqeust.NodeCreateTemplateDatabase;
@ -23,6 +25,7 @@ import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.entity.TemplateDatabase; import cn.axzo.nanopart.doc.entity.TemplateDatabase;
import cn.axzo.nanopart.doc.file.BizCodeGenerator; import cn.axzo.nanopart.doc.file.BizCodeGenerator;
import cn.axzo.nanopart.doc.file.index.IndexManager; import cn.axzo.nanopart.doc.file.index.IndexManager;
import cn.axzo.nanopart.doc.file.index.SubtreeCopyEventTransactional;
import cn.axzo.nanopart.doc.file.index.domain.IndexNodes; import cn.axzo.nanopart.doc.file.index.domain.IndexNodes;
import cn.axzo.nanopart.doc.utils.BizTransactional; import cn.axzo.nanopart.doc.utils.BizTransactional;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -32,7 +35,7 @@ import lombok.RequiredArgsConstructor;
*/ */
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class TemplateDatabaseManager { public class TemplateDatabaseManager implements ApplicationListener<SubtreeCopyEventTransactional> {
private final IndexManager indexManager; private final IndexManager indexManager;
private final TemplateDatabaseDao templateDatabaseDao; private final TemplateDatabaseDao templateDatabaseDao;
@ -110,4 +113,19 @@ public class TemplateDatabaseManager {
.update(); .update();
} }
@Override
public void onApplicationEvent(SubtreeCopyEventTransactional event) {
if (event.getCopiedRoot().getContext() != IndexNodeContext.TEMPLATE_DATABASE)
return;
if (event.getCopiedRoot().getNodeType() != IndexNodeType.DATABASE)
return;
TemplateDatabase templateDb = templateDatabaseDao.getOrThrow(event.getSrcNode().getCode());
TemplateDatabase db = new TemplateDatabase();
db.setCode(event.getCopiedRoot().getCode());
db.setScope(event.getCopiedRoot().getScope());
db.setCoopType(templateDb.getCoopType());
db.setCreateAt(new Date());
db.setUpdateAt(new Date());
templateDatabaseDao.save(db);
}
} }

View File

@ -8,6 +8,8 @@ import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse; import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.axzo.oss.http.model.ApiSignUrlUploadRequest; import cn.axzo.oss.http.model.ApiSignUrlUploadRequest;
import cn.axzo.oss.http.model.ApiSignUrlUploadResponse; import cn.axzo.oss.http.model.ApiSignUrlUploadResponse;
import cn.axzo.oss.http.model.file.FetchFileInfoRequest;
import cn.axzo.oss.http.model.file.FetchFileInfoResponse;
import cn.axzo.oss.http.model.file.UpdateFileInfoRequest; import cn.axzo.oss.http.model.file.UpdateFileInfoRequest;
import cn.axzo.oss.http.model.file.UpdateFileInfoResponse; import cn.axzo.oss.http.model.file.UpdateFileInfoResponse;
import cn.azxo.framework.common.model.CommonResponse; import cn.azxo.framework.common.model.CommonResponse;
@ -82,4 +84,20 @@ public class DocOssGateway {
} }
/**
* 获取文件基础信息
*/
public FetchFileInfoResponse fetchFileInfo(FetchFileInfoRequest request) {
try {
log.info("DocOssGateway-fetchFileInfo request:{}", JSON.toJSONString(request));
CommonResponse<FetchFileInfoResponse> response = serverFileServiceApi.fetchFileInfo(request);
log.info("DocOssGateway-fetchFileInfo result:{}", JSON.toJSONString(response));
return response.getData();
} catch (Exception e) {
log.warn("DocOssGateway-fetchFileInfo exception", e);
throw new WpsException(WpsErrorCodeEnum.UPLOAD_ERROR);
}
}
} }

View File

@ -8,6 +8,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -152,4 +153,21 @@ public class OssClient {
docLogDao.log(context, subject, logContents); docLogDao.log(context, subject, logContents);
} }
public List<ApiSignUrlDownloadResponse> batchGetOssUrl(Set<String> ossFileKeys) {
if (CollectionUtils.isEmpty(ossFileKeys)) {
return Collections.emptyList();
}
ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest();
request.setFileKeys(Lists.newArrayList(ossFileKeys));
try {
log.info("OssClient-batchGetOssUrl params:{}", JSON.toJSONString(ossFileKeys));
CommonResponse<List<ApiSignUrlDownloadResponse>> response = serverFileServiceApi.signUrlFetchDownload(request);
log.info("OssClient-batchGetOssUrl params:{},result:{}", JSON.toJSONString(ossFileKeys), JSON.toJSONString(response));
return response.getData();
} catch (Exception e) {
log.warn("OssClient-batchGetOssUrl exception, fileKeys:{}", JSON.toJSONString(ossFileKeys), e);
throw new RuntimeException(e);
}
}
} }

View File

@ -35,7 +35,7 @@ public class AsyncUtils {
return result; return result;
} }
catch (CannotAcquireLockException e) { catch (CannotAcquireLockException e) {
String message = String.format("%s等待超时, 可能正在移动节点, 请稍后刷新页面重试", op); String message = String.format("%s等待超时, 请稍后重试", op);
log.warn(message, e); log.warn(message, e);
throw fail(message); throw fail(message);
} }

View File

@ -0,0 +1,115 @@
package cn.axzo.nanopart.doc.wps.support;
import cn.axzo.nanopart.doc.api.enums.WpsErrorCodeEnum;
import cn.axzo.nanopart.doc.api.util.Constants;
import cn.axzo.nanopart.doc.api.wps.response.WpsFetchDownloadResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsFetchFileResponse;
import cn.axzo.nanopart.doc.integration.DocOssGateway;
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.axzo.oss.http.model.file.FetchFileInfoRequest;
import cn.axzo.oss.http.model.file.FetchFileInfoResponse;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
/**
* @author xudawei@axzo.cn
* @date 2025/3/21
* @description wps支持
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class OssSupport {
private final DocOssGateway docOssGateway;
public WpsFetchFileResponse fetchFileInfo(String fileKey, String personId) {
fileKey = url2FileKey(fileKey);
FetchFileInfoResponse response = docOssGateway.fetchFileInfo(FetchFileInfoRequest.builder().fileKey(fileKey).build());
if (Objects.isNull(response) || Objects.isNull(response.getId())) {
return null;
}
return WpsFetchFileResponse.builder()
.docCode(response.getFileUuid())
.name(response.getFileName())
.version(1)
.size(response.getStorageSize())
.createAt(response.getCreateAt())
.updateAt(response.getUpdateAt())
.creatorId(StringUtils.isNotBlank(response.getCreateBy()) ? response.getCreateBy() : personId)
.modifierId(StringUtils.isNotBlank(response.getUpdateBy()) ? response.getUpdateBy() : personId)
.build();
}
public WpsFetchDownloadResponse fetchDownload(String fileKey) {
fileKey = url2FileKey(fileKey);
FetchFileInfoResponse response = docOssGateway.fetchFileInfo(FetchFileInfoRequest.builder().fileKey(fileKey).build());
if (Objects.isNull(response) || Objects.isNull(response.getId())) {
return null;
}
return WpsFetchDownloadResponse.builder()
.url(this.downloadUrl(response.getFileUuid()))
.digest("")
.digestType("")
.headers(null)
.build();
}
/**
* 获取文件下载地址
*/
public String downloadUrl(String fileKey) {
if (StringUtils.isEmpty(fileKey)) {
return StringUtils.EMPTY;
}
fileKey = url2FileKey(fileKey);
ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest();
request.setFileKeys(Lists.newArrayList(fileKey));
List<ApiSignUrlDownloadResponse> responseList = docOssGateway.signUrlFetchDownload(request);
WpsAssertUtil.isFalse(CollectionUtil.isEmpty(responseList) || StringUtils.isBlank(responseList.get(0).getSignUrl()), WpsErrorCodeEnum.UPLOAD_ERROR);
return responseList.get(0).getSignUrl();
}
/**
* 从链接中提取fileKey比如如下链接获取fileKey:b4148fbee6954c2fa3139471f18a2dcd
* https://xx/identity/b4148fbee6954c2fa3139471f18a2dcd.docx?AccessKeyId=xx&Expires=xx&response-content-disposition=xx&Signature=xx
* https://xx/identity/b4148fbee6954c2fa3139471f18a2dcd.doc?AccessKeyId=xx&Expires=xx&response-content-disposition=xx&Signature=xx
* https://xxx/app/app/b4148fbee6954c2fa3139471f18a2dcd.docx
* https://xxx/app/app/b4148fbee6954c2fa3139471f18a2dcd.doc
*/
public String url2FileKey(String url) {
if (!url.startsWith(Constants.WPS_HTTP_START) && !url.startsWith(Constants.WPS_HTTPS_START)) {
return url;
}
if (url.contains("/") && url.contains("?")) {
url = url.split("\\?")[0];
String fileName = url.substring(url.lastIndexOf("/") + 1);
if (fileName.contains(".")) {
return fileName.substring(0, fileName.indexOf("."));
}
return fileName;
}
if (url.contains("/") ) {
String fileName = url.substring(url.lastIndexOf("/") + 1);
if (fileName.contains(".")) {
return fileName.substring(0, fileName.indexOf("."));
}
return fileName;
}
return url;
}
}

View File

@ -12,6 +12,7 @@ import cn.axzo.nanopart.doc.api.wps.response.WpsFetchFileResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsPermissionResponse; import cn.axzo.nanopart.doc.api.wps.response.WpsPermissionResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsRenameResponse; import cn.axzo.nanopart.doc.api.wps.response.WpsRenameResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsUsersResponse; import cn.axzo.nanopart.doc.api.wps.response.WpsUsersResponse;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -37,7 +38,10 @@ public class WpsBaseController implements WpsBaseApi {
*/ */
@Override @Override
public ApiResult<WpsFetchFileResponse> fetchFile(@Validated @RequestBody WpsFetchFileRequest request) { public ApiResult<WpsFetchFileResponse> fetchFile(@Validated @RequestBody WpsFetchFileRequest request) {
return ApiResult.ok(wpsBaseManager.fetchFileBase(request.getDocCode())); log.info("WpsBaseController-fetchFile-params: {}", JSON.toJSONString(request));
WpsFetchFileResponse wpsFetchFileResponse = wpsBaseManager.fetchFileBase(request.getDocCode(), request.getPersonId());
log.info("WpsBaseController-fetchFile-result: {}", JSON.toJSONString(wpsFetchFileResponse));
return ApiResult.ok(wpsFetchFileResponse);
} }
/** /**
@ -58,7 +62,10 @@ public class WpsBaseController implements WpsBaseApi {
*/ */
@Override @Override
public ApiResult<WpsPermissionResponse> permission(@Validated @RequestBody WpsPermissionRequest request) { public ApiResult<WpsPermissionResponse> permission(@Validated @RequestBody WpsPermissionRequest request) {
return ApiResult.ok(wpsBaseManager.permission(request)); log.info("WpsBaseController-permission-params: {}", JSON.toJSONString(request));
WpsPermissionResponse permission = wpsBaseManager.permission(request);
log.info("WpsBaseController-permission-params:{},result: {}", JSON.toJSONString(request),JSON.toJSONString(permission));
return ApiResult.ok(permission);
} }
/** /**
@ -68,7 +75,10 @@ public class WpsBaseController implements WpsBaseApi {
*/ */
@Override @Override
public ApiResult<WpsUsersResponse> users(@Validated @RequestBody WpsUsersRequest request) { public ApiResult<WpsUsersResponse> users(@Validated @RequestBody WpsUsersRequest request) {
return ApiResult.ok(wpsBaseManager.users(request)); log.info("WpsBaseController-users-params: {}", JSON.toJSONString(request));
WpsUsersResponse users = wpsBaseManager.users(request);
log.info("WpsBaseController-users-params:{},result: {}", JSON.toJSONString(request), JSON.toJSONString(users));
return ApiResult.ok(users);
} }
/** /**

View File

@ -3,6 +3,9 @@ package cn.axzo.nanopart.doc.wps.wpsbase;
import cn.axzo.basics.common.util.AssertUtil; import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto; import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
import cn.axzo.nanopart.doc.api.enums.WpsErrorCodeEnum; import cn.axzo.nanopart.doc.api.enums.WpsErrorCodeEnum;
import cn.axzo.nanopart.doc.api.enums.WpsPermissionStatusEnum;
import cn.axzo.nanopart.doc.api.util.Constants;
import cn.axzo.nanopart.doc.api.wps.exception.WpsException;
import cn.axzo.nanopart.doc.api.wps.request.WpsPermissionRequest; import cn.axzo.nanopart.doc.api.wps.request.WpsPermissionRequest;
import cn.axzo.nanopart.doc.api.wps.request.WpsRenameRequest; import cn.axzo.nanopart.doc.api.wps.request.WpsRenameRequest;
import cn.axzo.nanopart.doc.api.wps.request.WpsUsersRequest; import cn.axzo.nanopart.doc.api.wps.request.WpsUsersRequest;
@ -12,14 +15,14 @@ import cn.axzo.nanopart.doc.api.wps.response.WpsPermissionResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsRenameResponse; import cn.axzo.nanopart.doc.api.wps.response.WpsRenameResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsUsersResponse; import cn.axzo.nanopart.doc.api.wps.response.WpsUsersResponse;
import cn.axzo.nanopart.doc.config.DocPermissionProps; import cn.axzo.nanopart.doc.config.DocPermissionProps;
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
import cn.axzo.nanopart.doc.entity.IndexNode; import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.file.index.IndexManager;
import cn.axzo.nanopart.doc.file.index.domain.NameUsedException;
import cn.axzo.nanopart.doc.integration.DocOssGateway; import cn.axzo.nanopart.doc.integration.DocOssGateway;
import cn.axzo.nanopart.doc.integration.DocUserProfileGateway; import cn.axzo.nanopart.doc.integration.DocUserProfileGateway;
import cn.axzo.nanopart.doc.wps.support.OssSupport;
import cn.axzo.nanopart.doc.wps.support.WpsAssertUtil; import cn.axzo.nanopart.doc.wps.support.WpsAssertUtil;
import cn.axzo.nanopart.doc.wps.support.WpsSupport; import cn.axzo.nanopart.doc.wps.support.WpsSupport;
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.axzo.oss.http.model.file.UpdateFileInfoRequest; import cn.axzo.oss.http.model.file.UpdateFileInfoRequest;
import cn.axzo.oss.http.model.file.UpdateFileInfoResponse; import cn.axzo.oss.http.model.file.UpdateFileInfoResponse;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
@ -41,18 +44,26 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class WpsBaseManager { public class WpsBaseManager {
private final IndexNodeDao indexNodeDao; private final IndexManager indexManager;
private final DocOssGateway docOssGateway; private final DocOssGateway docOssGateway;
private final DocUserProfileGateway docUserProfileGateway; private final DocUserProfileGateway docUserProfileGateway;
private final DocPermissionProps docPermissionProps; private final DocPermissionProps docPermissionProps;
private final WpsSupport wpsSupport; private final WpsSupport wpsSupport;
private final OssSupport ossSupport;
/** /**
* 获取文件基础信息 * 获取文件基础信息
* @param docCode 文件编码 * @param docCode 文件编码
*/ */
public WpsFetchFileResponse fetchFileBase(String docCode) { public WpsFetchFileResponse fetchFileBase(String docCode, String personId) {
WpsFetchFileResponse wpsFetchFileResponse = ossSupport.fetchFileInfo(docCode, personId);
if (Objects.nonNull(wpsFetchFileResponse) && Objects.nonNull(wpsFetchFileResponse.getDocCode())) {
return wpsFetchFileResponse;
}
IndexNode node = wpsSupport.findAndCheckByCode(docCode); IndexNode node = wpsSupport.findAndCheckByCode(docCode);
return WpsFetchFileResponse.builder() return WpsFetchFileResponse.builder()
.docCode(docCode) .docCode(docCode)
@ -71,41 +82,37 @@ public class WpsBaseManager {
* @param docCode 文件编码 * @param docCode 文件编码
*/ */
public WpsFetchDownloadResponse fetchDownload(String docCode) { public WpsFetchDownloadResponse fetchDownload(String docCode) {
WpsFetchDownloadResponse wpsFetchDownloadResponse = ossSupport.fetchDownload(docCode);
if (Objects.nonNull(wpsFetchDownloadResponse) && StringUtils.isNotBlank(wpsFetchDownloadResponse.getUrl())) {
return wpsFetchDownloadResponse;
}
IndexNode node = wpsSupport.findAndCheckByCode(docCode); IndexNode node = wpsSupport.findAndCheckByCode(docCode);
return WpsFetchDownloadResponse.builder() return WpsFetchDownloadResponse.builder()
.url(this.downloadUrl(node.getAttributes().getFileAttributes().getOssFileKey())) .url(ossSupport.downloadUrl(node.getAttributes().getFileAttributes().getOssFileKey()))
.digest("") .digest("")
.digestType("") .digestType("")
.headers(null) .headers(null)
.build(); .build();
} }
/**
* 获取文件下载地址
*/
private String downloadUrl(String fileKey) {
if (StringUtils.isEmpty(fileKey)) {
return StringUtils.EMPTY;
}
ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest();
request.setFileKeys(Lists.newArrayList(fileKey));
List<ApiSignUrlDownloadResponse> responseList = docOssGateway.signUrlFetchDownload(request);
WpsAssertUtil.isFalse(CollectionUtil.isEmpty(responseList) || StringUtils.isBlank(responseList.get(0).getSignUrl()), WpsErrorCodeEnum.UPLOAD_ERROR);
return responseList.get(0).getSignUrl();
}
/** /**
* 文档权限 * 文档权限
* 暂时全部开放权限REQ-35401期只是OMS没有文件权限功能待REQ-3540的2期建立权限后再对接 * 暂时全部开放权限REQ-35401期只是OMS没有文件权限功能待REQ-3540的2期建立权限后再对接
*/ */
public WpsPermissionResponse permission(WpsPermissionRequest request) { public WpsPermissionResponse permission(WpsPermissionRequest request) {
IndexNode indexNode = indexNodeDao.findOrNull(request.getDocCode()); IndexNode indexNode = indexManager.findOrNull(request.getDocCode());
if (StringUtils.isNotBlank(indexNode.getOrCreateFileAttributes().getFileExtension()) if (Objects.nonNull(indexNode) && StringUtils.isNotBlank(indexNode.getOrCreateFileAttributes().getFileExtension())
&& indexNode.getOrCreateFileAttributes().getFileExtension().equalsIgnoreCase("pdf")) { && indexNode.getOrCreateFileAttributes().getFileExtension().equalsIgnoreCase("pdf")) {
return WpsPermissionResponse.preview(request.getPersonId()); return WpsPermissionStatusEnum.preview(request.getPersonId());
}
if (Objects.nonNull(request.getWpsPermissionStatus())) {
if (request.getWpsPermissionStatus() == WpsPermissionStatusEnum.PREVIEW) {
return WpsPermissionStatusEnum.preview(request.getPersonId());
}
} }
return WpsPermissionResponse.builder() return WpsPermissionResponse.builder()
@ -127,19 +134,54 @@ public class WpsBaseManager {
*/ */
public WpsUsersResponse users(WpsUsersRequest request) { public WpsUsersResponse users(WpsUsersRequest request) {
WpsAssertUtil.isFalse(Objects.isNull(request) || CollectionUtil.isEmpty(request.getPersonIds()), WpsErrorCodeEnum.REQUEST_PARAMETER_ERROR); WpsAssertUtil.isFalse(Objects.isNull(request) || CollectionUtil.isEmpty(request.getPersonIds()), WpsErrorCodeEnum.REQUEST_PARAMETER_ERROR);
//查询人员档案
List<PersonProfileDto> personProfiles = this.docUserProfileGateway.personProfileByPersonIds(request.getPersonIds().stream().map(Long::parseLong).collect(Collectors.toList())); List<WpsUsersResponse.WpsUser> allWpsUsers = Lists.newArrayList();
WpsAssertUtil.isFalse(CollectionUtil.isEmpty(personProfiles), WpsErrorCodeEnum.USER_NOT_EXIST); //构建默认用户信息
allWpsUsers.addAll(this.buildDefaultWpsUsers(request.getPersonIds()));
//构建正常用户信息
allWpsUsers.addAll(this.buildNormalWpsUsers(request.getPersonIds()));
return WpsUsersResponse.builder() return WpsUsersResponse.builder()
.users(personProfiles.stream() .users(allWpsUsers)
.map(item -> WpsUsersResponse.WpsUser.builder()
.personId(item.getId().toString())
.name(item.getRealName())
.avatarUrl(item.getAvatarUrl()).build()).collect(Collectors.toList()))
.build(); .build();
} }
/**
* 构建正常用户信息
*/
private List<WpsUsersResponse.WpsUser> buildNormalWpsUsers(List<String> personIds) {
List<Long> normalUserList = personIds.stream().filter(item -> !item.equalsIgnoreCase(Constants.WPS_DEFAULT_USER_ID)).map(Long::parseLong).collect(Collectors.toList());
if (CollectionUtil.isEmpty(normalUserList)) {
return Lists.newArrayList();
}
//查询人员档案
List<PersonProfileDto> personProfiles = this.docUserProfileGateway.personProfileByPersonIds(normalUserList);
WpsAssertUtil.isFalse(CollectionUtil.isEmpty(personProfiles), WpsErrorCodeEnum.USER_NOT_EXIST);
return personProfiles.stream()
.map(item -> WpsUsersResponse.WpsUser.builder()
.personId(item.getId().toString())
.name(item.getRealName())
.avatarUrl(item.getAvatarUrl()).build()).collect(Collectors.toList());
}
/**
* 构建默认用户信息
*/
private List<WpsUsersResponse.WpsUser> buildDefaultWpsUsers(List<String> personIds) {
List<Long> defaultUserList = personIds.stream().filter(item -> item.equalsIgnoreCase(Constants.WPS_DEFAULT_USER_ID)).map(Long::parseLong).collect(Collectors.toList());
if (CollectionUtil.isEmpty(defaultUserList)) {
return Lists.newArrayList();
}
return defaultUserList.stream().map(item ->
WpsUsersResponse.WpsUser.builder()
.personId(item.toString())
.name(StringUtils.EMPTY)
.avatarUrl(StringUtils.EMPTY).build()
).collect(Collectors.toList());
}
/** /**
* 文件重命名 * 文件重命名
*/ */
@ -152,13 +194,11 @@ public class WpsBaseManager {
|| StringUtils.isBlank(node.getAttributes().getFileAttributes().getOssFileKey())) { || StringUtils.isBlank(node.getAttributes().getFileAttributes().getOssFileKey())) {
return WpsRenameResponse.builder().updateFlag(false).build(); return WpsRenameResponse.builder().updateFlag(false).build();
} }
//TODO: 文件名重复 try {
//try { indexManager.rename(node.getCode(), request.getName());
// 调用IndexManager.rename(); } catch (NameUsedException e) {
//} catch (NameUsedException e) { throw new WpsException(WpsErrorCodeEnum.FILE_NAME_CONFLICT);
// // 处理文件已被使用的情况 }
//}
indexNodeDao.rename(request.getDocCode(), request.getName());
UpdateFileInfoResponse response = this.docOssGateway.updateFileInfo(UpdateFileInfoRequest.builder().fileKey(node.getAttributes().getFileAttributes().getOssFileKey()).build()); UpdateFileInfoResponse response = this.docOssGateway.updateFileInfo(UpdateFileInfoRequest.builder().fileKey(node.getAttributes().getFileAttributes().getOssFileKey()).build());
return WpsRenameResponse.builder().updateFlag(response.isUpdateFlag()).build(); return WpsRenameResponse.builder().updateFlag(response.isUpdateFlag()).build();
} }

View File

@ -62,40 +62,41 @@ public class GuideTenantProcedureStatusServiceImpl extends ServiceImpl<GuideTena
return Collections.emptyList(); return Collections.emptyList();
} }
// 将租户操作步骤数量与模板操作步骤数量进行对比如果模板操作步骤数量大于租户操作步骤数量则根据模板为租户初始化新步骤点 // 将租户操作步骤数量与模板操作步骤数量进行对比是否需要根据模板为租户初始化新步骤点
if (templateList.size() > procedureStatusList.size()) { // 将该租户未初始化的步骤点进行初始化
// 将该租户未初始化的步骤点进行初始化 List<Long> procedureStatusIdList = procedureStatusList.stream().map(GuideTenantProcedureStatus::getProcedureId).distinct().collect(Collectors.toList());
List<Long> procedureStatusIdList = procedureStatusList.stream().map(GuideTenantProcedureStatus::getProcedureId).collect(Collectors.toList()); List<GuideTenantProcedureStatusListResp> newInitProcedures = templateList.stream()
respList.addAll(templateList.stream() .filter(t -> !procedureStatusIdList.contains(t.getId()))
.filter(t -> !procedureStatusIdList.contains(t.getId())) .map(t -> {
.map(t -> { GuideTenantProcedureStatusCreateReq createReq = new GuideTenantProcedureStatusCreateReq();
GuideTenantProcedureStatusCreateReq createReq = new GuideTenantProcedureStatusCreateReq(); createReq.setWorkspaceId(req.getWorkspaceId());
createReq.setWorkspaceId(req.getWorkspaceId()); createReq.setCategoryCode(t.getCategoryCode());
createReq.setCategoryCode(t.getCategoryCode()); createReq.setProcedureId(t.getId());
createReq.setProcedureId(t.getId()); createReq.setProcedureName(t.getName());
createReq.setProcedureName(t.getName()); createReq.setStatus(GuideProcedureStatus.TODO);
createReq.setStatus(GuideProcedureStatus.TODO); create(createReq);
create(createReq); return BeanUtil.copyProperties(createReq, GuideTenantProcedureStatusListResp.class);
return BeanUtil.copyProperties(createReq, GuideTenantProcedureStatusListResp.class); })
}) .collect(Collectors.toList());
.collect(Collectors.toList())); if (CollUtil.isNotEmpty(newInitProcedures)) {
} else if (templateList.size() < procedureStatusList.size()) { respList.addAll(newInitProcedures);
log.warn("操作步骤模板:{},租户&分类:{},租户操作步骤状态:{}", JSONUtil.toJsonStr(templateList), JSONUtil.toJsonStr(req), JSONUtil.toJsonStr(procedureStatusList));
throw new ServiceException("数据异常,操作步骤不存在,请联系管理人员");
} }
// 对租户操作步骤的权限码和跳转链接进行补充 // 对租户操作步骤的权限码和跳转链接进行补充
Map<Long, GuideProcedureTemplateResp> templateMap = templateList.stream().collect(Collectors.toMap(GuideProcedureTemplateResp::getId, Function.identity(), (v1, v2) -> v1)); Map<Long, GuideProcedureTemplateResp> templateMap = templateList.stream().collect(Collectors.toMap(GuideProcedureTemplateResp::getId, Function.identity(), (v1, v2) -> v1));
respList.forEach(r -> { return respList.stream()
GuideProcedureTemplateResp t = templateMap.get(r.getProcedureId()); .collect(Collectors.toMap(r -> r.getWorkspaceId() + "_" + r.getProcedureId(), Function.identity(), (v1, v2) -> v1))
r.setDescription(t.getDescription()); .values().stream()
r.setIsMust(t.getIsMust()); .peek(r -> {
r.setAuthCode(t.getAuthCode()); GuideProcedureTemplateResp t = templateMap.get(r.getProcedureId());
r.setJumpUrl(t.getJumpUrl()); r.setDescription(t.getDescription());
r.setJumpReport(t.getJumpReport()); r.setIsMust(t.getIsMust());
r.setSort(t.getSort()); r.setAuthCode(t.getAuthCode());
}); r.setJumpUrl(t.getJumpUrl());
return respList; r.setJumpReport(t.getJumpReport());
r.setSort(t.getSort());
})
.collect(Collectors.toList());
} }
@Override @Override
@ -127,12 +128,15 @@ public class GuideTenantProcedureStatusServiceImpl extends ServiceImpl<GuideTena
log.info("步骤已完成无需重复操作workspaceId: {}, procedureId{}", req.getWorkspaceId(), req.getProcedureId()); log.info("步骤已完成无需重复操作workspaceId: {}, procedureId{}", req.getWorkspaceId(), req.getProcedureId());
return; return;
} }
tenantProcedure.setStatus(req.getStatus()); lambdaUpdate()
updateById(tenantProcedure); .eq(GuideTenantProcedureStatus::getWorkspaceId, req.getWorkspaceId())
.eq(GuideTenantProcedureStatus::getProcedureId, req.getProcedureId())
.set(GuideTenantProcedureStatus::getStatus, req.getStatus())
.update();
} }
@Override @Override
public Long create(GuideTenantProcedureStatusCreateReq req) { public synchronized Long create(GuideTenantProcedureStatusCreateReq req) {
// 若操作所属分类或操作名称为空则从对应模板获取 // 若操作所属分类或操作名称为空则从对应模板获取
if (Objects.isNull(req.getCategoryCode()) || CharSequenceUtil.isBlank(req.getProcedureName())) { if (Objects.isNull(req.getCategoryCode()) || CharSequenceUtil.isBlank(req.getProcedureName())) {
GuideProcedureTemplateResp byProcedureId = procedureTemplateService.getByProcedureId(req.getProcedureId()); GuideProcedureTemplateResp byProcedureId = procedureTemplateService.getByProcedureId(req.getProcedureId());

View File

@ -4,6 +4,7 @@ import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.framework.domain.web.result.PageData; import cn.axzo.framework.domain.web.result.PageData;
import cn.axzo.nanopart.visa.api.changerecord.ChangeRecordApi; import cn.axzo.nanopart.visa.api.changerecord.ChangeRecordApi;
import cn.axzo.nanopart.visa.api.enums.VisaConfirmBizTypeEnum;
import cn.axzo.nanopart.visa.api.enums.VisaStatusEnum; import cn.axzo.nanopart.visa.api.enums.VisaStatusEnum;
import cn.axzo.nanopart.visa.api.request.BizActivityAssigneeDecisionReq; import cn.axzo.nanopart.visa.api.request.BizActivityAssigneeDecisionReq;
import cn.axzo.nanopart.visa.api.request.ChangeRecordButtonOperationReq; import cn.axzo.nanopart.visa.api.request.ChangeRecordButtonOperationReq;
@ -30,6 +31,7 @@ import cn.axzo.nanopart.visa.server.service.ChangeRecordBillService;
import cn.axzo.nanopart.visa.server.service.ChangeRecordConfirmService; import cn.axzo.nanopart.visa.server.service.ChangeRecordConfirmService;
import cn.axzo.nanopart.visa.server.service.ChangeRecordService; import cn.axzo.nanopart.visa.server.service.ChangeRecordService;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -147,7 +149,7 @@ public class ChangeRecordController implements ChangeRecordApi {
@Override @Override
public ApiResult<List<VisaChangeApproveCreateReq.ApprovePersonInfo>> getVisaAllConfirm(FetchVisaAllConfirmReq req) { public ApiResult<List<VisaChangeApproveCreateReq.ApprovePersonInfo>> getVisaAllConfirm(FetchVisaAllConfirmReq req) {
return ApiResult.ok(changeRecordConfirmService.listAllConfirmByVisaId(req.getVisaId())); return ApiResult.ok(changeRecordConfirmService.listAllConfirmByVisaId(req.getVisaId(), Lists.newArrayList(VisaConfirmBizTypeEnum.CONFIRM)));
} }
@Override @Override

View File

@ -46,6 +46,8 @@ public class VisaConfirmDto {
*/ */
private VisaConfirmBizTypeEnum bizType; private VisaConfirmBizTypeEnum bizType;
private List<VisaConfirmBizTypeEnum> bizTypes;
/** /**
* 确认人 * 确认人
*/ */

View File

@ -1,11 +1,14 @@
package cn.axzo.nanopart.visa.server.mq.listener.workflow.process; package cn.axzo.nanopart.visa.server.mq.listener.workflow.process;
import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventConsumer;
import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.EventProducer;
import cn.axzo.msg.center.api.MessageAPIV3; import cn.axzo.msg.center.api.MessageAPIV3;
import cn.axzo.msg.center.api.request.v3.MessageSendReqV3; import cn.axzo.msg.center.api.request.v3.MessageSendReqV3;
import cn.axzo.msg.center.api.response.v3.MessageSendRespV3;
import cn.axzo.msg.center.service.dto.PersonV3DTO; import cn.axzo.msg.center.service.dto.PersonV3DTO;
import cn.axzo.nanopart.visa.api.enums.VisaConfirmBizTypeEnum;
import cn.axzo.nanopart.visa.api.enums.VisaStampStatusEnum; import cn.axzo.nanopart.visa.api.enums.VisaStampStatusEnum;
import cn.axzo.nanopart.visa.api.enums.VisaStatusEnum; import cn.axzo.nanopart.visa.api.enums.VisaStatusEnum;
import cn.axzo.nanopart.visa.api.enums.VisaTypeEnum; import cn.axzo.nanopart.visa.api.enums.VisaTypeEnum;
@ -18,14 +21,17 @@ import cn.axzo.nanopart.visa.server.mq.listener.workflow.BasicLogSupport;
import cn.axzo.nanopart.visa.server.mq.producer.VisaChangeLogPayload; import cn.axzo.nanopart.visa.server.mq.producer.VisaChangeLogPayload;
import cn.axzo.nanopart.visa.server.rpc.VisaOrganizationalNodeUserGateway; import cn.axzo.nanopart.visa.server.rpc.VisaOrganizationalNodeUserGateway;
import cn.axzo.nanopart.visa.server.service.ChangeRecordBillService; import cn.axzo.nanopart.visa.server.service.ChangeRecordBillService;
import cn.axzo.nanopart.visa.server.service.ChangeRecordConfirmService;
import cn.axzo.nanopart.visa.server.service.ChangeRecordRelationService; import cn.axzo.nanopart.visa.server.service.ChangeRecordRelationService;
import cn.axzo.nanopart.visa.server.service.ChangeRecordService; import cn.axzo.nanopart.visa.server.service.ChangeRecordService;
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO;
import cn.axzo.workflow.starter.handler.ProcessInstanceEventHandler; import cn.axzo.workflow.starter.handler.ProcessInstanceEventHandler;
import cn.azxo.framework.common.model.CommonResponse;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.groovy.util.Maps; import org.apache.groovy.util.Maps;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -35,6 +41,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors;
import static cn.axzo.nanopart.visa.api.constant.VisaConstant.FORM_FIELD_TOPIC; import static cn.axzo.nanopart.visa.api.constant.VisaConstant.FORM_FIELD_TOPIC;
import static cn.axzo.nanopart.visa.api.constant.VisaConstant.FORM_FIELD_WORKSPACE_NAME; import static cn.axzo.nanopart.visa.api.constant.VisaConstant.FORM_FIELD_WORKSPACE_NAME;
@ -54,11 +61,13 @@ import static cn.axzo.nanopart.visa.api.enums.VisaTypeEnum.TECHNOLOGY_APPROVED;
* @author wangli * @author wangli
* @since 2025-01-17 11:35 * @since 2025-01-17 11:35
*/ */
@Slf4j
@Component @Component
public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implements ProcessInstanceEventHandler { public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implements ProcessInstanceEventHandler {
protected final ChangeRecordService changeRecordService; protected final ChangeRecordService changeRecordService;
protected final ChangeRecordRelationService changeRecordRelationService; protected final ChangeRecordRelationService changeRecordRelationService;
protected final ChangeRecordBillService changeRecordBillService; protected final ChangeRecordBillService changeRecordBillService;
protected final ChangeRecordConfirmService changeRecordConfirmService;
protected final MessageAPIV3 noticeApi; protected final MessageAPIV3 noticeApi;
public final static List<String> SUPPORTED_DEFINITION_KEYS = Lists.newArrayList( public final static List<String> SUPPORTED_DEFINITION_KEYS = Lists.newArrayList(
DESIGN_CHANGE.getProcessDefinitionKey(), DESIGN_CHANGE.getProcessDefinitionKey(),
@ -72,11 +81,14 @@ public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implem
ChangeRecordService changeRecordService, ChangeRecordService changeRecordService,
ChangeRecordRelationService changeRecordRelationService, ChangeRecordRelationService changeRecordRelationService,
ChangeRecordBillService changeRecordBillService, ChangeRecordBillService changeRecordBillService,
MessageAPIV3 noticeApi, RefreshableConfiguration refreshableConfiguration) { ChangeRecordConfirmService changeRecordConfirmService,
MessageAPIV3 noticeApi,
RefreshableConfiguration refreshableConfiguration) {
super(eventProducer, visaOrganizationalNodeUserGateway); super(eventProducer, visaOrganizationalNodeUserGateway);
this.changeRecordService = changeRecordService; this.changeRecordService = changeRecordService;
this.changeRecordRelationService = changeRecordRelationService; this.changeRecordRelationService = changeRecordRelationService;
this.changeRecordBillService = changeRecordBillService; this.changeRecordBillService = changeRecordBillService;
this.changeRecordConfirmService = changeRecordConfirmService;
this.noticeApi = noticeApi; this.noticeApi = noticeApi;
this.refreshableConfiguration = refreshableConfiguration; this.refreshableConfiguration = refreshableConfiguration;
} }
@ -105,6 +117,10 @@ public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implem
public void onCompleted(ProcessInstanceDTO dto) { public void onCompleted(ProcessInstanceDTO dto) {
String visaTypeDesc = parseVisaType(dto); String visaTypeDesc = parseVisaType(dto);
log.info("send complete notice");
sendCompleteNotice(dto);
log.info("send complete notice success");
updateChangeRecordApprovalStatus(dto, BpmnProcessInstanceResultEnum.APPROVED); updateChangeRecordApprovalStatus(dto, BpmnProcessInstanceResultEnum.APPROVED);
changeRecordService.lambdaUpdate() changeRecordService.lambdaUpdate()
@ -112,15 +128,23 @@ public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implem
.set(ChangeRecord::getStampStatus, VisaStampStatusEnum.UNPRINTED.name()) .set(ChangeRecord::getStampStatus, VisaStampStatusEnum.UNPRINTED.name())
.update(); .update();
}
private void sendCompleteNotice(ProcessInstanceDTO dto) {
Map<String, Object> variables = dto.getVariables(); Map<String, Object> variables = dto.getVariables();
BpmnTaskDelegateAssigner initiator = dto.getInitiator();
MessageSendReqV3 completeNotice = new MessageSendReqV3(); MessageSendReqV3 completeNotice = new MessageSendReqV3();
completeNotice.setSender(PersonV3DTO.builder().build()); completeNotice.setSender(PersonV3DTO.builder().build());
completeNotice.setReceivers(Lists.newArrayList(PersonV3DTO.builder().build())); completeNotice.setReceivers(queryConfirm(dto));
completeNotice.setBizEventMappingCode(refreshableConfiguration.getProcessInstanceCompleteMsgEventCode()); completeNotice.setBizEventMappingCode(refreshableConfiguration.getProcessInstanceCompleteMsgEventCode());
completeNotice.setBizCode(dto.getBusinessKey()); completeNotice.setBizCode(dto.getBusinessKey());
String visaType = (String) variables.getOrDefault(WORKFLOW_VAR_VISA_TYPE_KEY, "");
String VisaTypeDesc = StringUtils.hasText(visaType) ? VisaTypeEnum.valueOf(visaType).getDesc() : "";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
completeNotice.setBizExtParams(new JSONObject(Maps.of( completeNotice.setBizExtParams(new JSONObject(Maps.of(
"initiatorName", initiator.getAssignerName(),
"topic", variables.getOrDefault(FORM_FIELD_TOPIC, ""), "topic", variables.getOrDefault(FORM_FIELD_TOPIC, ""),
"visaTypeDesc", VisaTypeDesc,
"workspaceName", variables.getOrDefault(FORM_FIELD_WORKSPACE_NAME, ""), "workspaceName", variables.getOrDefault(FORM_FIELD_WORKSPACE_NAME, ""),
"time", sdf.format(new Date()) "time", sdf.format(new Date())
))); )));
@ -129,7 +153,22 @@ public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implem
"ouId", variables.getOrDefault(IM_GROUP_BIZ_INFO_INITIATOR_OU_ID, ""), "ouId", variables.getOrDefault(IM_GROUP_BIZ_INFO_INITIATOR_OU_ID, ""),
"workspaceId", variables.getOrDefault(IM_GROUP_BIZ_INFO_INITIATOR_WORKSPACE_ID, "") "workspaceId", variables.getOrDefault(IM_GROUP_BIZ_INFO_INITIATOR_WORKSPACE_ID, "")
))); )));
noticeApi.send(completeNotice); CommonResponse<MessageSendRespV3> response = noticeApi.send(completeNotice);
if (Objects.nonNull(response) && response.getCode() == 200) {
log.info("send complete notice result: {}", JSON.toJSONString(response.getData()));
} else {
log.error("send complete notice failed: {}", Objects.isNull(response) ? "response is null" : JSON.toJSONString(response.getMsg()));
}
}
private List<PersonV3DTO> queryConfirm(ProcessInstanceDTO dto) {
Long visaId = Long.valueOf(dto.getBusinessKey());
return changeRecordConfirmService.listAllConfirmByVisaId(visaId, Lists.newArrayList(VisaConfirmBizTypeEnum.CREATE, VisaConfirmBizTypeEnum.CONFIRM))
.stream().map(e -> PersonV3DTO.builder()
.id(e.getPersonId())
.name(e.getRealName())
.imReceiveModel(new PersonV3DTO.ReceiveModel(e.getOuId(), e.getWorkspaceId()))
.build()).collect(Collectors.toList());
} }
/** /**
@ -160,6 +199,10 @@ public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implem
*/ */
@Override @Override
public void onRejected(ProcessInstanceDTO dto) { public void onRejected(ProcessInstanceDTO dto) {
log.info("send reject notice");
sendRejectNotice(dto);
log.info("send reject notice success");
BpmnTaskDelegateAssigner lastOperationAssigner = dto.getLastOperationAssigner(); BpmnTaskDelegateAssigner lastOperationAssigner = dto.getLastOperationAssigner();
ChangeRecordLog log = ChangeRecordLog.builder() ChangeRecordLog log = ChangeRecordLog.builder()
.visaId(Long.valueOf(dto.getBusinessKey())) .visaId(Long.valueOf(dto.getBusinessKey()))
@ -171,14 +214,23 @@ public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implem
updateChangeRecordApprovalStatus(dto, BpmnProcessInstanceResultEnum.REJECTED); updateChangeRecordApprovalStatus(dto, BpmnProcessInstanceResultEnum.REJECTED);
}
private void sendRejectNotice(ProcessInstanceDTO dto) {
Map<String, Object> variables = dto.getVariables(); Map<String, Object> variables = dto.getVariables();
BpmnTaskDelegateAssigner initiator = dto.getInitiator();
MessageSendReqV3 rejectNotice = new MessageSendReqV3(); MessageSendReqV3 rejectNotice = new MessageSendReqV3();
rejectNotice.setSender(PersonV3DTO.builder().build()); rejectNotice.setSender(PersonV3DTO.builder().build());
rejectNotice.setReceivers(Lists.newArrayList(PersonV3DTO.builder().build())); rejectNotice.setReceivers(queryConfirm(dto));
rejectNotice.setBizEventMappingCode(refreshableConfiguration.getProcessInstanceCompleteMsgEventCode()); rejectNotice.setBizEventMappingCode(refreshableConfiguration.getProcessInstanceRejectMsgEventCode());
rejectNotice.setBizCode(dto.getBusinessKey()); rejectNotice.setBizCode(dto.getBusinessKey());
String visaType = (String) variables.getOrDefault(WORKFLOW_VAR_VISA_TYPE_KEY, "");
String VisaTypeDesc = StringUtils.hasText(visaType) ? VisaTypeEnum.valueOf(visaType).getDesc() : "";
rejectNotice.setBizExtParams(new JSONObject(Maps.of( rejectNotice.setBizExtParams(new JSONObject(Maps.of(
"initiatorName", initiator.getAssignerName(),
"topic", variables.getOrDefault(FORM_FIELD_TOPIC, ""), "topic", variables.getOrDefault(FORM_FIELD_TOPIC, ""),
"visaTypeDesc", VisaTypeDesc,
"workspaceName", variables.getOrDefault(FORM_FIELD_WORKSPACE_NAME, ""), "workspaceName", variables.getOrDefault(FORM_FIELD_WORKSPACE_NAME, ""),
"reason", dto.getReason() "reason", dto.getReason()
))); )));
@ -187,7 +239,13 @@ public class ProcessInstanceOfVisaAllEventHandler extends BasicLogSupport implem
"ouId", variables.getOrDefault(IM_GROUP_BIZ_INFO_INITIATOR_OU_ID, ""), "ouId", variables.getOrDefault(IM_GROUP_BIZ_INFO_INITIATOR_OU_ID, ""),
"workspaceId", variables.getOrDefault(IM_GROUP_BIZ_INFO_INITIATOR_WORKSPACE_ID, "") "workspaceId", variables.getOrDefault(IM_GROUP_BIZ_INFO_INITIATOR_WORKSPACE_ID, "")
))); )));
noticeApi.send(rejectNotice);
CommonResponse<MessageSendRespV3> response = noticeApi.send(rejectNotice);
if (Objects.nonNull(response) && response.getCode() == 200) {
log.info("send reject notice result: {}", JSON.toJSONString(response.getData()));
} else {
log.error("send reject notice failed: {}", Objects.isNull(response) ? "response is null" : JSON.toJSONString(response.getMsg()));
}
} }
@Override @Override

View File

@ -76,7 +76,7 @@ public interface ChangeRecordConfirmService {
* @param visaId * @param visaId
* @return * @return
*/ */
List<VisaChangeApproveCreateReq.ApprovePersonInfo> listAllConfirmByVisaId(Long visaId); List<VisaChangeApproveCreateReq.ApprovePersonInfo> listAllConfirmByVisaId(Long visaId, List<VisaConfirmBizTypeEnum> bizTypes);
/** /**
* 构建公司的MaporgIdAndNameMap,key:ouId,value:ouName * 构建公司的MaporgIdAndNameMap,key:ouId,value:ouName

View File

@ -418,6 +418,7 @@ public class ChangeRecordConfirmServiceImpl extends ServiceImpl<ChangeRecordConf
.in(CollectionUtils.isNotEmpty(dto.getProjectIds()), ChangeRecordConfirm::getProjectId, dto.getProjectIds()) .in(CollectionUtils.isNotEmpty(dto.getProjectIds()), ChangeRecordConfirm::getProjectId, dto.getProjectIds())
.eq(Objects.nonNull(dto.getType()), ChangeRecordConfirm::getType, dto.getType()) .eq(Objects.nonNull(dto.getType()), ChangeRecordConfirm::getType, dto.getType())
.eq(Objects.nonNull(dto.getBizType()), ChangeRecordConfirm::getBizType, dto.getBizType()) .eq(Objects.nonNull(dto.getBizType()), ChangeRecordConfirm::getBizType, dto.getBizType())
.in(CollectionUtils.isNotEmpty(dto.getBizTypes()), ChangeRecordConfirm::getBizType, dto.getBizTypes())
.in(CollectionUtils.isNotEmpty(dto.getVisaTypes()), ChangeRecordConfirm::getVisaType, dto.getVisaTypes()) .in(CollectionUtils.isNotEmpty(dto.getVisaTypes()), ChangeRecordConfirm::getVisaType, dto.getVisaTypes())
.eq(ChangeRecordConfirm::getIsDelete, 0); .eq(ChangeRecordConfirm::getIsDelete, 0);
} }
@ -450,10 +451,10 @@ public class ChangeRecordConfirmServiceImpl extends ServiceImpl<ChangeRecordConf
} }
@Override @Override
public List<VisaChangeApproveCreateReq.ApprovePersonInfo> listAllConfirmByVisaId(Long visaId) { public List<VisaChangeApproveCreateReq.ApprovePersonInfo> listAllConfirmByVisaId(Long visaId, List<VisaConfirmBizTypeEnum> bizTypes) {
VisaConfirmDto dto = VisaConfirmDto.builder() VisaConfirmDto dto = VisaConfirmDto.builder()
.visaId(visaId) .visaId(visaId)
.bizType(VisaConfirmBizTypeEnum.CONFIRM).build(); .bizTypes(bizTypes).build();
List<ChangeRecordConfirm> list = this.findByCondition(dto); List<ChangeRecordConfirm> list = this.findByCondition(dto);
if (CollectionUtils.isEmpty(list)) { if (CollectionUtils.isEmpty(list)) {
return Lists.newArrayList(); return Lists.newArrayList();