前后端代码提交

main
Vks 3 weeks ago
parent e0edf15b42
commit 33f17306cc

@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.vksfeng</groupId>
<artifactId>quan</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>quan</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<modules>
<module>quan-common</module>
<module>quan-server</module>
<module>quan-gateway</module>
</modules>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
<spring-boot.version>3.4.2</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- 子模块中的自定义公共模块 -->
<dependency>
<groupId>com.vksfeng</groupId>
<artifactId>quan-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- MyBatis Spring Boot Starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
<!-- Spring Boot Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.1.0</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Jackson Databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.2</version>
</dependency>
<!-- JJWT API -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<!-- 处理java对象和xml之间转换。发现在jjwt中需要 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- 接口文档 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.5</version>
</dependency>
<!-- 集成redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.4.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.3.2.RELEASE</version>
</dependency>
<!-- 工具类 -->
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.36</version>
</dependency>
<!-- Email 支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>3.4.3</version>
</dependency>
<!-- 验证码生成工具 -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.minio/minio -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.17</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-websocket</artifactId>-->
<!-- <version>3.4.2</version>-->
<!-- </dependency>-->
<!-- 阿里云oss及一些java9以上版本需要安装的依赖 -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.vksfeng</groupId>
<artifactId>quan</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>quan-common</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 用于json的序列化 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
<!-- 阿里云oss及一些java9以上版本需要安装的依赖 -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,10 @@
package com.vksfeng.quan.constant;
public class AchievementConstant {
public static final String OBJECTIVE_ADDED = "OBJECTIVE_ADDED";
public static final String OBJECTIVE_COMPLETED = "OBJECTIVE_COMPLETED";
public static final String TASK_ADDED = "TASK_ADDED";
public static final String TASK_COMPLETED = "TASK_COMPLETED";
public static final String RESOURCE_SHARED = "RESOURCE_SHARED"; // 这里的一个小问题是,评论和资源分享都应该能触发
public static final String FRIEND_ADDED = "FRIEND_ADDED";
}

@ -0,0 +1,13 @@
package com.vksfeng.quan.constant;
public class RedisConstant {
public static final String USER_LOCATION_KEY = "quan:geo:users";
public static final String ACHIEVEMENT_STREAM_KEY = "quan:achievement_stream";
public static final String PROMPT_TEMPLATE_KEY = "quan:prompt:template";
public static final String PROMPT_DOMAIN_LIST_KEY = "quan:prompt:domains";
}

@ -0,0 +1,15 @@
package com.vksfeng.quan.context;
public class BaseContext {
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id) {
threadLocal.set(id);
}
public static Long getCurrentId() { return threadLocal.get(); }
public static void removeCurrentId() {
threadLocal.remove();
}
}

@ -0,0 +1,10 @@
package com.vksfeng.quan.exception;
public class BaseException extends RuntimeException{
BaseException() { }
BaseException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class DuplicateLikeException extends BaseException {
public DuplicateLikeException() {
super();
}
public DuplicateLikeException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class EmailExistsException extends BaseException{
public EmailExistsException() {
}
public EmailExistsException(String msg) {
super(msg);
}
}

@ -0,0 +1,13 @@
package com.vksfeng.quan.exception;
public class FavoriteAlreadyExistException extends BaseException {
public FavoriteAlreadyExistException() {
}
public FavoriteAlreadyExistException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class FeedNotExistException extends BaseException{
public FeedNotExistException() {
}
public FeedNotExistException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class FriendshipAlreadyExistException extends BaseException{
public FriendshipAlreadyExistException() {
super();
}
public FriendshipAlreadyExistException(String msg) {
super(msg);
}
}

@ -0,0 +1,12 @@
package com.vksfeng.quan.exception;
public class FriendshipNotExistException extends BaseException{
public FriendshipNotExistException() {
super("好友关系不存在");
}
public FriendshipNotExistException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class LikeAlreadyExistException extends BaseException{
public LikeAlreadyExistException() {
super("点赞已存在");
}
public LikeAlreadyExistException(String msg) {
super(msg);
}
}

@ -0,0 +1,12 @@
package com.vksfeng.quan.exception;
public class NotLoginException extends BaseException{
public NotLoginException() {
}
public NotLoginException(String msg) {
super(msg);
}
}

@ -0,0 +1,9 @@
package com.vksfeng.quan.exception;
public class ObjectiveCreationFailureException extends BaseException{
public ObjectiveCreationFailureException() {
}
public ObjectiveCreationFailureException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class PasswordErrorException extends BaseException{
public PasswordErrorException() {
}
public PasswordErrorException(String msg) {
super(msg);
}
}

@ -0,0 +1,10 @@
package com.vksfeng.quan.exception;
public class TaskNotExistException extends BaseException{
public TaskNotExistException() {
}
public TaskNotExistException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class UnknownException extends BaseException{
public UnknownException() {
}
public UnknownException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class UnknownTaskTypeException extends BaseException{
public UnknownTaskTypeException() {
}
public UnknownTaskTypeException(String msg) {
super(msg);
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.exception;
public class UserNotExistsException extends BaseException{
public UserNotExistsException(){
}
public UserNotExistsException(String msg) {
super(msg);
}
}

@ -0,0 +1,12 @@
package com.vksfeng.quan.exception;
public class UsernameExistsException extends BaseException{
public UsernameExistsException() {
}
public UsernameExistsException(String msg) {
super(msg);
}
}

@ -0,0 +1,15 @@
package com.vksfeng.quan.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "quan.alioss")
@Data
public class AliOSSProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}

@ -0,0 +1,16 @@
package com.vksfeng.quan.result;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult {
private Integer totalPage;
private Integer total;
private List list;
}

@ -0,0 +1,45 @@
package com.vksfeng.quan.result;
import lombok.Data;
import java.io.Serializable;
/**
*
* @param <T>
*/
@Data
public class Result<T> implements Serializable {
private Integer code; // 编码1成功0和其他数字为失败
private String msg; // 信息
private T data; // 数据
public static <T> Result<T> success() {
Result<T> result = new Result<T>();
result.code = 1;
return result;
}
public static <T> Result<T> success(String msg) {
Result<T> result = new Result<T>();
result.msg = msg;
result.code = 1;
return result;
}
public static <T> Result<T> success(T object) {
Result<T> result = new Result<T>();
result.data = object;
result.code = 1;
return result;
}
public static <T> Result<T> error(String msg) {
Result result = new Result();
result.msg = msg;
result.code = 0;
return result;
}
}

@ -0,0 +1,70 @@
package com.vksfeng.quan.util;
import com.aliyun.oss.*;
import com.vksfeng.quan.properties.AliOSSProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
@Data
@AllArgsConstructor
@Slf4j
public class AliOSSUtils {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
/**
*
*
* @param bytes
* @param objectName
* @return
*/
public String upload(byte[] bytes, String objectName) {
OSS ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
try {
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
//文件访问路径规则 https://BucketName.Endpoint/ObjectName
StringBuilder stringBuilder = new StringBuilder("https://");
stringBuilder
.append(bucketName)
.append(".")
.append(endpoint)
.append("/")
.append(objectName);
log.info("文件上传到:{}", stringBuilder.toString());
return stringBuilder.toString();
}
}

@ -0,0 +1,59 @@
package com.vksfeng.quan.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
public class JwtUtils {
/**
* jwt
* 使HS256
*
* @param secretKey jwt
* @param ttlMillis jwt()
* @param claims
* @return
*/
public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
// 指定签名的时候使用的签名算法也就是header那部分
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
// 生成JWT的时间
long expMillis = System.currentTimeMillis() + ttlMillis;
Date exp = new Date(expMillis);
// 设置jwt的body
JwtBuilder builder = Jwts.builder()
// 如果有私有声明,一定要先设置这个自己创建的私有的声明
// 这个是给builder的claim赋值一旦写在标准的声明赋值之后就会覆盖了那些标准的声明
.setClaims(claims)
// 设置签名使用的签名算法和签名使用的秘钥
.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
// 设置过期时间
.setExpiration(exp);
return builder.compact();
}
/**
* Token
*
* @param secretKey jwt , , sign,
* @param token token
* @return
*/
public static Claims parseJWT(String secretKey, String token) {
// 得到DefaultJwtParser
Claims claims = Jwts.parser()
// 设置签名的秘钥
.setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
// 设置需要解析的jwt
.parseClaimsJws(token).getBody();
return claims;
}
}

@ -0,0 +1,88 @@
//package com.vksfeng.quan.util;
//
//import cn.hutool.core.date.DateUtil;
//import cn.hutool.core.io.FileUtil;
//import cn.hutool.core.util.IdUtil;
//import io.minio.*;
//import io.minio.errors.*;
//import io.minio.http.Method;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.tomcat.util.http.fileupload.FileUploadException;
//import org.springframework.stereotype.Component;
//import org.springframework.web.multipart.MultipartFile;
//
//import java.io.IOException;
//import java.security.InvalidKeyException;
//import java.security.NoSuchAlgorithmException;
//import java.time.LocalDateTime;
//import java.util.concurrent.TimeUnit;
//
//
//
//@Slf4j
//@Component
//public class MinioUtils {
//
// private final MinioClient minioClient;
// private final String bucketName;
//
// public MinioUtils(MinioClient minioClient, String bucketName) {
// this.minioClient = minioClient;
// this.bucketName = bucketName;
// }
//
// private final int presignedUrlExpireDay = 7;
//
// public String uploadFile(MultipartFile file) throws FileUploadException {
// try {
// String objectId = generateFileName(file);
// uploadToMinio(file, objectId);
// String url = generatePresignedUrl(objectId);
// if (url == null || url.isEmpty()) {
// throw new FileUploadException("文件上传成功但无法生成 URL");
// }
// return url;
// } catch (Exception e) {
// log.error("MinIO 文件上传失败", e);
// throw new FileUploadException("文件上传失败", e);
// }
// }
//
// private String generateFileName(MultipartFile file) {
// String originalFilename = file.getOriginalFilename();
// String suffix = (originalFilename != null) ? FileUtil.getSuffix(originalFilename) : "";
// suffix = suffix.isEmpty() ? "bin" : suffix;
// String uuid = IdUtil.simpleUUID();
// return DateUtil.format(LocalDateTime.now(), "yyyy/MM/dd") + "/" + uuid + "." + suffix;
// }
//
// private void uploadToMinio(MultipartFile file, String objectId) throws IOException, MinioException, NoSuchAlgorithmException, InvalidKeyException {
// try {
// PutObjectArgs putArgs = PutObjectArgs.builder()
// .bucket(bucketName)
// .object(objectId)
// .contentType(file.getContentType())
// .stream(file.getInputStream(), file.getSize(), -1)
// .build();
// minioClient.putObject(putArgs);
// } catch (Exception e) {
//// throw new MinioException();
// throw e;
// }
// }
//
// private String generatePresignedUrl(String objectId) throws MinioException, IOException, NoSuchAlgorithmException, InvalidKeyException {
// try {
// GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
// .bucket(bucketName)
// .object(objectId)
// .method(Method.GET)
// .expiry(presignedUrlExpireDay, TimeUnit.DAYS)
// .build();
// return minioClient.getPresignedObjectUrl(args);
// } catch (Exception e) {
// throw e;
//// throw new MinioException();
// }
// }
//}

@ -0,0 +1,22 @@
package com.vksfeng.quan.util;
public abstract class RegexPatterns {
/**
*
*/
public static final String PHONE_REGEX = "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";
/**
*
*/
public static final String EMAIL_REGEX = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
/**
* 4~32线
*/
public static final String PASSWORD_REGEX = "^\\w{4,32}$";
/**
* , 6
*/
public static final String VERIFY_CODE_REGEX = "^[a-zA-Z\\d]{6}$";
}

@ -0,0 +1,41 @@
package com.vksfeng.quan.util;
import cn.hutool.core.util.StrUtil;
public class RegexUtils {
/**
*
* @param phone
* @return true:false
*/
public static boolean isPhoneValid(String phone){
return match(phone, RegexPatterns.PHONE_REGEX);
}
/**
*
* @param email
* @return true:false
*/
public static boolean isEmailValid(String email){
return match(email, RegexPatterns.EMAIL_REGEX);
}
/**
*
* @param code
* @return true:false
*/
public static boolean isCodeValid(String code){
return match(code, RegexPatterns.VERIFY_CODE_REGEX);
}
public static boolean isPasswordValid(String password){ return match(password, RegexPatterns.PASSWORD_REGEX); }
// 校验是否不符合正则格式
private static boolean match(String str, String regex){
if (StrUtil.isBlank(str)) {
return false;
}
return str.matches(regex);
}
}

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.vksfeng</groupId>
<artifactId>quan</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>quan-gateway</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

@ -0,0 +1,7 @@
package com.vksfeng;
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.vksfeng</groupId>
<artifactId>quan</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>quan-server</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.vksfeng</groupId>
<artifactId>quan-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 用于json的序列化 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<!-- jwt 用于鉴权系统 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 集成redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,17 @@
package com.vksfeng.quan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableConfigurationProperties
@EnableScheduling
public class QuanApplication {
public static void main(String[] args) {
SpringApplication.run(QuanApplication.class, args);
}
}

@ -0,0 +1,31 @@
package com.vksfeng.quan.achievement.controller;
import com.vksfeng.quan.achievement.pojo.dto.AchievementDTO;
import com.vksfeng.quan.achievement.pojo.vo.UserAchievementVO;
import com.vksfeng.quan.achievement.service.AchievementService;
import com.vksfeng.quan.result.Result;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/achievement")
public class AchievementController {
@Autowired
private AchievementService achievementService;
@Operation(summary = "获取用户成就")
@GetMapping
public Result<List<UserAchievementVO>> getUserAchievement() {
return achievementService.getUserAchievement();
}
@Operation(summary = "插入成就(管理员接口)")
@PostMapping("/admin/insert")
public Result insertAchievement(@RequestBody AchievementDTO achievementDTO) {
return achievementService.insertAchievement(achievementDTO);
}
}

@ -0,0 +1,13 @@
package com.vksfeng.quan.achievement.mapper;
import com.vksfeng.quan.achievement.pojo.entity.Achievement;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface AchievementMapper {
List<Achievement> findByType(String type);
void insert(Achievement achievement);
}

@ -0,0 +1,18 @@
package com.vksfeng.quan.achievement.mapper;
import com.vksfeng.quan.achievement.pojo.entity.UserAchievement;
import com.vksfeng.quan.achievement.pojo.vo.UserAchievementVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserAchievementMapper {
// 判断用户是否已经获得该成就
boolean exists(Long userId, Long achievementId);
// 插入用户获得成就记录
void insert(UserAchievement userAchievement);
List<UserAchievementVO> getUserAchievement(Long userId);
}

@ -0,0 +1,15 @@
package com.vksfeng.quan.achievement.pojo.dto;
import lombok.Data;
import java.util.Map;
@Data
public class AchievementDTO {
private String code;
private String name;
private String description;
private String iconUrl;
private String type;
private Map<String, Object> ruleJson;
}

@ -0,0 +1,17 @@
package com.vksfeng.quan.achievement.pojo.entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Achievement {
private Long id;
private String code;
private String name;
private String description;
private String iconUrl;
private String type;
private String ruleJson;
private LocalDateTime createdAt;
}

@ -0,0 +1,12 @@
package com.vksfeng.quan.achievement.pojo.entity;
import lombok.Data;
import java.util.Map;
@Data
public class AchievementTriggerEvent {
private Long userId;
private String type;
private Map<String, Object> payload;
}

@ -0,0 +1,17 @@
package com.vksfeng.quan.achievement.pojo.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class RuleCondition {
private String field;
private String op;
private Object value;
}

@ -0,0 +1,18 @@
package com.vksfeng.quan.achievement.pojo.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class RuleJson {
private String type;
private List<RuleCondition> conditions;
private String logic = "AND"; // 默认为AND
}

@ -0,0 +1,19 @@
package com.vksfeng.quan.achievement.pojo.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserAchievement {
private Long id;
private Long userId;
private Long achievementId;
private LocalDateTime achievedAt;
}

@ -0,0 +1,19 @@
package com.vksfeng.quan.achievement.pojo.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserAchievementVO {
private String name;
private String description;
private String iconUrl;
private LocalDateTime achievedAt;
}

@ -0,0 +1,13 @@
package com.vksfeng.quan.achievement.service;
import com.vksfeng.quan.achievement.pojo.dto.AchievementDTO;
import com.vksfeng.quan.achievement.pojo.vo.UserAchievementVO;
import com.vksfeng.quan.result.Result;
import java.util.List;
public interface AchievementService {
Result<List<UserAchievementVO>> getUserAchievement();
Result insertAchievement(AchievementDTO achievementDTO);
}

@ -0,0 +1,61 @@
package com.vksfeng.quan.achievement.service.Impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vksfeng.quan.achievement.mapper.AchievementMapper;
import com.vksfeng.quan.achievement.mapper.UserAchievementMapper;
import com.vksfeng.quan.achievement.pojo.dto.AchievementDTO;
import com.vksfeng.quan.achievement.pojo.entity.Achievement;
import com.vksfeng.quan.achievement.pojo.vo.UserAchievementVO;
import com.vksfeng.quan.achievement.service.AchievementService;
import com.vksfeng.quan.context.BaseContext;
import com.vksfeng.quan.exception.NotLoginException;
import com.vksfeng.quan.result.Result;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class AchievementServiceImpl implements AchievementService {
@Autowired
private UserAchievementMapper userAchievementMapper;
@Autowired
private AchievementMapper achievementMapper;
public Long getUserId() {
Long userId = BaseContext.getCurrentId();
if (userId == null) {
throw new NotLoginException("用户未登录");
}
return userId;
}
@Override
public Result<List<UserAchievementVO>> getUserAchievement() {
List<UserAchievementVO> userAchievementVOList = userAchievementMapper.getUserAchievement(getUserId());
return Result.success(userAchievementVOList);
}
@Override
public Result insertAchievement(AchievementDTO achievementDTO) {
if (getUserId() != 1) {
return Result.error("权限不足");
}
Achievement achievement = new Achievement();
BeanUtils.copyProperties(achievementDTO, achievement);
try {
ObjectMapper mapper = new ObjectMapper();
achievement.setRuleJson(mapper.writeValueAsString(achievementDTO.getRuleJson()));
} catch (JsonProcessingException e) {
throw new RuntimeException("规则 JSON 序列化失败", e);
}
achievement.setCreatedAt(LocalDateTime.now());
achievementMapper.insert(achievement);
return Result.success("插入成功");
}
}

@ -0,0 +1,55 @@
package com.vksfeng.quan.achievement.util;
import com.vksfeng.quan.achievement.pojo.entity.AchievementTriggerEvent;
import com.vksfeng.quan.mapper.FriendshipMapper;
import com.vksfeng.quan.mapper.ObjectiveMapper;
import com.vksfeng.quan.mapper.TaskMapper;
import com.vksfeng.quan.service.ResourceHubService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import static com.vksfeng.quan.constant.AchievementConstant.*;
@Component
public class AchievementContextBuilder {
@Autowired
private TaskMapper taskMapper;
@Autowired
private FriendshipMapper friendshipMapper;
@Autowired
private ObjectiveMapper objectiveMapper;
@Autowired
private ResourceHubService resourceHubService;
public Map<String, Object> buildContext(AchievementTriggerEvent event) {
Long userId = event.getUserId();
String type = event.getType();
Map<String, Object> ctx = new HashMap<>();
switch (type) {
case OBJECTIVE_ADDED -> {
ctx.put("createdObjectives", objectiveMapper.getObjectiveCount(userId));
}
case TASK_COMPLETED -> {
ctx.put("completedTasks", taskMapper.getCompletedTaskCount(userId));
}
case FRIEND_ADDED -> {
ctx.put("friendsCount", friendshipMapper.countFriends(userId));
}
case RESOURCE_SHARED -> {
ctx.put("sharedResources", resourceHubService.getUserResourceCount(userId));
ctx.put("resourceLikesReceived", resourceHubService.getUserReceivedLikes(userId));
ctx.put("resourceCommentsReceived", resourceHubService.getUserReceivedComments(userId));
}
// 扩展类型
}
return ctx;
}
}

@ -0,0 +1,35 @@
package com.vksfeng.quan.achievement.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import static com.vksfeng.quan.constant.RedisConstant.ACHIEVEMENT_STREAM_KEY;
@Component
public class AchievementEventPublisher {
@Autowired
private StringRedisTemplate redisTemplate;
public void publish(Long userId, String type, Map<String, Object> payload) {
ObjectMapper objectMapper = new ObjectMapper();
try {
Map<String, String> message = new HashMap<>();
message.put("userId", userId.toString());
message.put("type", type);
message.put("payload", objectMapper.writeValueAsString(payload == null ? Map.of() : payload));
redisTemplate.opsForStream().add(ACHIEVEMENT_STREAM_KEY, message);
} catch (Exception e) {
// 生产环境中可以 log.error + 监控上报
throw new RuntimeException("发布成就事件失败", e);
}
}
}

@ -0,0 +1,118 @@
package com.vksfeng.quan.achievement.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vksfeng.quan.achievement.mapper.AchievementMapper;
import com.vksfeng.quan.achievement.mapper.UserAchievementMapper;
import com.vksfeng.quan.achievement.pojo.entity.Achievement;
import com.vksfeng.quan.achievement.pojo.entity.AchievementTriggerEvent;
import com.vksfeng.quan.achievement.pojo.entity.RuleJson;
import com.vksfeng.quan.achievement.pojo.entity.UserAchievement;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.stream.MapRecord;
import org.springframework.data.redis.connection.stream.StreamOffset;
import org.springframework.data.redis.connection.stream.StreamReadOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import static com.vksfeng.quan.constant.RedisConstant.ACHIEVEMENT_STREAM_KEY;
@Slf4j
@Component
public class AchievementListener {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private AchievementMapper achievementMapper;
@Autowired
private UserAchievementMapper userAchievementMapper;
@Autowired
private RuleEvaluator ruleEvaluator;
@Autowired
private AchievementContextBuilder contextBuilder;
@PostConstruct
public void startListen() {
Executors.newSingleThreadExecutor().submit(() -> {
log.info("成就监听器启动...");
while (true) {
try {
List<MapRecord<String, Object, Object>> records =
redisTemplate.opsForStream().read(StreamReadOptions.empty().block(Duration.ofSeconds(2)).count(10),
StreamOffset.latest(ACHIEVEMENT_STREAM_KEY));
if (records != null) {
for (MapRecord<String, Object, Object> record : records) {
handleRecord(record);
}
}
} catch (Exception e) {
log.error("Redis Stream 成就事件监听失败:", e);
break;
}
}
});
}
private void handleRecord(MapRecord<String, Object, Object> record) throws JsonProcessingException {
Map<Object, Object> value = record.getValue();
AchievementTriggerEvent event = parseEvent(value);
log.info("收到行为事件:{}", event);
List<Achievement> achievements = achievementMapper.findByType(event.getType());
if (achievements.isEmpty()) {
log.info("没有找到类型为 {} 的成就", event.getType());
return;
}
for (Achievement achievement : achievements) {
// 是否已经达成
if (userAchievementMapper.exists(event.getUserId(), achievement.getId())) continue;
// 解析规则 JSON
RuleJson rule = null;
try {
rule = new ObjectMapper().readValue(achievement.getRuleJson(), RuleJson.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// 构造上下文
Map<String, Object> context = contextBuilder.buildContext(event);
// 规则判断
boolean passed = ruleEvaluator.evaluate(rule, context);
if (passed) {
log.info("用户 {} 达成成就:{}", event.getUserId(), achievement.getCode());
userAchievementMapper.insert(new UserAchievement(null, event.getUserId(), achievement.getId(), LocalDateTime.now()));
// TODO: 推送通知、插入日志、广播给好友
}
}
}
private AchievementTriggerEvent parseEvent(Map<Object, Object> value) throws JsonProcessingException {
Long userId = Long.parseLong(value.get("userId").toString());
String type = value.get("type").toString();
String payloadStr = value.getOrDefault("payload", "{}").toString();
Map<String, Object> payload = new ObjectMapper().readValue(payloadStr, new TypeReference<>() {});
AchievementTriggerEvent event = new AchievementTriggerEvent();
event.setUserId(userId);
event.setType(type);
event.setPayload(payload);
return event;
}
}

@ -0,0 +1,54 @@
package com.vksfeng.quan.achievement.util;
import com.vksfeng.quan.achievement.pojo.entity.RuleCondition;
import com.vksfeng.quan.achievement.pojo.entity.RuleJson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Component
@Slf4j
public class RuleEvaluator {
public boolean evaluate(RuleJson rule, Map<String, Object> context) {
List<Boolean> results = new ArrayList<>();
for (RuleCondition cond : rule.getConditions()) {
Object actual = context.get(cond.getField());
Object expected = cond.getValue();
boolean matched = compare(actual, cond.getOp(), expected);
results.add(matched);
}
return "AND".equals(rule.getLogic())
? results.stream().allMatch(Boolean::booleanValue)
: results.stream().anyMatch(Boolean::booleanValue);
}
private boolean compare(Object actual, String op, Object expected) {
if (actual instanceof Number && expected instanceof Number) {
double a = ((Number) actual).doubleValue();
double b = ((Number) expected).doubleValue();
return switch (op) {
case "==" -> a == b;
case "!=" -> a != b;
case ">" -> a > b;
case ">=" -> a >= b;
case "<" -> a < b;
case "<=" -> a <= b;
default -> false;
};
} else {
return switch (op) {
case "==" -> Objects.equals(actual, expected);
case "!=" -> !Objects.equals(actual, expected);
default -> false;
};
}
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.analysis_pojo.entity;
import lombok.Data;
import java.time.LocalDate;
@Data
public class TaskCompletionDay {
private LocalDate date; // 日期
private Integer count; // 当天完成任务次数
}

@ -0,0 +1,14 @@
package com.vksfeng.quan.analysis_pojo.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.time.LocalDate;
import java.util.Date;
@Data
@AllArgsConstructor
public class HeatMapVO {
private LocalDate date;
private Integer count;
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.analysis_pojo.vo;
import lombok.Data;
@Data
public class LeaderboardCountVO {
private Long userId;
private String username;
private String avatarUrl;
private Integer completeCount;
}

@ -0,0 +1,13 @@
package com.vksfeng.quan.analysis_pojo.vo;
import lombok.Data;
import java.time.LocalDate;
@Data
public class TaskCompletionRateVO {
private Integer completeCount;
private Integer totalCount;
private Double completionRate;
private LocalDate date;
}

@ -0,0 +1,17 @@
package com.vksfeng.quan.analysis_pojo.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserProfileForPeerVO {
private Integer objectiveCount;
private Integer objectiveCompletedCount;
private Integer taskCount;
private Integer taskDoneCompletedCount;
}

@ -0,0 +1,37 @@
//package com.vksfeng.quan.config;
//
//import com.vksfeng.quan.util.MinioUtils;
//import io.minio.MinioClient;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//@Configuration
//public class MinioConfig {
//
// @Value("${minio.endpoint}")
// private String minioEndpoint;
//
// @Value("${minio.access-key}")
// private String minioAccessKey;
//
// @Value("${minio.secret-key}")
// private String minioSecretKey;
//
// @Value("${minio.bucket-name}")
// private String bucketName;
//
// @Bean
// public MinioClient getMinioClient() {
// return MinioClient.builder()
// .endpoint(minioEndpoint)
// .credentials(minioAccessKey, minioSecretKey)
// .build();
// }
//
// @Bean
// public MinioUtils minioUtils(MinioClient minioClient) {
// return new MinioUtils(minioClient, bucketName);
// }
//
//}

@ -0,0 +1,30 @@
package com.vksfeng.quan.config;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.vksfeng.quan.properties.AliOSSProperties;
import com.vksfeng.quan.util.AliOSSUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class OssConfig {
/*在这个配置类中定义了一个名为aliOssUtil的@Bean方法用于创建一个AliOssUtil对象。*/
@Bean
/*@ConditionalOnMissingBeanaliOssUtilbeanbean
aliOssUtilbean*/
@ConditionalOnMissingBean
/*在方法体中通过依赖注入的方式获取AliOssProperties对象并使用它的属性值来创建AliOssUtil对象。*/
public AliOSSUtils aliOssUtil(AliOSSProperties aliOssProperties){
// log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties);
return new AliOSSUtils(aliOssProperties.getEndpoint(),
aliOssProperties.getAccessKeyId(),
aliOssProperties.getAccessKeySecret(),
aliOssProperties.getBucketName());
}
}

@ -0,0 +1,13 @@
package com.vksfeng.quan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

@ -0,0 +1,53 @@
package com.vksfeng.quan.config;
import com.vksfeng.quan.interceptor.JwtTokenInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@Slf4j
public class WebMvcConfiguration implements WebMvcConfigurer {
@Autowired
private JwtTokenInterceptor jwtTokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
log.info("开始注册自定义拦截器...");
registry.addInterceptor(jwtTokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/register", "/send-code")
.excludePathPatterns("/swagger-ui.html");
}
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许所有来源的跨域请求
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
// swagger
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springdoc-openapi-ui/")
.resourceChain(false);
}
}

@ -0,0 +1,14 @@
package com.vksfeng.quan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

@ -0,0 +1,80 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.analysis_pojo.vo.HeatMapVO;
import com.vksfeng.quan.analysis_pojo.vo.LeaderboardCountVO;
import com.vksfeng.quan.analysis_pojo.vo.TaskCompletionRateVO;
import com.vksfeng.quan.analysis_pojo.vo.UserProfileForPeerVO;
import com.vksfeng.quan.objectivehub_pojo.vo.TaskVO;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.AnalysisService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "分析统计模块")
@RestController
@RequestMapping("/analysis")
@Slf4j
public class AnalysisController {
@Autowired
private AnalysisService analysisService;
@Operation(summary = "获取月度任务日历")
@GetMapping("/calendar/tasks/month")
public Result<List<TaskVO>> getMonthlyTasksCalendar(@RequestParam Long userId, @RequestParam int year, @RequestParam int month) {
if (month < 1 || month > 12) {
return Result.error("月份不合法");
}
List<TaskVO> tasks = analysisService.getMonthlyTasksCalendar(userId, year, month);
return Result.success(tasks);
}
@Operation(summary = "获取年度任务热力图")
@GetMapping("/heatmap/tasks")
public Result<List<HeatMapVO>> getYearlyTasksHeatMap(@RequestParam Long userId, @RequestParam int year) {
return analysisService.getYearlyTasksHeatMap(userId, year);
}
@Operation(summary = "获取任务排行榜")
@GetMapping("/leaderboard/task")
public Result<List<LeaderboardCountVO>> getTaskLeaderboard(@RequestParam String period) {
if (period.equals("weekly")) {
return Result.success(analysisService.getWeeklyTaskLeaderboard());
} else if (period.equals("monthly")) {
return Result.success(analysisService.getMonthlyTaskLeaderboard());
} else {
return Result.error("参数不合法");
}
}
@Operation(summary = "获取好友任务目标状态")
@GetMapping("/friend/{friendId}/objhubstatus")
public Result<UserProfileForPeerVO> getFriendObjectiveHubStatus(@PathVariable Long friendId) {
UserProfileForPeerVO userProfileForPeerVO = analysisService.getFriendObjectiveHubStatus(friendId);
return Result.success(userProfileForPeerVO);
}
@Operation(summary = "获取近一周每日任务完成率")
@GetMapping("/completion/task/weekly")
public Result<List<TaskCompletionRateVO>> getWeeklyTaskCompletionRate() {
return analysisService.getWeeklyTaskCompletionRate();
}
@Operation(summary = "用户活跃度信息")
@GetMapping("/activity")
public Result getUserActivity() {
return analysisService.getUserActivity();
}
@Operation(summary = "获取用户社交成就")
@GetMapping("/social/achievement")
public Result getSocialAchievement() {
return analysisService.getUserSocialAchievement();
}
}

@ -0,0 +1,102 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.service.CaptchaService;
import com.vksfeng.quan.service.EmailService;
import com.vksfeng.quan.user_pojo.dto.RegisterDTO;
import com.vksfeng.quan.user_pojo.dto.UserDTO;
import com.vksfeng.quan.user_pojo.entity.User;
import com.vksfeng.quan.user_pojo.vo.LoginResponse;
import com.vksfeng.quan.user_pojo.vo.UserVO;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.UserService;
import com.vksfeng.quan.util.JwtUtils;
import com.vksfeng.quan.util.RegexUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.mail.MessagingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@CrossOrigin(origins = "http://localhost:5173")
@Tag(name = "登陆注册模块")
@RestController
@Slf4j
public class AuthController {
@Autowired
private UserService userService;
@Autowired
private CaptchaService captchaService;
@Autowired
private EmailService emailService;
@Value("${jwt.secret-key}")
private String SECRET_KEY;
@Operation(summary = "用户注册")
@PostMapping("/register")
public Result register(@RequestBody RegisterDTO registerDTO) {
log.info("用户注册");
if (!captchaService.validateCaptcha(registerDTO.getEmail(), registerDTO.getCaptcha())) {
return Result.error("验证码错误");
}
UserDTO userDTO = new UserDTO();
BeanUtils.copyProperties(registerDTO, userDTO);
userService.register(userDTO);
return Result.success();
}
@Operation(summary = "用户登录")
@PostMapping("/login")
public Result login(@RequestBody UserDTO userDTO) {
log.info("用户登录");
User user = userService.login(userDTO);
if (user == null) {
return Result.error("用户不存在");
}
// 登录成功生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put("userId", user.getId());
String token = JwtUtils.createJWT(SECRET_KEY, 3600000, claims);
UserVO userVO = new UserVO();
BeanUtils.copyProperties(user, userVO);
LoginResponse loginResponse = new LoginResponse(userVO, token);
return Result.success(loginResponse);
}
@Operation(summary = "发送验证码")
@PostMapping("/send-code")
public Result sendCode(@RequestParam String email) throws MessagingException {
if (!RegexUtils.isEmailValid(email)) {
return Result.error("邮箱格式非法");
}
if (userService.getUserByEmail(email) != null) {
return Result.error("邮箱已被注册");
}
String code = captchaService.generateCaptcha(email);
emailService.sendCaptchaEmail(email, code);
return Result.success();
}
@PostMapping("/send-test")
public Result sendCodeTest(@RequestParam String email) throws MessagingException {
if (!RegexUtils.isEmailValid(email)) {
return Result.error("邮箱格式非法");
}
String code = "666666";
emailService.sendCaptchaEmail(email, code);
return Result.success();
}
}

@ -0,0 +1,68 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.peerhub_pojo.dto.FeedCommentDTO;
import com.vksfeng.quan.peerhub_pojo.vo.FeedCommentVO;
import com.vksfeng.quan.peerhub_pojo.vo.FeedVO;
import com.vksfeng.quan.result.PageResult;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.FeedService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
// TODO 权限管理
@Tag(name = "动态模块")
@RestController
@RequestMapping("/feed")
public class FeedController {
@Autowired
private FeedService feedService;
@Operation(summary = "获取动态列表")
@GetMapping
public Result<PageResult> getFeedList(@RequestParam Integer page, @RequestParam Integer pageSize) {
PageResult pageResult = feedService.getFeedList(page, pageSize);
return Result.success(pageResult);
}
@Operation(summary = "点赞动态")
@PostMapping("/like")
public Result like(@RequestBody Map<String, Long> request) {
feedService.like(request.get("feed_id"));
return Result.success();
}
@Operation(summary = "取消点赞")
@DeleteMapping("/{feedId}/like")
public Result unlike(@PathVariable Long feedId) {
feedService.unlike(feedId);
return Result.success();
}
@Operation(summary = "评论动态")
@PostMapping("/comment")
public Result comment(@RequestBody FeedCommentDTO feedCommentDTO) {
feedService.comment(feedCommentDTO);
return Result.success();
}
@Operation(summary = "获取动态评论列表")
@GetMapping("/comments")
public Result<List<FeedCommentVO>> getCommentList(@RequestParam Long feedId) {
List<FeedCommentVO> commentList = feedService.getCommentList(feedId);
return Result.success(commentList);
}
@Operation(summary = "动态信息推送")
@GetMapping("/recent")
public Result<List<FeedVO>> getRecentFeed() {
return feedService.getRecentFeed();
}
}

@ -0,0 +1,26 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.FileService;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/files")
public class FileController {
@Autowired
private FileService fileService;
@PostMapping("/upload")
public Result uploadAvatar(MultipartFile file) throws FileUploadException {
if (file == null || file.isEmpty()) {
return Result.error("文件为空");
}
return fileService.uploadFile(file);
}
}

@ -0,0 +1,101 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.context.BaseContext;
import com.vksfeng.quan.peerhub_pojo.dto.FriendshipDTO;
import com.vksfeng.quan.peerhub_pojo.vo.UserSearchVO;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.FriendshipService;
import com.vksfeng.quan.user_pojo.vo.UserVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "好友管理")
@RestController
@RequestMapping("/friends")
@Slf4j
public class FriendshipController {
@Autowired
private FriendshipService friendshipService;
@Operation(summary = "获取好友列表")
@GetMapping("/list")
public Result<List<UserVO>> getFriends() {
Long userId = BaseContext.getCurrentId();
if (userId == null) {
return Result.error("用户未登录");
}
log.info("获取好友列表,userId:{}", userId);
List<UserVO> friends = friendshipService.getFriends(userId);
return Result.success(friends);
}
@Operation(summary = "获取好友申请信息")
@GetMapping("/requestlist")
public Result<List<UserVO>> getFriendRequests() {
Long userId = BaseContext.getCurrentId();
if (userId == null) {
return Result.error("用户未登录");
}
List<UserVO> request = friendshipService.getRequests(userId);
return Result.success(request);
}
@Operation(summary = "搜索用户以添加好友")
@GetMapping("/search")
public Result<UserSearchVO> searchUser(@RequestParam Long id) {
return friendshipService.searchUser(id);
}
@Operation(summary = "添加好友")
@PostMapping("/request")
public Result<String> addFriendRequest(@RequestBody FriendshipDTO friendshipDTO) {
Long userId = BaseContext.getCurrentId();
if (userId == null) {
return Result.error("用户未登录");
}
if (userId.equals(friendshipDTO.getUserId())) {
return Result.error("你已经是自己的好朋友啦,就不要加自己了");
}
friendshipDTO.setUserId(userId);
friendshipDTO.setStatus("pending");
friendshipService.addFriendRequest(friendshipDTO);
return Result.success("添加申请已发送");
}
@Operation(summary = "同意好友请求")
@PostMapping("/accept")
public Result<String> acceptFriend(@RequestBody FriendshipDTO friendshipDTO) {
Long userId = BaseContext.getCurrentId();
if (userId == null) {
return Result.error("用户未登录");
}
friendshipDTO.setFriendId(userId);
friendshipDTO.setStatus("accepted");
friendshipService.acceptFriendRequest(friendshipDTO);
return Result.success("好友申请已同意");
}
@Operation(summary = "拒绝好友请求/删除好友")
@PostMapping("/remove")
public Result<String> removeFriend(@RequestBody FriendshipDTO friendshipDTO) {
Long userId = BaseContext.getCurrentId();
if (userId == null) {
return Result.error("用户未登录");
}
friendshipDTO.setUserId(userId);
friendshipService.removeFriend(friendshipDTO);
return Result.success("好友申请已拒绝");
}
@Operation(summary = "附近的人推荐")
@GetMapping("/nearby")
public Result<List<UserSearchVO>> nearbyUsers() {
return friendshipService.getNearbyUsers();
}
}

@ -0,0 +1,30 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.resourcehub_pojo.vo.ImageResult;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.ImageProxyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ImageProxyController {
@Autowired
private ImageProxyService imageProxyService;
/**
*
* @param url URL
* @return Result
*/
@GetMapping("/img-proxy")
public Result<ImageResult> getImage(@RequestParam String url) {
if (url == null || url.isEmpty()) {
return Result.error("缺少 URL 参数");
}
return imageProxyService.getImage(url);
}
}

@ -0,0 +1,51 @@
package com.vksfeng.quan.controller;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.vksfeng.quan.obengine_pojo.dto.ObjectiveWithFeedbackDTO;
import com.vksfeng.quan.obengine_pojo.vo.FollowUpQuestionVO;
import com.vksfeng.quan.objectivehub_pojo.dto.ObjectiveDTO;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.SparkAIService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Tag(name = "OB引擎模块")
@Slf4j
@RestController
@RequestMapping("/obengine")
public class ObEngineController {
@Autowired
private SparkAIService sparkAIService;
@Operation(summary = "生成跟进问题")
@PostMapping("/generateFollowup")
public Result<List<FollowUpQuestionVO>> generateFollowup(@RequestBody ObjectiveDTO objectiveDTO) {
return sparkAIService.generateFollowupQuestions(objectiveDTO);
}
@Operation(summary = "生成详细计划")
@PostMapping("/generateDetailedPlan")
public Result generateDetailedPlan(@RequestBody ObjectiveWithFeedbackDTO objectiveWithFeedbackDTO) {
sparkAIService.generateDetailedPlan(objectiveWithFeedbackDTO);
return Result.success();
}
}

@ -0,0 +1,137 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.objectivehub_pojo.dto.ObjectiveDTO;
import com.vksfeng.quan.objectivehub_pojo.dto.RelationDTO;
import com.vksfeng.quan.objectivehub_pojo.vo.ObjectiveVO;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.ObjectiveHubService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "ObjHub模块")
@RestController
@RequestMapping("/objectives")
@Slf4j
public class ObjectiveController {
@Autowired
private ObjectiveHubService objectiveHubService;
/**
*
* @param objectiveDTO
* @return
*/
@Operation(summary = "创建目标")
@PostMapping
public Result<ObjectiveVO> createObjective(@RequestBody ObjectiveDTO objectiveDTO) {
ObjectiveVO objective = objectiveHubService.createObjective(objectiveDTO);
return Result.success(objective);
}
/**
*
* @param objectiveDTO
* @param parentObjectiveId
* @return
*/
@Operation(summary = "创建目标(自动关联目标关系版)")
@PostMapping("/parent/{id}/children")
public Result<ObjectiveVO> createObjectiveWithRelation(@RequestBody ObjectiveDTO objectiveDTO, @PathVariable("id") Long parentObjectiveId) {
ObjectiveVO objective = objectiveHubService.createObjectiveWithRelation(objectiveDTO, parentObjectiveId);
return Result.success(objective);
}
/**
*
* @param userId id
* @return
*/
@Operation(summary = "获取用户目标")
@GetMapping("/user/{id}")
public Result<List<ObjectiveVO>> getUserObjectives(@PathVariable("id") Long userId) {
log.info("获取用户目标");
List<ObjectiveVO> objectives = objectiveHubService.getUserObjectives(userId);
return Result.success(objectives);
}
/**
* id
* @param objectiveId id
* @return
*/
@Operation(summary = "根据id获取目标信息")
@GetMapping("/{id}")
public Result<ObjectiveVO> getObjectiveById(@PathVariable("id") Long objectiveId) {
ObjectiveVO objective = objectiveHubService.getObjectiveById(objectiveId);
if (objective == null) {
return Result.error("目标不存在");
}
return Result.success(objective);
}
@Operation(summary = "获取AI指导")
@GetMapping("/{id}/ai-guide")
public Result getAiGuide(@PathVariable("id") Long objectiveId) {
return objectiveHubService.getAiGuideForObjective(objectiveId);
}
/**
*
* @param objectiveDTO
* @return or
*/
@Operation(summary = "更新目标信息")
@PutMapping("/{id}")
public Result updateObjective(@RequestBody ObjectiveDTO objectiveDTO, @PathVariable("id") Long objectiveId) {
objectiveHubService.updateObjective(objectiveDTO, objectiveId);
return Result.success("目标修改成功");
}
/**
*
* @param objectiveId id
* @return or
*/
@Operation(summary = "根据id删除目标")
@DeleteMapping("/{id}")
public Result deleteObjective(@PathVariable("id") Long objectiveId) {
objectiveHubService.deleteObjective(objectiveId);
return Result.success("目标删除成功");
}
// @Operation(summary = "添加子目标")
// @PostMapping("/{id}/children")
// public Result addSubObjective(@RequestBody RelationDTO childObjectiveId, @PathVariable("id") Long parentObjectiveId) {
// objectiveHubService.createObjectiveRelation(parentObjectiveId, childObjectiveId.getChildObjectiveId());
// return Result.success("子目标关联成功");
// }
@Operation(summary = "为子目标添加任务")
@PostMapping("{id}/tasks")
public Result addTask(@RequestBody RelationDTO taskId, @PathVariable("id") Long objectiveId) {
objectiveHubService.createObjectiveTaskRelation(objectiveId, taskId.getTaskId());
return Result.success("任务关联成功");
}
@Operation(summary = "删除子目标")
@DeleteMapping("/{fatherObjectiveId}/children/{childObjectiveId}")
public Result deleteSubObjective(@PathVariable("fatherObjectiveId") Long fatherObjectiveId, @PathVariable("childObjectiveId") Long childObjectiveId) {
objectiveHubService.deleteObjectiveRelation(fatherObjectiveId, childObjectiveId);
return Result.success("子目标移除成功");
}
@Operation(summary = "为子目标删除任务")
@DeleteMapping("{objectiveId}/tasks/{taskId}")
public Result deleteTask(@PathVariable("objectiveId") Long objectiveId, @PathVariable("taskId") Long taskId) {
objectiveHubService.deleteObjectiveTaskRelation(objectiveId, taskId);
return Result.success("任务移除成功");
}
}

@ -0,0 +1,127 @@
package com.vksfeng.quan.controller;
import cn.hutool.db.Page;
import com.vksfeng.quan.resourcehub_pojo.dto.ResourceDTO;
import com.vksfeng.quan.resourcehub_pojo.vo.ResourceCommentVO;
import com.vksfeng.quan.resourcehub_pojo.vo.ResourceVO;
import com.vksfeng.quan.result.PageResult;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.ResourceHubService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@Tag(name = "资源中心模块")
@RestController
@RequestMapping("/resources")
@Slf4j
public class ResourceHubController {
@Autowired
private ResourceHubService resourceHubService;
@Operation(summary = "创建资源")
@PostMapping
public Result<ResourceVO> createResource(@RequestBody ResourceDTO resourceDTO) {
ResourceVO resourceVO = resourceHubService.createResource(resourceDTO);
return Result.success(resourceVO);
}
@Operation(summary = "获取资源")
@GetMapping("/{id}")
public Result<ResourceVO> getResource(@PathVariable Long id) {
ResourceVO resourceVO = resourceHubService.getResource(id);
if (resourceVO == null) {
return Result.error("资源不存在");
}
return Result.success(resourceVO);
}
@Operation(summary = "获取资源列表")
@GetMapping
public Result<PageResult> getResourceList(@RequestParam Integer page, @RequestParam Integer pageSize, @RequestParam(required = false) String category) {
PageResult pageResult = resourceHubService.getResourceList(page, pageSize, category);
return Result.success(pageResult);
}
@Operation(summary = "获取推荐资源列表")
@GetMapping("/recommend")
public Result<PageResult> getRecommendResourceList() {
return resourceHubService.getRecommendResourceList();
}
@Operation(summary = "获取指定id用户的资源")
@GetMapping("/user/{userId}")
public Result<PageResult> getUserResourceList(@PathVariable Long userId, @RequestParam Integer page, @RequestParam Integer pageSize, @RequestParam(required = false) String category) {
return resourceHubService.getUserResourceList(userId, page, pageSize, category);
}
@Operation(summary = "删除资源")
@DeleteMapping("/{id}")
public Result deleteResource(@PathVariable Long id) {
// TODO 删除关联点赞与评论等
resourceHubService.deleteResource(id);
return Result.success("删除成功");
}
@Operation(summary = "点赞资源")
@PostMapping("/{id}/like")
public Result likeResource(@PathVariable Long id) {
resourceHubService.addLike(id);
return Result.success("点赞成功");
}
@Operation(summary = "取消点赞资源")
@DeleteMapping("/{id}/like")
public Result unlikeResource(@PathVariable Long id) {
resourceHubService.removeLike(id);
return Result.success("取消点赞成功");
}
@Operation(summary = "发布评论")
@PostMapping("/{id}/comments")
public Result addComment(@PathVariable Long id, @RequestBody Map<String, String> requestBody) {
String content = requestBody.get("content");
ResourceCommentVO resourceCommentVO = resourceHubService.addComment(id, content);
if (resourceCommentVO == null) {
return Result.error("评论失败");
}
return Result.success(resourceCommentVO);
}
@Operation(summary = "获取指定帖子的评论")
@GetMapping("/{id}/comments")
public Result<List<ResourceCommentVO>> getComments(@PathVariable Long id) {
List<ResourceCommentVO> resourceCommentVOList = resourceHubService.getCommentsByResourceId(id);
return Result.success(resourceCommentVOList);
}
@Operation(summary = "收藏资源")
@PostMapping("/{id}/favorite")
public Result favoriteResource(@PathVariable Long id) {
resourceHubService.addFavorite(id);
return Result.success("收藏成功");
}
@Operation(summary = "取消收藏资源")
@DeleteMapping("/{id}/favorite")
public Result unfavoriteResource(@PathVariable Long id) {
resourceHubService.removeFavorite(id);
return Result.success("取消收藏成功");
}
@Operation(summary = "获取收藏列表")
@GetMapping("/favorite")
public Result<PageResult> getFavoriteList(@RequestParam Integer page, @RequestParam Integer pageSize, @RequestParam(required = false) String category) {
PageResult resourceVOList = resourceHubService.getFavoriteList(page, pageSize, category);
return Result.success(resourceVOList);
}
}

@ -0,0 +1,99 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.objectivehub_pojo.dto.RecurringTaskDTO;
import com.vksfeng.quan.objectivehub_pojo.dto.SingleTaskDTO;
import com.vksfeng.quan.objectivehub_pojo.vo.TaskVO;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.ObjectiveHubService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@Tag(name = "ObjHub模块")
@RestController
@RequestMapping("/tasks")
public class TaskController {
@Autowired
private ObjectiveHubService objectiveHubService;
// ----------------------------------------创建---------------------------------------------
@Operation(summary = "创建单次任务")
@PostMapping("/single")
public Result<TaskVO> createSingleTask(@RequestBody SingleTaskDTO taskDTO) {
if (taskDTO.getObjectiveId() == null) {
return Result.error("任务不能独立存在");
}
TaskVO taskVO = objectiveHubService.createSingleTask(taskDTO);
return Result.success(taskVO);
}
@Operation(summary = "创建重复任务")
@PostMapping("/recurring")
public Result<TaskVO> createRecurringTask(@RequestBody RecurringTaskDTO taskDTO) {
if (taskDTO.getObjectiveId() == null) {
return Result.error("任务不能独立存在");
}
TaskVO taskVO = objectiveHubService.createRecurringTask(taskDTO);
return Result.success(taskVO);
}
// ----------------------------------------查询---------------------------------------------
@Operation(summary = "获取用户今日任务")
@GetMapping("/user/{id}/today")
public Result<List<TaskVO>> getUserTodayTasks(@PathVariable("id") Long userId) {
return Result.success(objectiveHubService.getUserTodayTasks(userId));
}
@Operation(summary = "根据id获取任务信息")
@GetMapping("/{id}")
public Result<TaskVO> getTaskById(@PathVariable Long id) {
return Result.success(objectiveHubService.getTaskById(id));
}
// ----------------------------------------更新---------------------------------------------
@Operation(summary = "更新单次任务信息")
@PutMapping("/single/{id}")
public Result updateSingleTask(@RequestBody SingleTaskDTO taskDTO, @PathVariable Long id) {
objectiveHubService.updateSingleTask(taskDTO, id);
return Result.success("任务修改成功");
}
@Operation(summary = "更新重复任务信息")
@PutMapping("/recurring/{id}")
public Result<TaskVO> updateRecurringTask(@RequestBody RecurringTaskDTO taskDTO, @PathVariable Long id) {
objectiveHubService.updateRecurringTask(taskDTO, id);
return Result.success("任务修改成功");
}
@Operation(summary = "完成任务")
@PostMapping("/completion")
public Result completeTask(@RequestBody Map<String, Long> request) {
Long id = request.get("id");
return objectiveHubService.completeTask(id);
}
@Operation(summary = "撤销任务完成")
@DeleteMapping("/completion/{id}")
public Result deleteTaskCompletion(@PathVariable Long id) {
objectiveHubService.deleteTaskCompletion(id);
return Result.success("任务完成记录删除成功");
}
// ----------------------------------------删除---------------------------------------------
@Operation(summary = "根据id删除任务")
@DeleteMapping("/{id}")
public Result deleteTask(@PathVariable Long id) {
objectiveHubService.deleteTask(id);
return Result.success("任务删除成功");
}
}

@ -0,0 +1,52 @@
package com.vksfeng.quan.controller;
import com.vksfeng.quan.user_pojo.dto.UserDTO;
import com.vksfeng.quan.user_pojo.entity.User;
import com.vksfeng.quan.user_pojo.entity.UserLocation;
import com.vksfeng.quan.user_pojo.vo.UserVO;
import com.vksfeng.quan.result.Result;
import com.vksfeng.quan.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Tag(name = "用户模块")
@RestController
@RequestMapping("/user")
@CrossOrigin(origins = "http://localhost:5173")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@Operation(summary = "根据id获取用户信息")
@GetMapping("/{id}")
public Result getUserById(@PathVariable Long id) {
log.info("获取用户信息id:{}", id);
User user = userService.getUserById(id);
UserVO userVO = new UserVO();
BeanUtils.copyProperties(user, userVO);
return Result.success(userVO);
}
@Operation(summary = "更新用户信息")
@PutMapping
public Result update(@RequestBody UserDTO userDTO) {
log.info("更新用户信息id:{}", userDTO.getId());
userService.update(userDTO);
return Result.success();
}
@Operation(summary = "用户更新位置信息")
@PutMapping("/location")
public Result updateLocation(@RequestBody UserLocation userLocationDTO) {
return userService.setUserLocation(userLocationDTO);
}
}

@ -0,0 +1,44 @@
package com.vksfeng.quan.handler;
import com.vksfeng.quan.exception.BaseException;
import com.vksfeng.quan.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.sql.SQLIntegrityConstraintViolationException;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
*
* @param ex
* @return
*/
@ExceptionHandler
public Result exceptionHandler(BaseException ex){
log.error("异常信息:{}", ex.getMessage());
return Result.error(ex.getMessage());
}
/**
* SQL
* @param ex
* @return
*/
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex) {
//样例报错Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1-2' for key 'PRIMARY'
//; Duplicate entry '1-2' for key 'PRIMARY'] with root cause
String message = ex.getMessage();
if (message.contains("Duplicate entry")) {
// String[] split = message.split(" ");
// String relation = split[2];
// String msg = relation + "之间的好友申请已发送";
return Result.error("重复操作");
} else {
return Result.error("遇到此信息记得截图并且记录报错时的使用场景" + ex.getMessage());
}
}
}

@ -0,0 +1,70 @@
package com.vksfeng.quan.interceptor;
import com.vksfeng.quan.context.BaseContext;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.vksfeng.quan.util.JwtUtils;
@Component
@Slf4j
public class JwtTokenInterceptor implements HandlerInterceptor {
@Value("${jwt.secret-key}")
private String SECRET_KEY;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断当前拦截到的是Controller的方法还是其他资源
if (!(handler instanceof HandlerMethod)) {
//当前拦截到的不是动态方法,直接放行
return true;
}
// 获取Authorization头
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
// 设置响应的字符编码和内容类型
response.setCharacterEncoding("UTF-8");
response.setContentType("text/plain; charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回401
response.getWriter().write("缺少有效的认证凭证");
return false;
}
// 去掉 "Bearer " 前缀获取实际的Token
String token = authHeader.substring(7);
try {
// log.info("正在解析token{}", token);
// 去掉 "Bearer " 前缀获取实际的Token
Claims claims = JwtUtils.parseJWT(SECRET_KEY, token); // 解析Token
// // 将解析后的用户信息放到request的属性中以便后续使用
// request.setAttribute("userClaims", claims);
Long userId = Long.valueOf(claims.get("userId").toString());
// log.info("解析到的用户ID{}", userId);
BaseContext.setCurrentId(userId);
} catch (Exception e) {
// 设置响应的字符编码和内容类型
response.setCharacterEncoding("UTF-8");
response.setContentType("text/plain; charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回401
response.getWriter().write("Token无效或过期");
return false;
}
return true; // 继续执行下一个拦截器或控制器
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 请求完成后清理 ThreadLocal防止内存泄漏或用户污染
BaseContext.removeCurrentId();
}
}

@ -0,0 +1,32 @@
package com.vksfeng.quan.mapper;
import com.vksfeng.quan.peerhub_pojo.dto.FeedCommentDTO;
import com.vksfeng.quan.peerhub_pojo.entity.Feed;
import com.vksfeng.quan.peerhub_pojo.entity.FeedComment;
import com.vksfeng.quan.peerhub_pojo.entity.FeedLike;
import com.vksfeng.quan.peerhub_pojo.vo.FeedCommentVO;
import com.vksfeng.quan.peerhub_pojo.vo.FeedVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface FeedMapper {
Integer count();
List<FeedVO> page(Integer offset, Integer pageSize, List<Long> userIds, Long userId);
void addFeedLike(FeedLike feedLike);
FeedVO getFeedById(Long feedId, Long userId);
void addFeedComment(FeedComment feedComment);
void removeFeedLike(Long feedId, Long userId);
List<FeedCommentVO> getCommentList(Long feedId);
void insertFeed(Feed feed);
FeedLike getFeedLike(Long feedId, Long userId);
}

@ -0,0 +1,26 @@
package com.vksfeng.quan.mapper;
import com.vksfeng.quan.peerhub_pojo.dto.FriendshipDTO;
import com.vksfeng.quan.peerhub_pojo.entity.Friendship;
import com.vksfeng.quan.user_pojo.vo.UserVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface FriendshipMapper {
Integer countFriends(Long userId);
List<UserVO> list(Long userId);
void insert(Friendship friendship);
List<UserVO> getRequests(Long userId);
void update(Friendship friendship);
void remove(Long userId, Long friendId);
List<Friendship> selectByTwoId(Long aId, Long bId);
}

@ -0,0 +1,51 @@
package com.vksfeng.quan.mapper;
import com.vksfeng.quan.objectivehub_pojo.entity.Objective;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Mapper
public interface ObjectiveMapper {
void insert(Objective objective);
Objective selectById(Long objectiveId);
void updateById(Objective objective, Long objectiveId);
void deleteById(Long objectiveId);
List<Long> getAllSubObjectivesId(Long objectiveId);
void deleteRelationByChildId(Long objectiveId);
void deleteRelationByFatherId(Long objectiveId);
List<Long> getAllObjectivesId(Long userId);
List<Objective> getAllMainObjectives(List<Long> mainObjectivesIds);
void createObjectiveRelation(Long parentObjectiveId, Long childObjectiveId);
void deleteObjectiveRelation(Long parentObjectiveId, Long childObjectiveId);
boolean isSubObjective(Long objectiveId);
Integer getObjectiveCount(Long userId);
Integer getCompletedObjectiveCount(Long userId);
void updateProgress(Double progress, Long objectiveId);
void addAiGuideForObjective(Long objectiveId, String aiGuide);
String getAiGuideForObjective(Long objectiveId);
void deleteAiGuideForObjective(Long objectiveId);
void completeObjectiveById(LocalDateTime now, Long objectiveId);
Long getFatherObjectiveIdBySubObjectiveId(Long objectiveId);
}

@ -0,0 +1,54 @@
package com.vksfeng.quan.mapper;
import com.vksfeng.quan.resourcehub_pojo.entity.Resource;
import com.vksfeng.quan.resourcehub_pojo.entity.ResourceComment;
import com.vksfeng.quan.resourcehub_pojo.entity.ResourceFavorite;
import com.vksfeng.quan.resourcehub_pojo.entity.ResourceLike;
import com.vksfeng.quan.resourcehub_pojo.vo.ResourceCommentVO;
import com.vksfeng.quan.resourcehub_pojo.vo.ResourceVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ResourceMapper {
void createResource(Resource resource);
ResourceVO getResourceById(Long id, Long currentUserId);
// List<ResourceVO> getResourceList(List<Long> userIds, Long currentUserId);
void deleteResource(Long id, Long userId);
void addLike(ResourceLike resourceLike);
boolean isLiked(Long userId, Long resourceId);
void removeLike(Long resourceId, Long userId);
void addComment(ResourceComment resourceComment);
ResourceCommentVO getResourceCommentById(Long commentId);
List<ResourceCommentVO> getCommentsByResourceId(Long id);
void addFavorite(ResourceFavorite resourceFavorite);
boolean isFavorite(Long resourceId, Long userId);
void removeFavorite(Long resourceId, Long userId);
Integer getResourceCount(String category, List<Long> userIds);
List<ResourceVO> getResourceList(List<Long> userIds, Long currentUserId, Integer offset, Integer pageSize, String category);
List<ResourceVO> getFavoriteList(Long userId, Integer offset, Integer pageSize, String category);
Integer getFavoriteResourceCount(Long userId, String category);
Integer getUserReceivedLikes(Long userId);
Integer getUserReceivedComments(Long userId);
Integer getUserReceivedFavorites(Long userId);
}

@ -0,0 +1,72 @@
package com.vksfeng.quan.mapper;
import com.vksfeng.quan.analysis_pojo.entity.TaskCompletionDay;
import com.vksfeng.quan.analysis_pojo.vo.HeatMapVO;
import com.vksfeng.quan.analysis_pojo.vo.LeaderboardCountVO;
import com.vksfeng.quan.analysis_pojo.vo.TaskCompletionRateVO;
import com.vksfeng.quan.objectivehub_pojo.entity.Task;
import com.vksfeng.quan.objectivehub_pojo.entity.TaskCompletion;
import com.vksfeng.quan.objectivehub_pojo.vo.TaskVO;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
@Mapper
public interface TaskMapper {
void insert(Task task);
void insertObjectiveTaskRelation(Long objectiveId, Long taskId);
Task selectById(Long id);
void updateById(Task task, Long id);
void deleteById(Long id);
void deleteObjectiveTaskRelationByTaskId(Long id);
Long getObjectiveIdByTaskId(Long id);
List<TaskVO> getTodayTasks(Long userId, LocalDate today);
List<Long> getAllTasksIdByObjectiveId(Long objectiveId);
void deleteObjectiveTaskRelationByObjectiveId(Long objectiveId);
void createObjectiveTaskRelation(Long objectiveId, Long taskId);
void deleteObjectiveTaskRelation(Long objectiveId, Long taskId);
List<TaskVO> getMonthlyTasksCalendar(Long userId, int year, int month);
List<TaskCompletionDay> selectDailyCompletion(Long userId, int year, int month);
@Insert("INSERT INTO task_completion (task_id, user_id, completed_at) VALUES (#{taskId}, #{userId}, #{completedAt})")
void addTaskCompletion(TaskCompletion taskCompletion);
void deleteTaskCompletionByTaskId(Long taskId);
void deleteTaskCompletionByRecordId(Long id);
Long getLatestCompletionRecordId(Long taskId);
List<LeaderboardCountVO> getWeeklyTaskLeaderboard(List<Long> userIds);
List<LeaderboardCountVO> getMonthlyTaskLeaderboard(List<Long> userIds);
Integer getTaskCount(Long userId);
Integer getCompletedTaskCount(Long userId);
List<TaskCompletionRateVO> getTotalCount(Long userId, LocalDate startDate, LocalDate endDate);
List<TaskCompletionRateVO> getCompleteCount(Long userId, LocalDate startDate, LocalDate endDate);
List<Task> findRecurringCompletedTasks();
List<HeatMapVO> getYearlyTasksHeatMap(Long userId, int year);
}

@ -0,0 +1,42 @@
package com.vksfeng.quan.mapper;
import com.vksfeng.quan.peerhub_pojo.vo.UserSearchVO;
import com.vksfeng.quan.user_pojo.entity.User;
import com.vksfeng.quan.user_pojo.entity.UserLocation;
import com.vksfeng.quan.user_pojo.vo.UserActivityVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
/**
*
* @param user
*/
void save(User user);
/**
*
* @param user
*/
List<User> findUser(User user);
/**
* id
* @param id
* @return
*/
User getUserById(Long id);
/**
*
*/
void update(User user);
void saveUserLocation(UserLocation userLocation);
List<UserSearchVO> searchUsers(List<Long> userIds, Long currentUserId);
}

@ -0,0 +1,9 @@
package com.vksfeng.quan.obengine_pojo.dto;
import lombok.Data;
@Data
public class Feedback {
private String question;
private String answer;
}

@ -0,0 +1,13 @@
package com.vksfeng.quan.obengine_pojo.dto;
import com.vksfeng.quan.objectivehub_pojo.entity.Objective;
import com.vksfeng.quan.objectivehub_pojo.vo.ObjectiveVO;
import lombok.Data;
import java.util.List;
@Data
public class ObjectivePlanDTO {
private Objective masterObjective;
private List<SubObjectiveDTO> subObjectives;
}

@ -0,0 +1,16 @@
package com.vksfeng.quan.obengine_pojo.dto;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
@Data
public class ObjectiveWithFeedbackDTO {
private Long id;
private String name;
private String description;
private LocalDate startDate;
private LocalDate endDate;
private List<Feedback> feedback;
}

@ -0,0 +1,24 @@
package com.vksfeng.quan.obengine_pojo.dto;
import com.vksfeng.quan.objectivehub_pojo.entity.Task;
import com.vksfeng.quan.objectivehub_pojo.vo.ObjectiveVO;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class SubObjectiveDTO {
private Long id;
private Long userId;
private String name;
private String description;
private LocalDate startDate;
private LocalDate endDate;
private Boolean visibility;
private Double progress;
private Double weight;
private LocalDateTime createdAt;
private List<Task> tasks;
}

@ -0,0 +1,18 @@
package com.vksfeng.quan.obengine_pojo.spark;
import lombok.Data;
import java.util.List;
@Data
public class SparkRequest {
private String model;
private List<Message> messages;
@Data
public static class Message {
private String role;
private String content;
}
}

@ -0,0 +1,22 @@
package com.vksfeng.quan.obengine_pojo.spark;
import lombok.Data;
import java.util.List;
@Data
public class SparkResponse {
private List<Choice> choices;
@Data
public static class Choice {
private Message message;
}
@Data
public static class Message {
private String content;
}
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.obengine_pojo.vo;
import lombok.Data;
import java.util.List;
@Data
public class FollowUpQuestionVO {
private String question;
private List<String> options;
}

@ -0,0 +1,24 @@
package com.vksfeng.quan.objectivehub_pojo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ObjectiveDTO {
private Long id;
private Long objectiveId;
private Long userId;
private String name;
private String description;
private LocalDate startDate;
private LocalDate endDate;
private Boolean visibility;
private Double weight;
}

@ -0,0 +1,29 @@
package com.vksfeng.quan.objectivehub_pojo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class RecurringTaskDTO {
// task共有
private Long id;
private Long userId;
private Long objectiveId;
private String name;
private String description;
private String status; // 'pending' or 'completed'
private Boolean visibility;
private String type; // 'single' or 'recurring'
// recurring_task类特有
private String period; // 周期("daily", "weekly", "monthly"
private LocalDate startDate; // 周期性任务的开始日期
private LocalDate endDate; // 周期性任务的结束日期
}

@ -0,0 +1,9 @@
package com.vksfeng.quan.objectivehub_pojo.dto;
import lombok.Data;
@Data
public class RelationDTO {
private Long childObjectiveId;
private Long taskId;
}

@ -0,0 +1,30 @@
package com.vksfeng.quan.objectivehub_pojo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SingleTaskDTO {
// task共有
private Long id;
private Long userId;
private Long objectiveId;
private String name;
private String description;
private String status; // 'pending' or 'completed'
private Boolean visibility;
private String type; // 'single' or 'recurring'
// single_task类特有
private LocalDate ddl; // 单次任务的截止日期
private LocalDateTime completedAt; // 单次任务的完成时间
}

@ -0,0 +1,30 @@
package com.vksfeng.quan.objectivehub_pojo.entity;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Builder;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Objective {
private Long id; // 主键
private Long userId; // 用户ID
private String name; // 目标名称
private String description; // 目标描述
private LocalDate startDate; // 开始日期
private LocalDate endDate; // 结束日期
private Boolean visibility; // 可见性
private Double progress; // 进度
private Double weight; // 权重
private LocalDateTime completedAt; // 完成时间
private LocalDateTime createdAt; // 创建时间
private LocalDateTime updatedAt; // 更新时间
}

@ -0,0 +1,35 @@
package com.vksfeng.quan.objectivehub_pojo.entity;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Builder;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Task {
private Long id; // 主键
private Long userId; // 用户ID
private String name; // 任务名称
private String description; // 任务描述
private String status; // 'pending' or 'completed'
private Boolean visibility; // 可见性
private String type; // 'single' or 'recurring'
private LocalDateTime createdAt; // 创建时间
private LocalDateTime updatedAt; // 更新时间
private LocalDate ddl; // 单次任务的截止日期
private LocalDateTime completedAt; // 单次任务的完成时间
private String period; // 周期("daily", "weekly", "monthly"
private LocalDate startDate; // 周期性任务的开始日期
private LocalDate endDate; // 周期性任务的结束日期
private Integer totalCount;
private Integer completedCount;
}

@ -0,0 +1,23 @@
package com.vksfeng.quan.objectivehub_pojo.entity;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Builder;
import java.time.LocalDateTime;
/**
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TaskCompletion {
private Long id;
private Long taskId;
private Long userId;
private LocalDateTime completedAt; //完成时间
}

@ -0,0 +1,29 @@
package com.vksfeng.quan.objectivehub_pojo.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ObjectiveVO {
private Long id;
private Long userId;
private String name;
private String description;
private LocalDate startDate;
private LocalDate endDate;
private Boolean visibility;
private Double progress;
private Double weight;
private LocalDateTime createdAt;
private List<ObjectiveVO> children;
private List<TaskVO> tasks;
}

@ -0,0 +1,37 @@
package com.vksfeng.quan.objectivehub_pojo.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TaskVO {
// task共有
private Long id;
private Long userId;
private Long objectiveId;
private String name;
private String description;
private String status; // 'pending' or 'completed'
private Boolean visibility;
private String type; // 'single' or 'recurring'
private LocalDateTime createdAt;
// 单次任务特有
private LocalDate ddl;
private LocalDateTime completedAt;
// 重复任务特有
private String period; // 周期("daily", "weekly", "monthly"
private LocalDate startDate; // 周期性任务的开始日期
private LocalDate endDate; // 周期性任务的结束日期
private Integer totalCount;
private Integer completedCount;
}

@ -0,0 +1,11 @@
package com.vksfeng.quan.peerhub_pojo.dto;
import lombok.Data;
@Data
public class FeedCommentDTO {
private Long id;
private Long feedId;
private String content;
}

@ -0,0 +1,10 @@
package com.vksfeng.quan.peerhub_pojo.dto;
import lombok.Data;
@Data
public class FriendshipDTO {
private Long userId;
private Long friendId;
private String status; // 'pending', 'accepted', 'blocked'
}

@ -0,0 +1,20 @@
package com.vksfeng.quan.peerhub_pojo.entity;
import lombok.Builder;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Builder
public class Feed {
private Long id;
private Long userId;
private String type; // task_completed, objective_completed, 'post'
private Long relatedId;
private String content;
private Long likeCount;
private Long commentCount;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}

@ -0,0 +1,14 @@
package com.vksfeng.quan.peerhub_pojo.entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class FeedComment {
private Long id;
private Long feedId;
private Long userId;
private String content;
private LocalDateTime createdAt;
}

@ -0,0 +1,15 @@
package com.vksfeng.quan.peerhub_pojo.entity;
import lombok.Builder;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Builder
public class FeedLike {
private Long id;
private Long feedId;
private Long userId;
private LocalDateTime createdAt;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save