Compare commits
20 Commits
d12c76fe03
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| fa11b388db | |||
| b6eb7980e4 | |||
| 3410c540ab | |||
| 040a46934d | |||
| 7eb409f6d0 | |||
| 7b3d4e2a65 | |||
| 4e113e8fae | |||
| 7a34a481aa | |||
| a402ea86ef | |||
| 3eaa560aec | |||
| e61da7d8f9 | |||
| 355b192071 | |||
| c732f7cead | |||
| 812e33693b | |||
| a7b490240c | |||
| 959fc30758 | |||
| fe86a84204 | |||
| 42bcfcf70e | |||
| d82c5200e7 | |||
| 658765df6f |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,8 +1,10 @@
|
|||||||
/config
|
/config
|
||||||
/data
|
/data
|
||||||
|
/docs
|
||||||
/logs
|
/logs
|
||||||
/target
|
/target
|
||||||
/temp
|
/temp
|
||||||
|
CLAUDE.md
|
||||||
|
|
||||||
multilingualField/
|
multilingualField/
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|||||||
16
pom.xml
16
pom.xml
@ -39,6 +39,20 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<native.classifier>windows-x86_64</native.classifier>
|
<native.classifier>windows-x86_64</native.classifier>
|
||||||
</properties>
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>ffmpeg</artifactId>
|
||||||
|
<version>7.1.1-1.5.12</version>
|
||||||
|
<classifier>${native.classifier}</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bytedeco</groupId>
|
||||||
|
<artifactId>opencv</artifactId>
|
||||||
|
<version>4.11.0-1.5.12</version>
|
||||||
|
<classifier>${native.classifier}</classifier>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
</profile>
|
</profile>
|
||||||
<profile>
|
<profile>
|
||||||
<id>prod-linux</id>
|
<id>prod-linux</id>
|
||||||
@ -227,8 +241,6 @@
|
|||||||
<groupId>org.bytedeco</groupId>
|
<groupId>org.bytedeco</groupId>
|
||||||
<artifactId>ffmpeg</artifactId>
|
<artifactId>ffmpeg</artifactId>
|
||||||
<version>7.1.1-1.5.12</version>
|
<version>7.1.1-1.5.12</version>
|
||||||
<scope>provided</scope>
|
|
||||||
<classifier>windows-x86_64</classifier>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bytedeco</groupId>
|
<groupId>org.bytedeco</groupId>
|
||||||
|
|||||||
29
src/main/java/com/imyeyu/api/bean/PreviewPage.java
Normal file
29
src/main/java/com/imyeyu/api/bean/PreviewPage.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package com.imyeyu.api.bean;
|
||||||
|
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 23:07
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class PreviewPage<T> extends Page<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 23:09
|
||||||
|
*/
|
||||||
|
public enum Type {
|
||||||
|
|
||||||
|
NORMAL,
|
||||||
|
|
||||||
|
PREVIEW
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Type type;
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@ public interface ArticleMapper extends BaseMapper<Article, Long> {
|
|||||||
long countByPage(Page page);
|
long countByPage(Page page);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
List<Article> listByPage(Page page);
|
List<Article> selectByPage(Page page);
|
||||||
|
|
||||||
long countByKeyword(String keyword);
|
long countByKeyword(String keyword);
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,7 @@ public class ArticleServiceImplement extends AbstractEntityService<Article, Long
|
|||||||
@Override
|
@Override
|
||||||
public PageResult<Article> page(Page page) {
|
public PageResult<Article> page(Page page) {
|
||||||
PageResult<Article> result = new PageResult<>();
|
PageResult<Article> result = new PageResult<>();
|
||||||
result.setList(mapper.listByPage(page));
|
result.setList(mapper.selectByPage(page));
|
||||||
result.setTotal(mapper.countByPage(page));
|
result.setTotal(mapper.countByPage(page));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
package com.imyeyu.api.modules.common.bean;
|
package com.imyeyu.api.modules.common.bean;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2025-10-20 15:04
|
* @since 2025-10-20 15:04
|
||||||
@ -18,22 +16,4 @@ public class MediaAttach {
|
|||||||
|
|
||||||
THUMB
|
THUMB
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-10-20 15:04
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class ExtData {
|
|
||||||
|
|
||||||
private Long sourceId;
|
|
||||||
|
|
||||||
private String sourceMongoId;
|
|
||||||
|
|
||||||
private boolean isImage;
|
|
||||||
|
|
||||||
private boolean isVideo;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.api.modules.common.bean;
|
package com.imyeyu.api.modules.common.bean;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
@ -9,7 +10,7 @@ import lombok.Data;
|
|||||||
public class Metadata {
|
public class Metadata {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 图片
|
||||||
*
|
*
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2025-12-11 18:15
|
* @since 2025-12-11 18:15
|
||||||
@ -21,4 +22,21 @@ public class Metadata {
|
|||||||
|
|
||||||
private int height;
|
private int height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缩略图
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-01-04 18:10
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public static class ThumbImage extends Image {
|
||||||
|
|
||||||
|
private long sourceId;
|
||||||
|
|
||||||
|
private String sourceMongoId;
|
||||||
|
|
||||||
|
private String sourceMimeType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -131,7 +131,7 @@ public enum SettingKey {
|
|||||||
|
|
||||||
MUSIC_CONTROLLER_URI,
|
MUSIC_CONTROLLER_URI,
|
||||||
|
|
||||||
// ---------- ----------
|
// ---------- 日记 ----------
|
||||||
|
|
||||||
JOURNAL_KEY,
|
JOURNAL_KEY,
|
||||||
|
|
||||||
@ -139,7 +139,22 @@ public enum SettingKey {
|
|||||||
|
|
||||||
JOURNAL_APP_SECRET,
|
JOURNAL_APP_SECRET,
|
||||||
|
|
||||||
JOURNAL_TRAVEL,
|
// ---------- 临时文件 ----------
|
||||||
|
|
||||||
|
/** 临时文件最小缓存时间 */
|
||||||
|
TEMP_FILE_TTL_MIN,
|
||||||
|
|
||||||
|
/** 临时文件最长缓存时间 */
|
||||||
|
TEMP_FILE_TTL_MAX,
|
||||||
|
|
||||||
|
/** 临时文件默认缓存时间 */
|
||||||
|
TEMP_FILE_TTL_DEFAULT,
|
||||||
|
|
||||||
|
/** 已过期的临时文件保留时间 */
|
||||||
|
TEMP_FILE_RESIDUE_TIME,
|
||||||
|
|
||||||
|
/** 每个 IP 限制有效临时文件容量 */
|
||||||
|
TEMP_FILE_LIMIT,
|
||||||
|
|
||||||
// ---------- 系统 ----------
|
// ---------- 系统 ----------
|
||||||
|
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
package com.imyeyu.api.modules.common.bean;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-09-27 01:47
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class TempFileMetaData {
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private String originalName;
|
|
||||||
|
|
||||||
private Path path;
|
|
||||||
|
|
||||||
private Long lastAccessAt;
|
|
||||||
}
|
|
||||||
@ -19,7 +19,6 @@ import com.imyeyu.api.modules.common.service.TemplateService;
|
|||||||
import com.imyeyu.api.modules.common.service.VersionService;
|
import com.imyeyu.api.modules.common.service.VersionService;
|
||||||
import com.imyeyu.api.modules.common.vo.FeedbackRequest;
|
import com.imyeyu.api.modules.common.vo.FeedbackRequest;
|
||||||
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
|
||||||
import com.imyeyu.api.modules.system.util.ResourceHandler;
|
import com.imyeyu.api.modules.system.util.ResourceHandler;
|
||||||
import com.imyeyu.api.util.CaptchaManager;
|
import com.imyeyu.api.util.CaptchaManager;
|
||||||
import com.imyeyu.io.IO;
|
import com.imyeyu.io.IO;
|
||||||
@ -63,12 +62,8 @@ import java.awt.Graphics2D;
|
|||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -263,8 +258,8 @@ public class CommonController {
|
|||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@GetMapping("/attachment/{mongoId}")
|
@GetMapping("/attachment/{mongoId}")
|
||||||
public AttachmentView getAttachment(@PathVariable String mongoId) {
|
public Attachment getAttachment(@PathVariable String mongoId) {
|
||||||
return attachmentService.viewByMongoId(mongoId);
|
return attachmentService.getByMongoId(mongoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@ -379,41 +374,41 @@ public class CommonController {
|
|||||||
/**
|
/**
|
||||||
* 上传临时文件
|
* 上传临时文件
|
||||||
*
|
*
|
||||||
* @param files
|
* @param files 文件列表
|
||||||
* @return
|
* @param ttl 缓存时长(毫秒),最长 3 天(259200000ms)
|
||||||
|
* @return 临时文件响应列表
|
||||||
*/
|
*/
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@PostMapping("/temp/file/upload")
|
@PostMapping("/temp/file/upload")
|
||||||
public List<TempFileResponse> uploadFile(@RequestParam("file") List<MultipartFile> files) {
|
public List<TempFileResponse> tempFileUpload(@RequestParam("file") List<MultipartFile> files, @RequestParam(value = "ttl", required = false) Long ttl) {
|
||||||
return tempFileService.store(files);
|
return tempFileService.store(files, ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取临时文件
|
* 读取临时文件
|
||||||
*
|
*
|
||||||
* @param fileId
|
* @param mongoId mongoId
|
||||||
* @param req
|
* @param req 请求
|
||||||
* @param resp
|
* @param resp 返回
|
||||||
*/
|
*/
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@IgnoreGlobalReturn
|
@IgnoreGlobalReturn
|
||||||
@GetMapping("/temp/file/read/{fileId}")
|
@GetMapping("/temp/file/read/{mongoId}")
|
||||||
public void tempFileRead(@PathVariable String fileId, HttpServletRequest req, HttpServletResponse resp) {
|
public void tempFileRead(@PathVariable String mongoId, HttpServletRequest req, HttpServletResponse resp) {
|
||||||
try {
|
try {
|
||||||
File file = tempFileService.get(fileId);
|
Attachment attach = attachmentService.getByMongoId(mongoId);
|
||||||
if (TimiJava.isEmpty(file) && file.exists()) {
|
if (TimiJava.isEmpty(attach)) {
|
||||||
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Path filePath = file.toPath();
|
GridFSFile file = attachmentService.readByMongoId(attach.getMongoId());
|
||||||
resp.setContentLengthLong(Files.size(filePath));
|
GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(file.getObjectId());
|
||||||
String mimeType = new Tika().detect(filePath);
|
GridFsResource gridFsResource = new GridFsResource(file, downloadStream);
|
||||||
if (TimiJava.isNotEmpty(mimeType)) {
|
req.setAttribute(ResourceHandler.ATTR_TYPE, ResourceHandler.Type.MONGO);
|
||||||
resp.setContentType(mimeType);
|
req.setAttribute(ResourceHandler.ATTR_VALUE, gridFsResource);
|
||||||
}
|
|
||||||
req.setAttribute(ResourceHandler.ATTR_TYPE, ResourceHandler.Type.FILE);
|
resp.setContentType(attach.getMimeType());
|
||||||
req.setAttribute(ResourceHandler.ATTR_VALUE, filePath);
|
|
||||||
resourceHandler.handleRequest(req, resp);
|
resourceHandler.handleRequest(req, resp);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
@ -423,40 +418,40 @@ public class CommonController {
|
|||||||
/**
|
/**
|
||||||
* 下载临时文件
|
* 下载临时文件
|
||||||
*
|
*
|
||||||
* @param fileId
|
* @param mongoId
|
||||||
* @param resp
|
* @param resp
|
||||||
*/
|
*/
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@IgnoreGlobalReturn
|
@IgnoreGlobalReturn
|
||||||
@RequestMapping("/temp/file/download/{fileId}")
|
@RequestMapping("/temp/file/download/{mongoId}")
|
||||||
public void tempFileDownload(@PathVariable String fileId, HttpServletResponse resp) {
|
public void tempFileDownload(@PathVariable String mongoId, HttpServletResponse resp) {
|
||||||
try {
|
try {
|
||||||
File file = tempFileService.get(fileId);
|
Attachment attach = attachmentService.getByMongoId(mongoId);
|
||||||
if (TimiJava.isEmpty(file) && file.exists()) {
|
if (TimiJava.isEmpty(attach)) {
|
||||||
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String mimeType = new Tika().detect(file);
|
resp.setContentType(attach.getMimeType());
|
||||||
resp.setContentType(mimeType);
|
resp.setHeader("Content-Disposition", Network.getFileDownloadHeader(attach.getName()));
|
||||||
resp.setHeader("Content-Disposition", Network.getFileDownloadHeader(file.getName()));
|
|
||||||
resp.setHeader("Accept-Ranges", "bytes");
|
resp.setHeader("Accept-Ranges", "bytes");
|
||||||
|
|
||||||
RequestRange range = TimiSpring.requestRange(file.length());
|
GridFSFile file = attachmentService.readByMongoId(mongoId);
|
||||||
|
@Cleanup
|
||||||
|
GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(file.getObjectId());
|
||||||
|
RequestRange range = TimiSpring.requestRange(attach.getSize());
|
||||||
if (range == null) {
|
if (range == null) {
|
||||||
// 完整文件
|
// 完整文件
|
||||||
resp.setContentLengthLong(file.length());
|
resp.setContentLengthLong(attach.getSize());
|
||||||
resp.setStatus(HttpServletResponse.SC_OK);
|
resp.setStatus(HttpServletResponse.SC_OK);
|
||||||
IO.toOutputStream(resp.getOutputStream(), file);
|
IO.toOutputStream(downloadStream, resp.getOutputStream());
|
||||||
} else {
|
} else {
|
||||||
// 分片文件
|
// 分片文件
|
||||||
resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
|
resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
|
||||||
resp.setHeader("Content-Range", "bytes %s-%s/%s".formatted(range.getStart(), range.getEnd(), file.length()));
|
resp.setHeader("Content-Range", "bytes %s-%s/%s".formatted(range.getStart(), range.getEnd(), attach.getSize()));
|
||||||
resp.setContentLengthLong(range.getLength());
|
resp.setContentLengthLong(range.getLength());
|
||||||
|
IO.toOutputStream(downloadStream, resp.getOutputStream(), range.getStart(), range.getEnd());
|
||||||
@Cleanup RandomAccessFile raf = new RandomAccessFile(file, "r");
|
resp.flushBuffer();
|
||||||
raf.seek(range.getStart());
|
|
||||||
IO.toOutputStream(resp.getOutputStream(), raf, range.getStart(), range.getLength());
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("download error", e);
|
log.error("download error", e);
|
||||||
|
|||||||
@ -1,14 +1,19 @@
|
|||||||
package com.imyeyu.api.modules.common.entity;
|
package com.imyeyu.api.modules.common.entity;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.imyeyu.api.TimiServerAPI;
|
||||||
import com.imyeyu.api.bean.MultilingualHandler;
|
import com.imyeyu.api.bean.MultilingualHandler;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.java.ref.Ref;
|
import com.imyeyu.java.ref.Ref;
|
||||||
|
import com.imyeyu.spring.annotation.table.Transient;
|
||||||
import com.imyeyu.spring.entity.Entity;
|
import com.imyeyu.spring.entity.Entity;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2023-08-15 10:17
|
* @since 2023-08-15 10:17
|
||||||
@ -45,14 +50,20 @@ public class Attachment extends Entity implements MultilingualHandler {
|
|||||||
/** 镜像 */
|
/** 镜像 */
|
||||||
MIRROR,
|
MIRROR,
|
||||||
|
|
||||||
|
/** 日记 */
|
||||||
JOURNAL,
|
JOURNAL,
|
||||||
|
|
||||||
|
/** 日记出行 */
|
||||||
JOURNAL_TRAVEL,
|
JOURNAL_TRAVEL,
|
||||||
|
|
||||||
|
/** 日记瞬间 */
|
||||||
JOURNAL_MOMENT,
|
JOURNAL_MOMENT,
|
||||||
|
|
||||||
/** 系统 */
|
/** 系统 */
|
||||||
SYSTEM
|
SYSTEM,
|
||||||
|
|
||||||
|
/** 临时文件 */
|
||||||
|
TEMP_FILE
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BizType bizType;
|
protected BizType bizType;
|
||||||
@ -76,10 +87,20 @@ public class Attachment extends Entity implements MultilingualHandler {
|
|||||||
|
|
||||||
protected String md5;
|
protected String md5;
|
||||||
|
|
||||||
protected String ext;
|
protected String uploaderIp;
|
||||||
|
|
||||||
|
protected Boolean isDestroyed;
|
||||||
|
|
||||||
protected Long destroyAt;
|
protected Long destroyAt;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
protected InputStream inputStream;
|
||||||
|
|
||||||
|
public InputStream openInputStream() {
|
||||||
|
AttachmentService service = TimiServerAPI.applicationContext.getBean(AttachmentService.class);
|
||||||
|
return service.getInputStreamByMongoId(mongoId);
|
||||||
|
}
|
||||||
|
|
||||||
public void setAttachTypeValue(Enum<?> attachType) {
|
public void setAttachTypeValue(Enum<?> attachType) {
|
||||||
this.attachType = attachType.toString();
|
this.attachType = attachType.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.imyeyu.api.modules.common.mapper;
|
|||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import com.imyeyu.spring.mapper.RawMapper;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -11,10 +12,10 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2023-08-15 10:22
|
* @since 2023-08-15 10:22
|
||||||
*/
|
*/
|
||||||
public interface AttachmentMapper extends BaseMapper<Attachment, Long> {
|
public interface AttachmentMapper extends BaseMapper<Attachment, Long>, RawMapper<Attachment, Long> {
|
||||||
|
|
||||||
/** 有效条件,非删除和销毁 */
|
/** 有效条件,非删除和销毁 */
|
||||||
String VALID = NOT_DELETE + " AND destroy_at IS NULL";
|
String VALID = NOT_DELETE + " AND (`destroy_at` IS NULL OR " + UNIX_TIME + " < `destroy_at`)";
|
||||||
|
|
||||||
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} " + VALID + LIMIT_1)
|
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} " + VALID + LIMIT_1)
|
||||||
Attachment selectByBizId(Attachment.BizType bizType, long bizId);
|
Attachment selectByBizId(Attachment.BizType bizType, long bizId);
|
||||||
@ -25,9 +26,12 @@ public interface AttachmentMapper extends BaseMapper<Attachment, Long> {
|
|||||||
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND attach_type = #{attachType} " + VALID + LIMIT_1)
|
@Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND attach_type = #{attachType} " + VALID + LIMIT_1)
|
||||||
Attachment selectByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
Attachment selectByAttachType(Attachment.BizType bizType, long bizId, Enum<?> attachType);
|
||||||
|
|
||||||
List<Attachment> listByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes, Page page);
|
List<Attachment> listByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes, Page<Attachment> page);
|
||||||
|
|
||||||
long countByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes);
|
long countByBizId(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes);
|
||||||
|
|
||||||
List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes, List<String> md5s);
|
List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypes, List<String> md5s);
|
||||||
|
|
||||||
|
@Select("SELECT * FROM attachment WHERE `is_destroyed` = FALSE AND `destroy_at` < " + UNIX_TIME)
|
||||||
|
List<Attachment> selectNeedDestroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public interface CommentMapper extends BaseMapper<Comment, Long> {
|
|||||||
long countByPage(Page page);
|
long countByPage(Page page);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
List<Comment> listByPage(Page page);
|
List<Comment> selectByPage(Page page);
|
||||||
|
|
||||||
@Select("SELECT * FROM comment WHERE id = #{id}" + NOT_DELETE)
|
@Select("SELECT * FROM comment WHERE id = #{id}" + NOT_DELETE)
|
||||||
Comment select(Long id);
|
Comment select(Long id);
|
||||||
|
|||||||
@ -1,14 +1,8 @@
|
|||||||
package com.imyeyu.api.modules.common.service;
|
package com.imyeyu.api.modules.common.service;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.service.DeletableService;
|
import com.imyeyu.spring.service.BaseService;
|
||||||
import com.imyeyu.spring.service.DestroyableService;
|
|
||||||
import com.imyeyu.spring.service.GettableService;
|
|
||||||
import com.imyeyu.spring.service.PageableService;
|
|
||||||
import com.imyeyu.spring.service.UpdatableService;
|
|
||||||
import com.mongodb.client.gridfs.model.GridFSFile;
|
import com.mongodb.client.gridfs.model.GridFSFile;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -22,22 +16,9 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2023-08-15 10:21
|
* @since 2023-08-15 10:21
|
||||||
*/
|
*/
|
||||||
public interface AttachmentService extends GettableService<Attachment, Long>, PageableService<Attachment>, UpdatableService<Attachment>, DeletableService<Long>, DestroyableService<Long> {
|
public interface AttachmentService extends BaseService<Attachment, Long> {
|
||||||
|
|
||||||
/**
|
Attachment createMedia(Attachment attachment);
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
*/
|
|
||||||
void create(AttachmentRequest request);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建媒体附件,同步创建缩略图
|
|
||||||
*
|
|
||||||
* @param request 附件请求
|
|
||||||
* @return 缩略图附件
|
|
||||||
*/
|
|
||||||
Attachment createMedia(AttachmentRequest request) throws TimiException;
|
|
||||||
|
|
||||||
void deleteMedia(Long thumbId) throws TimiException;
|
void deleteMedia(Long thumbId) throws TimiException;
|
||||||
|
|
||||||
@ -47,8 +28,6 @@ public interface AttachmentService extends GettableService<Attachment, Long>, Pa
|
|||||||
|
|
||||||
Attachment getByMongoId(String mongoId);
|
Attachment getByMongoId(String mongoId);
|
||||||
|
|
||||||
AttachmentView viewByMongoId(String mongoId);
|
|
||||||
|
|
||||||
GridFSFile readByMongoId(String mongoId);
|
GridFSFile readByMongoId(String mongoId);
|
||||||
|
|
||||||
InputStream getInputStreamByMongoId(String mongoId);
|
InputStream getInputStreamByMongoId(String mongoId);
|
||||||
@ -77,7 +56,9 @@ public interface AttachmentService extends GettableService<Attachment, Long>, Pa
|
|||||||
*/
|
*/
|
||||||
long countByBizId(Attachment.BizType bizType, Long bizId, Enum<?> ...attachTypes);
|
long countByBizId(Attachment.BizType bizType, Long bizId, Enum<?> ...attachTypes);
|
||||||
|
|
||||||
List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, List<String> md5s) throws TimiException;
|
List<Attachment> listByMd5s(Attachment.BizType bizType, Long bizId, List<Enum<?>> attachTypeList, List<String> md5s);
|
||||||
|
|
||||||
void deleteByBizId(Attachment.BizType bizType, long bizId, Enum<?> ...attachTypes);
|
void deleteByBizId(Attachment.BizType bizType, long bizId, Enum<?> ...attachTypes);
|
||||||
|
|
||||||
|
List<Attachment> listNeedDestroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
package com.imyeyu.api.modules.common.service;
|
package com.imyeyu.api.modules.common.service;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.common.bean.TempFileMetaData;
|
|
||||||
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,9 +11,5 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface TempFileService {
|
public interface TempFileService {
|
||||||
|
|
||||||
List<TempFileResponse> store(List<MultipartFile> files) throws TimiException;
|
List<TempFileResponse> store(List<MultipartFile> files, Long ttl);
|
||||||
|
|
||||||
File get(String id) throws TimiException;
|
|
||||||
|
|
||||||
TempFileMetaData metadata(String id) throws TimiException;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.api.modules.common.service.implement;
|
package com.imyeyu.api.modules.common.service.implement;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
import com.imyeyu.api.modules.common.bean.Metadata;
|
import com.imyeyu.api.modules.common.bean.Metadata;
|
||||||
@ -8,14 +9,13 @@ import com.imyeyu.api.modules.common.entity.Attachment;
|
|||||||
import com.imyeyu.api.modules.common.mapper.AttachmentMapper;
|
import com.imyeyu.api.modules.common.mapper.AttachmentMapper;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentView;
|
|
||||||
import com.imyeyu.api.util.JavaCV;
|
import com.imyeyu.api.util.JavaCV;
|
||||||
import com.imyeyu.io.IO;
|
import com.imyeyu.io.IO;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.network.Network;
|
import com.imyeyu.network.Network;
|
||||||
|
import com.imyeyu.spring.TimiSpring;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
@ -25,7 +25,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.coobird.thumbnailator.Thumbnails;
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
import org.apache.tika.Tika;
|
import org.apache.tika.Tika;
|
||||||
import org.springframework.beans.BeanUtils;
|
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
|
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
|
||||||
@ -67,52 +66,36 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
public void destroy(Long id) {
|
public void create(Attachment attachment) {
|
||||||
try {
|
TimiException.required(attachment.getBizType(), "not found attachment.bizType");
|
||||||
Attachment attachment = get(id);
|
TimiException.required(attachment.getName(), "not found attachment.name");
|
||||||
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(attachment.getMongoId())));
|
|
||||||
|
|
||||||
attachment.setDeletedAt(Time.now());
|
|
||||||
attachment.setDestroyAt(Time.now());
|
|
||||||
mapper.update(attachment);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("delete mongo file error", e);
|
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO delete mongo file error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
|
||||||
@Override
|
|
||||||
public void create(AttachmentRequest request) {
|
|
||||||
TimiException.required(request.getBizType(), "not found request.bizType");
|
|
||||||
TimiException.required(request.getBizId(), "not found request.bizId");
|
|
||||||
TimiException.required(request.getName(), "not found request.name");
|
|
||||||
String mongoId = null;
|
String mongoId = null;
|
||||||
try {
|
try {
|
||||||
InputStream is = request.getInputStream();
|
InputStream is = attachment.getInputStream();
|
||||||
TimiException.required(is, "not found request.inputStream");
|
TimiException.required(is, "not found attachment.inputStream");
|
||||||
TimiException.requiredTrue(is.available() != 0, "empty request.inputStream");
|
|
||||||
|
|
||||||
StringBuilder mongoName = new StringBuilder(request.getBizType().toString());
|
StringBuilder mongoName = new StringBuilder(attachment.getBizType().toString());
|
||||||
if (TimiJava.isNotEmpty(request.getAttachType())) {
|
if (TimiJava.isNotEmpty(attachment.getAttachType())) {
|
||||||
mongoName.append("_").append(request.getAttachType().toUpperCase()).append("_");
|
mongoName.append("_").append(attachment.getAttachType().toUpperCase()).append("_");
|
||||||
}
|
}
|
||||||
mongoName.append(request.getName());
|
mongoName.append(attachment.getName());
|
||||||
|
|
||||||
mongoId = gridFsTemplate.store(request.getInputStream(), mongoName.toString()).toString();
|
mongoId = gridFsTemplate.store(attachment.getInputStream(), mongoName.toString()).toString();
|
||||||
GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(mongoId)));
|
GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(mongoId)));
|
||||||
request.setMongoId(mongoId);
|
attachment.setMongoId(mongoId);
|
||||||
request.setSize(gridFSFile.getLength());
|
attachment.setSize(gridFSFile.getLength());
|
||||||
request.setMd5(IO.md5(gridFSBucket.openDownloadStream(gridFSFile.getObjectId())));
|
attachment.setMd5(IO.md5(gridFSBucket.openDownloadStream(gridFSFile.getObjectId())));
|
||||||
request.setMimeType(new Tika().detect(gridFSBucket.openDownloadStream(gridFSFile.getObjectId())));
|
attachment.setMimeType(new Tika().detect(gridFSBucket.openDownloadStream(gridFSFile.getObjectId())));
|
||||||
if (request.getMimeType().startsWith("image")) {
|
attachment.setUploaderIp(TimiSpring.getRequestIP());
|
||||||
|
attachment.setIsDestroyed(false);
|
||||||
|
if (attachment.getMimeType().startsWith("image")) {
|
||||||
BufferedImage image = ImageIO.read(gridFSBucket.openDownloadStream(gridFSFile.getObjectId()));
|
BufferedImage image = ImageIO.read(gridFSBucket.openDownloadStream(gridFSFile.getObjectId()));
|
||||||
Metadata.Image metadata = new Metadata.Image();
|
attachment.setMetadata(TimiJava.defaultIfNull(attachment.getMetadata(), new JsonObject()));
|
||||||
metadata.setWidth(image.getWidth());
|
JsonObject metadata = attachment.getMetadata();
|
||||||
metadata.setHeight(image.getHeight());
|
metadata.addProperty("width", image.getWidth());
|
||||||
request.setMetadata(gson.toJsonTree(metadata).getAsJsonObject());
|
metadata.addProperty("height", image.getHeight());
|
||||||
}
|
}
|
||||||
mapper.insert(request);
|
mapper.insert(attachment);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (mongoId != null) {
|
if (mongoId != null) {
|
||||||
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(mongoId)));
|
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(mongoId)));
|
||||||
@ -124,53 +107,66 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
public Attachment createMedia(AttachmentRequest request) throws TimiException {
|
public void destroy(Long id) {
|
||||||
TimiException.required(request.getName(), "not found name");
|
try {
|
||||||
TimiException.required(request.getBizType(), "not found bizType");
|
Attachment attach = mapper.selectRaw(id);
|
||||||
TimiException.required(request.getInputStream(), "not found inputStream");
|
GridFSFile file = readByMongoId(attach.getMongoId());
|
||||||
|
if (file != null) {
|
||||||
|
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(attach.getMongoId())));
|
||||||
|
}
|
||||||
|
if (!attach.isDeleted()) {
|
||||||
|
attach.setDeletedAt(Time.now());
|
||||||
|
}
|
||||||
|
attach.setIsDestroyed(true);
|
||||||
|
attach.setDestroyAt(Time.now());
|
||||||
|
mapper.update(attach);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("delete mongo file error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO delete mongo file error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public Attachment createMedia(Attachment attachment) throws TimiException {
|
||||||
try {
|
try {
|
||||||
// 储存源文件
|
// 储存源文件
|
||||||
request.setAttachTypeValue(MediaAttach.Type.SOURCE);
|
attachment.setAttachTypeValue(MediaAttach.Type.SOURCE);
|
||||||
create(request);
|
create(attachment);
|
||||||
|
|
||||||
// 生成缩略图
|
// 生成缩略图
|
||||||
InputStream mimeStream = getInputStreamByMongoId(request.getMongoId());
|
InputStream mimeStream = attachment.openInputStream();
|
||||||
String mimeType = new Tika().detect(mimeStream);
|
String mimeType = new Tika().detect(mimeStream);
|
||||||
boolean isImage = false;
|
|
||||||
|
|
||||||
InputStream sourceStream = getInputStreamByMongoId(request.getMongoId());
|
InputStream sourceStream = attachment.openInputStream();
|
||||||
ByteArrayOutputStream thumbStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream thumbStream = new ByteArrayOutputStream();
|
||||||
switch (mimeType) {
|
switch (mimeType) {
|
||||||
case "image/png", "image/bmp", "image/jpeg" -> {
|
case "image/png", "image/bmp", "image/jpeg" -> Thumbnails.of(sourceStream).width(256).keepAspectRatio(true).toOutputStream(thumbStream);
|
||||||
isImage = true;
|
|
||||||
Thumbnails.of(sourceStream).width(256).keepAspectRatio(true).toOutputStream(thumbStream);
|
|
||||||
}
|
|
||||||
case "video/mp4", "video/quicktime" -> {
|
case "video/mp4", "video/quicktime" -> {
|
||||||
log.info("capturing thumbnail: {}", request.getName());
|
log.info("capturing thumbnail: {}", attachment.getName());
|
||||||
long start = Time.now();
|
long start = Time.now();
|
||||||
File tempFile = IO.file("temp/%s_%s".formatted(UUID.randomUUID().toString(), request.getName()));
|
File tempFile = IO.file("temp/%s_%s".formatted(UUID.randomUUID().toString(), attachment.getName()));
|
||||||
try {
|
try {
|
||||||
IO.toFile(tempFile, sourceStream);
|
IO.toFile(tempFile, sourceStream);
|
||||||
ByteArrayOutputStream baos = JavaCV.captureThumbnail(IO.getInputStream(tempFile), 2);
|
ByteArrayOutputStream baos = JavaCV.captureThumbnail(IO.getInputStream(tempFile), 2);
|
||||||
Thumbnails.of(IO.toInputStream(baos)).width(256).keepAspectRatio(true).toOutputStream(thumbStream);
|
Thumbnails.of(IO.toInputStream(baos)).width(256).keepAspectRatio(true).toOutputStream(thumbStream);
|
||||||
log.info("captured thumbnail: {} at {} ms", request.getName(), Time.now() - start);
|
log.info("captured thumbnail: {} at {} ms", attachment.getName(), Time.now() - start);
|
||||||
} finally {
|
} finally {
|
||||||
IO.destroy(tempFile);
|
IO.destroy(tempFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MediaAttach.ExtData extData = new MediaAttach.ExtData();
|
Metadata.ThumbImage thumbMetadata = new Metadata.ThumbImage();
|
||||||
extData.setImage(isImage);
|
thumbMetadata.setSourceId(attachment.getId());
|
||||||
extData.setVideo(!isImage);
|
thumbMetadata.setSourceMongoId(attachment.getMongoId());
|
||||||
extData.setSourceId(request.getId());
|
thumbMetadata.setSourceMimeType(mimeType);
|
||||||
extData.setSourceMongoId(request.getMongoId());
|
|
||||||
|
|
||||||
AttachmentRequest thumbAttach = new AttachmentRequest();
|
Attachment thumbAttach = new Attachment();
|
||||||
thumbAttach.setName(Network.simpleURIFileName(request.getName()) + ".png");
|
thumbAttach.setName(Network.simpleURIFileName(attachment.getName()) + ".png");
|
||||||
thumbAttach.setBizType(request.getBizType());
|
thumbAttach.setBizType(attachment.getBizType());
|
||||||
thumbAttach.setBizId(request.getBizId());
|
thumbAttach.setBizId(attachment.getBizId());
|
||||||
thumbAttach.setAttachTypeValue(MediaAttach.Type.THUMB);
|
thumbAttach.setAttachTypeValue(MediaAttach.Type.THUMB);
|
||||||
thumbAttach.setExt(gson.toJson(extData));
|
thumbAttach.setMetadata(gson.toJsonTree(thumbMetadata).getAsJsonObject());
|
||||||
thumbAttach.setInputStream(new ByteArrayInputStream(thumbStream.toByteArray()));
|
thumbAttach.setInputStream(new ByteArrayInputStream(thumbStream.toByteArray()));
|
||||||
create(thumbAttach);
|
create(thumbAttach);
|
||||||
|
|
||||||
@ -186,8 +182,8 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
public void deleteMedia(Long thumbId) throws TimiException {
|
public void deleteMedia(Long thumbId) throws TimiException {
|
||||||
Attachment attachment = get(thumbId);
|
Attachment attachment = get(thumbId);
|
||||||
delete(attachment.getId());
|
delete(attachment.getId());
|
||||||
MediaAttach.ExtData data = gson.fromJson(attachment.getExt(), MediaAttach.ExtData.class);
|
Metadata.ThumbImage thumbMetadata = gson.fromJson(attachment.getMetadata(), Metadata.ThumbImage.class);
|
||||||
delete(data.getSourceId());
|
delete(thumbMetadata.getSourceId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -205,22 +201,11 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
return mapper.selectByMongoId(mongoId);
|
return mapper.selectByMongoId(mongoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public AttachmentView viewByMongoId(String mongoId) {
|
|
||||||
Attachment attachment = getByMongoId(mongoId);
|
|
||||||
if (attachment == null) {
|
|
||||||
throw new TimiException(TimiCode.RESULT_NULL).msgKey("TODO not found attachment");
|
|
||||||
}
|
|
||||||
AttachmentView view = new AttachmentView();
|
|
||||||
BeanUtils.copyProperties(attachment, view);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GridFSFile readByMongoId(String mongoId) {
|
public GridFSFile readByMongoId(String mongoId) {
|
||||||
Attachment view = mapper.selectByMongoId(mongoId);
|
Attachment attach = mapper.selectByMongoId(mongoId);
|
||||||
TimiException.required(view, "not found attachment: %s".formatted(mongoId));
|
TimiException.required(attach, "not found attachment: %s".formatted(mongoId));
|
||||||
return gridFsTemplate.findOne(new Query(Criteria.where("_id").is(view.getMongoId())));
|
return gridFsTemplate.findOne(new Query(Criteria.where("_id").is(attach.getMongoId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -231,7 +216,7 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
@Override
|
@Override
|
||||||
public byte[] readAllByMongoId(String mongoId) {
|
public byte[] readAllByMongoId(String mongoId) {
|
||||||
try {
|
try {
|
||||||
return IO.toBytes(getInputStreamByMongoId(mongoId));
|
return IO.toBytes(getByMongoId(mongoId).openInputStream());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new TimiException(TimiCode.ERROR, "TODO 读取失败");
|
throw new TimiException(TimiCode.ERROR, "TODO 读取失败");
|
||||||
}
|
}
|
||||||
@ -266,4 +251,9 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Attachment> listNeedDestroy() {
|
||||||
|
return mapper.selectNeedDestroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +1,27 @@
|
|||||||
package com.imyeyu.api.modules.common.service.implement;
|
package com.imyeyu.api.modules.common.service.implement;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
import com.imyeyu.api.modules.common.bean.TempFileMetaData;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
import com.imyeyu.api.modules.common.service.TempFileService;
|
import com.imyeyu.api.modules.common.service.TempFileService;
|
||||||
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
import com.imyeyu.api.modules.common.vo.TempFileResponse;
|
||||||
import com.imyeyu.io.IO;
|
|
||||||
import com.imyeyu.io.IOSize;
|
import com.imyeyu.io.IOSize;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.network.Network;
|
|
||||||
import com.imyeyu.spring.TimiSpring;
|
import com.imyeyu.spring.TimiSpring;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
@ -41,56 +32,58 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TempFileServiceImplement implements TempFileService {
|
public class TempFileServiceImplement implements TempFileService {
|
||||||
|
|
||||||
private static final Long TTL = Time.H * 6;
|
private final Gson gson;
|
||||||
private static final Long LIMIT = IOSize.GB * 10;
|
|
||||||
|
|
||||||
private final SettingService settingService;
|
private final SettingService settingService;
|
||||||
private final AttachmentService attachmentService;
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
private Path storagePath;
|
public List<TempFileResponse> store(List<MultipartFile> files, Long ttl) throws TimiException {
|
||||||
|
String ttlMinStr = settingService.getAsString(SettingKey.TEMP_FILE_TTL_MIN);
|
||||||
|
String ttlMaxStr = settingService.getAsString(SettingKey.TEMP_FILE_TTL_MAX);
|
||||||
|
String limitStr = settingService.getAsString(SettingKey.TEMP_FILE_LIMIT);
|
||||||
|
|
||||||
private final Map<String, TempFileMetaData> metadataMap = new ConcurrentHashMap<>();
|
long minTTL = Time.parseToMS(ttlMinStr);
|
||||||
private final Map<String, Long> usageMap = new ConcurrentHashMap<>();
|
long maxTTL = Time.parseToMS(ttlMaxStr);
|
||||||
|
long defaultTTL = Time.parseToMS(settingService.getAsString(SettingKey.TEMP_FILE_TTL_DEFAULT));
|
||||||
|
long limit = IOSize.parse(limitStr);
|
||||||
|
long residueTime = Time.parseToMS(settingService.getAsString(SettingKey.TEMP_FILE_RESIDUE_TIME));
|
||||||
|
|
||||||
@PostConstruct
|
ttl = TimiJava.defaultIfNull(ttl, defaultTTL);
|
||||||
public void init() throws IOException {
|
TimiException.requiredTrue(minTTL < ttl && ttl <= maxTTL, String.format("ttl must be between %s and %s", ttlMinStr, ttlMaxStr));
|
||||||
storagePath = Paths.get(settingService.getAsString(SettingKey.TEMP_FILE_PATH));
|
|
||||||
IO.destroy(storagePath.toFile());
|
|
||||||
Files.createDirectories(storagePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TempFileResponse> store(List<MultipartFile> files) throws TimiException {
|
|
||||||
long newFileSize = files.stream().mapToLong(MultipartFile::getSize).sum();
|
long newFileSize = files.stream().mapToLong(MultipartFile::getSize).sum();
|
||||||
long currentUsage = usageMap.getOrDefault(TimiSpring.getRequestIP(), 0L);
|
{
|
||||||
TimiException.requiredTrue(currentUsage + newFileSize < LIMIT, "out of storage limit(10 GB)");
|
// 缓存池大小限制
|
||||||
|
Page<Attachment> page = new Page<>();
|
||||||
|
page.setIndex(0);
|
||||||
|
page.setSize(Long.MAX_VALUE);
|
||||||
|
{
|
||||||
|
Attachment example = new Attachment();
|
||||||
|
example.setUploaderIp(TimiSpring.getRequestIP());
|
||||||
|
page.setEqualsExample(example);
|
||||||
|
}
|
||||||
|
long currentUsage = attachmentService.page(page).getList().stream().mapToLong(Attachment::getSize).sum();
|
||||||
|
TimiException.requiredTrue(currentUsage + newFileSize < limit, "out of storage limit(%s)".formatted(limitStr));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
List<TempFileResponse> result = new ArrayList<>();
|
List<TempFileResponse> result = new ArrayList<>();
|
||||||
|
|
||||||
|
long deletedAt = Time.now() + ttl;
|
||||||
|
long destroyAt = deletedAt + residueTime;
|
||||||
for (int i = 0; i < files.size(); i++) {
|
for (int i = 0; i < files.size(); i++) {
|
||||||
MultipartFile file = files.get(i);
|
MultipartFile file = files.get(i);
|
||||||
|
|
||||||
String fileId = UUID.randomUUID().toString();
|
Attachment attach = new Attachment();
|
||||||
String fileName = fileId;
|
attach.setBizType(Attachment.BizType.TEMP_FILE);
|
||||||
if (TimiJava.isNotEmpty(file.getOriginalFilename())) {
|
attach.setName(file.getOriginalFilename());
|
||||||
fileName = fileId + "." + Network.uriFileExtension(file.getOriginalFilename());
|
attach.setDeletedAt(deletedAt);
|
||||||
}
|
attach.setDestroyAt(destroyAt);
|
||||||
Path filePath = storagePath.resolve(fileName);
|
attach.setInputStream(file.getInputStream());
|
||||||
Files.copy(file.getInputStream(), filePath);
|
attachmentService.create(attach);
|
||||||
|
|
||||||
// 创建元数据
|
|
||||||
TempFileMetaData metadata = new TempFileMetaData();
|
|
||||||
metadata.setId(fileId);
|
|
||||||
metadata.setPath(filePath);
|
|
||||||
metadata.setName(fileName);
|
|
||||||
metadata.setOriginalName(file.getOriginalFilename());
|
|
||||||
metadata.setLastAccessAt(Time.now());
|
|
||||||
metadataMap.put(metadata.getId(), metadata);
|
|
||||||
|
|
||||||
TempFileResponse resp = new TempFileResponse();
|
TempFileResponse resp = new TempFileResponse();
|
||||||
resp.setId(metadata.getId());
|
resp.setId(attach.getMongoId());
|
||||||
resp.setExpireAt(metadata.getLastAccessAt() + TTL);
|
resp.setExpireAt(deletedAt);
|
||||||
|
|
||||||
usageMap.put(TimiSpring.getRequestIP(), currentUsage + newFileSize);
|
|
||||||
result.add(resp);
|
result.add(resp);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -100,33 +93,20 @@ public class TempFileServiceImplement implements TempFileService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public File get(String id) throws TimiException {
|
|
||||||
TempFileMetaData metaData = metadataMap.get(id);
|
|
||||||
TimiException.required(metaData, "not found temp file");
|
|
||||||
metaData.setLastAccessAt(Time.now());
|
|
||||||
return metaData.getPath().toFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TempFileMetaData metadata(String id) throws TimiException {
|
|
||||||
return metadataMap.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Scheduled(fixedRate = 3600000)
|
@Scheduled(fixedRate = 3600000)
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
List<String> expiredIds = metadataMap.values()
|
// List<String> expiredIds = metadataMap.values()
|
||||||
.stream()
|
// .stream()
|
||||||
.filter(metadata -> metadata.getLastAccessAt() + TTL < Time.now())
|
// .filter(metadata -> metadata.getLastAccessAt() + metadata.getTtl() < Time.now())
|
||||||
.map(TempFileMetaData::getId)
|
// .map(TempFileMetaData::getId)
|
||||||
.toList();
|
// .toList();
|
||||||
for (int i = 0; i < expiredIds.size(); i++) {
|
// for (int i = 0; i < expiredIds.size(); i++) {
|
||||||
TempFileMetaData removed = metadataMap.remove(expiredIds.get(i));
|
// TempFileMetaData removed = metadataMap.remove(expiredIds.get(i));
|
||||||
if (TimiJava.isNotEmpty(removed)) {
|
// if (TimiJava.isNotEmpty(removed)) {
|
||||||
File file = removed.getPath().toFile();
|
// File file = removed.getPath().toFile();
|
||||||
IO.destroy(file);
|
// IO.destroy(file);
|
||||||
usageMap.computeIfPresent(TimiSpring.getRequestIP(), (ip, usage) -> usage - file.length());
|
// usageMap.computeIfPresent(TimiSpring.getRequestIP(), (ip, usage) -> usage - file.length());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
package com.imyeyu.api.modules.common.service.implement;
|
package com.imyeyu.api.modules.common.service.implement;
|
||||||
|
|
||||||
import com.imyeyu.io.IOSize;
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.entity.User;
|
import com.imyeyu.api.modules.common.entity.User;
|
||||||
@ -12,8 +8,11 @@ import com.imyeyu.api.modules.common.mapper.UserProfileMapper;
|
|||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.service.UserProfileService;
|
import com.imyeyu.api.modules.common.service.UserProfileService;
|
||||||
import com.imyeyu.api.modules.common.service.UserService;
|
import com.imyeyu.api.modules.common.service.UserService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.common.vo.user.UserRequest;
|
import com.imyeyu.api.modules.common.vo.user.UserRequest;
|
||||||
|
import com.imyeyu.io.IOSize;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -73,7 +72,7 @@ public class UserProfileServiceImplement extends AbstractEntityService<UserProfi
|
|||||||
if (IOSize.MB < bytes.length) {
|
if (IOSize.MB < bytes.length) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("限制上传文件大小 1 MB");
|
throw new TimiException(TimiCode.ARG_BAD).msgKey("限制上传文件大小 1 MB");
|
||||||
}
|
}
|
||||||
AttachmentRequest wrapperAttach = new AttachmentRequest();
|
Attachment wrapperAttach = new Attachment();
|
||||||
wrapperAttach.setName(request.getId() + ".png");
|
wrapperAttach.setName(request.getId() + ".png");
|
||||||
wrapperAttach.setBizType(Attachment.BizType.USER);
|
wrapperAttach.setBizType(Attachment.BizType.USER);
|
||||||
wrapperAttach.setBizId(request.getId());
|
wrapperAttach.setBizId(request.getId());
|
||||||
@ -88,7 +87,7 @@ public class UserProfileServiceImplement extends AbstractEntityService<UserProfi
|
|||||||
attachmentService.delete(dbAvatar.getId());
|
attachmentService.delete(dbAvatar.getId());
|
||||||
}
|
}
|
||||||
MultipartFile avatar = request.getProfile().getAvatar();
|
MultipartFile avatar = request.getProfile().getAvatar();
|
||||||
AttachmentRequest avatarAttach = new AttachmentRequest();
|
Attachment avatarAttach = new Attachment();
|
||||||
avatarAttach.setName(request.getId() + ".png");
|
avatarAttach.setName(request.getId() + ".png");
|
||||||
avatarAttach.setBizType(Attachment.BizType.USER);
|
avatarAttach.setBizType(Attachment.BizType.USER);
|
||||||
avatarAttach.setBizId(request.getId());
|
avatarAttach.setBizId(request.getId());
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
package com.imyeyu.api.modules.common.task;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件清除定时任务。每天凌晨 1 点执行,清除已过期但未销毁的附件
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-01-05 12:37
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AttachmentClearTask {
|
||||||
|
|
||||||
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
|
@Scheduled(cron = "0 0 1 * * ?")
|
||||||
|
public void run() {
|
||||||
|
log.info("start clear expired attachments");
|
||||||
|
try {
|
||||||
|
List<Attachment> needDestroyList = attachmentService.listNeedDestroy();
|
||||||
|
if (needDestroyList.isEmpty()) {
|
||||||
|
log.info("nothing attachment need clear");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Attachment attach : needDestroyList) {
|
||||||
|
try {
|
||||||
|
attachmentService.destroy(attach.getId());
|
||||||
|
log.info("clear attachment success: id[{}]", attach.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("clear attachment error: id[{}]", attach.getId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("end clear expired attachments");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("attachment clear task error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package com.imyeyu.api.modules.common.vo.attachment;
|
|
||||||
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
|
||||||
import com.imyeyu.spring.annotation.table.Transient;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-02-21 10:58
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Transient
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class AttachmentRequest extends Attachment {
|
|
||||||
|
|
||||||
private InputStream inputStream;
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
package com.imyeyu.api.modules.common.vo.attachment;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import com.imyeyu.api.bean.MultilingualHandler;
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2024-02-21 10:55
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class AttachmentView extends Attachment implements MultilingualHandler {
|
|
||||||
}
|
|
||||||
@ -56,7 +56,7 @@ public class ServerServiceImplement implements ServerService {
|
|||||||
public void report(ReportRequest request) {
|
public void report(ReportRequest request) {
|
||||||
ServerStatus status = serverMap.get(request.getId());
|
ServerStatus status = serverMap.get(request.getId());
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
request.setBaseInfo(TimiJava.firstNotNull(request.getBaseInfo(), status.getBaseInfo()));
|
request.setBaseInfo(TimiJava.defaultIfNull(request.getBaseInfo(), status.getBaseInfo()));
|
||||||
if (request.getBaseInfo() == null || TimiJava.isEmpty(request.getBaseInfo().getCore())) {
|
if (request.getBaseInfo() == null || TimiJava.isEmpty(request.getBaseInfo().getCore())) {
|
||||||
// 需要报告基本信息,与调用方约定返回代码为 IGNORE
|
// 需要报告基本信息,与调用方约定返回代码为 IGNORE
|
||||||
throw new TimiException(TimiCode.IGNORE);
|
throw new TimiException(TimiCode.IGNORE);
|
||||||
|
|||||||
@ -1,59 +0,0 @@
|
|||||||
package com.imyeyu.api.modules.journal.bean;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-09-30 11:51
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class Travel {
|
|
||||||
|
|
||||||
private Luggage luggage;
|
|
||||||
|
|
||||||
private List<Guide> guides;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-09-30 11:52
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class Luggage {
|
|
||||||
|
|
||||||
private List<Item> gao;
|
|
||||||
|
|
||||||
private List<Item> yu;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-09-30 11:52
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class Item {
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private boolean isTaken;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-09-30 11:54
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class Guide {
|
|
||||||
|
|
||||||
private String title;
|
|
||||||
|
|
||||||
private List<String> images;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +1,18 @@
|
|||||||
package com.imyeyu.api.modules.journal.controller;
|
package com.imyeyu.api.modules.journal.controller;
|
||||||
|
|
||||||
|
import com.imyeyu.api.bean.PreviewPage;
|
||||||
import com.imyeyu.api.bean.wechat.InitCodeResponse;
|
import com.imyeyu.api.bean.wechat.InitCodeResponse;
|
||||||
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
import com.imyeyu.api.modules.common.bean.SettingKey;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
import com.imyeyu.api.modules.journal.bean.Travel;
|
|
||||||
import com.imyeyu.api.modules.journal.entity.Journal;
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
import com.imyeyu.api.modules.journal.service.JournalService;
|
import com.imyeyu.api.modules.journal.service.JournalService;
|
||||||
import com.imyeyu.api.modules.journal.vo.ArchiveRequest;
|
import com.imyeyu.api.modules.journal.vo.journal.ArchiveRequest;
|
||||||
import com.imyeyu.api.modules.journal.vo.JournalPage;
|
import com.imyeyu.api.modules.journal.vo.journal.JournalRequest;
|
||||||
import com.imyeyu.api.modules.journal.vo.JournalRequest;
|
import com.imyeyu.api.modules.journal.vo.journal.JournalResponse;
|
||||||
import com.imyeyu.api.modules.journal.vo.JournalResponse;
|
import com.imyeyu.api.modules.journal.vo.journal.UpdateRequest;
|
||||||
import com.imyeyu.api.modules.journal.vo.UpdateRequest;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.network.ArgMap;
|
import com.imyeyu.network.ArgMap;
|
||||||
@ -141,7 +140,7 @@ public class JournalController {
|
|||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequestMapping("/list")
|
@RequestMapping("/list")
|
||||||
public PageResult<JournalResponse> list(@RequestBody JournalPage page) {
|
public PageResult<JournalResponse> list(@RequestBody PreviewPage<Journal> page) {
|
||||||
PageResult<Journal> pageResult = service.page(page);
|
PageResult<Journal> pageResult = service.page(page);
|
||||||
|
|
||||||
PageResult<JournalResponse> result = new PageResult<>();
|
PageResult<JournalResponse> result = new PageResult<>();
|
||||||
@ -206,24 +205,6 @@ public class JournalController {
|
|||||||
return journal + journalTravel;
|
return journal + journalTravel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@RequestRateLimit
|
|
||||||
@GetMapping("/travel")
|
|
||||||
public Travel getTravel() {
|
|
||||||
return service.getTravel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@AOPLog
|
|
||||||
@RequestRateLimit
|
|
||||||
@PostMapping("/travel/luggage/update")
|
|
||||||
public void updateTravel(@RequestBody Travel.Luggage luggage) {
|
|
||||||
service.updateTravelLuggage(luggage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建瞬间(上传的临时文件持久化储存,微信限制单次上传数量)
|
* 创建瞬间(上传的临时文件持久化储存,微信限制单次上传数量)
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,97 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.controller;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Travel;
|
||||||
|
import com.imyeyu.api.modules.journal.service.TravelService;
|
||||||
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
|
import com.imyeyu.spring.annotation.RequestSingleParam;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行计划接口
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:50
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/journal/travel")
|
||||||
|
public class TravelController {
|
||||||
|
|
||||||
|
private final TravelService service;
|
||||||
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建旅行计划
|
||||||
|
*
|
||||||
|
* @param travel 旅行计划
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/create")
|
||||||
|
public void create(@RequestBody @Valid Travel travel) {
|
||||||
|
service.create(travel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新旅行计划
|
||||||
|
*
|
||||||
|
* @param travel 旅行计划
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/update")
|
||||||
|
public void update(@RequestBody @Valid Travel travel) {
|
||||||
|
service.update(travel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除旅行计划(级联删除关联地点和附件)
|
||||||
|
*
|
||||||
|
* @param id 旅行 ID
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public void delete(@RequestSingleParam Long id) {
|
||||||
|
service.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询旅行计划详情
|
||||||
|
*
|
||||||
|
* @param id 旅行 ID
|
||||||
|
* @return 旅行计划
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Travel detail(@PathVariable Long id) {
|
||||||
|
return service.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行计划列表
|
||||||
|
*
|
||||||
|
* @param page 分页参数
|
||||||
|
* @return 旅行列表
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/list")
|
||||||
|
public PageResult<Travel> list(@RequestBody Page<Travel> page) {
|
||||||
|
return service.page(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.controller;
|
||||||
|
|
||||||
|
import com.imyeyu.api.bean.PreviewPage;
|
||||||
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import com.imyeyu.api.modules.journal.entity.TravelLocation;
|
||||||
|
import com.imyeyu.api.modules.journal.service.TravelLocationService;
|
||||||
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
|
import com.imyeyu.spring.annotation.RequestSingleParam;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行地点接口
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:50
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/journal/travel/location")
|
||||||
|
public class TravelLocationController {
|
||||||
|
|
||||||
|
private final AttachmentService attachmentService;
|
||||||
|
private final TravelLocationService service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建旅行地点
|
||||||
|
*
|
||||||
|
* @param location 旅行地点
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/create")
|
||||||
|
public void create(@RequestBody @Valid TravelLocation location) {
|
||||||
|
service.create(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新旅行地点
|
||||||
|
*
|
||||||
|
* @param location 旅行地点
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/update")
|
||||||
|
public void update(@RequestBody @Valid TravelLocation location) {
|
||||||
|
service.update(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除旅行地点(级联删除附件)
|
||||||
|
*
|
||||||
|
* @param id 地点 ID
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public void delete(@RequestSingleParam Long id) {
|
||||||
|
service.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询旅行地点详情
|
||||||
|
*
|
||||||
|
* @param id 地点 ID
|
||||||
|
* @return 旅行地点
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public TravelLocation detail(@PathVariable Long id) {
|
||||||
|
TravelLocation location = service.get(id);
|
||||||
|
location.setItems(attachmentService.listByBizId(Attachment.BizType.JOURNAL_TRAVEL, location.getId()));
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行地点列表
|
||||||
|
*
|
||||||
|
* @param page 分页参数
|
||||||
|
* @return 地点列表
|
||||||
|
*/
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/list")
|
||||||
|
public PageResult<TravelLocation> list(@RequestBody PreviewPage<TravelLocation> page) {
|
||||||
|
PageResult<TravelLocation> result = service.page(page);
|
||||||
|
for (TravelLocation location : result.getList()) {
|
||||||
|
Page<Attachment> attachPage = new Page<>();
|
||||||
|
{
|
||||||
|
Attachment example = new Attachment();
|
||||||
|
example.setBizType(Attachment.BizType.JOURNAL_TRAVEL);
|
||||||
|
example.setBizId(location.getId());
|
||||||
|
example.setAttachTypeValue(MediaAttach.Type.THUMB);
|
||||||
|
attachPage.setEqualsExample(example);
|
||||||
|
}
|
||||||
|
attachPage.setIndex(0);
|
||||||
|
attachPage.setSize(1); // 列表接口只允许预览
|
||||||
|
location.setItems(attachmentService.page(attachPage).getList());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@PostMapping("/list/ids")
|
||||||
|
public List<TravelLocation> listByIds(@RequestBody Long[] ids) {
|
||||||
|
List<TravelLocation> locationList = service.listByIds(ids);
|
||||||
|
for (TravelLocation location : locationList) {
|
||||||
|
Page<Attachment> attachPage = new Page<>();
|
||||||
|
{
|
||||||
|
Attachment example = new Attachment();
|
||||||
|
example.setBizType(Attachment.BizType.JOURNAL_TRAVEL);
|
||||||
|
example.setBizId(location.getId());
|
||||||
|
attachPage.setEqualsExample(example);
|
||||||
|
}
|
||||||
|
attachPage.setIndex(0);
|
||||||
|
attachPage.setSize(Long.MAX_VALUE);
|
||||||
|
location.setItems(attachmentService.page(attachPage).getList());
|
||||||
|
}
|
||||||
|
return locationList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.entity;
|
||||||
|
|
||||||
|
import com.imyeyu.spring.annotation.table.PageIgnore;
|
||||||
|
import com.imyeyu.spring.entity.Entity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行计划
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:30
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class Travel extends Entity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交通类型
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:30
|
||||||
|
*/
|
||||||
|
public enum TransportationType {
|
||||||
|
|
||||||
|
/** 飞机 */
|
||||||
|
PLANE,
|
||||||
|
|
||||||
|
/** 火车 */
|
||||||
|
TRAIN,
|
||||||
|
|
||||||
|
/** 汽车 */
|
||||||
|
CAR,
|
||||||
|
|
||||||
|
/** 轮船 */
|
||||||
|
SHIP,
|
||||||
|
|
||||||
|
/** 自驾 */
|
||||||
|
SELF_DRIVING,
|
||||||
|
|
||||||
|
/** 其他 */
|
||||||
|
OTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行状态
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:30
|
||||||
|
*/
|
||||||
|
public enum Status {
|
||||||
|
|
||||||
|
/** 计划中 */
|
||||||
|
PLANNING,
|
||||||
|
|
||||||
|
/** 进行中 */
|
||||||
|
ONGOING,
|
||||||
|
|
||||||
|
/** 已完成 */
|
||||||
|
COMPLETED,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 交通类型 */
|
||||||
|
private TransportationType transportationType;
|
||||||
|
|
||||||
|
/** 标题 */
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 内容 */
|
||||||
|
@PageIgnore
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/** 出行时间 */
|
||||||
|
private Long travelAt;
|
||||||
|
|
||||||
|
/** 天数 */
|
||||||
|
private Integer days;
|
||||||
|
|
||||||
|
/** 状态 */
|
||||||
|
private Status status;
|
||||||
|
}
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.entity;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.spring.annotation.table.Transient;
|
||||||
|
import com.imyeyu.spring.entity.Entity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行地点
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:30
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class TravelLocation extends Entity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 地点类型
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:30
|
||||||
|
*/
|
||||||
|
public enum Type {
|
||||||
|
|
||||||
|
/** 美食 */
|
||||||
|
FOOD,
|
||||||
|
|
||||||
|
/** 酒店 */
|
||||||
|
HOTEL,
|
||||||
|
|
||||||
|
/** 交通站点 */
|
||||||
|
TRANSPORT,
|
||||||
|
|
||||||
|
/** 景点 */
|
||||||
|
ATTRACTION,
|
||||||
|
|
||||||
|
/** 商场 */
|
||||||
|
MALL,
|
||||||
|
|
||||||
|
/** 购物 */
|
||||||
|
SHOPPING,
|
||||||
|
|
||||||
|
/** 玩乐 */
|
||||||
|
PLAY,
|
||||||
|
|
||||||
|
/** 生活 */
|
||||||
|
LIFE,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 旅行计划 ID */
|
||||||
|
private Long travelId;
|
||||||
|
|
||||||
|
/** 类型 */
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
/** 标题 */
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 说明 */
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/** 纬度 */
|
||||||
|
private Double lat;
|
||||||
|
|
||||||
|
/** 经度 */
|
||||||
|
private Double lng;
|
||||||
|
|
||||||
|
/** 位置 */
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
/** 费用 */
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
/** true 为需要身份证 */
|
||||||
|
private Boolean requireIdCard;
|
||||||
|
|
||||||
|
/** true 为需要预约 */
|
||||||
|
private Boolean requireAppointment;
|
||||||
|
|
||||||
|
/** 评分 */
|
||||||
|
private Integer score;
|
||||||
|
|
||||||
|
/** 重要程度 */
|
||||||
|
private Integer importance;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private Long[] attachmentIds;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private String[] tempFileIds;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private List<Attachment> items;
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.mapper;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.journal.entity.TravelLocation;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行地点 Mapper
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:35
|
||||||
|
*/
|
||||||
|
public interface TravelLocationMapper extends BaseMapper<TravelLocation, Long> {
|
||||||
|
|
||||||
|
List<TravelLocation> listByIds(Long[] ids);
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.mapper;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Travel;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行计划 Mapper
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:35
|
||||||
|
*/
|
||||||
|
public interface TravelMapper extends BaseMapper<Travel, Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 ID 列表查询
|
||||||
|
*
|
||||||
|
* @param ids ID 列表
|
||||||
|
* @return 旅行列表
|
||||||
|
*/
|
||||||
|
List<Travel> listByIds(@Param("ids") Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态查询
|
||||||
|
*
|
||||||
|
* @param status 状态
|
||||||
|
* @return 旅行列表
|
||||||
|
*/
|
||||||
|
List<Travel> listByStatus(@Param("status") Travel.Status status);
|
||||||
|
}
|
||||||
@ -1,11 +1,10 @@
|
|||||||
package com.imyeyu.api.modules.journal.service;
|
package com.imyeyu.api.modules.journal.service;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.journal.bean.Travel;
|
|
||||||
import com.imyeyu.api.modules.journal.entity.Journal;
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
import com.imyeyu.api.modules.journal.vo.ArchiveRequest;
|
import com.imyeyu.api.modules.journal.vo.journal.ArchiveRequest;
|
||||||
import com.imyeyu.api.modules.journal.vo.JournalRequest;
|
import com.imyeyu.api.modules.journal.vo.journal.JournalRequest;
|
||||||
import com.imyeyu.api.modules.journal.vo.UpdateRequest;
|
import com.imyeyu.api.modules.journal.vo.journal.UpdateRequest;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.service.DeletableService;
|
import com.imyeyu.spring.service.DeletableService;
|
||||||
import com.imyeyu.spring.service.GettableService;
|
import com.imyeyu.spring.service.GettableService;
|
||||||
@ -39,8 +38,4 @@ public interface JournalService extends PageableService<Journal>, GettableServic
|
|||||||
void deleteMoment(Long[] thumbIds) throws TimiException;
|
void deleteMoment(Long[] thumbIds) throws TimiException;
|
||||||
|
|
||||||
void archiveMoment(ArchiveRequest request) throws TimiException;
|
void archiveMoment(ArchiveRequest request) throws TimiException;
|
||||||
|
|
||||||
Travel getTravel() throws TimiException;
|
|
||||||
|
|
||||||
void updateTravelLuggage(Travel.Luggage luggage) throws TimiException;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.journal.entity.TravelLocation;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.service.BaseService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行地点服务
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:40
|
||||||
|
*/
|
||||||
|
public interface TravelLocationService extends BaseService<TravelLocation, Long> {
|
||||||
|
|
||||||
|
List<TravelLocation> listByIds(Long... ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据旅行 ID 删除所有地点
|
||||||
|
*
|
||||||
|
* @param travelId 旅行 ID
|
||||||
|
* @throws TimiException 服务异常
|
||||||
|
*/
|
||||||
|
void deleteByTravelId(Long travelId) throws TimiException;
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Travel;
|
||||||
|
import com.imyeyu.spring.service.BaseService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行计划服务
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:40
|
||||||
|
*/
|
||||||
|
public interface TravelService extends BaseService<Travel, Long> {
|
||||||
|
}
|
||||||
@ -3,22 +3,17 @@ package com.imyeyu.api.modules.journal.service.implement;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
import com.imyeyu.api.modules.common.bean.SettingKey;
|
import com.imyeyu.api.modules.common.bean.Metadata;
|
||||||
import com.imyeyu.api.modules.common.bean.TempFileMetaData;
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.entity.Setting;
|
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
import com.imyeyu.api.modules.common.service.TempFileService;
|
import com.imyeyu.api.modules.common.service.TempFileService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.journal.bean.Travel;
|
|
||||||
import com.imyeyu.api.modules.journal.entity.Journal;
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
import com.imyeyu.api.modules.journal.mapper.JournalMapper;
|
import com.imyeyu.api.modules.journal.mapper.JournalMapper;
|
||||||
import com.imyeyu.api.modules.journal.service.JournalService;
|
import com.imyeyu.api.modules.journal.service.JournalService;
|
||||||
import com.imyeyu.api.modules.journal.vo.ArchiveRequest;
|
import com.imyeyu.api.modules.journal.vo.journal.ArchiveRequest;
|
||||||
import com.imyeyu.api.modules.journal.vo.JournalRequest;
|
import com.imyeyu.api.modules.journal.vo.journal.JournalRequest;
|
||||||
import com.imyeyu.api.modules.journal.vo.UpdateRequest;
|
import com.imyeyu.api.modules.journal.vo.journal.UpdateRequest;
|
||||||
import com.imyeyu.io.IO;
|
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
@ -30,7 +25,6 @@ import org.springframework.beans.BeanUtils;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -72,14 +66,13 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < tempFileIds.length; i++) {
|
for (int i = 0; i < tempFileIds.length; i++) {
|
||||||
TempFileMetaData metadata = tempFileService.metadata(tempFileIds[i]);
|
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileIds[i]);
|
||||||
File file = tempFileService.get(tempFileIds[i]);
|
|
||||||
|
|
||||||
AttachmentRequest sourceAttach = new AttachmentRequest();
|
Attachment sourceAttach = new Attachment();
|
||||||
sourceAttach.setName(metadata.getOriginalName());
|
sourceAttach.setName(tempFileAttach.getName());
|
||||||
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
||||||
sourceAttach.setBizId(journal.getId());
|
sourceAttach.setBizId(journal.getId());
|
||||||
sourceAttach.setInputStream(IO.getInputStream(file));
|
sourceAttach.setInputStream(tempFileAttach.openInputStream());
|
||||||
attachmentService.createMedia(sourceAttach);
|
attachmentService.createMedia(sourceAttach);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -92,7 +85,6 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
|
|||||||
@Override
|
@Override
|
||||||
public void update(UpdateRequest request) throws TimiException {
|
public void update(UpdateRequest request) throws TimiException {
|
||||||
TimiException.required(request.getId(), "not found request.id");
|
TimiException.required(request.getId(), "not found request.id");
|
||||||
try {
|
|
||||||
Journal journal = get(request.getId());
|
Journal journal = get(request.getId());
|
||||||
BeanUtils.copyProperties(request, journal);
|
BeanUtils.copyProperties(request, journal);
|
||||||
super.update(journal);
|
super.update(journal);
|
||||||
@ -108,25 +100,17 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
|
|||||||
attachmentService.deleteMedia(removeId);
|
attachmentService.deleteMedia(removeId);
|
||||||
}
|
}
|
||||||
// 新增
|
// 新增
|
||||||
String[] tempFileIds = request.getTempFileIds();
|
for (String tempFileId : TimiJava.defaultIfNull(request.getTempFileIds(), new String[0])) {
|
||||||
if (TimiJava.isNotEmpty(tempFileIds)) {
|
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileId);
|
||||||
for (int i = 0; i < tempFileIds.length; i++) {
|
|
||||||
TempFileMetaData metadata = tempFileService.metadata(tempFileIds[i]);
|
|
||||||
File file = tempFileService.get(tempFileIds[i]);
|
|
||||||
|
|
||||||
AttachmentRequest sourceAttach = new AttachmentRequest();
|
Attachment sourceAttach = new Attachment();
|
||||||
sourceAttach.setName(metadata.getOriginalName());
|
sourceAttach.setName(tempFileAttach.getName());
|
||||||
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
||||||
sourceAttach.setBizId(journal.getId());
|
sourceAttach.setBizId(journal.getId());
|
||||||
sourceAttach.setInputStream(IO.getInputStream(file));
|
sourceAttach.setInputStream(tempFileAttach.openInputStream());
|
||||||
attachmentService.createMedia(sourceAttach);
|
attachmentService.createMedia(sourceAttach);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("update journal error", e);
|
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO update journal error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
@ -160,16 +144,15 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
|
|||||||
try {
|
try {
|
||||||
List<Attachment> thumbResult = new ArrayList<>();
|
List<Attachment> thumbResult = new ArrayList<>();
|
||||||
for (int i = 0; i < tempFileIds.length; i++) {
|
for (int i = 0; i < tempFileIds.length; i++) {
|
||||||
TempFileMetaData metadata = tempFileService.metadata(tempFileIds[i]);
|
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileIds[i]);
|
||||||
File file = tempFileService.get(tempFileIds[i]);
|
|
||||||
|
|
||||||
AttachmentRequest sourceAttach = new AttachmentRequest();
|
Attachment sourceAttach = new Attachment();
|
||||||
sourceAttach.setName(metadata.getOriginalName());
|
sourceAttach.setName(tempFileAttach.getName());
|
||||||
sourceAttach.setBizType(Attachment.BizType.JOURNAL_MOMENT);
|
sourceAttach.setBizType(Attachment.BizType.JOURNAL_MOMENT);
|
||||||
sourceAttach.setBizId(0L);
|
sourceAttach.setBizId(0L);
|
||||||
sourceAttach.setAttachTypeValue(MediaAttach.Type.SOURCE);
|
sourceAttach.setAttachTypeValue(MediaAttach.Type.SOURCE);
|
||||||
sourceAttach.setSize(file.length());
|
sourceAttach.setSize(tempFileAttach.getSize());
|
||||||
sourceAttach.setInputStream(IO.getInputStream(file));
|
sourceAttach.setInputStream(tempFileAttach.openInputStream());
|
||||||
thumbResult.add(attachmentService.createMedia(sourceAttach));
|
thumbResult.add(attachmentService.createMedia(sourceAttach));
|
||||||
}
|
}
|
||||||
return thumbResult;
|
return thumbResult;
|
||||||
@ -209,8 +192,8 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
|
|||||||
thumbAttach.setBizId(journal.getId());
|
thumbAttach.setBizId(journal.getId());
|
||||||
attachmentService.update(thumbAttach);
|
attachmentService.update(thumbAttach);
|
||||||
|
|
||||||
MediaAttach.ExtData extData = gson.fromJson(thumbAttach.getExt(), MediaAttach.ExtData.class);
|
Metadata.ThumbImage thumbMetadata = gson.fromJson(thumbAttach.getMetadata(), Metadata.ThumbImage.class);
|
||||||
Attachment sourceAttach = attachmentService.get(extData.getSourceId());
|
Attachment sourceAttach = attachmentService.get(thumbMetadata.getSourceId());
|
||||||
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
sourceAttach.setBizType(Attachment.BizType.JOURNAL);
|
||||||
sourceAttach.setBizId(journal.getId());
|
sourceAttach.setBizId(journal.getId());
|
||||||
attachmentService.update(sourceAttach);
|
attachmentService.update(sourceAttach);
|
||||||
@ -220,19 +203,4 @@ public class JournalServiceImplement extends AbstractEntityService<Journal, Long
|
|||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO archive journal error");
|
throw new TimiException(TimiCode.ERROR).msgKey("TODO archive journal error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Travel getTravel() throws TimiException {
|
|
||||||
return gson.fromJson(settingService.getAsJsonObject(SettingKey.JOURNAL_TRAVEL), Travel.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateTravelLuggage(Travel.Luggage luggage) throws TimiException {
|
|
||||||
Travel dbTravel = getTravel();
|
|
||||||
dbTravel.setLuggage(luggage);
|
|
||||||
Setting setting = settingService.getByKey(SettingKey.JOURNAL_TRAVEL);
|
|
||||||
setting.setValue(gson.toJson(dbTravel));
|
|
||||||
settingService.update(setting);
|
|
||||||
settingService.clearCache(SettingKey.JOURNAL_TRAVEL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,118 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.service.implement;
|
||||||
|
|
||||||
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
|
import com.imyeyu.api.modules.common.bean.MediaAttach;
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
|
import com.imyeyu.api.modules.journal.entity.TravelLocation;
|
||||||
|
import com.imyeyu.api.modules.journal.mapper.TravelLocationMapper;
|
||||||
|
import com.imyeyu.api.modules.journal.service.TravelLocationService;
|
||||||
|
import com.imyeyu.api.modules.journal.service.TravelService;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行地点服务实现
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:45
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
|
||||||
|
public class TravelLocationServiceImplement extends AbstractEntityService<TravelLocation, Long> implements TravelLocationService {
|
||||||
|
|
||||||
|
private final TravelService travelService;
|
||||||
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
|
private final TravelLocationMapper mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BaseMapper<TravelLocation, Long> mapper() {
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void create(TravelLocation travelLocation) {
|
||||||
|
super.create(travelLocation);
|
||||||
|
for (String tempFileId : travelLocation.getTempFileIds()) {
|
||||||
|
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileId);
|
||||||
|
|
||||||
|
Attachment attach = new Attachment();
|
||||||
|
attach.setName(tempFileAttach.getName());
|
||||||
|
attach.setBizType(Attachment.BizType.JOURNAL_TRAVEL);
|
||||||
|
attach.setBizId(travelLocation.getId());
|
||||||
|
attach.setInputStream(tempFileAttach.openInputStream());
|
||||||
|
attachmentService.createMedia(attach);
|
||||||
|
}
|
||||||
|
// 更新操作时间以保证排序
|
||||||
|
travelService.update(travelService.get(travelLocation.getTravelId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void update(TravelLocation travelLocation) {
|
||||||
|
// 使用 update 以允许设置 score 和 importance 为 null
|
||||||
|
mapper.update(travelLocation);
|
||||||
|
// 删除
|
||||||
|
if (TimiJava.isNotEmpty(travelLocation.getAttachmentIds())) {
|
||||||
|
Set<Long> dbAttachSet = attachmentService.listByBizId(Attachment.BizType.JOURNAL_TRAVEL, travelLocation.getId(), MediaAttach.Type.THUMB)
|
||||||
|
.stream()
|
||||||
|
.map(Attachment::getId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Set<Long> retainIds = Set.of(travelLocation.getAttachmentIds());
|
||||||
|
dbAttachSet.removeAll(retainIds);
|
||||||
|
for (Long removeId : dbAttachSet) {
|
||||||
|
attachmentService.deleteMedia(removeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 新增
|
||||||
|
for (String tempFileId : TimiJava.defaultIfNull(travelLocation.getTempFileIds(), new String[0])) {
|
||||||
|
Attachment tempFileAttach = attachmentService.getByMongoId(tempFileId);
|
||||||
|
|
||||||
|
Attachment attach = new Attachment();
|
||||||
|
attach.setName(tempFileAttach.getName());
|
||||||
|
attach.setBizType(Attachment.BizType.JOURNAL_TRAVEL);
|
||||||
|
attach.setBizId(travelLocation.getId());
|
||||||
|
attach.setInputStream(tempFileAttach.openInputStream());
|
||||||
|
attachmentService.createMedia(attach);
|
||||||
|
}
|
||||||
|
// 更新操作时间以保证排序
|
||||||
|
travelService.update(travelService.get(travelLocation.getTravelId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void delete(Long id) {
|
||||||
|
super.delete(id);
|
||||||
|
attachmentService.deleteByBizId(Attachment.BizType.JOURNAL_TRAVEL, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TravelLocation> listByIds(Long... ids) {
|
||||||
|
return mapper.listByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void deleteByTravelId(Long travelId) throws TimiException {
|
||||||
|
TravelLocation example = new TravelLocation();
|
||||||
|
example.setTravelId(travelId);
|
||||||
|
List<TravelLocation> locationList = mapper.selectAllByExample(example);
|
||||||
|
for (TravelLocation location : locationList) {
|
||||||
|
delete(location.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package com.imyeyu.api.modules.journal.service.implement;
|
||||||
|
|
||||||
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
|
import com.imyeyu.api.modules.journal.entity.Travel;
|
||||||
|
import com.imyeyu.api.modules.journal.mapper.TravelMapper;
|
||||||
|
import com.imyeyu.api.modules.journal.service.TravelLocationService;
|
||||||
|
import com.imyeyu.api.modules.journal.service.TravelService;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旅行计划服务实现
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2025-12-12 14:45
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
|
||||||
|
public class TravelServiceImplement extends AbstractEntityService<Travel, Long> implements TravelService {
|
||||||
|
|
||||||
|
private final TravelMapper mapper;
|
||||||
|
private final TravelLocationService travelLocationService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BaseMapper<Travel, Long> mapper() {
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void update(Travel travel) {
|
||||||
|
// 使用 update 以允许设置 travelAt 和 days 为 null
|
||||||
|
mapper.update(travel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void delete(Long id) {
|
||||||
|
super.delete(id);
|
||||||
|
travelLocationService.deleteByTravelId(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package com.imyeyu.api.modules.journal.vo;
|
|
||||||
|
|
||||||
import com.imyeyu.api.modules.journal.entity.Journal;
|
|
||||||
import com.imyeyu.spring.bean.Page;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-10-09 18:48
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Valid
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class JournalPage extends Page<Journal> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2025-12-08 16:01
|
|
||||||
*/
|
|
||||||
public enum Type {
|
|
||||||
|
|
||||||
NORMAL,
|
|
||||||
|
|
||||||
PREVIEW
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private Type type;
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.imyeyu.api.modules.journal.vo;
|
package com.imyeyu.api.modules.journal.vo.journal;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.journal.entity.Journal;
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.imyeyu.api.modules.journal.vo;
|
package com.imyeyu.api.modules.journal.vo.journal;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.journal.entity.Journal;
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
import com.imyeyu.spring.annotation.table.Transient;
|
import com.imyeyu.spring.annotation.table.Transient;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.imyeyu.api.modules.journal.vo;
|
package com.imyeyu.api.modules.journal.vo.journal;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.journal.entity.Journal;
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.imyeyu.api.modules.journal.vo;
|
package com.imyeyu.api.modules.journal.vo.journal;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.journal.entity.Journal;
|
import com.imyeyu.api.modules.journal.entity.Journal;
|
||||||
import com.imyeyu.spring.annotation.table.Transient;
|
import com.imyeyu.spring.annotation.table.Transient;
|
||||||
@ -1,18 +1,17 @@
|
|||||||
package com.imyeyu.api.modules.lyric.service.implement;
|
package com.imyeyu.api.modules.lyric.service.implement;
|
||||||
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.entity.User;
|
import com.imyeyu.api.modules.common.entity.User;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.service.UserService;
|
import com.imyeyu.api.modules.common.service.UserService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.lyric.entity.LyricCorrect;
|
import com.imyeyu.api.modules.lyric.entity.LyricCorrect;
|
||||||
import com.imyeyu.api.modules.lyric.mapper.LyricCorrectMapper;
|
import com.imyeyu.api.modules.lyric.mapper.LyricCorrectMapper;
|
||||||
import com.imyeyu.api.modules.lyric.service.LyricCorrectService;
|
import com.imyeyu.api.modules.lyric.service.LyricCorrectService;
|
||||||
import com.imyeyu.api.modules.lyric.vo.LyricCorrectRequest;
|
import com.imyeyu.api.modules.lyric.vo.LyricCorrectRequest;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.TimiSpring;
|
import com.imyeyu.spring.TimiSpring;
|
||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.bean.PageResult;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
@ -76,7 +75,7 @@ public class LyricCorrectServiceImplement extends AbstractEntityService<LyricCor
|
|||||||
create(correct);
|
create(correct);
|
||||||
try {
|
try {
|
||||||
MultipartFile file = request.getFile();
|
MultipartFile file = request.getFile();
|
||||||
AttachmentRequest attachment = new AttachmentRequest();
|
Attachment attachment = new Attachment();
|
||||||
attachment.setBizType(Attachment.BizType.LYRIC);
|
attachment.setBizType(Attachment.BizType.LYRIC);
|
||||||
attachment.setBizId(correct.getId());
|
attachment.setBizId(correct.getId());
|
||||||
attachment.setName(correct.getId() + ".lrc");
|
attachment.setName(correct.getId() + ".lrc");
|
||||||
|
|||||||
@ -95,7 +95,7 @@ public class PlayerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
public List<MinecraftPlayer> listPlayer(@RequestHeader("Token") String token) {
|
public List<MinecraftPlayer> listPlayer(@RequestHeader("Token") String token) {
|
||||||
Long userId = TimiJava.firstNotNull(redis.get(token), userToken.getUserId(token));
|
Long userId = TimiJava.defaultIfNull(redis.get(token), userToken.getUserId(token));
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
throw new TimiException(TimiCode.RESULT_BAD).msgKey("token.illegal");
|
throw new TimiException(TimiCode.RESULT_BAD).msgKey("token.illegal");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
package com.imyeyu.api.modules.mirror;
|
package com.imyeyu.api.modules.mirror;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import com.imyeyu.api.TimiServerAPI;
|
import com.imyeyu.api.TimiServerAPI;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.mirror.entity.Mirror;
|
import com.imyeyu.api.modules.mirror.entity.Mirror;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ public abstract class AttachmentMirror extends AbstractMirror {
|
|||||||
* @return 新增附件
|
* @return 新增附件
|
||||||
* @throws Exception 处理异常
|
* @throws Exception 处理异常
|
||||||
*/
|
*/
|
||||||
protected abstract List<AttachmentRequest> diffAdd(List<Attachment> dbFiles) throws Exception;
|
protected abstract List<Attachment> diffAdd(List<Attachment> dbFiles) throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 差分移除附件
|
* 差分移除附件
|
||||||
@ -70,10 +69,10 @@ public abstract class AttachmentMirror extends AbstractMirror {
|
|||||||
attachmentService.destroy(diffRemoveList.get(i).getId());
|
attachmentService.destroy(diffRemoveList.get(i).getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AttachmentRequest> diffAddList = diffAdd(dbFiles);
|
List<Attachment> diffAddList = diffAdd(dbFiles);
|
||||||
syncAdded = diffAddList.size();
|
syncAdded = diffAddList.size();
|
||||||
for (int i = 0; i < diffAddList.size(); i++) {
|
for (int i = 0; i < diffAddList.size(); i++) {
|
||||||
AttachmentRequest request = diffAddList.get(i);
|
Attachment request = diffAddList.get(i);
|
||||||
request.setBizType(Attachment.BizType.MIRROR);
|
request.setBizType(Attachment.BizType.MIRROR);
|
||||||
request.setBizId(mirror.getId());
|
request.setBizId(mirror.getId());
|
||||||
attachmentService.create(request);
|
attachmentService.create(request);
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package com.imyeyu.api.modules.mirror;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.mirror.bean.AttachType;
|
import com.imyeyu.api.modules.mirror.bean.AttachType;
|
||||||
import com.imyeyu.api.modules.mirror.data.FabricAPI;
|
import com.imyeyu.api.modules.mirror.data.FabricAPI;
|
||||||
import com.imyeyu.api.modules.mirror.entity.Mirror;
|
import com.imyeyu.api.modules.mirror.entity.Mirror;
|
||||||
@ -106,10 +105,10 @@ public class FabricAPIMirror extends AttachmentMirror {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<AttachmentRequest> diffAdd(List<Attachment> dbFiles) throws Exception {
|
protected List<Attachment> diffAdd(List<Attachment> dbFiles) throws Exception {
|
||||||
Set<String> dbNameSet = dbFiles.stream().map(Attachment::getName).collect(Collectors.toSet());
|
Set<String> dbNameSet = dbFiles.stream().map(Attachment::getName).collect(Collectors.toSet());
|
||||||
|
|
||||||
List<AttachmentRequest> result = new ArrayList<>();
|
List<Attachment> result = new ArrayList<>();
|
||||||
for (Map.Entry<String, String> item : versionMap.entrySet()) {
|
for (Map.Entry<String, String> item : versionMap.entrySet()) {
|
||||||
String version = "%s+%s".formatted(item.getValue(), item.getKey());
|
String version = "%s+%s".formatted(item.getValue(), item.getKey());
|
||||||
String name = "fabric-api-%s.jar".formatted(version);
|
String name = "fabric-api-%s.jar".formatted(version);
|
||||||
@ -119,7 +118,7 @@ public class FabricAPIMirror extends AttachmentMirror {
|
|||||||
|
|
||||||
byte[] bytes = Request.get(url).viaProxy(proxy).execute().returnContent().asBytes();
|
byte[] bytes = Request.get(url).viaProxy(proxy).execute().returnContent().asBytes();
|
||||||
|
|
||||||
AttachmentRequest attachment = new AttachmentRequest();
|
Attachment attachment = new Attachment();
|
||||||
attachment.setAttachTypeValue(AttachType.FABRIC_API);
|
attachment.setAttachTypeValue(AttachType.FABRIC_API);
|
||||||
attachment.setName(name);
|
attachment.setName(name);
|
||||||
attachment.setSize((long) bytes.length);
|
attachment.setSize((long) bytes.length);
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package com.imyeyu.api.modules.mirror;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.mirror.bean.AttachType;
|
import com.imyeyu.api.modules.mirror.bean.AttachType;
|
||||||
import com.imyeyu.api.modules.mirror.data.OpenJDK;
|
import com.imyeyu.api.modules.mirror.data.OpenJDK;
|
||||||
import com.imyeyu.api.modules.mirror.entity.Mirror;
|
import com.imyeyu.api.modules.mirror.entity.Mirror;
|
||||||
@ -70,11 +69,11 @@ public class OpenJDKMirror extends AttachmentMirror {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<AttachmentRequest> diffAdd(List<Attachment> dbFiles) throws Exception {
|
protected List<Attachment> diffAdd(List<Attachment> dbFiles) throws Exception {
|
||||||
Map<String, OpenJDK> githubNameMap = githubMirrorResult.stream().collect(Collectors.toMap(OpenJDK::getName, item -> item));
|
Map<String, OpenJDK> githubNameMap = githubMirrorResult.stream().collect(Collectors.toMap(OpenJDK::getName, item -> item));
|
||||||
Set<String> dbNameSet = dbFiles.stream().map(Attachment::getName).collect(Collectors.toSet());
|
Set<String> dbNameSet = dbFiles.stream().map(Attachment::getName).collect(Collectors.toSet());
|
||||||
|
|
||||||
List<AttachmentRequest> result = new ArrayList<>();
|
List<Attachment> result = new ArrayList<>();
|
||||||
for (Map.Entry<String, OpenJDK> item : githubNameMap.entrySet()) {
|
for (Map.Entry<String, OpenJDK> item : githubNameMap.entrySet()) {
|
||||||
if (!dbNameSet.contains(item.getKey())) {
|
if (!dbNameSet.contains(item.getKey())) {
|
||||||
String url = item.getValue().getData();
|
String url = item.getValue().getData();
|
||||||
@ -82,7 +81,7 @@ public class OpenJDKMirror extends AttachmentMirror {
|
|||||||
|
|
||||||
byte[] bytes = Request.get(url).viaProxy(proxy).execute().returnContent().asBytes();
|
byte[] bytes = Request.get(url).viaProxy(proxy).execute().returnContent().asBytes();
|
||||||
|
|
||||||
AttachmentRequest attachment = new AttachmentRequest();
|
Attachment attachment = new Attachment();
|
||||||
attachment.setAttachTypeValue(AttachType.OPEN_JDK);
|
attachment.setAttachTypeValue(AttachType.OPEN_JDK);
|
||||||
attachment.setName(item.getKey());
|
attachment.setName(item.getKey());
|
||||||
attachment.setSize((long) bytes.length);
|
attachment.setSize((long) bytes.length);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.api.modules.system.controller;
|
package com.imyeyu.api.modules.system.controller;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
import com.imyeyu.api.modules.common.vo.attachment.AttachmentRequest;
|
|
||||||
import com.imyeyu.api.modules.system.bean.ServerStatus;
|
import com.imyeyu.api.modules.system.bean.ServerStatus;
|
||||||
import com.imyeyu.api.modules.system.service.SystemService;
|
import com.imyeyu.api.modules.system.service.SystemService;
|
||||||
import com.imyeyu.api.modules.system.vo.TempAttachRequest;
|
import com.imyeyu.api.modules.system.vo.TempAttachRequest;
|
||||||
@ -119,7 +119,7 @@ public class SystemController {
|
|||||||
for (MultipartFile file : request.getFile()) {
|
for (MultipartFile file : request.getFile()) {
|
||||||
byte[] bytes = IO.toBytes(file.getInputStream());
|
byte[] bytes = IO.toBytes(file.getInputStream());
|
||||||
|
|
||||||
AttachmentRequest attach = new AttachmentRequest();
|
Attachment attach = new Attachment();
|
||||||
attach.setName(file.getOriginalFilename());
|
attach.setName(file.getOriginalFilename());
|
||||||
attach.setBizType(request.getBizType());
|
attach.setBizType(request.getBizType());
|
||||||
attach.setBizId(request.getBizId());
|
attach.setBizId(request.getBizId());
|
||||||
|
|||||||
@ -145,7 +145,7 @@ public class AsyncTaskServiceImplement implements AsyncTaskService {
|
|||||||
for (int i = 0; i < taskList.size(); i++) {
|
for (int i = 0; i < taskList.size(); i++) {
|
||||||
AbstractAsyncTask task = taskList.get(i);
|
AbstractAsyncTask task = taskList.get(i);
|
||||||
task.setMessage(task.logBuffer.toString());
|
task.setMessage(task.logBuffer.toString());
|
||||||
task.setMessage(TimiJava.firstNotNull(task.getMessage(), ""));
|
task.setMessage(TimiJava.defaultIfNull(task.getMessage(), ""));
|
||||||
if (IOSize.KB * 4 < task.getMessage().length()) {
|
if (IOSize.KB * 4 < task.getMessage().length()) {
|
||||||
task.setMessage(task.getMessage().substring((int) (task.getMessage().length() - IOSize.KB * 4)));
|
task.setMessage(task.getMessage().substring((int) (task.getMessage().length() - IOSize.KB * 4)));
|
||||||
}
|
}
|
||||||
|
|||||||
677
src/main/resources/db.sql
Normal file
677
src/main/resources/db.sql
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
/*
|
||||||
|
Navicat Premium Dump SQL
|
||||||
|
|
||||||
|
Source Server : dev_mariadb
|
||||||
|
Source Server Type : MariaDB
|
||||||
|
Source Server Version : 110802 (11.8.2-MariaDB-ubu2404)
|
||||||
|
Source Host : vm.imyeyu.dev:3307
|
||||||
|
Source Schema : timi_server
|
||||||
|
|
||||||
|
Target Server Type : MariaDB
|
||||||
|
Target Server Version : 110802 (11.8.2-MariaDB-ubu2404)
|
||||||
|
File Encoding : 65001
|
||||||
|
|
||||||
|
Date: 12/12/2025 14:24:29
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for article
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `article`;
|
||||||
|
CREATE TABLE `article` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`title` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题',
|
||||||
|
`type` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '类型',
|
||||||
|
`digest` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '摘要',
|
||||||
|
`data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '数据',
|
||||||
|
`extend_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '扩展数据 JSON' CHECK (json_valid(`extend_data`)),
|
||||||
|
`reads` int(11) NULL DEFAULT 0 COMMENT '阅读',
|
||||||
|
`likes` int(11) NULL DEFAULT 0 COMMENT '喜欢',
|
||||||
|
`show_comment` tinyint(1) NULL DEFAULT 1 COMMENT '1 为显示历史评论',
|
||||||
|
`can_comment` tinyint(1) NULL DEFAULT 1 COMMENT '1 为允许评论',
|
||||||
|
`can_ranking` tinyint(1) NULL DEFAULT 1 COMMENT '1 为允许进入每周排行列表',
|
||||||
|
`can_list` tinyint(1) NULL DEFAULT NULL COMMENT '1 为允许通过列表查询',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 128 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文章' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for async_task
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `async_task`;
|
||||||
|
CREATE TABLE `async_task` (
|
||||||
|
`uuid` varchar(38) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`message` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`status` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`progress` double NULL DEFAULT NULL,
|
||||||
|
`start_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`interrupt_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`error_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`died_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`can_pause` tinyint(1) NULL DEFAULT NULL,
|
||||||
|
`can_interrupt` tinyint(1) NULL DEFAULT NULL,
|
||||||
|
`is_periodical` tinyint(1) NULL DEFAULT NULL,
|
||||||
|
`cron` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`uuid`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for attachment
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `attachment`;
|
||||||
|
CREATE TABLE `attachment` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`biz_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`biz_id` bigint(20) NOT NULL,
|
||||||
|
`attach_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`mongo_id` varchar(24) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`title` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`mime_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`size` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`md5` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`ext` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`created_at` bigint(20) NOT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`destroy_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 530 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '附件' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for bill
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `bill`;
|
||||||
|
CREATE TABLE `bill` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`revenue_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收入类型',
|
||||||
|
`expenditure_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '支出类型',
|
||||||
|
`description` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '说明',
|
||||||
|
`remarks` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
|
`decimal` bigint(20) NOT NULL DEFAULT 0 COMMENT '金额(放大了 100 倍)',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 3687 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消费账单' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for comment
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `comment`;
|
||||||
|
CREATE TABLE `comment` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`biz_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '关联业务',
|
||||||
|
`biz_id` bigint(20) NOT NULL COMMENT '关联业务 ID',
|
||||||
|
`user_id` bigint(20) NULL DEFAULT NULL COMMENT '评论者',
|
||||||
|
`nick` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '评论者昵称',
|
||||||
|
`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '内容',
|
||||||
|
`ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 69 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for comment_remind_queue
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `comment_remind_queue`;
|
||||||
|
CREATE TABLE `comment_remind_queue` (
|
||||||
|
`uuid` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'UUID',
|
||||||
|
`user_id` bigint(20) NOT NULL COMMENT '被回复用户 ID',
|
||||||
|
`reply_id` bigint(20) NOT NULL COMMENT '回复 ID',
|
||||||
|
PRIMARY KEY (`uuid`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论回复提醒队列,被回复用户是注册用户并且开启邮件推送时,缓存在本表,由邮件推送服务操作' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for comment_reply
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `comment_reply`;
|
||||||
|
CREATE TABLE `comment_reply` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`comment_id` bigint(20) NOT NULL,
|
||||||
|
`reply_id` bigint(20) NULL DEFAULT NULL COMMENT '被回复的回复,回复主评论时为 NULL',
|
||||||
|
`sender_id` bigint(20) NULL DEFAULT NULL COMMENT '回复者',
|
||||||
|
`receiver_id` bigint(20) NULL DEFAULT NULL COMMENT '被回复者',
|
||||||
|
`sender_nick` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '回复者昵称',
|
||||||
|
`receiver_nick` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '被回复者昵称',
|
||||||
|
`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '内容',
|
||||||
|
`ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '回复时 IP',
|
||||||
|
`ignored_at` bigint(20) NULL DEFAULT NULL COMMENT '被回复者忽略该回复的时间',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 38 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论回复' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for comment_reply_record
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `comment_reply_record`;
|
||||||
|
CREATE TABLE `comment_reply_record` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` bigint(20) NOT NULL COMMENT '用户 ID',
|
||||||
|
`reply_id` bigint(20) NOT NULL COMMENT '回复 ID',
|
||||||
|
`created_at` bigint(20) NOT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论回复记录(显示在个人空间\"回复我的\"),因“仅删除回复记录不删除实体回复”功能而作此表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for email_filter
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `email_filter`;
|
||||||
|
CREATE TABLE `email_filter` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`email` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`from` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '通过邮件直接拒绝系统发送的列表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for email_queue
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `email_queue`;
|
||||||
|
CREATE TABLE `email_queue` (
|
||||||
|
`uuid` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'UUID',
|
||||||
|
`biz_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'EmailType 推送类型',
|
||||||
|
`biz_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '推送数据 ID',
|
||||||
|
`send_at` bigint(20) NOT NULL DEFAULT 0 COMMENT '推送时间',
|
||||||
|
PRIMARY KEY (`uuid`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件推送队列' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for email_queue_log
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `email_queue_log`;
|
||||||
|
CREATE TABLE `email_queue_log` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`uuid` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '队列 UUID',
|
||||||
|
`biz_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'EmailType 类型',
|
||||||
|
`biz_id` bigint(20) NULL DEFAULT NULL COMMENT '数据 ID',
|
||||||
|
`send_to` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '目标',
|
||||||
|
`send_at` bigint(20) NULL DEFAULT NULL COMMENT '时间',
|
||||||
|
`is_sent` tinyint(4) NULL DEFAULT NULL COMMENT '1 为成功',
|
||||||
|
`exception_msg` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '异常信息',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件推送队列日志' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for feedback
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `feedback`;
|
||||||
|
CREATE TABLE `feedback` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`from` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '来自',
|
||||||
|
`email` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系邮箱',
|
||||||
|
`data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '内容',
|
||||||
|
`ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'IP',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '反馈' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for friend
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `friend`;
|
||||||
|
CREATE TABLE `friend` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`icon` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '图标 Base64',
|
||||||
|
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题',
|
||||||
|
`link` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '链接',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '友链' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for git_issue
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `git_issue`;
|
||||||
|
CREATE TABLE `git_issue` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`repository_id` bigint(20) NOT NULL COMMENT '所属仓库 ID',
|
||||||
|
`publisher_id` bigint(20) NULL DEFAULT NULL COMMENT '所属用户 ID',
|
||||||
|
`publisher_nick` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '游客昵称',
|
||||||
|
`type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '类型',
|
||||||
|
`version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '版本',
|
||||||
|
`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题',
|
||||||
|
`description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '说明',
|
||||||
|
`status` varbinary(50) NULL DEFAULT NULL COMMENT '状态',
|
||||||
|
`confirmed_at` bigint(20) NULL DEFAULT NULL COMMENT '确认时间',
|
||||||
|
`develop_at` bigint(20) NULL DEFAULT NULL COMMENT '开发时间',
|
||||||
|
`closed_at` bigint(20) NULL DEFAULT NULL COMMENT '关闭时间',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Git 问题报告' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for git_merge
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `git_merge`;
|
||||||
|
CREATE TABLE `git_merge` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`repository_id` bigint(20) NOT NULL COMMENT '所属仓库 ID',
|
||||||
|
`requester_id` bigint(20) NOT NULL COMMENT '请求用户 ID',
|
||||||
|
`issue_id` bigint(20) NULL DEFAULT NULL COMMENT '相关反馈 ID',
|
||||||
|
`type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '类型',
|
||||||
|
`from_branch` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '来源分支',
|
||||||
|
`to_branch` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '去向分支',
|
||||||
|
`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题',
|
||||||
|
`description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '说明',
|
||||||
|
`checked_at` bigint(20) NULL DEFAULT NULL COMMENT '通过审查时间',
|
||||||
|
`merged_at` bigint(20) NULL DEFAULT NULL COMMENT '合并时间',
|
||||||
|
`rejected_at` bigint(20) NULL DEFAULT NULL COMMENT '拒绝时间',
|
||||||
|
`reject_reason` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '拒绝原因',
|
||||||
|
`closed_at` bigint(20) NULL DEFAULT NULL COMMENT '关闭时间',
|
||||||
|
`status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '状态',
|
||||||
|
`created_at` bigint(20) NOT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Git 合并申请' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for git_release
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `git_release`;
|
||||||
|
CREATE TABLE `git_release` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`repository_id` bigint(20) NOT NULL COMMENT '所属仓库 ID',
|
||||||
|
`version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '版本',
|
||||||
|
`description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '说明',
|
||||||
|
`sha1` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '版本 SHA1',
|
||||||
|
`commits` int(11) NOT NULL DEFAULT 0 COMMENT '此版本后提交次数',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Git 版本发布' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for icon
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `icon`;
|
||||||
|
CREATE TABLE `icon` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`unicode` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`svg` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 150 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字体图标' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for journal
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `journal`;
|
||||||
|
CREATE TABLE `journal` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`idea` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`lat` double NULL DEFAULT NULL,
|
||||||
|
`lng` double NULL DEFAULT NULL,
|
||||||
|
`location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`weather` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`pusher` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 48 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for lyric
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `lyric`;
|
||||||
|
CREATE TABLE `lyric` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`song` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '歌曲名',
|
||||||
|
`singer` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '演唱',
|
||||||
|
`data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '歌词',
|
||||||
|
`citations` bigint(20) NOT NULL DEFAULT 0 COMMENT '被引用次数,更新者不为空时开始计数',
|
||||||
|
`updated_by` bigint(20) NULL DEFAULT NULL COMMENT '更新者 ID',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '歌词' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for lyric_corrects
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `lyric_corrects`;
|
||||||
|
CREATE TABLE `lyric_corrects` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`lyric_id` bigint(20) NULL DEFAULT NULL COMMENT '申请更新歌词 ID',
|
||||||
|
`song` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '歌曲名',
|
||||||
|
`singer` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '演唱',
|
||||||
|
`data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '歌词',
|
||||||
|
`request_by` bigint(20) NULL DEFAULT NULL COMMENT '申请人',
|
||||||
|
`request_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '申请人 IP',
|
||||||
|
`cancel_at` bigint(20) NULL DEFAULT NULL COMMENT '取消时间',
|
||||||
|
`approval_at` bigint(20) NULL DEFAULT NULL COMMENT '通过时间',
|
||||||
|
`reject_at` bigint(20) NULL DEFAULT NULL COMMENT '拒绝时间',
|
||||||
|
`reject_reason` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '拒绝原因',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '歌词更新申请' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for minecraft_pack
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `minecraft_pack`;
|
||||||
|
CREATE TABLE `minecraft_pack` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '游戏 ID',
|
||||||
|
`ver` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '整合包版本',
|
||||||
|
`title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '标题',
|
||||||
|
`description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '简介',
|
||||||
|
`game_ver` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '游戏版本',
|
||||||
|
`def_option` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '默认配置',
|
||||||
|
`size` bigint(20) NOT NULL DEFAULT 0 COMMENT '文件大小',
|
||||||
|
`is_deprecated` tinyint(4) NOT NULL DEFAULT 0 COMMENT 'true 为已过时',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Minecraft 客户端列表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for minecraft_pack_source
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `minecraft_pack_source`;
|
||||||
|
CREATE TABLE `minecraft_pack_source` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`pack_id` bigint(20) NOT NULL COMMENT '整合版 ID',
|
||||||
|
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '数据源名称',
|
||||||
|
`type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '数据类型',
|
||||||
|
`data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '数据',
|
||||||
|
`order` int(11) NOT NULL DEFAULT 0 COMMENT '排序',
|
||||||
|
`is_default` tinyint(4) NOT NULL DEFAULT 0 COMMENT 'true 为默认',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Minecraft 客户端下载源' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for minecraft_player
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `minecraft_player`;
|
||||||
|
CREATE TABLE `minecraft_player` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` bigint(20) NOT NULL COMMENT '关联 User.id',
|
||||||
|
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '游戏名',
|
||||||
|
`last_login_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '最近登录 IP',
|
||||||
|
`last_login_at` bigint(20) NULL DEFAULT NULL COMMENT '最近登录',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`, `user_id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Minecraft 玩家' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for mirror
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `mirror`;
|
||||||
|
CREATE TABLE `mirror` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`bean` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '执行类',
|
||||||
|
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '名称',
|
||||||
|
`data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '镜像数据',
|
||||||
|
`period` int(11) NOT NULL COMMENT '周期(分钟)',
|
||||||
|
`last_sync_at` bigint(20) NULL DEFAULT NULL COMMENT '最近同步时间',
|
||||||
|
`is_enable` tinyint(4) NOT NULL DEFAULT 0 COMMENT 'true 为启用同步',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '镜像' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for multilingual
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `multilingual`;
|
||||||
|
CREATE TABLE `multilingual` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`key` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`zh_cn` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`zh_tw` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`en_us` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`ru_ru` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`ja_jp` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`de_de` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`ko_kr` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 795 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '多语言映射' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for setting
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `setting`;
|
||||||
|
CREATE TABLE `setting` (
|
||||||
|
`key` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`description` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`is_private` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`key`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统配置' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for tag
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `tag`;
|
||||||
|
CREATE TABLE `tag` (
|
||||||
|
`id` bigint(20) NOT NULL,
|
||||||
|
`biz_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`biz_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for task
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `task`;
|
||||||
|
CREATE TABLE `task` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '名称',
|
||||||
|
`digest` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '摘要',
|
||||||
|
`status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '状态',
|
||||||
|
`is_public` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'true 为公开',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '任务列表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for task_detail
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `task_detail`;
|
||||||
|
CREATE TABLE `task_detail` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`task_id` bigint(20) NOT NULL,
|
||||||
|
`type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '类型',
|
||||||
|
`status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务状态',
|
||||||
|
`digest` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '摘要',
|
||||||
|
`description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '附加说明',
|
||||||
|
`complete_at` bigint(20) NULL DEFAULT NULL COMMENT '完成时间',
|
||||||
|
`close_at` bigint(20) NULL DEFAULT NULL COMMENT '关闭时间',
|
||||||
|
`close_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关闭原因',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '任务详细列表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for template
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `template`;
|
||||||
|
CREATE TABLE `template` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`biz_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`biz_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '模板' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for travel
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `travel`;
|
||||||
|
CREATE TABLE `travel` (
|
||||||
|
`id` bigint(20) NOT NULL,
|
||||||
|
`transportation_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '交通类型',
|
||||||
|
`title` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题',
|
||||||
|
`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '内容',
|
||||||
|
`travel_at` bigint(20) NULL DEFAULT NULL COMMENT '出行时间',
|
||||||
|
`days` int(11) NULL DEFAULT NULL COMMENT '天数',
|
||||||
|
`status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '状态',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '旅行计划' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for travel_location
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `travel_location`;
|
||||||
|
CREATE TABLE `travel_location` (
|
||||||
|
`id` bigint(20) NOT NULL,
|
||||||
|
`travel_id` bigint(20) NOT NULL COMMENT '旅行计划 ID',
|
||||||
|
`type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '类型',
|
||||||
|
`title` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标题',
|
||||||
|
`description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '说明',
|
||||||
|
`lat` double NULL DEFAULT NULL COMMENT '经度',
|
||||||
|
`lng` double NULL DEFAULT NULL COMMENT '维度',
|
||||||
|
`location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '位置',
|
||||||
|
`amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '费用',
|
||||||
|
`require_id_card` tinyint(4) NULL DEFAULT NULL COMMENT '1 为需要身份证',
|
||||||
|
`score` int(11) NULL DEFAULT NULL COMMENT '必要评分',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '旅行地点' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for user
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `user`;
|
||||||
|
CREATE TABLE `user` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名',
|
||||||
|
`password` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密码摘要',
|
||||||
|
`email` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮箱',
|
||||||
|
`email_verify_at` bigint(20) NULL DEFAULT NULL COMMENT '邮箱验证时间',
|
||||||
|
`unmute_at` bigint(20) NULL DEFAULT NULL COMMENT '解除禁言时间',
|
||||||
|
`unban_at` bigint(20) NULL DEFAULT NULL COMMENT '解除封禁时间',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for user_config
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `user_config`;
|
||||||
|
CREATE TABLE `user_config` (
|
||||||
|
`user_id` bigint(20) NOT NULL,
|
||||||
|
`email_reply_remind` tinyint(1) NOT NULL DEFAULT 1 COMMENT '1 为邮箱接收回复提醒',
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL COMMENT '配置更新时间',
|
||||||
|
PRIMARY KEY (`user_id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户配置' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for user_privacy
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `user_privacy`;
|
||||||
|
CREATE TABLE `user_privacy` (
|
||||||
|
`user_id` bigint(20) NOT NULL,
|
||||||
|
`email` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`sex` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`birthdate` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`qq` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`last_login_at` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`created_at` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`user_id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户隐私控制,user_id 关联用户,updated_at 为本表更新时间,其他字段 1 为公开,0 为不公开' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for user_profile
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `user_profile`;
|
||||||
|
CREATE TABLE `user_profile` (
|
||||||
|
`user_id` bigint(20) NOT NULL COMMENT '用户 ID',
|
||||||
|
`wrapper_type` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'PIXELATED' COMMENT '背景图渲染算法',
|
||||||
|
`avatar_type` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'PIXELATED' COMMENT '头像渲染算法',
|
||||||
|
`exp` int(11) NOT NULL DEFAULT 0 COMMENT '经验值',
|
||||||
|
`sex` int(11) NULL DEFAULT NULL COMMENT '性别:0 女,1 男',
|
||||||
|
`birthdate` bigint(20) NULL DEFAULT NULL COMMENT '出生日期',
|
||||||
|
`qq` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'QQ',
|
||||||
|
`description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '说明',
|
||||||
|
`last_login_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '上次登录 IP',
|
||||||
|
`last_login_at` bigint(20) NULL DEFAULT NULL COMMENT '上次登录时间',
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`user_id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户资料' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for version
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `version`;
|
||||||
|
CREATE TABLE `version` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '名称',
|
||||||
|
`version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '版本',
|
||||||
|
`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新摘要',
|
||||||
|
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新地址',
|
||||||
|
`created_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`updated_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
`deleted_at` bigint(20) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '软件版本管理' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<select id="countByPage" resultType="long">
|
<select id="countByPage" resultType="long">
|
||||||
SELECT COUNT(1) <include refid="normalCondition" />
|
SELECT COUNT(1) <include refid="normalCondition" />
|
||||||
</select>
|
</select>
|
||||||
<select id="listByPage" resultType="com.imyeyu.api.modules.blog.entity.Article">
|
<select id="selectByPage" resultType="com.imyeyu.api.modules.blog.entity.Article">
|
||||||
SELECT
|
SELECT
|
||||||
<include refid="listColumn" />
|
<include refid="listColumn" />
|
||||||
<include refid="normalCondition" />
|
<include refid="normalCondition" />
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<mapper namespace="com.imyeyu.api.modules.common.mapper.CommentMapper">
|
<mapper namespace="com.imyeyu.api.modules.common.mapper.CommentMapper">
|
||||||
<sql id="table">comment</sql>
|
<sql id="table">comment</sql>
|
||||||
<!-- 主评论 -->
|
<!-- 主评论 -->
|
||||||
<select id="list" resultMap="listResult">
|
<select id="selectByPage" resultMap="selectResult">
|
||||||
SELECT
|
SELECT
|
||||||
-- 主评论
|
-- 主评论
|
||||||
comment.id,
|
comment.id,
|
||||||
@ -77,7 +77,7 @@
|
|||||||
ON
|
ON
|
||||||
reply_count.id = comment.id
|
reply_count.id = comment.id
|
||||||
</select>
|
</select>
|
||||||
<resultMap id="listResult" type="com.imyeyu.api.modules.common.vo.comment.CommentView">
|
<resultMap id="selectResult" type="com.imyeyu.api.modules.common.vo.comment.CommentView">
|
||||||
<id property="id" column="id" />
|
<id property="id" column="id" />
|
||||||
<result property="userId" column="user_id" />
|
<result property="userId" column="user_id" />
|
||||||
<result property="nick" column="nick" />
|
<result property="nick" column="nick" />
|
||||||
@ -96,7 +96,7 @@
|
|||||||
<result property="createdAt" column="reply_created_at" />
|
<result property="createdAt" column="reply_created_at" />
|
||||||
</collection>
|
</collection>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<select id="countAll" resultType="long">
|
<select id="countByPage" resultType="long">
|
||||||
SELECT
|
SELECT
|
||||||
SUM(result.total_comment + result.total_reply)
|
SUM(result.total_comment + result.total_reply)
|
||||||
FROM (
|
FROM (
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
<resultMap id="listByRepositoryIdResult" type="com.imyeyu.api.modules.git.vo.release.ReleaseView" autoMapping="true">
|
<resultMap id="listByRepositoryIdResult" type="com.imyeyu.api.modules.git.vo.release.ReleaseView" autoMapping="true">
|
||||||
<id property="id" column="id" />
|
<id property="id" column="id" />
|
||||||
<!-- 关联附件 -->
|
<!-- 关联附件 -->
|
||||||
<collection property="attachmentList" ofType="com.imyeyu.api.modules.common.vo.attachment.AttachmentView">
|
<collection property="attachmentList" ofType="com.imyeyu.api.modules.common.entity.Attachment">
|
||||||
<id property="id" column="attachmentId" />
|
<id property="id" column="attachmentId" />
|
||||||
<result property="bizType" column="biz_type" />
|
<result property="bizType" column="biz_type" />
|
||||||
<result property="bizId" column="biz_id" />
|
<result property="bizId" column="biz_id" />
|
||||||
|
|||||||
20
src/main/resources/mapper/journal/TravelLocationMapper.xml
Normal file
20
src/main/resources/mapper/journal/TravelLocationMapper.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
<mapper namespace="com.imyeyu.api.modules.journal.mapper.TravelLocationMapper">
|
||||||
|
<sql id="table">travel_location</sql>
|
||||||
|
<select id="listByIds" resultType="com.imyeyu.api.modules.journal.entity.TravelLocation">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
<include refid="table" />
|
||||||
|
WHERE
|
||||||
|
1 = 1
|
||||||
|
<if test="ids != null and 0 < ids.length">
|
||||||
|
AND `id` IN
|
||||||
|
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
Reference in New Issue
Block a user