diff --git a/quan_backend - without config/.gitignore b/quan_backend - without config/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/quan_backend - without config/.gitignore @@ -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/ diff --git a/quan_backend - without config/pom.xml b/quan_backend - without config/pom.xml new file mode 100644 index 0000000..8915647 --- /dev/null +++ b/quan_backend - without config/pom.xml @@ -0,0 +1,232 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.2 + + + com.vksfeng + quan + 0.0.1-SNAPSHOT + pom + quan + Demo project for Spring Boot + + + + + + + + + quan-common + quan-server + quan-gateway + + + + + + + + + 17 + 3.4.2 + + + + + + + com.vksfeng + quan-common + 0.0.1-SNAPSHOT + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 3.0.4 + + + + org.springframework.boot + spring-boot-starter-data-redis + ${spring-boot.version} + + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} + + + + com.mysql + mysql-connector-j + 9.1.0 + + + + org.projectlombok + lombok + 1.18.30 + + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + + + + com.fasterxml.jackson.core + jackson-databind + 2.18.2 + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + javax.xml.bind + jaxb-api + 2.3.1 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.8.5 + + + + + org.springframework.boot + spring-boot-starter-data-redis + 3.4.2 + + + + org.apache.commons + commons-pool2 + 2.11.1 + + + + io.lettuce + lettuce-core + 6.3.2.RELEASE + + + + + + cn.hutool + hutool-all + 5.8.36 + + + + + org.springframework.boot + spring-boot-starter-mail + 3.4.3 + + + + + commons-lang + commons-lang + 2.6 + + + + + io.minio + minio + 8.5.17 + + + + + + + + + + + com.aliyun.oss + aliyun-sdk-oss + 3.17.4 + + + javax.xml.bind + jaxb-api + 2.3.1 + + + javax.activation + activation + 1.1.1 + + + + org.glassfish.jaxb + jaxb-runtime + 2.3.3 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 3.4.2 + + + + org.projectlombok + lombok + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.projectlombok + lombok + 1.18.36 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + + \ No newline at end of file diff --git a/quan_backend - without config/quan-common/pom.xml b/quan_backend - without config/quan-common/pom.xml new file mode 100644 index 0000000..787ac48 --- /dev/null +++ b/quan_backend - without config/quan-common/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + com.vksfeng + quan + 0.0.1-SNAPSHOT + + + quan-common + + + 17 + 17 + UTF-8 + + + + + io.jsonwebtoken + jjwt + + + javax.xml.bind + jaxb-api + + + org.projectlombok + lombok + + + + com.fasterxml.jackson.core + jackson-databind + + + org.springframework.boot + spring-boot-starter-web + + + cn.hutool + hutool-all + + + io.minio + minio + + + + com.aliyun.oss + aliyun-sdk-oss + + + javax.xml.bind + jaxb-api + + + javax.activation + activation + + + + org.glassfish.jaxb + jaxb-runtime + + + + + + \ No newline at end of file diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/constant/AchievementConstant.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/constant/AchievementConstant.java new file mode 100644 index 0000000..57abe7e --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/constant/AchievementConstant.java @@ -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"; +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/constant/RedisConstant.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/constant/RedisConstant.java new file mode 100644 index 0000000..296d537 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/constant/RedisConstant.java @@ -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"; + + +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/context/BaseContext.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/context/BaseContext.java new file mode 100644 index 0000000..a2e2244 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/context/BaseContext.java @@ -0,0 +1,15 @@ +package com.vksfeng.quan.context; + +public class BaseContext { + public static ThreadLocal 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(); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/BaseException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/BaseException.java new file mode 100644 index 0000000..a061508 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/BaseException.java @@ -0,0 +1,10 @@ +package com.vksfeng.quan.exception; + +public class BaseException extends RuntimeException{ + + BaseException() { } + + BaseException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/DuplicateLikeException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/DuplicateLikeException.java new file mode 100644 index 0000000..d03f812 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/DuplicateLikeException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class DuplicateLikeException extends BaseException { + public DuplicateLikeException() { + super(); + } + + public DuplicateLikeException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/EmailExistsException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/EmailExistsException.java new file mode 100644 index 0000000..3681922 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/EmailExistsException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class EmailExistsException extends BaseException{ + public EmailExistsException() { + + } + + public EmailExistsException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FavoriteAlreadyExistException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FavoriteAlreadyExistException.java new file mode 100644 index 0000000..70e6cc2 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FavoriteAlreadyExistException.java @@ -0,0 +1,13 @@ +package com.vksfeng.quan.exception; + +public class FavoriteAlreadyExistException extends BaseException { + + public FavoriteAlreadyExistException() { + + } + + public FavoriteAlreadyExistException(String msg) { + super(msg); + } + +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FeedNotExistException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FeedNotExistException.java new file mode 100644 index 0000000..14c7c4a --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FeedNotExistException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class FeedNotExistException extends BaseException{ + public FeedNotExistException() { + + } + + public FeedNotExistException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FriendshipAlreadyExistException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FriendshipAlreadyExistException.java new file mode 100644 index 0000000..c4e6e28 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FriendshipAlreadyExistException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class FriendshipAlreadyExistException extends BaseException{ + public FriendshipAlreadyExistException() { + super(); + } + + public FriendshipAlreadyExistException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FriendshipNotExistException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FriendshipNotExistException.java new file mode 100644 index 0000000..f752559 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/FriendshipNotExistException.java @@ -0,0 +1,12 @@ +package com.vksfeng.quan.exception; + +public class FriendshipNotExistException extends BaseException{ + + public FriendshipNotExistException() { + super("好友关系不存在"); + } + + public FriendshipNotExistException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/LikeAlreadyExistException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/LikeAlreadyExistException.java new file mode 100644 index 0000000..b7b5a30 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/LikeAlreadyExistException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class LikeAlreadyExistException extends BaseException{ + public LikeAlreadyExistException() { + super("点赞已存在"); + } + + public LikeAlreadyExistException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/NotLoginException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/NotLoginException.java new file mode 100644 index 0000000..27ee27a --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/NotLoginException.java @@ -0,0 +1,12 @@ +package com.vksfeng.quan.exception; + +public class NotLoginException extends BaseException{ + public NotLoginException() { + + } + + public NotLoginException(String msg) { + super(msg); + } + +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/ObjectiveCreationFailureException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/ObjectiveCreationFailureException.java new file mode 100644 index 0000000..19988bd --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/ObjectiveCreationFailureException.java @@ -0,0 +1,9 @@ +package com.vksfeng.quan.exception; + +public class ObjectiveCreationFailureException extends BaseException{ + public ObjectiveCreationFailureException() { + } + public ObjectiveCreationFailureException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/PasswordErrorException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/PasswordErrorException.java new file mode 100644 index 0000000..9c323f2 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/PasswordErrorException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class PasswordErrorException extends BaseException{ + public PasswordErrorException() { + + } + + public PasswordErrorException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/TaskNotExistException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/TaskNotExistException.java new file mode 100644 index 0000000..bceea2c --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/TaskNotExistException.java @@ -0,0 +1,10 @@ +package com.vksfeng.quan.exception; + +public class TaskNotExistException extends BaseException{ + public TaskNotExistException() { + } + + public TaskNotExistException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UnknownException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UnknownException.java new file mode 100644 index 0000000..1501864 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UnknownException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class UnknownException extends BaseException{ + public UnknownException() { + + } + + public UnknownException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UnknownTaskTypeException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UnknownTaskTypeException.java new file mode 100644 index 0000000..3bcbba7 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UnknownTaskTypeException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class UnknownTaskTypeException extends BaseException{ + public UnknownTaskTypeException() { + + } + + public UnknownTaskTypeException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UserNotExistsException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UserNotExistsException.java new file mode 100644 index 0000000..9fbe1a8 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UserNotExistsException.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.exception; + +public class UserNotExistsException extends BaseException{ + public UserNotExistsException(){ + + } + + public UserNotExistsException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UsernameExistsException.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UsernameExistsException.java new file mode 100644 index 0000000..ab450b2 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/exception/UsernameExistsException.java @@ -0,0 +1,12 @@ +package com.vksfeng.quan.exception; + +public class UsernameExistsException extends BaseException{ + + public UsernameExistsException() { + + } + + public UsernameExistsException(String msg) { + super(msg); + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/properties/AliOSSProperties.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/properties/AliOSSProperties.java new file mode 100644 index 0000000..8f2b5b3 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/properties/AliOSSProperties.java @@ -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; +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/result/PageResult.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/result/PageResult.java new file mode 100644 index 0000000..5b0cd6f --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/result/PageResult.java @@ -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; +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/result/Result.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/result/Result.java new file mode 100644 index 0000000..45ff4b2 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/result/Result.java @@ -0,0 +1,45 @@ +package com.vksfeng.quan.result; + +import lombok.Data; +import java.io.Serializable; + +/** + * 后端统一返回结果 + * @param + */ +@Data +public class Result implements Serializable { + + private Integer code; // 编码:1成功,0和其他数字为失败 + private String msg; // 信息 + private T data; // 数据 + + + + public static Result success() { + Result result = new Result(); + result.code = 1; + return result; + } + + public static Result success(String msg) { + Result result = new Result(); + result.msg = msg; + result.code = 1; + return result; + } + + public static Result success(T object) { + Result result = new Result(); + result.data = object; + result.code = 1; + return result; + } + + public static Result error(String msg) { + Result result = new Result(); + result.msg = msg; + result.code = 0; + return result; + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/AliOSSUtils.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/AliOSSUtils.java new file mode 100644 index 0000000..1576610 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/AliOSSUtils.java @@ -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(); + } +} + diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/JwtUtils.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/JwtUtils.java new file mode 100644 index 0000000..1f94483 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/JwtUtils.java @@ -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 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; + } +} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/MinioUtils.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/MinioUtils.java new file mode 100644 index 0000000..919e3d0 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/MinioUtils.java @@ -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(); +// } +// } +//} diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/RegexPatterns.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/RegexPatterns.java new file mode 100644 index 0000000..f3ecd8b --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/RegexPatterns.java @@ -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}$"; + +} + diff --git a/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/RegexUtils.java b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/RegexUtils.java new file mode 100644 index 0000000..917f675 --- /dev/null +++ b/quan_backend - without config/quan-common/src/main/java/com/vksfeng/quan/util/RegexUtils.java @@ -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); + } +} diff --git a/quan_backend - without config/quan-gateway/pom.xml b/quan_backend - without config/quan-gateway/pom.xml new file mode 100644 index 0000000..f8a4f72 --- /dev/null +++ b/quan_backend - without config/quan-gateway/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + com.vksfeng + quan + 0.0.1-SNAPSHOT + + + quan-gateway + + + 17 + 17 + UTF-8 + + + \ No newline at end of file diff --git a/quan_backend - without config/quan-gateway/src/main/java/com/vksfeng/Main.java b/quan_backend - without config/quan-gateway/src/main/java/com/vksfeng/Main.java new file mode 100644 index 0000000..7003352 --- /dev/null +++ b/quan_backend - without config/quan-gateway/src/main/java/com/vksfeng/Main.java @@ -0,0 +1,7 @@ +package com.vksfeng; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/quan_backend - without config/quan-server/pom.xml b/quan_backend - without config/quan-server/pom.xml new file mode 100644 index 0000000..8219aac --- /dev/null +++ b/quan_backend - without config/quan-server/pom.xml @@ -0,0 +1,125 @@ + + + 4.0.0 + + com.vksfeng + quan + 0.0.1-SNAPSHOT + + + quan-server + + + 17 + 17 + UTF-8 + + + + + + com.vksfeng + quan-common + 0.0.1-SNAPSHOT + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-web + + + + com.mysql + mysql-connector-j + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + + com.fasterxml.jackson.core + jackson-databind + + + + + + io.jsonwebtoken + jjwt + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + + org.springframework.boot + spring-boot-starter-mail + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.apache.commons + commons-pool2 + + + io.lettuce + lettuce-core + + + + org.springframework.boot + spring-boot-starter-websocket + 2.7.4 + + + com.aliyun.oss + aliyun-sdk-oss + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/QuanApplication.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/QuanApplication.java new file mode 100644 index 0000000..28490cc --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/QuanApplication.java @@ -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); + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/controller/AchievementController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/controller/AchievementController.java new file mode 100644 index 0000000..7513219 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/controller/AchievementController.java @@ -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> getUserAchievement() { + return achievementService.getUserAchievement(); + } + + @Operation(summary = "插入成就(管理员接口)") + @PostMapping("/admin/insert") + public Result insertAchievement(@RequestBody AchievementDTO achievementDTO) { + return achievementService.insertAchievement(achievementDTO); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/mapper/AchievementMapper.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/mapper/AchievementMapper.java new file mode 100644 index 0000000..d49b057 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/mapper/AchievementMapper.java @@ -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 findByType(String type); + + void insert(Achievement achievement); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/mapper/UserAchievementMapper.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/mapper/UserAchievementMapper.java new file mode 100644 index 0000000..650b100 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/mapper/UserAchievementMapper.java @@ -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 getUserAchievement(Long userId); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/dto/AchievementDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/dto/AchievementDTO.java new file mode 100644 index 0000000..526f0fd --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/dto/AchievementDTO.java @@ -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 ruleJson; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/Achievement.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/Achievement.java new file mode 100644 index 0000000..9f45b7a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/Achievement.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/AchievementTriggerEvent.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/AchievementTriggerEvent.java new file mode 100644 index 0000000..da4e817 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/AchievementTriggerEvent.java @@ -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 payload; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/RuleCondition.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/RuleCondition.java new file mode 100644 index 0000000..bf4d48c --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/RuleCondition.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/RuleJson.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/RuleJson.java new file mode 100644 index 0000000..3f44058 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/RuleJson.java @@ -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 conditions; + private String logic = "AND"; // 默认为AND +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/UserAchievement.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/UserAchievement.java new file mode 100644 index 0000000..97289ce --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/entity/UserAchievement.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/vo/UserAchievementVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/vo/UserAchievementVO.java new file mode 100644 index 0000000..b1e8692 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/pojo/vo/UserAchievementVO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/service/AchievementService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/service/AchievementService.java new file mode 100644 index 0000000..1fe2daf --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/service/AchievementService.java @@ -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> getUserAchievement(); + + Result insertAchievement(AchievementDTO achievementDTO); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/service/Impl/AchievementServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/service/Impl/AchievementServiceImpl.java new file mode 100644 index 0000000..1d3450a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/service/Impl/AchievementServiceImpl.java @@ -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> getUserAchievement() { + List 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("插入成功"); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementContextBuilder.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementContextBuilder.java new file mode 100644 index 0000000..7dc746b --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementContextBuilder.java @@ -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 buildContext(AchievementTriggerEvent event) { + Long userId = event.getUserId(); + String type = event.getType(); + + Map 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; + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementEventPublisher.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementEventPublisher.java new file mode 100644 index 0000000..d29529e --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementEventPublisher.java @@ -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 payload) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + Map 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); + } + } +} + diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementListener.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementListener.java new file mode 100644 index 0000000..859701e --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/AchievementListener.java @@ -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> records = + redisTemplate.opsForStream().read(StreamReadOptions.empty().block(Duration.ofSeconds(2)).count(10), + StreamOffset.latest(ACHIEVEMENT_STREAM_KEY)); + + if (records != null) { + for (MapRecord record : records) { + handleRecord(record); + } + } + } catch (Exception e) { + log.error("Redis Stream 成就事件监听失败:", e); + break; + } + } + }); + } + + private void handleRecord(MapRecord record) throws JsonProcessingException { + Map value = record.getValue(); + AchievementTriggerEvent event = parseEvent(value); + + log.info("收到行为事件:{}", event); + + List 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 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 value) throws JsonProcessingException { + Long userId = Long.parseLong(value.get("userId").toString()); + String type = value.get("type").toString(); + String payloadStr = value.getOrDefault("payload", "{}").toString(); + Map payload = new ObjectMapper().readValue(payloadStr, new TypeReference<>() {}); + AchievementTriggerEvent event = new AchievementTriggerEvent(); + event.setUserId(userId); + event.setType(type); + event.setPayload(payload); + return event; + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/RuleEvaluator.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/RuleEvaluator.java new file mode 100644 index 0000000..6ab2232 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/achievement/util/RuleEvaluator.java @@ -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 context) { + + List 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; + }; + } + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/entity/TaskCompletionDay.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/entity/TaskCompletionDay.java new file mode 100644 index 0000000..500a407 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/entity/TaskCompletionDay.java @@ -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; // 当天完成任务次数 +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/HeatMapVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/HeatMapVO.java new file mode 100644 index 0000000..3952af1 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/HeatMapVO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/LeaderboardCountVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/LeaderboardCountVO.java new file mode 100644 index 0000000..dc12529 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/LeaderboardCountVO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/TaskCompletionRateVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/TaskCompletionRateVO.java new file mode 100644 index 0000000..3f13117 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/TaskCompletionRateVO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/UserProfileForPeerVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/UserProfileForPeerVO.java new file mode 100644 index 0000000..de48450 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/analysis_pojo/vo/UserProfileForPeerVO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/MinioConfig.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/MinioConfig.java new file mode 100644 index 0000000..0761642 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/MinioConfig.java @@ -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); +// } +// +//} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/OssConfig.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/OssConfig.java new file mode 100644 index 0000000..ef1d95a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/OssConfig.java @@ -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 + /*@ConditionalOnMissingBean注解表示当不存在名为aliOssUtil的bean时,才会创建该bean。 + 这意味着如果已经有其他地方定义了名为aliOssUtil的bean,那么这个方法将不会执行。*/ + @ConditionalOnMissingBean + /*在方法体中,通过依赖注入的方式获取AliOssProperties对象,并使用它的属性值来创建AliOssUtil对象。*/ + public AliOSSUtils aliOssUtil(AliOSSProperties aliOssProperties){ +// log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties); + return new AliOSSUtils(aliOssProperties.getEndpoint(), + aliOssProperties.getAccessKeyId(), + aliOssProperties.getAccessKeySecret(), + aliOssProperties.getBucketName()); + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/RestConfig.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/RestConfig.java new file mode 100644 index 0000000..7995144 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/RestConfig.java @@ -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(); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/WebMvcConfiguration.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/WebMvcConfiguration.java new file mode 100644 index 0000000..e5fef13 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/WebMvcConfiguration.java @@ -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); + } +} \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/WebSocketConfig.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/WebSocketConfig.java new file mode 100644 index 0000000..71c3304 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/config/WebSocketConfig.java @@ -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(); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/AnalysisController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/AnalysisController.java new file mode 100644 index 0000000..d39d933 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/AnalysisController.java @@ -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> getMonthlyTasksCalendar(@RequestParam Long userId, @RequestParam int year, @RequestParam int month) { + if (month < 1 || month > 12) { + return Result.error("月份不合法"); + } + List tasks = analysisService.getMonthlyTasksCalendar(userId, year, month); + return Result.success(tasks); + } + + @Operation(summary = "获取年度任务热力图") + @GetMapping("/heatmap/tasks") + public Result> getYearlyTasksHeatMap(@RequestParam Long userId, @RequestParam int year) { + return analysisService.getYearlyTasksHeatMap(userId, year); + } + + @Operation(summary = "获取任务排行榜") + @GetMapping("/leaderboard/task") + public Result> 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 getFriendObjectiveHubStatus(@PathVariable Long friendId) { + UserProfileForPeerVO userProfileForPeerVO = analysisService.getFriendObjectiveHubStatus(friendId); + return Result.success(userProfileForPeerVO); + } + + @Operation(summary = "获取近一周每日任务完成率") + @GetMapping("/completion/task/weekly") + public Result> 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(); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/AuthController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/AuthController.java new file mode 100644 index 0000000..f017177 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/AuthController.java @@ -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 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(); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FeedController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FeedController.java new file mode 100644 index 0000000..e59cfa6 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FeedController.java @@ -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 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 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> getCommentList(@RequestParam Long feedId) { + List commentList = feedService.getCommentList(feedId); + return Result.success(commentList); + } + + @Operation(summary = "动态信息推送") + @GetMapping("/recent") + public Result> getRecentFeed() { + return feedService.getRecentFeed(); + } + + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FileController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FileController.java new file mode 100644 index 0000000..24457f6 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FileController.java @@ -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); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FriendshipController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FriendshipController.java new file mode 100644 index 0000000..31f5cbf --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/FriendshipController.java @@ -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> getFriends() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + return Result.error("用户未登录"); + } + log.info("获取好友列表,userId:{}", userId); + List friends = friendshipService.getFriends(userId); + return Result.success(friends); + } + + @Operation(summary = "获取好友申请信息") + @GetMapping("/requestlist") + public Result> getFriendRequests() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + return Result.error("用户未登录"); + } + List request = friendshipService.getRequests(userId); + return Result.success(request); + } + + @Operation(summary = "搜索用户以添加好友") + @GetMapping("/search") + public Result searchUser(@RequestParam Long id) { + return friendshipService.searchUser(id); + } + + @Operation(summary = "添加好友") + @PostMapping("/request") + public Result 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 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 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> nearbyUsers() { + return friendshipService.getNearbyUsers(); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ImageProxyController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ImageProxyController.java new file mode 100644 index 0000000..1026c43 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ImageProxyController.java @@ -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 getImage(@RequestParam String url) { + if (url == null || url.isEmpty()) { + return Result.error("缺少 URL 参数"); + } + + return imageProxyService.getImage(url); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ObEngineController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ObEngineController.java new file mode 100644 index 0000000..8b2b2b6 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ObEngineController.java @@ -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> generateFollowup(@RequestBody ObjectiveDTO objectiveDTO) { + return sparkAIService.generateFollowupQuestions(objectiveDTO); + } + + @Operation(summary = "生成详细计划") + @PostMapping("/generateDetailedPlan") + public Result generateDetailedPlan(@RequestBody ObjectiveWithFeedbackDTO objectiveWithFeedbackDTO) { + sparkAIService.generateDetailedPlan(objectiveWithFeedbackDTO); + return Result.success(); + } + + + +} + + diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ObjectiveController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ObjectiveController.java new file mode 100644 index 0000000..046ca37 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ObjectiveController.java @@ -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 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 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> getUserObjectives(@PathVariable("id") Long userId) { + log.info("获取用户目标"); + List objectives = objectiveHubService.getUserObjectives(userId); + return Result.success(objectives); + } + + /** + * 获取根据id获取目标信息 + * @param objectiveId 目标id + * @return 目标信息 + */ + @Operation(summary = "根据id获取目标信息") + @GetMapping("/{id}") + public Result 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("任务移除成功"); + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ResourceHubController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ResourceHubController.java new file mode 100644 index 0000000..e380723 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/ResourceHubController.java @@ -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 createResource(@RequestBody ResourceDTO resourceDTO) { + ResourceVO resourceVO = resourceHubService.createResource(resourceDTO); + return Result.success(resourceVO); + } + + @Operation(summary = "获取资源") + @GetMapping("/{id}") + public Result getResource(@PathVariable Long id) { + ResourceVO resourceVO = resourceHubService.getResource(id); + if (resourceVO == null) { + return Result.error("资源不存在"); + } + return Result.success(resourceVO); + } + + @Operation(summary = "获取资源列表") + @GetMapping + public Result 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 getRecommendResourceList() { + return resourceHubService.getRecommendResourceList(); + } + + @Operation(summary = "获取指定id用户的资源") + @GetMapping("/user/{userId}") + public Result 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 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> getComments(@PathVariable Long id) { + List 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 getFavoriteList(@RequestParam Integer page, @RequestParam Integer pageSize, @RequestParam(required = false) String category) { + PageResult resourceVOList = resourceHubService.getFavoriteList(page, pageSize, category); + return Result.success(resourceVOList); + } + + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/TaskController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/TaskController.java new file mode 100644 index 0000000..389ba0f --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/TaskController.java @@ -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 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 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> getUserTodayTasks(@PathVariable("id") Long userId) { + return Result.success(objectiveHubService.getUserTodayTasks(userId)); + } + + @Operation(summary = "根据id获取任务信息") + @GetMapping("/{id}") + public Result 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 updateRecurringTask(@RequestBody RecurringTaskDTO taskDTO, @PathVariable Long id) { + objectiveHubService.updateRecurringTask(taskDTO, id); + return Result.success("任务修改成功"); + } + + + @Operation(summary = "完成任务") + @PostMapping("/completion") + public Result completeTask(@RequestBody Map 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("任务删除成功"); + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/UserController.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/UserController.java new file mode 100644 index 0000000..dbed274 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/controller/UserController.java @@ -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); + } + + + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/handler/GlobalExceptionHandler.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..b578a27 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/handler/GlobalExceptionHandler.java @@ -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()); + } + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/interceptor/JwtTokenInterceptor.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/interceptor/JwtTokenInterceptor.java new file mode 100644 index 0000000..e55b41a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/interceptor/JwtTokenInterceptor.java @@ -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(); + } + +} \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/FeedMapper.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/FeedMapper.java new file mode 100644 index 0000000..be590a6 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/FeedMapper.java @@ -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 page(Integer offset, Integer pageSize, List userIds, Long userId); + + void addFeedLike(FeedLike feedLike); + + FeedVO getFeedById(Long feedId, Long userId); + + void addFeedComment(FeedComment feedComment); + + void removeFeedLike(Long feedId, Long userId); + + List getCommentList(Long feedId); + + void insertFeed(Feed feed); + + FeedLike getFeedLike(Long feedId, Long userId); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/FriendshipMapper.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/FriendshipMapper.java new file mode 100644 index 0000000..244b8de --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/FriendshipMapper.java @@ -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 list(Long userId); + + void insert(Friendship friendship); + + List getRequests(Long userId); + + void update(Friendship friendship); + + void remove(Long userId, Long friendId); + + List selectByTwoId(Long aId, Long bId); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/ObjectiveMapper.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/ObjectiveMapper.java new file mode 100644 index 0000000..a42d269 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/ObjectiveMapper.java @@ -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 getAllSubObjectivesId(Long objectiveId); + + void deleteRelationByChildId(Long objectiveId); + + void deleteRelationByFatherId(Long objectiveId); + + List getAllObjectivesId(Long userId); + + List getAllMainObjectives(List 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); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/ResourceMapper.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/ResourceMapper.java new file mode 100644 index 0000000..55ace63 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/ResourceMapper.java @@ -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 getResourceList(List 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 getCommentsByResourceId(Long id); + + void addFavorite(ResourceFavorite resourceFavorite); + + boolean isFavorite(Long resourceId, Long userId); + + void removeFavorite(Long resourceId, Long userId); + + Integer getResourceCount(String category, List userIds); + + List getResourceList(List userIds, Long currentUserId, Integer offset, Integer pageSize, String category); + + List 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); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/TaskMapper.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/TaskMapper.java new file mode 100644 index 0000000..1c0e070 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/TaskMapper.java @@ -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 getTodayTasks(Long userId, LocalDate today); + + List getAllTasksIdByObjectiveId(Long objectiveId); + + void deleteObjectiveTaskRelationByObjectiveId(Long objectiveId); + + void createObjectiveTaskRelation(Long objectiveId, Long taskId); + + void deleteObjectiveTaskRelation(Long objectiveId, Long taskId); + + List getMonthlyTasksCalendar(Long userId, int year, int month); + + List 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 getWeeklyTaskLeaderboard(List userIds); + + List getMonthlyTaskLeaderboard(List userIds); + + Integer getTaskCount(Long userId); + + Integer getCompletedTaskCount(Long userId); + + List getTotalCount(Long userId, LocalDate startDate, LocalDate endDate); + + List getCompleteCount(Long userId, LocalDate startDate, LocalDate endDate); + + List findRecurringCompletedTasks(); + + List getYearlyTasksHeatMap(Long userId, int year); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/UserMapper.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/UserMapper.java new file mode 100644 index 0000000..1c2bb78 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/mapper/UserMapper.java @@ -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 findUser(User user); + + /** + * 根据id查找条件 + * @param id + * @return + */ + User getUserById(Long id); + + /** + * 更新用户信息 + */ + void update(User user); + + void saveUserLocation(UserLocation userLocation); + + List searchUsers(List userIds, Long currentUserId); + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/Feedback.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/Feedback.java new file mode 100644 index 0000000..4b1a86d --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/Feedback.java @@ -0,0 +1,9 @@ +package com.vksfeng.quan.obengine_pojo.dto; + +import lombok.Data; + +@Data +public class Feedback { + private String question; + private String answer; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/ObjectivePlanDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/ObjectivePlanDTO.java new file mode 100644 index 0000000..78837ab --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/ObjectivePlanDTO.java @@ -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 subObjectives; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/ObjectiveWithFeedbackDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/ObjectiveWithFeedbackDTO.java new file mode 100644 index 0000000..01486de --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/ObjectiveWithFeedbackDTO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/SubObjectiveDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/SubObjectiveDTO.java new file mode 100644 index 0000000..698adeb --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/dto/SubObjectiveDTO.java @@ -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 tasks; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/spark/SparkRequest.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/spark/SparkRequest.java new file mode 100644 index 0000000..b38bf0a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/spark/SparkRequest.java @@ -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 messages; + + @Data + public static class Message { + private String role; + private String content; + + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/spark/SparkResponse.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/spark/SparkResponse.java new file mode 100644 index 0000000..3d89455 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/spark/SparkResponse.java @@ -0,0 +1,22 @@ +package com.vksfeng.quan.obengine_pojo.spark; + +import lombok.Data; + +import java.util.List; + +@Data +public class SparkResponse { + private List choices; + + @Data + public static class Choice { + private Message message; + + } + + @Data + public static class Message { + private String content; + + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/vo/FollowUpQuestionVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/vo/FollowUpQuestionVO.java new file mode 100644 index 0000000..63ffad4 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/obengine_pojo/vo/FollowUpQuestionVO.java @@ -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 options; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/ObjectiveDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/ObjectiveDTO.java new file mode 100644 index 0000000..626cddb --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/ObjectiveDTO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/RecurringTaskDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/RecurringTaskDTO.java new file mode 100644 index 0000000..f18ab2b --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/RecurringTaskDTO.java @@ -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; // 周期性任务的结束日期 +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/RelationDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/RelationDTO.java new file mode 100644 index 0000000..0505457 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/RelationDTO.java @@ -0,0 +1,9 @@ +package com.vksfeng.quan.objectivehub_pojo.dto; + +import lombok.Data; + +@Data +public class RelationDTO { + private Long childObjectiveId; + private Long taskId; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/SingleTaskDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/SingleTaskDTO.java new file mode 100644 index 0000000..d9ebbbf --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/dto/SingleTaskDTO.java @@ -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; // 单次任务的完成时间 +} + diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/Objective.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/Objective.java new file mode 100644 index 0000000..e7ff3af --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/Objective.java @@ -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; // 更新时间 + +} \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/Task.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/Task.java new file mode 100644 index 0000000..daf21be --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/Task.java @@ -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; +} \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/TaskCompletion.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/TaskCompletion.java new file mode 100644 index 0000000..5726238 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/entity/TaskCompletion.java @@ -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; //完成时间 +} + diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/vo/ObjectiveVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/vo/ObjectiveVO.java new file mode 100644 index 0000000..218c28a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/vo/ObjectiveVO.java @@ -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 children; + private List tasks; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/vo/TaskVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/vo/TaskVO.java new file mode 100644 index 0000000..a9d97a4 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/objectivehub_pojo/vo/TaskVO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/dto/FeedCommentDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/dto/FeedCommentDTO.java new file mode 100644 index 0000000..2fc2222 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/dto/FeedCommentDTO.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/dto/FriendshipDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/dto/FriendshipDTO.java new file mode 100644 index 0000000..45207e6 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/dto/FriendshipDTO.java @@ -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' +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/Feed.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/Feed.java new file mode 100644 index 0000000..be377d2 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/Feed.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/FeedComment.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/FeedComment.java new file mode 100644 index 0000000..0bf6620 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/FeedComment.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/FeedLike.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/FeedLike.java new file mode 100644 index 0000000..c30880a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/FeedLike.java @@ -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; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/Friendship.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/Friendship.java new file mode 100644 index 0000000..85a1230 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/entity/Friendship.java @@ -0,0 +1,14 @@ +package com.vksfeng.quan.peerhub_pojo.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class Friendship { + private Long userId; + private Long friendId; + private String status; // 'pending', 'accepted', 'blocked' + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FeedCommentVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FeedCommentVO.java new file mode 100644 index 0000000..52ca35d --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FeedCommentVO.java @@ -0,0 +1,16 @@ +package com.vksfeng.quan.peerhub_pojo.vo; + +import com.vksfeng.quan.user_pojo.vo.UserVO; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class FeedCommentVO { + private Long id; + private Long feedId; + private Long userId; + private UserVO user; + private String content; + private LocalDateTime createdAt; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FeedVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FeedVO.java new file mode 100644 index 0000000..4c4a4eb --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FeedVO.java @@ -0,0 +1,21 @@ +package com.vksfeng.quan.peerhub_pojo.vo; + +import com.vksfeng.quan.user_pojo.vo.UserVO; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class FeedVO { + private Long id; + private Long userId; + private UserVO user; + private String type; // task_completed, objective_completed, 'post' + private Long relatedId; + private String content; + private Boolean isLiked; + private Long likeCount; + private Long commentCount; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FriendshipVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FriendshipVO.java new file mode 100644 index 0000000..96a29b5 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/FriendshipVO.java @@ -0,0 +1,10 @@ +package com.vksfeng.quan.peerhub_pojo.vo; + +public class FriendshipVO { + private Long userId; + private Long friendId; + private String friendUsername; + private String friendNickname; + private String friendAvatarUrl; + private String status; // 'pending', 'accepted', 'blocked' +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/UserSearchVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/UserSearchVO.java new file mode 100644 index 0000000..4ab83bf --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/peerhub_pojo/vo/UserSearchVO.java @@ -0,0 +1,13 @@ +package com.vksfeng.quan.peerhub_pojo.vo; + +import lombok.Data; + +@Data +public class UserSearchVO { + private Long id; + private String username; + private String email; + private String nickname; + private String avatarUrl; + private Boolean isFriend; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/dto/ResourceCommentDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/dto/ResourceCommentDTO.java new file mode 100644 index 0000000..a240b5f --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/dto/ResourceCommentDTO.java @@ -0,0 +1,13 @@ +package com.vksfeng.quan.resourcehub_pojo.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ResourceCommentDTO { + private Long id; + private Long userId; + private Long resourceId; + private String content; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/dto/ResourceDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/dto/ResourceDTO.java new file mode 100644 index 0000000..3af206c --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/dto/ResourceDTO.java @@ -0,0 +1,15 @@ +package com.vksfeng.quan.resourcehub_pojo.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ResourceDTO { + private Long id; + private String title; + private String description; + private String category; // "article","book","course","insight" + private String url; + private String content; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/Resource.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/Resource.java new file mode 100644 index 0000000..f0d9a95 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/Resource.java @@ -0,0 +1,18 @@ +package com.vksfeng.quan.resourcehub_pojo.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class Resource { + private Long id; + private Long userId; + private String title; + private String description; + private String category; // "article","book","course","tool","insight" + private String url; + private String content; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceComment.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceComment.java new file mode 100644 index 0000000..13d4d93 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceComment.java @@ -0,0 +1,16 @@ +package com.vksfeng.quan.resourcehub_pojo.entity; + +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Builder +public class ResourceComment { + private Long id; + private Long userId; + private Long resourceId; + private String content; + private LocalDateTime createdAt; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceFavorite.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceFavorite.java new file mode 100644 index 0000000..3c98671 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceFavorite.java @@ -0,0 +1,15 @@ +package com.vksfeng.quan.resourcehub_pojo.entity; + +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Builder +public class ResourceFavorite { + private Long id; + private Long userId; + private Long resourceId; + private LocalDateTime createdAt; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceLike.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceLike.java new file mode 100644 index 0000000..02b09b1 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/entity/ResourceLike.java @@ -0,0 +1,13 @@ +package com.vksfeng.quan.resourcehub_pojo.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ResourceLike { + private Long id; + private Long userId; + private Long resourceId; + private LocalDateTime createdAt; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ImageResult.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ImageResult.java new file mode 100644 index 0000000..3ee4941 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ImageResult.java @@ -0,0 +1,13 @@ +package com.vksfeng.quan.resourcehub_pojo.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ImageResult { + private String base64; + private String contentType; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ResourceCommentVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ResourceCommentVO.java new file mode 100644 index 0000000..5fc1dd6 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ResourceCommentVO.java @@ -0,0 +1,15 @@ +package com.vksfeng.quan.resourcehub_pojo.vo; + +import com.vksfeng.quan.user_pojo.vo.UserVO; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ResourceCommentVO { + private Long id; + private Long resourceId; + private String content; + private LocalDateTime createdAt; + private UserVO userVO; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ResourceVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ResourceVO.java new file mode 100644 index 0000000..93a7a11 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/resourcehub_pojo/vo/ResourceVO.java @@ -0,0 +1,24 @@ +package com.vksfeng.quan.resourcehub_pojo.vo; + +import com.vksfeng.quan.user_pojo.vo.UserVO; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ResourceVO { + private Long id; + private Long userId; + private String title; + private String description; + private String category; // "article","book","course","insight" + private String url; + private String content; + private LocalDateTime createdAt; + private UserVO userVO; + private Boolean isLiked; + private Boolean isFavorite; + private Long likeCount; + private Long commentCount; + private Long favoriteCount; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/scheduler/TaskStatusScheduler.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/scheduler/TaskStatusScheduler.java new file mode 100644 index 0000000..7ac289c --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/scheduler/TaskStatusScheduler.java @@ -0,0 +1,55 @@ +package com.vksfeng.quan.scheduler; + +import com.vksfeng.quan.mapper.TaskMapper; +import com.vksfeng.quan.objectivehub_pojo.entity.Task; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +@Slf4j +@Component +public class TaskStatusScheduler { + + @Autowired + private TaskMapper taskMapper; + + @Scheduled(cron = "0 0 0 * * ?") // 每天凌晨执行 + public void refreshRecurringTasks() { + doRefresh(); + } + + public void doRefresh() { + log.info("开始刷新周期任务状态..."); + List tasks = taskMapper.findRecurringCompletedTasks(); + + LocalDateTime now = LocalDateTime.now(); + for (Task task : tasks) { + LocalDateTime completedAt = task.getCompletedAt(); + if (completedAt == null) { + continue; + } + boolean needReset = switch (task.getPeriod()) { +// case "daily" -> Duration.between(completedAt, now).toDays() >= 1; +// case "weekly" -> Duration.between(completedAt, now).toDays() >= 7; + case "daily" -> now.isAfter(completedAt.plusDays(1)); + case "weekly" -> now.isAfter(completedAt.plusWeeks(1)); + case "monthly" -> now.isAfter(completedAt.plusMonths(1)); + default -> false; + }; + if (needReset) { + task.setStatus("pending"); + task.setUpdatedAt(now); + task.setCompletedAt(null); + taskMapper.updateById(task, task.getId()); + log.info("任务 [{}] 状态已重置为 pending", task.getId()); + } + } + log.info("周期任务状态刷新完毕"); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/AnalysisService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/AnalysisService.java new file mode 100644 index 0000000..63682d3 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/AnalysisService.java @@ -0,0 +1,28 @@ +package com.vksfeng.quan.service; + +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 java.util.List; + +public interface AnalysisService { + List getMonthlyTasksCalendar(Long userId, int year, int month); + + List getWeeklyTaskLeaderboard(); + + List getMonthlyTaskLeaderboard(); + + UserProfileForPeerVO getFriendObjectiveHubStatus(Long friendId); + + Result> getWeeklyTaskCompletionRate(); + + Result getUserActivity(); + + Result getUserSocialAchievement(); + + Result> getYearlyTasksHeatMap(Long userId, int year); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/CaptchaService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/CaptchaService.java new file mode 100644 index 0000000..a2d9ee0 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/CaptchaService.java @@ -0,0 +1,7 @@ +package com.vksfeng.quan.service; + +public interface CaptchaService { + String generateCaptcha(String email); + + boolean validateCaptcha(String email, String code); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/EmailService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/EmailService.java new file mode 100644 index 0000000..2a1ca40 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/EmailService.java @@ -0,0 +1,7 @@ +package com.vksfeng.quan.service; + +import jakarta.mail.MessagingException; + +public interface EmailService { + void sendCaptchaEmail(String email, String authCode) throws MessagingException; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FeedService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FeedService.java new file mode 100644 index 0000000..f954840 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FeedService.java @@ -0,0 +1,29 @@ +package com.vksfeng.quan.service; + +import com.vksfeng.quan.objectivehub_pojo.entity.Objective; +import com.vksfeng.quan.objectivehub_pojo.entity.Task; +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 java.util.List; + +public interface FeedService { + PageResult getFeedList(Integer page, Integer pageSize); + + void like(Long feedId); + + void unlike(Long feedId); + + void comment(FeedCommentDTO feedCommentDTO); + + List getCommentList(Long feedId); + + void autoPostTaskCompletion(Task task); + + void autoPostObjectiveCompletion(Objective objective); + + Result> getRecentFeed(); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FileService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FileService.java new file mode 100644 index 0000000..7918c15 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FileService.java @@ -0,0 +1,9 @@ +package com.vksfeng.quan.service; + +import com.vksfeng.quan.result.Result; +import org.apache.tomcat.util.http.fileupload.FileUploadException; +import org.springframework.web.multipart.MultipartFile; + +public interface FileService { + Result uploadFile(MultipartFile file) throws FileUploadException; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FriendshipService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FriendshipService.java new file mode 100644 index 0000000..18f4d6a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/FriendshipService.java @@ -0,0 +1,26 @@ +package com.vksfeng.quan.service; + +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.user_pojo.vo.UserVO; + +import java.util.List; + +public interface FriendshipService { + List getFriends(Long userId); + + void addFriendRequest(FriendshipDTO friendshipDTO); + + List getRequests(Long userId); + + void acceptFriendRequest(FriendshipDTO friendshipDTO); + + void removeFriend(FriendshipDTO friendshipDTO); + + public boolean isExist(Long aId, Long bId); + + Result searchUser(Long id); + + Result> getNearbyUsers(); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ImageProxyService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ImageProxyService.java new file mode 100644 index 0000000..9f81f94 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ImageProxyService.java @@ -0,0 +1,8 @@ +package com.vksfeng.quan.service; + +import com.vksfeng.quan.resourcehub_pojo.vo.ImageResult; +import com.vksfeng.quan.result.Result; + +public interface ImageProxyService { + Result getImage(String url); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ObjectiveHubService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ObjectiveHubService.java new file mode 100644 index 0000000..2cf69be --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ObjectiveHubService.java @@ -0,0 +1,87 @@ +package com.vksfeng.quan.service; + +import com.vksfeng.quan.obengine_pojo.dto.SubObjectiveDTO; +import com.vksfeng.quan.objectivehub_pojo.dto.ObjectiveDTO; +import com.vksfeng.quan.objectivehub_pojo.dto.RecurringTaskDTO; +import com.vksfeng.quan.objectivehub_pojo.dto.SingleTaskDTO; +import com.vksfeng.quan.objectivehub_pojo.vo.ObjectiveVO; +import com.vksfeng.quan.objectivehub_pojo.vo.TaskVO; +import com.vksfeng.quan.result.Result; + +import java.util.List; + +public interface ObjectiveHubService { + + // ------------------------------------------- 目标相关 ------------------------------------------- + + // 创建目标 + ObjectiveVO createObjective(ObjectiveDTO objectiveDTO); + + // 创建子目标(创建目标同时关联其与父目标的关系) + ObjectiveVO createObjectiveWithRelation(ObjectiveDTO objectiveDTO, Long parentObjectiveId); + + // 获取用户所有目标的结构化信息 + List getUserObjectives(Long userId); + + // 根据id获取目标信息 + ObjectiveVO getObjectiveById(Long objectiveId); + + // 更新目标信息 + void updateObjective(ObjectiveDTO objectiveDTO, Long objectiveId); + + // 删除目标,及目标所含有的信息 + void deleteObjective(Long objectiveId); + + void addAiGuideForObjective(Long objectiveId, String aiGuide); + + // 创建目标与目标的关系 + void createObjectiveRelation(Long parentObjectiveId, Long childObjectiveId); + + void createObjectiveTaskRelation(Long objectiveId, Long taskId); + + void deleteObjectiveRelation(Long parentObjectiveId, Long childObjectiveId); + + void deleteObjectiveTaskRelation(Long objectiveId, Long taskId); + + + // ------------------------------------------- 任务相关 ------------------------------------------- + + // 获取用户今日任务 + List getUserTodayTasks(Long userId); + + // 创建单次任务(DTO中包含与目标的关联信息) + TaskVO createSingleTask(SingleTaskDTO taskDTO); + + // 创建重复任务(DTO中包含与目标的关联信息) + TaskVO createRecurringTask(RecurringTaskDTO taskDTO); + + // 根据id获取任务信息 + TaskVO getTaskById(Long id); + + // 更新单次任务信息 + void updateSingleTask(SingleTaskDTO taskDTO, Long id); + + // 更新重复任务信息 + void updateRecurringTask(RecurringTaskDTO taskDTO, Long id); + + // 删除任务,及其与目标之间的关联 + void deleteTask(Long id); + + // 完成任务 + Result completeTask(Long id); + + // 撤销任务完成 + void deleteTaskCompletion(Long id); + + // ------------------------------------------- 统计相关 ------------------------------------------- + + Integer getObjectiveCount(Long userId); + + Integer getCompletedObjectiveCount(Long userId); + + Integer getTaskCount(Long userId); + + Integer getCompletedTaskCount(Long userId); + + Result getAiGuideForObjective(Long objectiveId); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/PromptTemplateManager.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/PromptTemplateManager.java new file mode 100644 index 0000000..5d34ed4 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/PromptTemplateManager.java @@ -0,0 +1,4 @@ +package com.vksfeng.quan.service; + +public interface PromptTemplateManager { +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ResourceHubService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ResourceHubService.java new file mode 100644 index 0000000..26dd624 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/ResourceHubService.java @@ -0,0 +1,47 @@ +package com.vksfeng.quan.service; + +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 java.util.List; + +public interface ResourceHubService { + ResourceVO createResource(ResourceDTO resourceDTO); + + ResourceVO getResource(Long id); + +// List getResourceList(); + + void deleteResource(Long id); + + void addLike(Long id); + + void removeLike(Long id); + + ResourceCommentVO addComment(Long resourceId, String content); + + List getCommentsByResourceId(Long id); + + void addFavorite(Long resourceId); + + void removeFavorite(Long resourceId); + + PageResult getResourceList(Integer page, Integer pageSize, String category); + + PageResult getFavoriteList(Integer page, Integer pageSize, String category); + + Result getUserResourceList(Long userId, Integer page, Integer pageSize, String category); + + Result getRecommendResourceList(); + + Integer getUserResourceCount(Long userId); + + Integer getUserReceivedLikes(Long userId); + + Integer getUserReceivedComments(Long userId); + + Integer getUserReceivedFavorites(Long userId); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/SparkAIService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/SparkAIService.java new file mode 100644 index 0000000..1d8b20f --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/SparkAIService.java @@ -0,0 +1,14 @@ +package com.vksfeng.quan.service; + +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 java.util.List; + +public interface SparkAIService { + Result> generateFollowupQuestions(ObjectiveDTO objectiveDTO); + + void generateDetailedPlan(ObjectiveWithFeedbackDTO objectiveWithFeedbackDTO); +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/UserService.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/UserService.java new file mode 100644 index 0000000..e3eea7c --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/UserService.java @@ -0,0 +1,27 @@ +package com.vksfeng.quan.service; + +import com.vksfeng.quan.peerhub_pojo.vo.UserSearchVO; +import com.vksfeng.quan.result.Result; +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 java.util.List; + +public interface UserService { + void register(UserDTO userDTO); + + User login(UserDTO userDTO); + + User getUserById(Long id); + + void update(UserDTO userDTO); + + User getUserByEmail(String email); + + Result setUserLocation(UserLocation userLocationDTO); + + List searchUsers(List userIds, Long userId); + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/AnalysisServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/AnalysisServiceImpl.java new file mode 100644 index 0000000..47bc7ef --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/AnalysisServiceImpl.java @@ -0,0 +1,201 @@ +package com.vksfeng.quan.service.impl; + +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.analysis_pojo.vo.UserProfileForPeerVO; +import com.vksfeng.quan.context.BaseContext; +import com.vksfeng.quan.exception.FriendshipAlreadyExistException; +import com.vksfeng.quan.exception.FriendshipNotExistException; +import com.vksfeng.quan.exception.NotLoginException; +import com.vksfeng.quan.mapper.FriendshipMapper; +import com.vksfeng.quan.mapper.TaskMapper; +import com.vksfeng.quan.objectivehub_pojo.vo.TaskVO; +import com.vksfeng.quan.result.Result; +import com.vksfeng.quan.service.*; +import com.vksfeng.quan.user_pojo.vo.UserActivityVO; +import com.vksfeng.quan.user_pojo.vo.UserSocialAchievementVO; +import com.vksfeng.quan.user_pojo.vo.UserVO; +import io.swagger.v3.oas.models.security.SecurityScheme; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.Year; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +@Service +@Slf4j +public class AnalysisServiceImpl implements AnalysisService { + + @Autowired + private TaskMapper taskMapper; + + @Autowired + private ObjectiveHubService objectiveHubService; + + @Autowired + private ResourceHubService resourceHubService; + + @Autowired + private FriendshipService friendshipService; + + public Long getUserId() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + throw new NotLoginException("用户未登录"); + } + return userId; + } + + public List getMonthlyTasksCalendar(Long userId, int year, int month) { + List tasks = taskMapper.getMonthlyTasksCalendar(userId, year, month); + return tasks; + } + +// public List getMonthlyTasksHeatMap(Long userId, int year, int month) { +// // 1. 获取数据库记录 +// List dbData = taskMapper.selectDailyCompletion(userId, year, month); +// +// // 2. 创建当月日期模板 +// YearMonth yearMonth = YearMonth.of(year, month); +// Map countMap = dbData.stream() +// .collect(Collectors.toMap(TaskCompletionDay::getDay, TaskCompletionDay::getCount)); +// +// // 3. 生成完整日期数据 +// return IntStream.rangeClosed(1, yearMonth.lengthOfMonth()) +// .mapToObj(day -> { +// LocalDate date = yearMonth.atDay(day); +// return new HeatMapVO( +// date.format(DateTimeFormatter.ISO_DATE), +// countMap.getOrDefault(day, 0) +// ); +// }) +// .collect(Collectors.toList()); +// } + + @Override + public List getWeeklyTaskLeaderboard() { + Long userId = getUserId(); + List friendId = friendshipService.getFriends(userId); + List userIds = new ArrayList<>(friendId.stream().map(UserVO::getId).toList()); + userIds.add(userId); + return taskMapper.getWeeklyTaskLeaderboard(userIds); + } + + @Override + public List getMonthlyTaskLeaderboard() { + Long userId = getUserId(); + List friendId = friendshipService.getFriends(userId); + List userIds = new ArrayList<>(friendId.stream().map(UserVO::getId).toList()); + userIds.add(userId); + return taskMapper.getMonthlyTaskLeaderboard(userIds); + } + + @Override + public UserProfileForPeerVO getFriendObjectiveHubStatus(Long friendId) { + Long userId = getUserId(); + if (!friendshipService.isExist(userId, friendId) && friendId != userId) { + throw new FriendshipNotExistException("对方还不是你的好友哦"); + } + Integer objectiveCount = objectiveHubService.getObjectiveCount(friendId); + Integer completedObjectiveCount = objectiveHubService.getCompletedObjectiveCount(friendId); + Integer taskCount = objectiveHubService.getTaskCount(friendId); + Integer completedTaskCount = objectiveHubService.getCompletedTaskCount(friendId); + return new UserProfileForPeerVO( + objectiveCount, + completedObjectiveCount, + taskCount, + completedTaskCount + ); + } + + @Override + public Result> getWeeklyTaskCompletionRate() { + Long userId = getUserId(); + List last7Days = getLast7Days(); + LocalDate startDate = last7Days.get(last7Days.size() - 1); + LocalDate endDate = last7Days.get(0); + + // 获取 totalCount + Map totalCountMap = taskMapper.getTotalCount(userId, startDate, endDate) + .stream().collect(Collectors.toMap(TaskCompletionRateVO::getDate, TaskCompletionRateVO::getTotalCount)); + + // 获取 completeCount + Map completeCountMap = taskMapper.getCompleteCount(userId, startDate, endDate) + .stream().collect(Collectors.toMap(TaskCompletionRateVO::getDate, TaskCompletionRateVO::getCompleteCount)); + + // 组装最终结果 + List result = new ArrayList<>(); + for (LocalDate date : last7Days) { + int totalCount = totalCountMap.getOrDefault(date, 0); + int completeCount = completeCountMap.getOrDefault(date, 0); + double completionRate = (totalCount == 0) ? 0 : (completeCount * 100.0 / totalCount); + + TaskCompletionRateVO vo = new TaskCompletionRateVO(); + vo.setDate(date); + vo.setTotalCount(totalCount); + vo.setCompleteCount(completeCount); + vo.setCompletionRate(completionRate); + result.add(vo); + } + + return Result.success(result); + } + + public List getLast7Days() { + List last7Days = new ArrayList<>(); + LocalDate today = LocalDate.now(); + for (int i = 0; i < 7; i++) { + last7Days.add(today.minusDays(i)); + } + return last7Days; + } + + @Override + public Result getUserActivity() { + Long userId = getUserId(); + Integer taskCompletedCount = taskMapper.getCompletedTaskCount(userId); + Integer objectiveCompletedCount = objectiveHubService.getCompletedObjectiveCount(userId); + Integer resourcePostedCount = resourceHubService.getUserResourceCount(userId); + UserActivityVO userActivityVO = new UserActivityVO(taskCompletedCount, objectiveCompletedCount, resourcePostedCount); + return Result.success(userActivityVO); + } + + @Override + public Result getUserSocialAchievement() { + Long userId = getUserId(); + Integer receivedLikes = resourceHubService.getUserReceivedLikes(userId); + Integer receivedComments = resourceHubService.getUserReceivedComments(userId); + Integer receivedFavorites = resourceHubService.getUserReceivedFavorites(userId); + UserSocialAchievementVO userSocialAchievementVO = new UserSocialAchievementVO(receivedLikes, receivedComments, receivedFavorites); + return Result.success(userSocialAchievementVO); + } + + @Override + public Result> getYearlyTasksHeatMap(Long userId, int year) { + List heatMap = taskMapper.getYearlyTasksHeatMap(userId, year); + Map map = heatMap.stream() + .collect(Collectors.toMap(HeatMapVO::getDate, HeatMapVO::getCount)); + + List fullYear = new ArrayList<>(); + LocalDate start = LocalDate.of(year, 1, 1); + LocalDate end = LocalDate.of(year, 12, 31); + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { + fullYear.add(new HeatMapVO(date, map.getOrDefault(date, 0))); + } + return Result.success(fullYear); + } + + + + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/CaptchaServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/CaptchaServiceImpl.java new file mode 100644 index 0000000..5b8c541 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/CaptchaServiceImpl.java @@ -0,0 +1,43 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.service.CaptchaService; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import java.time.Duration; + +@Service +public class CaptchaServiceImpl implements CaptchaService { + + @Autowired + private StringRedisTemplate redisTemplate; + + /** + * 生成验证码 + * @param email 目标邮箱 + * @return 验证码 + */ + public String generateCaptcha(String email) { + String code = RandomStringUtils.randomNumeric(6); + redisTemplate.opsForValue().set( + "CAPTCHA:" + email, + code, + Duration.ofMinutes(5) // 5分钟有效期 + ); + return code; + } + + /** + * 验证码校验 + * @param email 邮箱 + * @param code 验证码 + * @return 是否验证通过 + */ + public boolean validateCaptcha(String email, String code) { + String captcha = redisTemplate.opsForValue().get("CAPTCHA:" + email); + return captcha != null && captcha.equals(code); + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/EmailServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/EmailServiceImpl.java new file mode 100644 index 0000000..a03a2ab --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/EmailServiceImpl.java @@ -0,0 +1,173 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.service.EmailService; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.stereotype.Service; + +import java.util.concurrent.CompletableFuture; + +@Service +@Slf4j +@EnableAsync +public class EmailServiceImpl implements EmailService{ + + @Autowired + private JavaMailSender mailSender; + +// public void sendCaptchaEmail(String email, String authCode) { +// SimpleMailMessage message = new SimpleMailMessage(); +// message.setFrom("872556642@qq.com"); +// message.setTo(email); +// message.setSubject("Quan验证码"); +// message.setText("您的验证码为:" + authCode + "有效时间5分钟"); +// mailSender.send(message); +// } + + + public void sendCaptchaEmail(String email, String authCode) throws MessagingException { + CompletableFuture.runAsync(() -> { + try { + processEmailSending(email, authCode); + } catch (MessagingException e) { + throw new RuntimeException(e); + } + }); + } + + @Async + private void processEmailSending(String email, String authCode) throws MessagingException { + MimeMessage message = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); + + // Set sender, recipient, and subject + helper.setFrom("872556642@qq.com"); + helper.setTo(email); + helper.setSubject("Quan 验证服务"); + + String htmlContent = buildHtmlishContent(authCode); + helper.setText(htmlContent, true); + + addInkElements(helper); + + mailSender.send(message); + } + + private String buildHtmlishContent(String authCode) { + return "\n" + + "\n" + + "\n" + + " \n" + + " \n" + + " 验证函\n" + + " \n" + + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " 验证函\n" + + " \n" + + " \n" + + " 阁下台鉴:\n" + + " 您的验证码为:\n" + + " " + authCode + "\n" + + " 有效期5分钟,请及时研磨书写。\n" + + " \n" + + " \n" + + " \n" + + "\n" + + ""; + } + + private void addInkElements(MimeMessageHelper helper) throws MessagingException { + // 使用 ClassPathResource 加载资源目录下的图片 + ClassPathResource imageResource = new ClassPathResource("static/email_img/ink.jpg"); + if (imageResource.exists()) { + helper.addInline("ink", imageResource); + } + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FeedServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FeedServiceImpl.java new file mode 100644 index 0000000..e496bf4 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FeedServiceImpl.java @@ -0,0 +1,136 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.context.BaseContext; +import com.vksfeng.quan.exception.FeedNotExistException; +import com.vksfeng.quan.exception.NotLoginException; +import com.vksfeng.quan.mapper.FeedMapper; +import com.vksfeng.quan.objectivehub_pojo.entity.Objective; +import com.vksfeng.quan.objectivehub_pojo.entity.Task; +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 com.vksfeng.quan.result.PageResult; +import com.vksfeng.quan.result.Result; +import com.vksfeng.quan.service.FeedService; +import com.vksfeng.quan.service.FriendshipService; +import com.vksfeng.quan.user_pojo.vo.UserVO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +public class FeedServiceImpl implements FeedService { + + @Autowired + private FeedMapper feedMapper; + + @Autowired + private FriendshipService friendshipService; + + public Long getUserId() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + throw new NotLoginException("用户未登录"); + } + return userId; + } + + public PageResult getFeedList(Integer page, Integer pageSize) { + // 1. 获取总记录数和总页数 + Integer total = feedMapper.count(); + Integer totalPage = (int) (total % pageSize == 0 ? total / pageSize : total / pageSize + 1); + // 2. 获取分页查询结果列表 + Integer offset = (page - 1) * pageSize; + Long userId = getUserId(); + List friendId = friendshipService.getFriends(userId); + List userIds = new ArrayList<>(friendId.stream().map(UserVO::getId).toList()); + userIds.add(userId); + List list = feedMapper.page(offset, pageSize, userIds, userId); + + return new PageResult(totalPage, total, list); + } + + public void like(Long feedId) { + // TODO 权限管理、仅能点赞自己与好友的动态 + Long userId = getUserId(); + if (feedMapper.getFeedById(feedId, userId) == null) { + throw new FeedNotExistException("动态不存在"); + } + FeedLike feedLike = FeedLike.builder() + .feedId(feedId) + .userId(userId) + .createdAt(LocalDateTime.now()) + .build(); + feedMapper.addFeedLike(feedLike); + } + + + public void unlike(Long feedId) { + Long userId = getUserId(); + feedMapper.removeFeedLike(feedId, userId); + } + + public void comment(FeedCommentDTO feedCommentDTO) { + Long userId = getUserId(); + if (feedMapper.getFeedById(feedCommentDTO.getFeedId(), userId) == null) { + throw new FeedNotExistException("动态不存在"); + } + FeedComment feedComment = new FeedComment(); + feedComment.setFeedId(feedCommentDTO.getFeedId()); + feedComment.setContent(feedCommentDTO.getContent()); + feedComment.setUserId(userId); + feedComment.setCreatedAt(LocalDateTime.now()); + feedMapper.addFeedComment(feedComment); + } + + public List getCommentList(Long feedId) { + if (feedMapper.getFeedById(feedId, getUserId()) == null) { + throw new FeedNotExistException("动态不存在"); + } + return feedMapper.getCommentList(feedId); + } + + public void autoPostTaskCompletion(Task task) { + Long userId = getUserId(); + Feed feed = Feed.builder() + .userId(userId) + .type("task_completed") + .relatedId(task.getId()) + .content("完成了任务:" + task.getName()) + .createdAt(LocalDateTime.now()) + .updatedAt(LocalDateTime.now()) + .build(); + feedMapper.insertFeed(feed); + } + + public void autoPostObjectiveCompletion(Objective objective) { + Long userId = getUserId(); + Feed feed = Feed.builder() + .userId(userId) + .type("objective_completed") + .relatedId(objective.getId()) + .content("完成了目标:" + objective.getName()) + .createdAt(LocalDateTime.now()) + .updatedAt(LocalDateTime.now()) + .build(); + feedMapper.insertFeed(feed); + } + + @Override + public Result> getRecentFeed() { + PageResult result = getFeedList(1, 3); + List list = result.getList(); + if (list != null && !list.isEmpty()) { + return Result.success(list); + } else { + return Result.success(new ArrayList<>()); + } + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FileServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FileServiceImpl.java new file mode 100644 index 0000000..7f8726e --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FileServiceImpl.java @@ -0,0 +1,61 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.result.Result; +import com.vksfeng.quan.service.FileService; +import com.vksfeng.quan.util.AliOSSUtils; +//import com.vksfeng.quan.util.MinioUtils; +//import io.minio.MinioAsyncClient; +import lombok.extern.slf4j.Slf4j; +import org.apache.tomcat.util.http.fileupload.FileUploadException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.UUID; + +@Service +@Slf4j +public class FileServiceImpl implements FileService { + +// @Autowired +// private MinioUtils minioUtils; + + @Autowired + private AliOSSUtils aliOSSUtils; + +// public Result uploadFile(MultipartFile file) throws FileUploadException { +// log.info("文件上传:{}", file); +// try { +// return Result.success(minioUtils.uploadFile(file)); +// } catch (IOException e) { +// log.error("文件上传失败:{}", e); +// } +// return Result.error("文件上传失败"); +// } + + public Result uploadFile(MultipartFile file) throws FileUploadException { + log.info("文件上传:{}", file); + try { + //原始文件名 + /*首先通过file.getOriginalFilename()获取原始文件名*/ + String originalFilename = file.getOriginalFilename(); + //截取原始文件名的后缀 dfdfdf.png + /*然后通过originalFilename.lastIndexOf(".")获取文件名的后缀。*/ + String extension = originalFilename.substring(originalFilename.lastIndexOf(".")); + //构造新文件名称 + /*使用UUID.randomUUID().toString()生成一个随机的文件名,并将后缀拼接在文件名后面,构造出新的文件名。*/ + String objectName = UUID.randomUUID().toString() + extension; + + //文件的请求路径 + /*然后,调用aliOssUtil.upload方法将文件上传到OSS,并获取文件的请求路径。*/ + String filePath = aliOSSUtils.upload(file.getBytes(), objectName); + /*最后,返回一个Result对象,其中包含上传文件的请求路径。*/ + return Result.success((Object)filePath); + } catch (IOException e) { + log.error("文件上传失败:{}", e); + } + return Result.error("文件上传失败"); + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FriendshipServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FriendshipServiceImpl.java new file mode 100644 index 0000000..168ed09 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/FriendshipServiceImpl.java @@ -0,0 +1,176 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.achievement.util.AchievementEventPublisher; +import com.vksfeng.quan.constant.RedisConstant; +import com.vksfeng.quan.context.BaseContext; +import com.vksfeng.quan.exception.FriendshipAlreadyExistException; +import com.vksfeng.quan.exception.NotLoginException; +import com.vksfeng.quan.mapper.FriendshipMapper; +import com.vksfeng.quan.peerhub_pojo.dto.FriendshipDTO; +import com.vksfeng.quan.peerhub_pojo.entity.Friendship; +import com.vksfeng.quan.peerhub_pojo.vo.UserSearchVO; +import com.vksfeng.quan.result.Result; +import com.vksfeng.quan.service.FriendshipService; +import com.vksfeng.quan.service.UserService; +import com.vksfeng.quan.user_pojo.entity.User; +import com.vksfeng.quan.user_pojo.vo.UserVO; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.geo.Distance; +import org.springframework.data.geo.GeoResult; +import org.springframework.data.geo.GeoResults; +import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.domain.geo.GeoReference; +import org.springframework.data.redis.domain.geo.Metrics; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static com.vksfeng.quan.constant.AchievementConstant.FRIEND_ADDED; + +@Service +@Slf4j +public class FriendshipServiceImpl implements FriendshipService { + + @Autowired + private FriendshipMapper friendshipMapper; + + @Autowired + private UserService userService; + + @Autowired + private AchievementEventPublisher achievementEventPublisher; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public Long getUserId() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + throw new NotLoginException("用户未登录"); + } + return userId; + } + + /** + * 获取好友列表,双向,自己可是user可是friend + * @param userId + * @return + */ + public List getFriends(Long userId) { + return friendshipMapper.list(userId); + } + + public boolean isExist(Long aId, Long bId) { + List list = friendshipMapper.selectByTwoId(aId, bId); + return !list.isEmpty(); + } + + @Override + public Result searchUser(Long id) { + Long userId = getUserId(); + User user = userService.getUserById(id); + if (user == null) { + return Result.success("用户不存在"); + } + UserSearchVO userSearchVO = new UserSearchVO(); + BeanUtils.copyProperties(user, userSearchVO); + if (userId.equals(id) || isExist(userId, id)) { + userSearchVO.setIsFriend(true); + } else { + userSearchVO.setIsFriend(false); + } + return Result.success(userSearchVO); + } + + @Override + public Result> getNearbyUsers() { + Long userId = getUserId(); + Boolean exists = stringRedisTemplate.opsForGeo() + .position(RedisConstant.USER_LOCATION_KEY, userId.toString()) + .get(0) != null; + + if (!exists) { + return Result.error("请先上传位置信息"); + } + + double radiusMeters = 5000; + GeoResults> results = stringRedisTemplate.opsForGeo().search( + RedisConstant.USER_LOCATION_KEY, + new GeoReference.GeoMemberReference(userId.toString()), // 以当前用户为中心 + new Distance(radiusMeters, Metrics.METERS), // 指定查询半径 + RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs() + .includeDistance() // 返回距离信息 + .sortAscending() // 结果按距离从近到远排序 + ); + + // 解析结果,提取 userId 列表 + List userIds = new ArrayList<>(); + if (results != null && !results.getContent().isEmpty()) { + for (GeoResult> result : results.getContent()) { + Long nearbyUserId = Long.valueOf(result.getContent().getName()); // 提取 userId + if (!nearbyUserId.equals(userId)) { // 过滤掉自己 + userIds.add(nearbyUserId); + } + } + } else { + return Result.success(List.of()); + } + if (userIds.isEmpty()) { + return Result.success(List.of()); + } + List userSearchVOs = userService.searchUsers(userIds, userId); + return Result.success(userSearchVOs); + } + + /** + * 添加好友请求:单向,自己是user + * @param friendshipDTO + */ + public void addFriendRequest(FriendshipDTO friendshipDTO) { + if (isExist(friendshipDTO.getUserId(), friendshipDTO.getFriendId())) { + throw new FriendshipAlreadyExistException("好友关系或好友申请已存在"); + } + Friendship friendship = new Friendship(); + BeanUtils.copyProperties(friendshipDTO, friendship); + friendship.setCreatedAt(LocalDateTime.now()); + friendship.setUpdatedAt(LocalDateTime.now()); + friendshipMapper.insert(friendship); + } + + /** + * 获取好友请求,单向,自己是friend + * @param userId + * @return + */ + public List getRequests(Long userId) { + return friendshipMapper.getRequests(userId); + } + + /** + * 接受好友请求,单向,自己是friend + * @param friendshipDTO + */ + public void acceptFriendRequest(FriendshipDTO friendshipDTO) { + Friendship friendship = new Friendship(); + BeanUtils.copyProperties(friendshipDTO, friendship); + friendship.setStatus("accepted"); + friendship.setUpdatedAt(LocalDateTime.now()); + friendshipMapper.update(friendship); + achievementEventPublisher.publish(friendshipDTO.getUserId(), FRIEND_ADDED, null); + achievementEventPublisher.publish(friendshipDTO.getFriendId(), FRIEND_ADDED, null); + } + + /** + * 删除好友,双向,自己可是user可是friend + * @param friendshipDTO + */ + public void removeFriend(FriendshipDTO friendshipDTO) { + friendshipMapper.remove(friendshipDTO.getUserId(), friendshipDTO.getFriendId()); + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ImageProxyServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ImageProxyServiceImpl.java new file mode 100644 index 0000000..6a51560 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ImageProxyServiceImpl.java @@ -0,0 +1,42 @@ +package com.vksfeng.quan.service.impl; + +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.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Base64; + +@Service +public class ImageProxyServiceImpl implements ImageProxyService { + @Autowired + private RestTemplate restTemplate; + + /** + * 代理图片请求 + * @param imageUrl 外部图片的 URL + * @return 返回 Result 封装的图片数据 + */ + public Result getImage(String imageUrl) { + try { + // 获取图片内容 + ResponseEntity response = restTemplate.exchange(imageUrl, HttpMethod.GET, null, byte[].class); + byte[] imageBytes = response.getBody(); + String contentType = response.getHeaders().getContentType().toString(); // 例如 image/png + + // 编码为 base64 字符串 + String base64 = Base64.getEncoder().encodeToString(imageBytes); + + // 返回包含 base64 和 contentType 的 ImageResult + ImageResult imageResult = new ImageResult(base64, contentType); + return Result.success(imageResult); + } catch (Exception e) { + return Result.error("图片代理失败: " + e.getMessage()); + } + } +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ObjectiveHubServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ObjectiveHubServiceImpl.java new file mode 100644 index 0000000..c2963be --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ObjectiveHubServiceImpl.java @@ -0,0 +1,649 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.achievement.util.AchievementEventPublisher; +import com.vksfeng.quan.context.BaseContext; +import com.vksfeng.quan.exception.NotLoginException; +import com.vksfeng.quan.exception.ObjectiveCreationFailureException; +import com.vksfeng.quan.exception.TaskNotExistException; +import com.vksfeng.quan.mapper.ObjectiveMapper; +import com.vksfeng.quan.mapper.TaskMapper; +import com.vksfeng.quan.objectivehub_pojo.dto.ObjectiveDTO; +import com.vksfeng.quan.objectivehub_pojo.dto.RecurringTaskDTO; +import com.vksfeng.quan.objectivehub_pojo.dto.SingleTaskDTO; +import com.vksfeng.quan.objectivehub_pojo.entity.Objective; +import com.vksfeng.quan.objectivehub_pojo.entity.Task; +import com.vksfeng.quan.objectivehub_pojo.entity.TaskCompletion; +import com.vksfeng.quan.objectivehub_pojo.vo.ObjectiveVO; +import com.vksfeng.quan.objectivehub_pojo.vo.TaskVO; +import com.vksfeng.quan.result.Result; +import com.vksfeng.quan.service.FeedService; +import com.vksfeng.quan.service.ObjectiveHubService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.*; + +import static com.vksfeng.quan.constant.AchievementConstant.OBJECTIVE_ADDED; +import static com.vksfeng.quan.constant.AchievementConstant.TASK_COMPLETED; + +@Service +@Slf4j +public class ObjectiveHubServiceImpl implements ObjectiveHubService { + + @Autowired + private ObjectiveMapper objectiveMapper; + + @Autowired + private TaskMapper taskMapper; + + @Autowired + private FeedService feedService; + + @Autowired + private AchievementEventPublisher achievementEventPublisher; + + public Long getUserId() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + throw new NotLoginException("用户未登录"); + } + return userId; + } + + /** + * 新增目标 + * @param objectiveDTO + * @return + */ + public ObjectiveVO createObjective(ObjectiveDTO objectiveDTO) { + Objective objective = new Objective(); +// log.info("传入的对象:{}", objectiveDTO); + BeanUtils.copyProperties(objectiveDTO, objective); + if (objective.getUserId() == null) { + objective.setUserId(getUserId()); + } + // 字段补充 + objective.setCreatedAt(LocalDateTime.now()); + objective.setUpdatedAt(LocalDateTime.now()); + // 默认字段 + objective.setVisibility(true); + objective.setProgress(0.0); + objective.setWeight(1.0); + objectiveMapper.insert(objective); + achievementEventPublisher.publish(objective.getUserId(), OBJECTIVE_ADDED, null); + ObjectiveVO objectiveVO = new ObjectiveVO(); + BeanUtils.copyProperties(objective, objectiveVO); + return objectiveVO; + } + + /** + * 获取用户目标及其结构信息 + * @param userId + * @return + */ + public List getUserObjectives(Long userId) { + // 获取用户的所有主目标id + List mainObjectivesIds = getAllMainObjectivesId(userId); + if(mainObjectivesIds == null || mainObjectivesIds.isEmpty()) { + // 如果没有主目标,则直接返回空 + return null; + } + // 建立主目标数组,查找所有主目标内容 + List mainObjectives = objectiveMapper.getAllMainObjectives(mainObjectivesIds); + List mainObjectiveVOs = new ArrayList<>(); + for (Objective mainObjective: mainObjectives) { + mainObjectiveVOs.add(loadMainObjectiveDetails(mainObjective)); + } + return mainObjectiveVOs; + } + + /** + * 获取用户所有主目标id + * @param userId + * @return + */ + public List getAllMainObjectivesId(Long userId) { + List mainObjectivesIds = objectiveMapper.getAllObjectivesId(userId); + Iterator iterator = mainObjectivesIds.iterator(); + while (iterator.hasNext()) { + Long objectiveId = iterator.next(); + if (isSubObjective(objectiveId)) { + iterator.remove(); + } + } + return mainObjectivesIds; + } + + /** + * 判断是否为子目标,即只要没有出现在孩子列表中,则不是子目标(不能用是否出现在父目标中来判断,否则空目标不能找到) + * @param objectiveId + * @return + */ + private boolean isSubObjective(Long objectiveId) { + return objectiveMapper.isSubObjective(objectiveId); + } + + /** + * 根据目标 ID 获取目标信息。 + * 该方法支持主目标与子目标的判断及处理: + * - 若该目标没有子目标,视为子目标,直接加载相关任务信息; + * - 若该目标含有子目标,视为主目标,递归加载所有子目标和任务信息,并计算进度。 + * 主目标在计算进度后需要同步其完成状态,规则如下: + * 1. 当目标未完成(即 completedAt == null): + * - 若子目标或任务变动使得进度达到 1.0,视为完成,更新完成时间; + * 2. 当目标已完成(即 completedAt != null): + * - 若子目标或任务变动导致进度 < 1.0,视为未完成,清除完成时间; + * 3. 无论目标是否完成: + * - 若本次计算出的进度与数据库中记录的进度不同,则更新数据库中的进度; + * - 否则不做更新操作,避免不必要的写操作。 + * 注意:子目标和任务的完成或取消完成会引起主目标进度的实时变动, + * 因此每次获取主目标信息时需重新计算以确保一致性。 + * @param objectiveId + * @return + */ + @Transactional + public ObjectiveVO getObjectiveById(Long objectiveId) { + Objective objective = objectiveMapper.selectById(objectiveId); + if (objective == null) { + return null; + } + // 获取其所有子目标 + List subObjectivesIds = objectiveMapper.getAllSubObjectivesId(objectiveId); + if (subObjectivesIds.isEmpty()) { + // 子目标为空,则其本身是子目标,只需补全所有任务信息 + return loadSubObjectiveDetails(objective); + } else { + // 有子目标,则为主目标,先补全子目标信息,再补全自己的信息,包含进度计算 + ObjectiveVO objectiveVO = loadMainObjectiveDetails(objective); + Double progress = calculateParentObjectiveProgress(objectiveVO); + if (objective.getCompletedAt() != null) { + // 目标完成时间不为null,则证明目标已完成 + if (progress < 1.0) { + // 证明任务有变动,取消完成状态 + objectiveMapper.completeObjectiveById(null, objectiveId); + } + } else { + // 目标时间为null,则证明目标未完成 + if (progress >= 1.0) { + // 证明任务已完成,设置完成时间 + objectiveMapper.completeObjectiveById(LocalDateTime.now(), objectiveId); + feedService.autoPostObjectiveCompletion(objective); + } + } + if (!Objects.equals(objective.getProgress(), progress)) { + objectiveMapper.updateProgress(progress, objectiveId); + objectiveVO.setProgress(progress); + } + return objectiveVO; + } + } + + /** + * 为主目标填充信息 + * @param mainObjective + * @return + */ + private ObjectiveVO loadMainObjectiveDetails(Objective mainObjective) { + List children = new ArrayList<>(); + List subObjectivesIds = objectiveMapper.getAllSubObjectivesId(mainObjective.getId()); + for (Long subObjectiveId : subObjectivesIds) { + Objective subObjective = objectiveMapper.selectById(subObjectiveId); + children.add(loadSubObjectiveDetails(subObjective)); + } + ObjectiveVO mainObjectiveVO = new ObjectiveVO(); + BeanUtils.copyProperties(mainObjective, mainObjectiveVO); + mainObjectiveVO.setChildren(children); + return mainObjectiveVO; + } + + /** + * 为子目标补全信息 + * @param subObjective + * @return + */ + public ObjectiveVO loadSubObjectiveDetails(Objective subObjective) { + ObjectiveVO subObjectiveVO = new ObjectiveVO(); + BeanUtils.copyProperties(subObjective, subObjectiveVO); + // 补全所有任务信息 + List tasks = new ArrayList<>(); + List taskIds = taskMapper.getAllTasksIdByObjectiveId(subObjective.getId()); + for (Long taskId : taskIds) { + Task task = taskMapper.selectById(taskId); + TaskVO taskVO = new TaskVO(); + BeanUtils.copyProperties(task, taskVO); + tasks.add(taskVO); + } + subObjectiveVO.setTasks(tasks); + return subObjectiveVO; + } + + /** + * 根据id更新目标 + * @param objectiveDTO + * @param objectiveId + */ + public void updateObjective(ObjectiveDTO objectiveDTO, Long objectiveId) { + Objective objective = new Objective(); + BeanUtils.copyProperties(objectiveDTO, objective); + objectiveMapper.updateById(objective, objectiveId); + } + + /** + * 根据id删除目标 + * @param objectiveId + */ + @Transactional + public void deleteObjective(Long objectiveId) { + // 获取其所有子目标 + List subObjectivesIds = objectiveMapper.getAllSubObjectivesId(objectiveId); + if (subObjectivesIds.isEmpty()) { + // 子目标为空,则其本身是子目标,删除子目标与任务的关系及任务本身 + deleteSubObjective(objectiveId); + } else { + // 有子目标,则自己为父目标 + // 先删除所有子目标,再删除本身 + for (Long subObjectiveId : subObjectivesIds) { + deleteSubObjective(subObjectiveId); + } + // 把自己和所有子目标与的关系删除掉 + objectiveMapper.deleteRelationByFatherId(objectiveId); + // 删除ai指导 + objectiveMapper.deleteAiGuideForObjective(objectiveId); + // 再删除自己 + objectiveMapper.deleteById(objectiveId); + } + } + + @Override + public void addAiGuideForObjective(Long objectiveId, String aiGuide) { + objectiveMapper.addAiGuideForObjective(objectiveId, aiGuide); + } + + /** + * 根据id删除子目标 + * @param objectiveId + */ + @Transactional + public void deleteSubObjective(Long objectiveId) { + + // 获取其所有任务id + List tasksIds = taskMapper.getAllTasksIdByObjectiveId(objectiveId); + // 先删除该子目标与任务的关系 + for (Long taskId : tasksIds) { + // 再删除所有任务 + deleteTask(taskId); + } + // 先删除子目标与父目标的关联关系 + objectiveMapper.deleteRelationByChildId(objectiveId); + // 再删除目标本身 + objectiveMapper.deleteById(objectiveId); + } + + /** + * 获取用户今日需要完成的任务 + * @param userId + * @return + */ + public List getUserTodayTasks(Long userId) { + List task = taskMapper.getTodayTasks(userId, LocalDate.now()); + return task; + } + + /** + * 创建单次任务 + * @param taskDTO + * @return + */ + @Transactional + public TaskVO createSingleTask(SingleTaskDTO taskDTO) { + // 补充字段,准备插入 + Task task = new Task(); + BeanUtils.copyProperties(taskDTO, task); + if (task.getUserId() == null) { + task.setUserId(getUserId()); + } + task.setCreatedAt(LocalDateTime.now()); + task.setUpdatedAt(LocalDateTime.now()); + task.setStatus("pending"); + task.setVisibility(true); + task.setType("single"); + // 这俩字段对于单次任务来说,都是1和0,无意义,后续也不改动 + task.setTotalCount(1); + task.setCompletedCount(0); + taskMapper.insert(task); + + // 获取目标id,建立与目标的关系 + Long objectiveId = taskDTO.getObjectiveId(); + Long taskId = task.getId(); + if (objectiveId != null) { + // 建立关系 + taskMapper.insertObjectiveTaskRelation(objectiveId, taskId); + } else { + throw new IllegalArgumentException("任务不能独立存在"); + } + + // 返回VO + TaskVO taskVO = new TaskVO(); + BeanUtils.copyProperties(task, taskVO); + taskVO.setObjectiveId(objectiveId); + + return taskVO; + } + + public Integer calculateTaskTotalCount(LocalDate start, LocalDate end, String period) { + // period 为 daily weekly monthly + if (start.isAfter(end)) { + throw new IllegalArgumentException("Start date must be before or equal to end date."); + } + + switch (period.toLowerCase()) { + case "daily": + return (int) ChronoUnit.DAYS.between(start, end) + 1; // 包含起始和结束日期 + case "weekly": + long weeks = ChronoUnit.WEEKS.between(start, end); + // 如果起始日期和结束日期在同一周,也算作一周 + if (weeks == 0) { + return 1; + } + // 计算完整的周数,并加上起始日期所在的那周 + return (int) (weeks + 1); + case "monthly": + long months = ChronoUnit.MONTHS.between(start, end); + // 如果起始日期和结束日期在同一个月,也算作一个月 + if (months == 0) { + return 1; + } + // 计算完整的月数,并加上起始日期所在的那个月 + return (int) (months + 1); + default: + throw new IllegalArgumentException("Invalid period. Period must be 'daily', 'weekly', or 'monthly'."); + } + } + + /** + * 创建重复任务 + * @param taskDTO + * @return + */ + @Transactional + public TaskVO createRecurringTask(RecurringTaskDTO taskDTO) { + // 补充字段,准备插入 + Task task = new Task(); + BeanUtils.copyProperties(taskDTO, task); + if (task.getUserId() == null) { + task.setUserId(getUserId()); + } + task.setCreatedAt(LocalDateTime.now()); + task.setUpdatedAt(LocalDateTime.now()); + task.setStatus("pending"); + task.setVisibility(true); + task.setType("recurring"); + task.setTotalCount(calculateTaskTotalCount(taskDTO.getStartDate(),taskDTO.getEndDate(), taskDTO.getPeriod())); + task.setCompletedCount(0); + taskMapper.insert(task); + + // 获取目标id,建立与目标的关系 + Long objectiveId = taskDTO.getObjectiveId(); + Long taskId = task.getId(); + if (objectiveId != null) { + // 建立关系 + taskMapper.insertObjectiveTaskRelation(objectiveId, taskId); + } else { + throw new IllegalArgumentException("任务不能独立存在"); + } + + // 返回VO + TaskVO taskVO = new TaskVO(); + BeanUtils.copyProperties(task, taskVO); + taskVO.setObjectiveId(objectiveId); + + return taskVO; + } + + /** + * 根据id获取任务信息 + * @param id + * @return + */ + public TaskVO getTaskById(Long id) { + Task task = taskMapper.selectById(id); + TaskVO taskVO = new TaskVO(); + BeanUtils.copyProperties(task, taskVO); + Long objectiveId = taskMapper.getObjectiveIdByTaskId(id); + taskVO.setObjectiveId(objectiveId); + return taskVO; + } + + /** + * 更新单次任务 + * @param id + */ + public void updateSingleTask(SingleTaskDTO taskDTO, Long id) { + Task task = new Task(); + BeanUtils.copyProperties(taskDTO, task); + task.setUpdatedAt(LocalDateTime.now()); + taskMapper.updateById(task, id); + } + + /** + * 更新重复任务 + * @param id + */ + @Transactional + public void updateRecurringTask(RecurringTaskDTO taskDTO, Long id) { + Task task = new Task(); + BeanUtils.copyProperties(taskDTO, task); + task.setUpdatedAt(LocalDateTime.now()); + if (taskDTO.getStartDate() != null || taskDTO.getEndDate() != null) { + task.setTotalCount(calculateTaskTotalCount(taskDTO.getStartDate(), taskDTO.getEndDate(), taskDTO.getPeriod())); + } + taskMapper.updateById(task, id); + } + + /** + * 删除任务及其关联信息 + * @param id + */ + @Transactional + public void deleteTask(Long id) { + // 先删关系 + taskMapper.deleteObjectiveTaskRelationByTaskId(id); + taskMapper.deleteTaskCompletionByTaskId(id); + // 再删任务 + taskMapper.deleteById(id); + } + + public void createObjectiveRelation(Long parentObjectiveId, Long childObjectiveId) { + objectiveMapper.createObjectiveRelation(parentObjectiveId, childObjectiveId); + } + + public void createObjectiveTaskRelation(Long objectiveId, Long taskId) { + taskMapper.createObjectiveTaskRelation(objectiveId, taskId); + } + + public void deleteObjectiveRelation(Long parentObjectiveId, Long childObjectiveId) { + objectiveMapper.deleteObjectiveRelation(parentObjectiveId, childObjectiveId); + } + + public void deleteObjectiveTaskRelation(Long objectiveId, Long taskId) { + taskMapper.deleteObjectiveTaskRelation(objectiveId, taskId); + } + + @Transactional + public Result completeTask(Long id) { + // 判断任务类型 + Task task = taskMapper.selectById(id); + if (task == null) { + throw new TaskNotExistException("任务不存在"); + } + LocalDateTime now = LocalDateTime.now(); + if (task.getType().equals("single")) { + if (task.getStatus().equals("completed")) { + // 任务已完成,不重复执行 + return Result.success("任务已经完成,无需重复操作"); + } + task.setStatus("completed"); + task.setCompletedAt(now); + task.setUpdatedAt(now); + taskMapper.updateById(task, id); + } else if (task.getType().equals("recurring")) { + // TODO 下一周期自动刷新状态 + if (task.getStatus().equals("completed")) { + // 任务已完成,不重复执行 + return Result.success("已完成本周期内的任务"); + } + task.setCompletedCount(task.getCompletedCount() + 1); + task.setStatus("completed"); + task.setCompletedAt(now); + task.setUpdatedAt(now); + taskMapper.updateById(task, id); + } + TaskCompletion taskCompletion = TaskCompletion.builder() + .taskId(id) + .userId(task.getUserId()) + .completedAt(now) + .build(); + taskMapper.addTaskCompletion(taskCompletion); + // 自动发布动态 + feedService.autoPostTaskCompletion(task); + // 发布完成任务时间 + achievementEventPublisher.publish(task.getUserId(), TASK_COMPLETED, null); +// Long objectiveId = taskMapper.getObjectiveIdByTaskId(id); +// Long fatherObjectiveId = objectiveMapper.getFatherObjectiveIdBySubObjectiveId(objectiveId); +// if (fatherObjectiveId != null) { +// objectiveId = fatherObjectiveId; +// } +// calculateProgress(); + return Result.success(); + } + + @Transactional + public void deleteTaskCompletion(Long id) { + LocalDateTime now = LocalDateTime.now(); + Task task = taskMapper.selectById(id); + if (task == null) { + throw new TaskNotExistException("任务不存在"); + } + if (task.getStatus().equals("pending")) { + // 任务未完成,不执行取消操作 + return; + } + if (task.getType().equals("single")) { + task.setStatus("pending"); + task.setCompletedAt(null); + task.setUpdatedAt(now); + taskMapper.updateById(task, id); + taskMapper.deleteTaskCompletionByTaskId(id); + } else if (task.getType().equals("recurring")) { + task.setStatus("pending"); + task.setUpdatedAt(now); + task.setCompletedCount(task.getCompletedCount() - 1); + taskMapper.updateById(task, id); + // 获取最新的一条完成记录并删除 + Long recordId = taskMapper.getLatestCompletionRecordId(id); + taskMapper.deleteTaskCompletionByRecordId(recordId); + } + } + + @Transactional + public ObjectiveVO createObjectiveWithRelation(ObjectiveDTO objectiveDTO, Long parentObjectiveId) { + ObjectiveVO objectiveVO = createObjective(objectiveDTO); + Long childId = objectiveVO.getId(); + if (parentObjectiveId == null) { + throw new ObjectiveCreationFailureException("未指定父任务"); + } + if (parentObjectiveId.equals(childId)) { + throw new ObjectiveCreationFailureException("父任务不能是子任务"); + } + createObjectiveRelation(parentObjectiveId, objectiveVO.getId()); + + return objectiveVO; + } + + @Override + public Integer getObjectiveCount(Long userId) { + return objectiveMapper.getObjectiveCount(userId); + } + + @Override + public Integer getCompletedObjectiveCount(Long userId) { + return objectiveMapper.getCompletedObjectiveCount(userId); + } + + @Override + public Integer getTaskCount(Long userId) { + return taskMapper.getTaskCount(userId); + } + + @Override + public Integer getCompletedTaskCount(Long userId) { + return taskMapper.getCompletedTaskCount(userId); + } + + @Override + public Result getAiGuideForObjective(Long objectiveId) { + String aiGuide = objectiveMapper.getAiGuideForObjective(objectiveId); + return Result.success((Object) aiGuide); + } + + public double calculateTaskProgress(TaskVO task) { + if ("single".equals(task.getType())) { + return "completed".equals(task.getStatus()) ? 1.0 : 0.0; + } else if ("recurring".equals(task.getType())) { + return task.getTotalCount() > 0 ? + (double) task.getCompletedCount() / task.getTotalCount() : 0.0; + } + return 0.0; + } + + public Double calculateProgress(ObjectiveVO objectiveVO) { + if (objectiveVO == null) { + return 1.0; + } + + List tasks = objectiveVO.getTasks(); + if (tasks == null || tasks.isEmpty()) { + return 1.0; + } + + double totalProgress = 0.0; + int taskCount = 0; + + for (TaskVO task : tasks) { + totalProgress += calculateTaskProgress(task); + taskCount++; + } + + return taskCount > 0 ? totalProgress / taskCount : 0.0; + } + + /** + * 计算父目标,真正用于展示的数据 + * @param parentObjective + * @return + */ + public Double calculateParentObjectiveProgress(ObjectiveVO parentObjective) { + if (parentObjective == null || parentObjective.getChildren() == null) { + return 1.0; + } +// log.info("正在计算{}的进度", parentObjective.getName()); + double totalProgress = 0.0; + int childCount = 0; + + for (ObjectiveVO child : parentObjective.getChildren()) { +// log.info("{}的进度为{}", child.getName(), calculateProgress(child)); + totalProgress += calculateProgress(child); + childCount++; + } + return childCount > 0 ? totalProgress / childCount : 0.0; + } + + + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/PromptTemplateManagerImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/PromptTemplateManagerImpl.java new file mode 100644 index 0000000..9b596a7 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/PromptTemplateManagerImpl.java @@ -0,0 +1,122 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.constant.RedisConstant; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Map; + + +import java.nio.file.*; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Service +public class PromptTemplateManagerImpl { + + @Autowired + private StringRedisTemplate redisTemplate; + + private static final String REDIS_KEY_PREFIX = RedisConstant.PROMPT_TEMPLATE_KEY + ":"; + + @Value("classpath:prompts") + private Resource promptsDirectory; + + // 文件夹路径 + private Path promptsPath; + + @PostConstruct + public void loadPromptTemplates() { + try { + File folder = promptsDirectory.getFile(); + promptsPath = folder.toPath(); + + // 先加载现有模板 + loadTemplatesFromFolder(promptsPath); + + // 启动监听器监控文件变化 + startFileWatchService(); + } catch (IOException e) { + throw new RuntimeException("Failed to load prompt templates", e); + } + } + + private void loadTemplatesFromFolder(Path folder) throws IOException { + File[] files = folder.toFile().listFiles((dir, name) -> name.endsWith(".txt") || name.endsWith(".md")); + if (files != null) { + for (File file : files) { + String code = file.getName().substring(0, file.getName().lastIndexOf('.')); + String content = Files.readString(file.toPath(), StandardCharsets.UTF_8); + redisTemplate.opsForValue().set(REDIS_KEY_PREFIX + code, content); + } + } + } + + // 文件监听方法 + private void startFileWatchService() { + Thread watchThread = new Thread(() -> { + try (WatchService watchService = FileSystems.getDefault().newWatchService()) { + // 注册文件夹,监听修改和创建事件 + promptsPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY); + + while (true) { + WatchKey key; + try { + key = watchService.poll(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + break; + } + + if (key == null) continue; + + for (WatchEvent> event : key.pollEvents()) { + if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE || event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) { + String filename = event.context().toString(); + if (filename.endsWith(".txt") || filename.endsWith(".md")) { + // 文件修改或新增时更新缓存 + String code = filename.substring(0, filename.lastIndexOf('.')); + File file = new File(promptsPath.toFile(), filename); + String content = Files.readString(file.toPath(), StandardCharsets.UTF_8); + redisTemplate.opsForValue().set(REDIS_KEY_PREFIX + code, content); + } + } + } + + // 重置密钥 + boolean valid = key.reset(); + if (!valid) { + break; + } + } + } catch (IOException e) { + throw new RuntimeException("Failed to start file watch service", e); + } + }); + + watchThread.setDaemon(true); + watchThread.start(); + } + + public String getContent(String code) { + return redisTemplate.opsForValue().get(REDIS_KEY_PREFIX + code); + } + + public String render(String code, Map variables) { + String template = getContent(code); + if (template == null) return null; + for (Map.Entry entry : variables.entrySet()) { + // 使用正则表达式来替换所有的占位符 + template = template.replaceAll("\\{" + entry.getKey() + "\\}", entry.getValue()); + } + return template; + } +} + diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ResourceHubServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ResourceHubServiceImpl.java new file mode 100644 index 0000000..59bc137 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/ResourceHubServiceImpl.java @@ -0,0 +1,230 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.achievement.util.AchievementEventPublisher; +import com.vksfeng.quan.context.BaseContext; +import com.vksfeng.quan.exception.FavoriteAlreadyExistException; +import com.vksfeng.quan.exception.FriendshipAlreadyExistException; +import com.vksfeng.quan.exception.LikeAlreadyExistException; +import com.vksfeng.quan.exception.NotLoginException; +import com.vksfeng.quan.mapper.ResourceMapper; +import com.vksfeng.quan.resourcehub_pojo.dto.ResourceDTO; +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 com.vksfeng.quan.result.PageResult; +import com.vksfeng.quan.result.Result; +import com.vksfeng.quan.service.FriendshipService; +import com.vksfeng.quan.service.ResourceHubService; +import com.vksfeng.quan.user_pojo.vo.UserVO; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static com.vksfeng.quan.constant.AchievementConstant.RESOURCE_SHARED; + +@Service +public class ResourceHubServiceImpl implements ResourceHubService { + + @Autowired + private ResourceMapper resourceMapper; + + @Autowired + private FriendshipService friendshipService; + + @Autowired + private AchievementEventPublisher achievementEventPublisher; + + private Long getUserId() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + throw new NotLoginException("用户未登录"); + } + return userId; + } + + @Transactional + public ResourceVO createResource(ResourceDTO resourceDTO) { + Long userId = getUserId(); + Resource resource = new Resource(); + BeanUtils.copyProperties(resourceDTO, resource); + resource.setUserId(userId); + resource.setCreatedAt(LocalDateTime.now()); + resource.setUpdatedAt(LocalDateTime.now()); + resourceMapper.createResource(resource); + achievementEventPublisher.publish(userId, RESOURCE_SHARED, null); + return resourceMapper.getResourceById(resource.getId(), userId); + } + + public ResourceVO getResource(Long id) { + ResourceVO resourceVO = resourceMapper.getResourceById(id, getUserId()); + if (resourceVO == null) { + return null; + } + return resourceVO; + } + +// public List getResourceList() { +// Long userId = getUserId(); +// List friendId = friendshipService.getFriends(userId); +// List userIds = new ArrayList<>(friendId.stream().map(UserVO::getId).toList()); +// userIds.add(userId); +// List resourceList = resourceMapper.getResourceList(userIds, userId); +// return resourceList; +// } + + /** + * 删除资源 + * 只有当资源拥有者才能删除,否则即时返回删除成功也没删除 + * @param id + */ + public void deleteResource(Long id) { + Long userId = getUserId(); + resourceMapper.deleteResource(id, userId); + } + + public void addLike(Long id) { + if (resourceMapper.isLiked(id, getUserId())) { + throw new LikeAlreadyExistException(); + } + ResourceLike resourceLike = new ResourceLike(); + resourceLike.setUserId(getUserId()); + resourceLike.setResourceId(id); + resourceLike.setCreatedAt(LocalDateTime.now()); + resourceMapper.addLike(resourceLike); + } + + public void removeLike(Long resourceId) { + resourceMapper.removeLike(resourceId, getUserId()); + } + + @Transactional + public ResourceCommentVO addComment(Long resourceId, String content) { + ResourceComment resourceComment = ResourceComment.builder() + .userId(getUserId()) + .resourceId(resourceId) + .content(content) + .createdAt(LocalDateTime.now()) + .build(); + resourceMapper.addComment(resourceComment); + if (resourceComment.getId() == null) { + throw new RuntimeException("评论失败"); + } + return resourceMapper.getResourceCommentById(resourceComment.getId()); + } + + public List getCommentsByResourceId(Long id) { + return resourceMapper.getCommentsByResourceId(id); + } + + public void addFavorite(Long resourceId) { + Long userId = getUserId(); + if (resourceMapper.isFavorite(resourceId, userId)) { + throw new FavoriteAlreadyExistException("已经收藏过啦"); + } + ResourceFavorite resourceFavorite = ResourceFavorite.builder() + .userId(userId) + .resourceId(resourceId) + .createdAt(LocalDateTime.now()) + .build(); + resourceMapper.addFavorite(resourceFavorite); + } + + public void removeFavorite(Long resourceId) { + resourceMapper.removeFavorite(resourceId, getUserId()); + } + + public PageResult getResourceList(Integer page, Integer pageSize, String category) { + Long userId = getUserId(); + List friendId = friendshipService.getFriends(userId); + List userIds = new ArrayList<>(friendId.stream().map(UserVO::getId).toList()); + userIds.add(userId); + Integer total = resourceMapper.getResourceCount(category, userIds); + if (total <= 0) { + return null; + } + Integer totalPage = (total + pageSize - 1) / pageSize; + Integer offset = (page - 1) * pageSize; + List resourceList = resourceMapper.getResourceList(userIds, userId, offset, pageSize, category); + return new PageResult(totalPage, total, resourceList); + } + + public PageResult getFavoriteList(Integer page, Integer pageSize, String category) { + Long userId = getUserId(); + Integer total = resourceMapper.getFavoriteResourceCount(userId, category); + if (total <= 0) { + return null; + } + Integer totalPage = (total + pageSize - 1) / pageSize; + Integer offset = (page - 1) * pageSize; + List resourceList = resourceMapper.getFavoriteList(userId, offset, pageSize, category); + return new PageResult(totalPage, total, resourceList); + } + + @Override + public Result getUserResourceList(Long userId, Integer page, Integer pageSize, String category) { + if (!Objects.equals(userId, getUserId()) && friendshipService.isExist(getUserId(), userId)) { + return Result.error("对方不是你的好友"); + } + List userIds = new ArrayList<>(); + userIds.add(userId); + Integer total = resourceMapper.getResourceCount(category, userIds); + Integer totalPage = (total + pageSize - 1) / pageSize; + Integer offset = (page - 1) * pageSize; + if (total <= 0) { + return Result.success(new PageResult(0, 0, null)); + } + List resourceList = resourceMapper.getResourceList(userIds, userId, offset, pageSize, category); + return Result.success(new PageResult(totalPage, total, resourceList)); + } + + @Override + public Result getRecommendResourceList() { + PageResult pageResult = getResourceList(1, 20, null); + if (pageResult == null || pageResult.getList() == null || pageResult.getList().isEmpty()) { + return Result.success(new PageResult(0, 0, new ArrayList<>())); + } + + // TODO 获取推荐资源,这里简单地随机抽取三个资源作为示例 + List resourceList = pageResult.getList(); + if (resourceList.size() <= 3) { + return Result.success(new PageResult(1, resourceList.size(), resourceList)); + } + + // 随机抽取三个资源 + List recommendedResources = new ArrayList<>(); + java.util.Collections.shuffle(resourceList); + recommendedResources.addAll(resourceList.subList(0, 3)); + + return Result.success(new PageResult(1, 3, recommendedResources)); + } + + @Override + public Integer getUserResourceCount(Long userId) { + return resourceMapper.getResourceCount(null, List.of(userId)); + } + + @Override + public Integer getUserReceivedLikes(Long userId) { + return resourceMapper.getUserReceivedLikes(userId); + } + + @Override + public Integer getUserReceivedComments(Long userId) { + return resourceMapper.getUserReceivedComments(userId); + } + + @Override + public Integer getUserReceivedFavorites(Long userId) { + return resourceMapper.getUserReceivedFavorites(userId); + } + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/SparkAIProServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/SparkAIProServiceImpl.java new file mode 100644 index 0000000..9f57a74 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/SparkAIProServiceImpl.java @@ -0,0 +1,236 @@ +package com.vksfeng.quan.service.impl; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.vksfeng.quan.constant.RedisConstant; +import com.vksfeng.quan.context.BaseContext; +import com.vksfeng.quan.exception.NotLoginException; +import com.vksfeng.quan.obengine_pojo.dto.ObjectiveWithFeedbackDTO; +import com.vksfeng.quan.obengine_pojo.spark.SparkRequest; +import com.vksfeng.quan.obengine_pojo.spark.SparkResponse; +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.ObjectiveHubService; +import com.vksfeng.quan.service.SparkAIService; +import com.vksfeng.quan.websocket.WebSocketServer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.vksfeng.quan.constant.RedisConstant.PROMPT_DOMAIN_LIST_KEY; + +@Slf4j +public class SparkAIProServiceImpl implements SparkAIService { + + + private static final String DEFAULT_DOMAIN = "通用"; + + @Value("${spark.api.url}") + private String SPARK_API_URL; + + @Value("${spark.api.password}") + private String API_PASSWORD; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private ObjectiveHubService objectiveHubService; + + @Autowired + private WebSocketServer webSocketServer; + + @Autowired + private RedisTemplate redisTemplate; + + + + /** + * 生成跟进问题 + * @param objectiveDTO + * @return + */ + @Override + public Result> generateFollowupQuestions(ObjectiveDTO objectiveDTO) { + // 构建 prompt + String prompt = String.format( + "请根据以下主目标信息生成 3 个跟进问题,每个问题请提供 4 个选项,以便更好地了解用户的实际情况。\n\n" + + "主目标名称:%s\n目标描述:%s\n开始日期:%s\n结束日期:%s\n\n" + + "输出要求:请按照以下 JSON 格式返回结果:\n" + + "{\n" + + " \"questions\": [\n" + + " {\n" + + " \"question\": \"问题1内容\",\n" + + " \"options\": [\"选项1\", \"选项2\", \"选项3\", \"选项4\"]\n" + + " },\n" + + " {\n" + + " \"question\": \"问题2内容\",\n" + + " \"options\": [\"选项1\", \"选项2\", \"选项3\", \"选项4\"]\n" + + " },\n" + + " {\n" + + " \"question\": \"问题3内容\",\n" + + " \"options\": [\"选项1\", \"选项2\", \"选项3\", \"选项4\"]\n" + + " }\n" + + " ]\n" + + "}" + , objectiveDTO.getName(), objectiveDTO.getDescription(), objectiveDTO.getStartDate(), objectiveDTO.getEndDate()); + + ResponseEntity response = sendSparkRequest(prompt); + // 处理响应 + String aiResponse = null; + if (response.getStatusCode().is2xxSuccessful()) { + SparkResponse sparkResponse = response.getBody(); + if (sparkResponse != null && !sparkResponse.getChoices().isEmpty()) { + aiResponse = sparkResponse.getChoices().get(0).getMessage().getContent(); + } + } + + if (aiResponse == null || aiResponse.isEmpty()) { + return Result.error("AI 生成失败"); + } + + // **去掉 JSON 代码块标记** + aiResponse = aiResponse.replaceAll("```json", "").replaceAll("```", "").trim(); + + // 解析 JSON 响应 + List followUpQuestionVOList = new ArrayList<>(); + try { + JSONObject jsonResponse = new JSONObject(aiResponse); + JSONArray questionsArray = jsonResponse.getJSONArray("questions"); + + for (int i = 0; i < questionsArray.size(); i++) { + JSONObject questionObj = questionsArray.getJSONObject(i); + FollowUpQuestionVO questionVO = new FollowUpQuestionVO(); + questionVO.setQuestion(questionObj.getStr("question")); + questionVO.setOptions(questionObj.getJSONArray("options").toList(String.class)); + followUpQuestionVOList.add(questionVO); + } + } catch (Exception e) { + return Result.error("解析 AI 返回结果失败: " + e.getMessage()); + } + return Result.success(followUpQuestionVOList); + } + + /** + * 智能目标拆解,输入主目标信息,生成详细计划 + * @param objectiveWithFeedbackDTO + */ + @Override + public void generateDetailedPlan(ObjectiveWithFeedbackDTO objectiveWithFeedbackDTO) { + // 1. 领域识别 + String domain = detectDomain(objectiveWithFeedbackDTO.getName(), objectiveWithFeedbackDTO.getDescription()); + // 2. 根据领域识别结果,选择合适的prompt模板 + String promptTemplate = getPromptTemplate(domain); + // 3. 构造实际使用prompt + + // 4. 调用AI接口,获取详细计划 + // 5. 持久化 + // 6. websocket进行通知 + } + + private String getPromptTemplate(String domain) { + return (String) redisTemplate.opsForValue().get(RedisConstant.PROMPT_TEMPLATE_KEY + ":" + domain); + } + + /** + * 获取Redis中的支持领域列表 + * @return + */ + private List getValidDomainsFromRedis() { + List domainList = redisTemplate.opsForList().range(RedisConstant.PROMPT_DOMAIN_LIST_KEY, 0, -1); + return domainList == null ? Collections.emptyList() : domainList; + } + + /** + * 调用AI进行领域识别 + * @param objectiveName + * @param objectiveDescription + * @return + */ + private String detectDomain(String objectiveName, String objectiveDescription) { + try { + List domains = getValidDomainsFromRedis(); + domains.add("通用"); // 一方面不用存通用,另一方面可以保证list不为空 + String domainsString = String.join("、", domains); + String prompt = String.format(""" + 请根据下列用户目标判断它属于哪个领域,并且严格地只返回领域关键词): + 可选领域:%s。 + 如果不确定请返回“通用”。 + 目标名称:%s + 目标描述:%s + """, domainsString, objectiveName, objectiveDescription); + + // 从 Redis 校验是否是合法领域 + ResponseEntity response = sendSparkRequest(prompt); + // 处理响应 + String result = null; + if (response.getStatusCode().is2xxSuccessful()) { + SparkResponse sparkResponse = response.getBody(); + if (sparkResponse != null && !sparkResponse.getChoices().isEmpty()) { + result = sparkResponse.getChoices().get(0).getMessage().getContent(); + } + } + if (domains != null && domains.contains(result)) { + return result; + } + } catch (Exception e) { + log.warn("AI 识别领域失败,使用默认通用模板", e); + } + return DEFAULT_DOMAIN; + } + + public Long getUserId() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + throw new NotLoginException("用户未登录"); + } + return userId; + } + + /** + * 发送请求给 Spark API + * + * @param prompt 输入prompt + * @return + */ + private ResponseEntity sendSparkRequest(String prompt) { + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/json"); + headers.set("Authorization", "Bearer " + API_PASSWORD); + + // 构建请求体 + SparkRequest request = new SparkRequest(); + // request.setModel("generalv3.5"); // 根据需要选择模型版本 + request.setModel("lite"); // 根据需要选择模型版本 + SparkRequest.Message message = new SparkRequest.Message(); + message.setRole("user"); + message.setContent(prompt); + request.setMessages(List.of(message)); + + // 发送请求 + HttpEntity entity = new HttpEntity<>(request, headers); + ResponseEntity response = restTemplate.exchange( + SPARK_API_URL, + HttpMethod.POST, + entity, + SparkResponse.class + ); + return response; + } + + + + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/SparkAIServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/SparkAIServiceImpl.java new file mode 100644 index 0000000..af1186e --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/SparkAIServiceImpl.java @@ -0,0 +1,426 @@ +package com.vksfeng.quan.service.impl; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.vksfeng.quan.context.BaseContext; +import com.vksfeng.quan.exception.NotLoginException; +import com.vksfeng.quan.exception.UnknownTaskTypeException; +import com.vksfeng.quan.obengine_pojo.dto.Feedback; +import com.vksfeng.quan.obengine_pojo.dto.ObjectiveWithFeedbackDTO; +import com.vksfeng.quan.obengine_pojo.dto.SubObjectiveDTO; +import com.vksfeng.quan.obengine_pojo.vo.FollowUpQuestionVO; +import com.vksfeng.quan.objectivehub_pojo.dto.ObjectiveDTO; +import com.vksfeng.quan.objectivehub_pojo.dto.RecurringTaskDTO; +import com.vksfeng.quan.objectivehub_pojo.dto.SingleTaskDTO; +import com.vksfeng.quan.objectivehub_pojo.entity.Task; +import com.vksfeng.quan.objectivehub_pojo.vo.ObjectiveVO; +import com.vksfeng.quan.result.Result; +import com.vksfeng.quan.service.ObjectiveHubService; +import com.vksfeng.quan.service.SparkAIService; +import com.vksfeng.quan.obengine_pojo.spark.SparkRequest; +import com.vksfeng.quan.obengine_pojo.spark.SparkResponse; +import com.vksfeng.quan.websocket.WebSocketServer; +import io.swagger.v3.core.util.Json; +import jakarta.annotation.PostConstruct; +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.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Service +@Slf4j +@EnableAsync // 开启 Spring 异步功能 +public class SparkAIServiceImpl implements SparkAIService { + + @Value("${spark.api.url}") + private String SPARK_API_URL; + + @Value("${spark.api.password}") + private String API_PASSWORD; + +// @Value("${spark.api.max-url}") +// private String MAX_SPARK_API_URL; + +// @Value("${spark.api.max-password}") +// private String MAX_API_PASSWORD; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private ObjectiveHubService objectiveHubService; + + @Autowired + private WebSocketServer webSocketServer; +// +// private static final ExecutorService OBJECTIVES_EXECUTOR = Executors.newSingleThreadExecutor(); +// +// @PostConstruct +// private void init() { +// OBJECTIVES_EXECUTOR.submit(new ObjectiveHandler()); +// } +// +// private class ObjectiveHandler implements Runnable { +// @Override +// public void run() { +// String queueName = "stream.objectives"; +// while (true) { +// +// } +// } +// } + + private ResponseEntity sendSparkRequest(String prompt) { + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/json"); + headers.set("Authorization", "Bearer " + API_PASSWORD); + + // 构建请求体 + SparkRequest request = new SparkRequest(); +// request.setModel("generalv3.5"); // 根据需要选择模型版本 + request.setModel("lite"); // 根据需要选择模型版本 + SparkRequest.Message message = new SparkRequest.Message(); + message.setRole("user"); + message.setContent(prompt); + request.setMessages(List.of(message)); + + // 发送请求 + HttpEntity entity = new HttpEntity<>(request, headers); + ResponseEntity response = restTemplate.exchange( + SPARK_API_URL, + HttpMethod.POST, + entity, + SparkResponse.class + ); + return response; + } + + public Long getUserId() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + throw new NotLoginException("用户未登录"); + } + return userId; + } + + public Result> generateFollowupQuestions(ObjectiveDTO objectiveDTO) { + // 构建 prompt + String prompt = String.format( + "请根据以下主目标信息生成 3 个跟进问题,每个问题请提供 4 个选项,以便更好地了解用户的实际情况。\n\n" + + "主目标名称:%s\n目标描述:%s\n开始日期:%s\n结束日期:%s\n\n" + + "输出要求:请按照以下 JSON 格式返回结果:\n" + + "{\n" + + " \"questions\": [\n" + + " {\n" + + " \"question\": \"问题1内容\",\n" + + " \"options\": [\"选项1\", \"选项2\", \"选项3\", \"选项4\"]\n" + + " },\n" + + " {\n" + + " \"question\": \"问题2内容\",\n" + + " \"options\": [\"选项1\", \"选项2\", \"选项3\", \"选项4\"]\n" + + " },\n" + + " {\n" + + " \"question\": \"问题3内容\",\n" + + " \"options\": [\"选项1\", \"选项2\", \"选项3\", \"选项4\"]\n" + + " }\n" + + " ]\n" + + "}" + , objectiveDTO.getName(), objectiveDTO.getDescription(), objectiveDTO.getStartDate(), objectiveDTO.getEndDate()); + + ResponseEntity response = sendSparkRequest(prompt); + // 处理响应 + String aiResponse = null; + if (response.getStatusCode().is2xxSuccessful()) { + SparkResponse sparkResponse = response.getBody(); + if (sparkResponse != null && !sparkResponse.getChoices().isEmpty()) { + aiResponse = sparkResponse.getChoices().get(0).getMessage().getContent(); + } + } + + if (aiResponse == null || aiResponse.isEmpty()) { + return Result.error("AI 生成失败"); + } + + // **去掉 JSON 代码块标记** + aiResponse = aiResponse.replaceAll("```json", "").replaceAll("```", "").trim(); + + // 解析 JSON 响应 + List followUpQuestionVOList = new ArrayList<>(); + try { + JSONObject jsonResponse = new JSONObject(aiResponse); + JSONArray questionsArray = jsonResponse.getJSONArray("questions"); + + for (int i = 0; i < questionsArray.size(); i++) { + JSONObject questionObj = questionsArray.getJSONObject(i); + FollowUpQuestionVO questionVO = new FollowUpQuestionVO(); + questionVO.setQuestion(questionObj.getStr("question")); + questionVO.setOptions(questionObj.getJSONArray("options").toList(String.class)); + followUpQuestionVOList.add(questionVO); + } + } catch (Exception e) { + return Result.error("解析 AI 返回结果失败: " + e.getMessage()); + } + return Result.success(followUpQuestionVOList); + } + + public String generateObjectivePrompt(ObjectiveWithFeedbackDTO objectiveWithFeedbackDTO) { + // 构建用户输入部分 + StringBuilder feedbackStr = new StringBuilder(); + if (objectiveWithFeedbackDTO.getFeedback() != null && !objectiveWithFeedbackDTO.getFeedback().isEmpty()) { + feedbackStr.append("\n用户反馈:\n"); + for (Feedback feedback : objectiveWithFeedbackDTO.getFeedback()) { + feedbackStr.append("- ").append(feedback.getQuestion()).append(": ").append(feedback.getAnswer()).append("\n"); + } + } + + // 构建最终的 prompt + return String.format(""" + 你是一个智能任务规划助手,专门帮助用户拆解目标并制定详细的执行计划。 + + 任务要求 + 用户在**用户输入**部分提供一个 **主目标**,包含目标名称、描述、开始时间和结束时间。并请你根据该目标自动拆解成多个**子目标**,为每个子目标生成合适的**任务清单**(至少一到两个任务),包括 **单次任务** 和 **重复任务**。 + + ### **拆解逻辑** + 1. **时间分析** + - 计算目标的总持续时间(结束时间 - 开始时间)。 + - 识别关键时间节点(如周末、月份切换)。 + - 根据时间跨度选择拆解策略: + - ≤7天 → 按天拆解 + - 8 - 30天 → 按周拆解 + - >30天 → 按月拆解,并设定里程碑子目标 + + 2. **子目标拆解** + - **流程拆解法**:如果目标包含明确的执行步骤(如"开发应用" → "设计UI" → "编写代码" → "测试")。 + - **模块拆解法**:如果目标涉及多个领域(如"学习编程" → "学习Java" + "学习数据库" + "学习Spring")。 + - **数值递减拆解法**:如果目标有量化指标(如"读书10本" → "每周2本")。 + - **时间轴基准拆解法(默认)**:均匀分配任务。 + + 3. **任务生成** + - **单次任务(SingleTask)**: + - 有明确截止日期(DDL) + - 需要特定资源调配 + - **重复任务(RecurringTask)**: + - 适用于习惯养成和持续任务 + - 频率:"daily"(每天)、"weekly"(每周)、"monthly"(每月) + - 任务周期覆盖至少 30%% 的总时间 + + 4. **时间范围约束** + - 所有子目标的时间范围(subObjectives.startDate 和 subObjectives.endDate)必须在主目标时间范围内: + - subObjectives.startDate ≥ masterObjective.startDate + - subObjectives.endDate ≤ masterObjective.endDate + - **单次任务**的截止日期必须在其所属子目标的时间范围内。 + - **重复任务**的开始和结束日期必须在其所属子目标的时间范围内。 + - 在生成任务时,如计算得到的任务时间超出子目标范围,应自动调整为子目标时间范围的边界。 + + ### **用户输入** + - **主目标名称**: %s + - **目标描述**: %s + - **开始日期**: %s + - **结束日期**: %s + %s + + ### **输出格式** + 请严格按照以下 JSON 格式返回数据: + ```json + { + "masterObjective": { + "name": "%s", + "description": "%s", + "startDate": "%s", + "endDate": "%s" + }, + "subObjectives": [ + { + "name": "{子目标名称}", + "description": "{子目标描述}", + "startDate": "{YYYY-MM-DD}", + "endDate": "{YYYY-MM-DD}", + "tasks": [ + { + "name": "{单次任务名称}", + "type": "single", + "description": "{任务描述}", + "ddl": "{YYYY-MM-DD}" + }, + { + "name": "{重复任务名称}", + "type": "recurring", + "description": "{任务描述}", + "period": "daily", + "startDate": "{YYYY-MM-DD}", + "endDate": "{YYYY-MM-DD}" + } + ] + } + ], + "aiGuide": "{智能建议:针对用户目标的优化或执行策略,100字左右}" + } + ``` + """, + objectiveWithFeedbackDTO.getName(), + objectiveWithFeedbackDTO.getDescription(), + objectiveWithFeedbackDTO.getStartDate(), + objectiveWithFeedbackDTO.getEndDate(), + feedbackStr.toString(), + + objectiveWithFeedbackDTO.getName(), + objectiveWithFeedbackDTO.getDescription(), + objectiveWithFeedbackDTO.getStartDate(), + objectiveWithFeedbackDTO.getEndDate() + ); + } + + public String getAIDetailedPlan(String prompt) { + ResponseEntity response = sendSparkRequest(prompt); + + // 处理响应 + if (response.getStatusCode().is2xxSuccessful()) { + SparkResponse sparkResponse = response.getBody(); + if (sparkResponse != null && !sparkResponse.getChoices().isEmpty()) { + String aiResponse = sparkResponse.getChoices().get(0).getMessage().getContent(); + aiResponse = aiResponse.replaceAll("```json", "").replaceAll("```", "").trim(); + return aiResponse; + } + } + return null; + } + + public void createObjectives(String detail, Long userId) { + log.info("AI 生成的详细计划:{}", detail); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + ObjectiveDTO masterObjective; + List subObjectives; + String aiGuide; + try { + JsonNode rootNode = objectMapper.readTree(detail); + log.info(rootNode.toPrettyString()); + JsonNode masterObjectiveNode = rootNode.get("masterObjective"); + log.info("解析的主目标:{}", masterObjectiveNode); + masterObjective = objectMapper.treeToValue(masterObjectiveNode, ObjectiveDTO.class); + subObjectives = new ArrayList<>(); + JsonNode subObjectivesNode = rootNode.get("subObjectives"); + if (subObjectivesNode.isArray()) { + for (JsonNode subObjectiveNode : subObjectivesNode) { + SubObjectiveDTO subObjective = objectMapper.treeToValue(subObjectiveNode, SubObjectiveDTO.class); + log.info("解析的子目标:{}", subObjective); + subObjectives.add(subObjective); + } + } + JsonNode aiGuideNode = rootNode.get("aiGuide"); + log.info("解析的主目标:{}", masterObjectiveNode); + aiGuide = aiGuideNode.asText(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + saveObjectives(masterObjective, subObjectives, aiGuide, userId); + } + + @Transactional + public void saveObjectives(ObjectiveDTO masterObjective, List subObjectives, String aiGuide, Long userId) { + masterObjective.setUserId(userId); + ObjectiveVO master; + // 创建主目标 + try { + master = objectiveHubService.createObjective(masterObjective); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + Long masterId = master.getId(); + // 创建子目标 + for (SubObjectiveDTO subObjective : subObjectives) { + ObjectiveDTO subObjectiveDTO = new ObjectiveDTO(); + BeanUtils.copyProperties(subObjective, subObjectiveDTO); + subObjectiveDTO.setUserId(userId); + ObjectiveVO subObjectiveVO; + try { + subObjectiveVO = objectiveHubService.createObjectiveWithRelation(subObjectiveDTO, masterId); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + if (subObjective.getTasks() == null) { + continue; + } + for (Task task : subObjective.getTasks()) { + if (task.getType().equals("single")) { + SingleTaskDTO taskDTO = new SingleTaskDTO(); + BeanUtils.copyProperties(task, taskDTO); + taskDTO.setUserId(userId); + taskDTO.setObjectiveId(subObjectiveVO.getId()); + try { + objectiveHubService.createSingleTask(taskDTO); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } else if (task.getType().equals("recurring")) { + RecurringTaskDTO taskDTO = new RecurringTaskDTO(); + BeanUtils.copyProperties(task, taskDTO); + taskDTO.setObjectiveId(subObjectiveVO.getId()); + taskDTO.setUserId(userId); + try { + objectiveHubService.createRecurringTask(taskDTO); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } else { + throw new UnknownTaskTypeException("未知的任务类型"); + } + } + } + // 添加AI指导 + try { + objectiveHubService.addAiGuideForObjective(masterId, aiGuide); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + webSocketServer.sendToClient(userId.toString(), "AI智能目标创建成功"); + } + + @Async + public void processObjectives(ObjectiveWithFeedbackDTO objectiveWithFeedbackDTO, Long userId) { + String prompt = generateObjectivePrompt(objectiveWithFeedbackDTO); + String details = getAIDetailedPlan(prompt); + createObjectives(details, userId); + } + + public void generateDetailedPlan(ObjectiveWithFeedbackDTO objectiveWithFeedbackDTO) { + Long userId = getUserId(); + // 立即返回一个任务提交成功的响应(此处假设用 HTTP Controller 调用) + try { + CompletableFuture.runAsync(() -> processObjectives(objectiveWithFeedbackDTO, userId)); + } catch (Exception e) { + log.info("智能目标解析任务失败,用户id:{}", userId); + webSocketServer.sendToClient(userId.toString(), "智能目标解析任务失败"); + webSocketServer.onClose(userId.toString()); + } +// processObjectives(objectiveWithFeedbackDTO, userId); + } +} \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/UserServiceImpl.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..b68777a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/service/impl/UserServiceImpl.java @@ -0,0 +1,148 @@ +package com.vksfeng.quan.service.impl; + +import com.vksfeng.quan.constant.RedisConstant; +import com.vksfeng.quan.context.BaseContext; +import com.vksfeng.quan.exception.*; +import com.vksfeng.quan.mapper.UserMapper; +import com.vksfeng.quan.peerhub_pojo.vo.UserSearchVO; +import com.vksfeng.quan.result.Result; +import com.vksfeng.quan.user_pojo.dto.UserDTO; +import com.vksfeng.quan.user_pojo.entity.User; +import com.vksfeng.quan.service.UserService; +import com.vksfeng.quan.user_pojo.entity.UserLocation; +import com.vksfeng.quan.user_pojo.vo.UserActivityVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.DigestUtils; +import org.springframework.data.geo.Point; + +import java.time.LocalDateTime; +import java.util.List; + + +@Slf4j +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserMapper userMapper; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + /** + * 用户注册 + * @param userDTO 用户信息 + */ + public void register(UserDTO userDTO) { + // 1. 判断用户名和邮箱是否已经存在 + User userWithUsername = User.builder().username(userDTO.getUsername()).build(); + if (!userMapper.findUser(userWithUsername).isEmpty()) { + throw new UsernameExistsException("用户名已存在"); + } + User userWithEmail = User.builder().email(userDTO.getEmail()).build(); + if (!userMapper.findUser(userWithEmail).isEmpty()) { + throw new EmailExistsException("该邮箱已注册"); + } + + // 2. 插入用户数据 + User user = new User(); + BeanUtils.copyProperties(userDTO, user); + // 通过md5算法对密码进行加密 + user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes())); + user.setCreatedAt(LocalDateTime.now()); + user.setUpdatedAt(LocalDateTime.now()); + String avatarUrl = "https://www.dummyimage.com/600x400/fff/000000&text=" + user.getUsername().charAt(0); + user.setAvatarUrl(avatarUrl); + userMapper.save(user); + } + + /** + * 用户登录 + * @param userDTO 用户账密 + * @return 用户信息 + */ + public User login(UserDTO userDTO) { + User userForLogin = User.builder() + .email(userDTO.getEmail()) + .build(); + List users = userMapper.findUser(userForLogin); + if (users.isEmpty()) { + throw new UserNotExistsException("用户不存在"); + } + userForLogin = users.get(0); + String password = DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes()); + log.info(password); + if (!password.equals(userForLogin.getPassword())) { + throw new PasswordErrorException("密码错误"); + } +// if (users.size() > 1) { +// throw new UnknownException("未知错误:存在多个用户"); +// } + return userForLogin; + } + + private Long getUserId() { + Long userId = BaseContext.getCurrentId(); + if (userId == null) { + throw new NotLoginException("用户未登录"); + } + return userId; + } + + /** + * 根据id获取用户信息 + * @param id 用户id + * @return 用户信息 + */ + public User getUserById(Long id) { +// User userWithId = User.builder().id(id).build(); +// return userMapper.findUser(userWithId).get(0); + return userMapper.getUserById(id); + } + + public void update(UserDTO userDTO) { + User user = new User(); + BeanUtils.copyProperties(userDTO, user); + user.setUpdatedAt(LocalDateTime.now()); + userMapper.update(user); + } + + public User getUserByEmail(String email) { + User userWithEmail = User.builder().email(email).build(); + List users = userMapper.findUser(userWithEmail); + if (users == null || users.isEmpty()) { + return null; + } + return users.get(0); + } + + @Override + public Result setUserLocation(UserLocation userLocationDTO) { + if (userLocationDTO.getLatitude() == null || userLocationDTO.getLongitude() == null) { + return Result.error("位置信息错误"); + } + Long userId = getUserId(); + userLocationDTO.setUserId(userId); + userLocationDTO.setLastUpdate(LocalDateTime.now()); + // 存储到 Redis GEO + // GEOADD quan:geo:users 116.397128 39.916527 1 + stringRedisTemplate.opsForGeo().add( + RedisConstant.USER_LOCATION_KEY, + new Point(userLocationDTO.getLongitude(), userLocationDTO.getLatitude()), + userId.toString() // 以 `user:id` 作为 member 存入 Redis + ); +// userMapper.saveUserLocation(userLocationDTO); + return Result.success("位置信息更新成功"); + } + + @Override + public List searchUsers(List userIds, Long currentUserId) { + return userMapper.searchUsers(userIds, currentUserId); + } + + +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/dto/RegisterDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/dto/RegisterDTO.java new file mode 100644 index 0000000..bb490c7 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/dto/RegisterDTO.java @@ -0,0 +1,14 @@ +package com.vksfeng.quan.user_pojo.dto; + +import lombok.Data; + +@Data +public class RegisterDTO { + private Long id; + private String username; + private String password; + private String email; + private String nickname; + private String avatarUrl; + private String captcha; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/dto/UserDTO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/dto/UserDTO.java new file mode 100644 index 0000000..baa7f4f --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/dto/UserDTO.java @@ -0,0 +1,14 @@ +package com.vksfeng.quan.user_pojo.dto; + +import lombok.Data; + +// User.java +@Data +public class UserDTO { + private Long id; + private String username; + private String password; + private String email; + private String nickname; + private String avatarUrl; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/entity/User.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/entity/User.java new file mode 100644 index 0000000..165ce10 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/entity/User.java @@ -0,0 +1,26 @@ +package com.vksfeng.quan.user_pojo.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +// User.java +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class User { + private Long id; + private String username; + private String password; + private String email; + private String nickname; + private String avatarUrl; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} + + diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/entity/UserLocation.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/entity/UserLocation.java new file mode 100644 index 0000000..3f9ace1 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/entity/UserLocation.java @@ -0,0 +1,13 @@ +package com.vksfeng.quan.user_pojo.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class UserLocation { + private Long userId; + private Double latitude; + private Double longitude; + private LocalDateTime lastUpdate; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/LoginResponse.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/LoginResponse.java new file mode 100644 index 0000000..0cdd7df --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/LoginResponse.java @@ -0,0 +1,11 @@ +package com.vksfeng.quan.user_pojo.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class LoginResponse { + UserVO userVO; + String token; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserActivityVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserActivityVO.java new file mode 100644 index 0000000..d37169a --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserActivityVO.java @@ -0,0 +1,14 @@ +package com.vksfeng.quan.user_pojo.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserActivityVO { + private Integer taskCompletedCount; + private Integer objectiveCompletedCount; + private Integer resourcePostedCount; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserSocialAchievementVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserSocialAchievementVO.java new file mode 100644 index 0000000..13f26e6 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserSocialAchievementVO.java @@ -0,0 +1,14 @@ +package com.vksfeng.quan.user_pojo.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserSocialAchievementVO { + private Integer receivedLikes; + private Integer receivedComments; + private Integer receivedFavorites; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserVO.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserVO.java new file mode 100644 index 0000000..5f4e40d --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/user_pojo/vo/UserVO.java @@ -0,0 +1,12 @@ +package com.vksfeng.quan.user_pojo.vo; + +import lombok.Data; + +@Data +public class UserVO { + private Long id; + private String username; + private String email; + private String nickname; + private String avatarUrl; +} diff --git a/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/websocket/WebSocketServer.java b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/websocket/WebSocketServer.java new file mode 100644 index 0000000..7417c79 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/java/com/vksfeng/quan/websocket/WebSocketServer.java @@ -0,0 +1,93 @@ +package com.vksfeng.quan.websocket; + +import jakarta.websocket.OnClose; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.server.PathParam; +import jakarta.websocket.server.ServerEndpoint; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * WebSocket服务 + */ +@Component +@ServerEndpoint("/ws/{sid}") +@Slf4j +public class WebSocketServer { + + //存放会话对象 + private static Map sessionMap = new HashMap(); + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session, @PathParam("sid") String sid) { + log.info("客户端:{}建立连接", sid); + sessionMap.put(sid, session); + } + + /** + * 收到客户端消息后调用的方法 + * + * @param message 客户端发送过来的消息 + */ + @OnMessage + public void onMessage(String message, @PathParam("sid") String sid) { + log.info("收到来自客户端:{}的信息:{}", sid, message); + } + + /** + * 连接关闭调用的方法 + * + * @param sid + */ + @OnClose + public void onClose(@PathParam("sid") String sid) { + log.info("连接断开:{}", sid); + sessionMap.remove(sid); + } + + /** + * 发送消息 + * + * @param sid + * @param message + */ + public void sendToClient(String sid, String message) { + Session session = sessionMap.get(sid); + if (session != null) { + try { + //服务器向客户端发送消息 + session.getBasicRemote().sendText(message); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * 群发 + * + * @param message + */ + public void sendToAllClient(String message) { + Collection sessions = sessionMap.values(); + for (Session session : sessions) { + try { + //服务器向客户端发送消息 + session.getBasicRemote().sendText(message); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} + diff --git a/quan_backend - without config/quan-server/src/main/resources/mapper/AchievementMapper.xml b/quan_backend - without config/quan-server/src/main/resources/mapper/AchievementMapper.xml new file mode 100644 index 0000000..459894c --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/mapper/AchievementMapper.xml @@ -0,0 +1,14 @@ + + + + + insert into achievement (code, name, description, icon_url, type, rule_json, created_at) + values (#{code}, #{name}, #{description}, #{iconUrl}, #{type}, #{ruleJson}, #{createdAt}) + + + + + select * from achievement where type = #{type} + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/mapper/FeedMapper.xml b/quan_backend - without config/quan-server/src/main/resources/mapper/FeedMapper.xml new file mode 100644 index 0000000..f9d9985 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/mapper/FeedMapper.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM feed_like + WHERE feed_id = #{feedId} AND user_id = #{userId} + + + + SELECT + f.id, f.user_id, f.type, f.related_id, f.content, f.created_at, f.updated_at, + (SELECT COUNT(*) FROM feed_like fl WHERE fl.feed_id = f.id) AS count_like, + (SELECT COUNT(*) FROM feed_comment fc WHERE fc.feed_id = f.id) AS count_comment, + (SELECT COUNT(*) FROM feed_like fl WHERE fl.feed_id = f.id AND fl.user_id = #{userId}) > 0 AS is_liked, + u.id AS user_id, u.username, u.email, u.nickname, u.avatar_url + FROM feed f + JOIN user u ON f.user_id = u.id + WHERE f.id = #{feedId} + + + + + SELECT + f.id, f.user_id, f.type, f.related_id, f.content, f.created_at, f.updated_at, + COALESCE(like_count, 0) AS count_like, + COALESCE(comment_count, 0) AS count_comment, + CASE WHEN fl.user_id IS NOT NULL THEN 1 ELSE 0 END AS is_liked, -- 是否点赞 + u.id AS user_id, u.username, u.email, u.nickname, u.avatar_url + FROM feed f + JOIN user u ON f.user_id = u.id + LEFT JOIN ( + SELECT feed_id, COUNT(*) AS like_count FROM feed_like GROUP BY feed_id + ) AS likes ON f.id = likes.feed_id + LEFT JOIN ( + SELECT feed_id, COUNT(*) AS comment_count FROM feed_comment GROUP BY feed_id + ) AS comments ON f.id = comments.feed_id + LEFT JOIN feed_like fl ON f.id = fl.feed_id AND fl.user_id = #{userId} -- 判断当前用户是否点赞 + WHERE f.user_id IN + + #{userId} + + ORDER BY f.created_at DESC + LIMIT #{pageSize} OFFSET #{offset} + + + + + insert into feed_like (feed_id, user_id, created_at) + values (#{feedId}, #{userId}, #{createdAt}) + + + + insert into feed_comment (feed_id, user_id, content, created_at) + values (#{feedId}, #{userId}, #{content}, #{createdAt}) + + + + INSERT INTO feed (user_id, type, related_id, content, created_at, updated_at) + VALUES (#{userId}, #{type}, #{relatedId}, #{content}, #{createdAt}, #{updatedAt}) + + + + select count(*) from feed + + + + SELECT fc.*, + u.id AS user_id, u.username, u.email, u.nickname, u.avatar_url + FROM feed_comment fc + JOIN user u ON fc.user_id = u.id + WHERE fc.feed_id = #{feedId} + ORDER BY fc.created_at DESC + + + SELECT * FROM feed_like WHERE feed_id = #{feedId} AND user_id = #{userId} + + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/mapper/FriendshipMapper.xml b/quan_backend - without config/quan-server/src/main/resources/mapper/FriendshipMapper.xml new file mode 100644 index 0000000..9277d9c --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/mapper/FriendshipMapper.xml @@ -0,0 +1,48 @@ + + + + + insert into friendship (user_id, friend_id, status, created_at, updated_at) + values (#{userId}, #{friendId}, #{status}, #{createdAt}, #{updatedAt}) + + + + update friendship + set status = #{status}, updated_at = #{updatedAt} + where user_id = #{userId} and friend_id = #{friendId} + + + delete from friendship + where + (user_id = #{userId} and friend_id = #{friendId}) + or + (user_id = #{friendId} and friend_id = #{userId}) + + + + SELECT + u.id, + u.username, + u.email, + u.nickname, + u.avatar_url + FROM user u + INNER JOIN friendship f + ON u.id = f.friend_id AND f.user_id = #{userId} + OR u.id = f.user_id AND f.friend_id = #{userId} + WHERE f.status = 'accepted' + + + + select u.id, u.username, u.email, u.nickname, u.avatar_url from user u + inner join friendship f on u.id = f.user_id + where f.friend_id = #{userId} and f.status = 'pending' + + + select * from friendship where (user_id = #{aId} and friend_id = #{bId}) or (user_id = #{bId} and friend_id = #{aId}) + + + select count(*) from friendship where user_id = #{userId} or friend_id = #{userId} + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/mapper/ObjectiveMapper.xml b/quan_backend - without config/quan-server/src/main/resources/mapper/ObjectiveMapper.xml new file mode 100644 index 0000000..61f5c7d --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/mapper/ObjectiveMapper.xml @@ -0,0 +1,106 @@ + + + + + + INSERT INTO objective (id, user_id, name, description, start_date, end_date, visibility, progress, weight, completed_at, created_at, updated_at) + VALUES (#{id}, #{userId}, #{name}, #{description}, #{startDate}, #{endDate}, #{visibility}, #{progress}, #{weight}, #{completedAt}, #{createdAt}, #{updatedAt}) + + + + UPDATE objective + + name = #{objective.name}, + description = #{objective.description}, + start_date = #{objective.startDate}, + end_date = #{objective.endDate}, + completed_at = #{objective.completedAt}, + + where id = #{objectiveId} + + + UPDATE objective + SET progress = #{progress} + WHERE id = #{objectiveId} + + + UPDATE objective + SET completed_at = #{now} + WHERE id = #{objectiveId} + + + + INSERT INTO objective_relationship (father_id, child_id) + VALUES (#{parentObjectiveId}, #{childObjectiveId}) + + + INSERT INTO objective_ai (objective_id, ai_guide) + VALUES (#{objectiveId}, #{aiGuide}) + + + + DELETE FROM objective WHERE id = #{objectiveId} + + + DELETE FROM objective_relationship WHERE child_id = #{objectiveId} + + + DELETE FROM objective_relationship WHERE father_id = #{objectiveId} + + + DELETE FROM objective_relationship WHERE father_id = #{parentObjectiveId} AND child_id = #{childObjectiveId} + + + DELETE FROM objective_ai WHERE objective_id = #{objectiveId} + + + + SELECT * FROM objective WHERE id = #{id} + + + SELECT child_id FROM objective_relationship where father_id = #{objectiveId} + + + SELECT father_id FROM objective_relationship where child_id = #{objectiveId} + + + SELECT id FROM objective where user_id = #{userId} + + + SELECT * FROM objective WHERE id IN + + #{id} + + + + SELECT EXISTS( + SELECT 1 + FROM objective_relationship + WHERE child_id = #{objectiveId} + ) + + + SELECT + COUNT(*) + FROM + objective o + WHERE + o.user_id = #{userId} + AND + NOT EXISTS ( + SELECT 1 + FROM objective_relationship r + WHERE r.child_id = o.id + ) + + + SELECT COUNT(*) FROM objective WHERE user_id = #{userId} AND completed_at IS NOT NULL + + + SELECT ai_guide FROM objective_ai WHERE objective_id = #{objectiveId} + + + SELECT father_id FROM objective_relationship WHERE child_id = #{objectiveId} + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/mapper/ResourceMapper.xml b/quan_backend - without config/quan-server/src/main/resources/mapper/ResourceMapper.xml new file mode 100644 index 0000000..005d6ae --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/mapper/ResourceMapper.xml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into resource (user_id, title, description, category, url, content, created_at, updated_at) + values (#{userId}, #{title}, #{description}, #{category}, #{url}, #{content}, #{createdAt}, #{updatedAt}) + + + insert into resource_like (user_id, resource_id, created_at) + values (#{userId}, #{resourceId}, #{createdAt}) + + + insert into resource_comment (user_id, resource_id, content, created_at) + values (#{userId}, #{resourceId}, #{content}, #{createdAt}) + + + insert into resource_favorite (user_id, resource_id, created_at) + values (#{userId}, #{resourceId}, #{createdAt}) + + + delete from resource + where id = #{id} and user_id = #{userId} + + + delete from resource_like + where user_id = #{userId} and resource_id = #{resourceId} + + + delete from resource_favorite + where user_id = #{userId} and resource_id = #{resourceId} + + + select + r.id, r.user_id, r.title, r.description, r.category, + r.url, r.content, r.created_at, r.updated_at, + u.id as user_id, u.username, u.email, u.nickname, u.avatar_url, + (select count(*) from resource_like rl where rl.resource_id = r.id) as like_count, + (select count(*) from resource_comment rc where rc.resource_id = r.id) as comment_count, + (select count(*) from resource_favorite rf where rf.resource_id = r.id) as favorite_count, + (select count(*) from resource_like rl where rl.resource_id = r.id and rl.user_id = #{currentUserId}) > 0 as is_liked, + (select count(*) from resource_favorite rf where rf.resource_id = r.id and rf.user_id = #{currentUserId}) > 0 as is_favorite + from resource r + left join user u on r.user_id = u.id + where r.id = #{id} + + + select + r.id, r.user_id, r.title, r.description, r.category, + r.url, r.content, r.created_at, r.updated_at, + u.id as user_id, u.username, u.email, u.nickname, u.avatar_url, + (select count(*) from resource_like rl where rl.resource_id = r.id) as like_count, + (select count(*) from resource_comment rc where rc.resource_id = r.id) as comment_count, + (select count(*) from resource_favorite rf where rf.resource_id = r.id) as favorite_count, + (select count(*) from resource_like rl where rl.resource_id = r.id and rl.user_id = #{currentUserId}) > 0 as is_liked, + (select count(*) from resource_favorite rf where rf.resource_id = r.id and rf.user_id = #{currentUserId}) > 0 as is_favorite + from resource r + left join user u on r.user_id = u.id + where r.user_id in + + #{userId} + + + and r.category = #{category} + + order by r.created_at desc + limit #{offset}, #{pageSize} + + + + + select exists(select 1 from resource_like where user_id = #{userId} and resource_id = #{resourceId}) + + + select rc.id, rc.resource_id, rc.content, rc.created_at, + u.id as user_id, u.username, u.email, u.nickname, u.avatar_url + from resource_comment rc + left join user u on u.id = rc.user_id + where rc.id = #{commentId} + + + select rc.id, rc.resource_id, rc.content, rc.created_at, + u.id as user_id, u.username, u.email, u.nickname, u.avatar_url + from resource_comment rc + left join user u on u.id = rc.user_id + where rc.resource_id = #{id} + + + select exists(select 1 from resource_favorite where user_id = #{userId} and resource_id = #{resourceId}) + + + select count(*) from resource + + + category = #{category} + + + and user_id in + + #{userId} + + + + + + + + select + r.id, r.user_id, r.title, r.description, r.category, + r.url, r.content, r.created_at, r.updated_at, + u.id as user_id, u.username, u.email, u.nickname, u.avatar_url, + (select count(*) from resource_like rl where rl.resource_id = r.id) as like_count, + (select count(*) from resource_comment rc where rc.resource_id = r.id) as comment_count, + (select count(*) from resource_favorite rf where rf.resource_id = r.id) as favorite_count + from resource r + left join user u on r.user_id = u.id + left join resource_favorite rf on rf.resource_id = r.id and rf.user_id = #{userId} + where rf.user_id IS NOT NULL + + and r.category = #{category} + + order by r.created_at desc + limit #{offset}, #{pageSize} + + + + select count(*) from resource_favorite rf + left join resource r on rf.resource_id = r.id + where rf.user_id = #{userId} + + and r.category = #{category} + + + + select count(*) from resource_like rl + left join resource r on rl.resource_id = r.id + where rl.user_id = #{userId} + + + select count(*) from resource_comment rc + left join resource r on rc.resource_id = r.id + where rc.user_id = #{userId} + + + select count(*) from resource_favorite rf + left join resource r on rf.resource_id = r.id + where rf.user_id = #{userId} + + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/mapper/TaskMapper.xml b/quan_backend - without config/quan-server/src/main/resources/mapper/TaskMapper.xml new file mode 100644 index 0000000..1c028d0 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/mapper/TaskMapper.xml @@ -0,0 +1,219 @@ + + + + + + INSERT INTO task (user_id, name, description, status, visibility, type, created_at, updated_at, ddl, completed_at, period, start_date, end_date, completed_count, total_count) + VALUES (#{userId}, #{name}, #{description}, #{status}, #{visibility}, #{type}, #{createdAt}, #{updatedAt}, #{ddl}, #{completedAt}, #{period}, #{startDate}, #{endDate}, #{completedCount}, #{totalCount}) + + + INSERT INTO objective_task (objective_id, task_id) + VALUES (#{objectiveId}, #{taskId}) + + + INSERT INTO objective_task (objective_id, task_id) + VALUES (#{objectiveId}, #{taskId}) + + + + UPDATE task + + name = #{task.name}, + description = #{task.description}, + status = #{task.status}, + visibility = #{task.visibility}, + ddl = #{task.ddl}, + period = #{task.period}, + start_date = #{task.startDate}, + end_date = #{task.endDate}, + completed_at = #{task.completedAt}, + updated_at = #{task.updatedAt}, + completed_count = #{task.completedCount}, + total_count = #{task.totalCount}, + + WHERE id = #{id} + + + DELETE FROM task WHERE id = #{id} + + + DELETE FROM objective_task WHERE task_id = #{id} + + + DELETE FROM objective_task WHERE objective_id = #{objectiveId} + + + DELETE FROM objective_task WHERE objective_id = #{objectiveId} AND task_id = #{taskId} + + + DELETE FROM task_completion WHERE task_id = #{taskId} + + + DELETE FROM task_completion WHERE id = #{id} + + + SELECT * FROM task WHERE id = #{id} + + + SELECT objective_id FROM objective_task WHERE task_id = #{id} + + + = #{today}) + OR + (type = 'recurring' AND start_date <= #{today} AND (end_date >= #{today} OR end_date IS NULL)) + ) + ]]> + + + SELECT task_id FROM objective_task WHERE objective_id = #{objectiveId} + + + #{year} OR (YEAR(end_date) = #{year} AND MONTH(end_date) >= #{month})) + )) + ) + ]]> + + + = CONCAT(#{year}, '-', #{month}, '-01') + GROUP BY DATE_ADD(start_date, INTERVAL n DAY) + ]]> + + + SELECT + DATE(completed_at) AS date, + COUNT(id) AS count + FROM task_completion + WHERE + user_id = #{userId} + AND YEAR(completed_at) = #{year} + + AND MONTH(completed_at) = #{month} + + GROUP BY DATE(completed_at) + ORDER BY date ASC + + + SELECT id FROM task_completion WHERE taks_id = #{taskId} ORDER BY completed_at DESC LIMIT 1 + + + SELECT + u.id AS user_id, + u.username, + u.avatar_url, + COALESCE(COUNT(t.id), 0) AS complete_count + FROM user u + LEFT JOIN task_completion t ON u.id = t.user_id + AND t.completed_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) + WHERE u.id IN + + #{item} + + GROUP BY u.id, u.username, u.avatar_url + ORDER BY complete_count DESC + + + + + SELECT + u.id AS user_id, + u.username, + u.avatar_url, + COALESCE(COUNT(t.id), 0) AS complete_count + FROM user u + LEFT JOIN task_completion t ON u.id = t.user_id + AND t.completed_at >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH) + WHERE u.id IN + + #{item} + + GROUP BY u.id, u.username, u.avatar_url + ORDER BY complete_count DESC + + + SELECT COUNT(*) FROM task WHERE user_id = #{userId} + + + SELECT COUNT(*) FROM task_completion WHERE user_id = #{userId} + + + = #{startDate})) + ) + GROUP BY date + ]]> + + + SELECT DATE(completed_at) AS date, COUNT(id) AS completeCount + FROM task_completion + WHERE user_id = #{userId} + AND DATE(completed_at) BETWEEN #{startDate} AND #{endDate} + GROUP BY date + + + SELECT * + FROM task + WHERE type = 'recurring' + AND status = 'completed' + + + SELECT + DATE(completed_at) AS date, + COUNT(*) AS count + FROM task_completion + WHERE + user_id = #{userId} + AND YEAR(completed_at) = #{year} + GROUP BY DATE(completed_at) + ORDER BY date ASC + + + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/mapper/UserAchievementMapper.xml b/quan_backend - without config/quan-server/src/main/resources/mapper/UserAchievementMapper.xml new file mode 100644 index 0000000..4533a79 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/mapper/UserAchievementMapper.xml @@ -0,0 +1,33 @@ + + + + + INSERT INTO user_achievement + (user_id, achievement_id, achieved_at) + VALUES + (#{userId}, #{achievementId}, #{achievedAt}) + + + + + SELECT + EXISTS ( + SELECT 1 + FROM user_achievement + WHERE user_id = #{userId} + AND achievement_id = #{achievementId} + ) + + + SELECT + ua.achieved_at, + a.name, + a.description, + a.icon_url + FROM user_achievement ua + JOIN achievement a ON ua.achievement_id = a.id + WHERE ua.user_id = #{userId} + ORDER BY ua.achieved_at ASC + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/mapper/UserMapper.xml b/quan_backend - without config/quan-server/src/main/resources/mapper/UserMapper.xml new file mode 100644 index 0000000..6be6628 --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/mapper/UserMapper.xml @@ -0,0 +1,70 @@ + + + + + + insert into user (username, password, email, nickname, avatar_url, created_at, updated_at) + values (#{username}, #{password}, #{email}, #{nickname}, #{avatarUrl}, #{createdAt}, #{updatedAt}) + + + update user + + nickname = #{nickname}, + updated_at = #{updatedAt}, + avatar_url = #{avatarUrl}, + + WHERE id = #{id} + + + + INSERT INTO user_location (user_id, latitude, longitude, last_update) + VALUES (#{userId}, #{latitude}, #{longitude}, #{lastUpdate}) + ON DUPLICATE KEY UPDATE + latitude = #{latitude}, + longitude = #{longitude}, + last_update = #{lastUpdate}; + + + + select * from user + + + and username = #{username} + + + and email = #{email} + + + and name like concat('%', #{name}, '%') + + + order by created_at desc + + + select * from user where id = #{id} + + + SELECT + u.id, + u.username, + u.email, + u.nickname, + u.avatar_url, + CASE + WHEN f.user_id IS NOT NULL THEN TRUE + ELSE FALSE + END AS isFriend + FROM user u + LEFT JOIN ( + SELECT friend_id AS uid, user_id FROM friendship WHERE user_id = #{currentUserId} + UNION + SELECT user_id AS uid, friend_id AS user_id FROM friendship WHERE friend_id = #{currentUserId} + ) f ON u.id = f.uid + WHERE u.id IN + + #{id} + + + + \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/prompts/objective_prompt.txt b/quan_backend - without config/quan-server/src/main/resources/prompts/objective_prompt.txt new file mode 100644 index 0000000..dcb9f0e --- /dev/null +++ b/quan_backend - without config/quan-server/src/main/resources/prompts/objective_prompt.txt @@ -0,0 +1,100 @@ +你是一个专业的智能任务规划助手,具备项目管理、时间拆解、任务生成等能力,擅长帮助用户将高层次目标拆解为可执行的步骤,并规划合理的时间安排与节奏。 + +## 任务要求 + +用户在“用户输入”部分提供一个 **主目标**,包括目标名称、描述、开始时间和结束时间。你的任务是: + +1. 根据目标整体时间与内容,合理拆解出多个 **子目标**; +2. 每个子目标下应包含一个详细的 **任务清单**,任务包括: + - **单次任务**(SingleTask) + - **重复任务**(RecurringTask) + +所有输出必须严格遵守后文定义的 **拆解逻辑** 和 **输出格式**。 + +## 拆解逻辑 + +### 1. 时间分析 +- 计算目标总持续时间(结束时间 - 开始时间) +- 判断时间跨度并选择拆解方式: + - ≤7天:按天划分子目标 + - 8-30天:按周划分子目标 + - >30天:按月划分子目标,并加入里程碑式子目标 +- 识别关键时间点(如周末、月初等)用于任务分布参考 + +### 2. 子目标拆解方式 +根据目标特点选择最合适的拆解方式,可组合使用: + +- **流程导向法**:适合步骤明确的目标(如:开发流程、活动流程) +- **模块导向法**:适合跨领域或多子技能目标(如学习多个知识点) +- **数值分解法**:适合量化目标(如“10小时学习”或“读5本书”) +- **时间轴平分法(默认)**:将任务按时间平均分布 + +### 3. 任务类型及特征 +- **单次任务(type: "single")** + - 有明确的截止时间(ddl) + - 通常为独立、不可重复任务 +- **重复任务(type: "recurring")** + - 用于习惯养成或重复行为 + - 周期频率为:daily / weekly / monthly + - 时间范围覆盖子目标周期的 ≥30% + +### 4. 时间范围规则 +- 子目标时间必须完全落在主目标时间范围内 + - 子目标开始时间 ≥ 主目标开始时间 + - 子目标结束时间 ≤ 主目标结束时间 +- 所有任务的时间必须在所属子目标时间范围内: + - 单次任务的 ddl 在子目标范围内 + - 重复任务的开始/结束时间在子目标范围内 +- 若生成时间超出范围,请自动将其调整为边界值 + +--- + +## 用户输入 + +- **主目标名称**: %s +- **目标描述**: %s +- **开始日期**: %s +- **结束日期**: %s +%s + +--- + +## 输出格式 + +请严格按照以下 JSON 格式返回内容(不要添加解释或多余信息): + +```json +{ + "masterObjective": { + "name": "%s", + "description": "%s", + "startDate": "%s", + "endDate": "%s" + }, + "subObjectives": [ + { + "name": "{子目标名称}", + "description": "{子目标描述}", + "startDate": "{YYYY-MM-DD}", + "endDate": "{YYYY-MM-DD}", + "tasks": [ + { + "name": "{单次任务名称}", + "type": "single", + "description": "{任务描述}", + "ddl": "{YYYY-MM-DD}" + }, + { + "name": "{重复任务名称}", + "type": "recurring", + "description": "{任务描述}", + "period": "daily", + "startDate": "{YYYY-MM-DD}", + "endDate": "{YYYY-MM-DD}" + } + ] + } + ], + "aiGuide": "{智能建议:针对用户目标的优化或执行策略,100字左右}" +} +``` \ No newline at end of file diff --git a/quan_backend - without config/quan-server/src/main/resources/static/email_img/background.png b/quan_backend - without config/quan-server/src/main/resources/static/email_img/background.png new file mode 100644 index 0000000..2a1b698 Binary files /dev/null and b/quan_backend - without config/quan-server/src/main/resources/static/email_img/background.png differ diff --git a/quan_backend - without config/quan-server/src/main/resources/static/email_img/ink.jpg b/quan_backend - without config/quan-server/src/main/resources/static/email_img/ink.jpg new file mode 100644 index 0000000..49646eb Binary files /dev/null and b/quan_backend - without config/quan-server/src/main/resources/static/email_img/ink.jpg differ diff --git a/quan_backend - without config/quan-server/src/test/java/com/vksfeng/quan/QuanApplicationTests.java b/quan_backend - without config/quan-server/src/test/java/com/vksfeng/quan/QuanApplicationTests.java new file mode 100644 index 0000000..db72f91 --- /dev/null +++ b/quan_backend - without config/quan-server/src/test/java/com/vksfeng/quan/QuanApplicationTests.java @@ -0,0 +1,58 @@ +package com.vksfeng.quan; + +import com.vksfeng.quan.achievement.pojo.entity.RuleCondition; +import com.vksfeng.quan.achievement.pojo.entity.RuleJson; +import com.vksfeng.quan.achievement.util.AchievementEventPublisher; +import com.vksfeng.quan.achievement.util.AchievementListener; +import com.vksfeng.quan.achievement.util.RuleEvaluator; +import com.vksfeng.quan.scheduler.TaskStatusScheduler; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; +import java.util.Map; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class QuanApplicationTests { + + @Test + void contextLoads() { + } + + @Autowired + private RuleEvaluator ruleEvaluator; + + @Test + void textRuleEvaluator() { + RuleJson rule = new RuleJson(); + rule.setType("IS_ADULT_MALE"); + rule.setLogic("AND"); + rule.setConditions(List.of( + new RuleCondition("age", ">", 18), + new RuleCondition("gender", "==", "Male") + )); + System.out.println(ruleEvaluator.evaluate(rule, Map.of("age", 20, "gender", "Male"))); + } + + @Autowired + private AchievementEventPublisher achievementEventPublisher; + + @Test + void testEventPublisher() { +// achievementEventPublisher.publish(1L, "OBJECTIVE_ADDED", null); + achievementEventPublisher.publish(1L, "TASK_COMPLETED", null); + } + + + @Autowired + private TaskStatusScheduler taskStatusScheduler; + + @Test + void testTaskStatusScheduler() { + taskStatusScheduler.doRefresh(); + } + + +} diff --git a/quan_frontend-without config/.gitignore b/quan_frontend-without config/.gitignore new file mode 100644 index 0000000..61d123f --- /dev/null +++ b/quan_frontend-without config/.gitignore @@ -0,0 +1,35 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo + + + +/src/config.prod.js +/src/config.dev.js diff --git a/quan_frontend-without config/README.md b/quan_frontend-without config/README.md new file mode 100644 index 0000000..c912730 --- /dev/null +++ b/quan_frontend-without config/README.md @@ -0,0 +1,29 @@ +# Quan + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Compile and Minify for Production + +```sh +npm run build +``` diff --git a/quan_frontend-without config/index.html b/quan_frontend-without config/index.html new file mode 100644 index 0000000..b0bd0d4 --- /dev/null +++ b/quan_frontend-without config/index.html @@ -0,0 +1,15 @@ + + + + + + + + + Quan + + + + + + diff --git a/quan_frontend-without config/jsconfig.json b/quan_frontend-without config/jsconfig.json new file mode 100644 index 0000000..5a1f2d2 --- /dev/null +++ b/quan_frontend-without config/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + }, + "exclude": ["node_modules", "dist"] +} diff --git a/quan_frontend-without config/package-lock.json b/quan_frontend-without config/package-lock.json new file mode 100644 index 0000000..974fd6a --- /dev/null +++ b/quan_frontend-without config/package-lock.json @@ -0,0 +1,7616 @@ +{ + "name": "quan", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "quan", + "version": "0.0.0", + "dependencies": { + "@kangc/v-md-editor": "^2.3.18", + "apexcharts": "^4.5.0", + "axios": "^1.8.1", + "echarts": "^5.6.0", + "element-plus": "^2.9.5", + "filepond": "^4.32.7", + "gsap": "^3.12.7", + "highlight.js": "^11.11.1", + "katex": "^0.16.21", + "lucide-vue-next": "^0.483.0", + "markdown-it-katex": "^2.0.3", + "markdown-it-task-lists": "^2.1.1", + "markdown-it-toc-done-right": "^4.2.0", + "quan": "file:", + "vue": "^3.5.13", + "vue-filepond": "^7.0.4", + "vue-router": "^4.5.0", + "vue3-apexcharts": "^1.8.0", + "vue3-markdown-it": "^1.0.10", + "vuex": "^4.0.2" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.2.1", + "sass-embedded": "^1.85.0", + "vite": "^6.1.0", + "vite-plugin-vue-devtools": "^7.7.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.8", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.26.9.tgz", + "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.26.9.tgz", + "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz", + "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.26.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", + "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.26.9.tgz", + "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.9.tgz", + "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.9" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", + "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-decorators": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", + "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.26.8", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz", + "integrity": "sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.0", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.26.9.tgz", + "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.9", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.9.tgz", + "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "6.0.4", + "resolved": "https://registry.npmmirror.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", + "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==", + "license": "MIT" + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/@bufbuild/protobuf/-/protobuf-2.2.3.tgz", + "integrity": "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.1.1.tgz", + "integrity": "sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.1.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kangc/v-md-editor": { + "version": "2.3.18", + "resolved": "https://registry.npmmirror.com/@kangc/v-md-editor/-/v-md-editor-2.3.18.tgz", + "integrity": "sha512-wjI9lUQs4Ktn3gYru3C1hauOuOo2na5cF4ycHCgBZmIk08RjQVNbHO169yqkt9PMj6Djnl8W6ZknCBhTQfFbzQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.14.0", + "@vuepress/markdown": "^1.8.2", + "codemirror": "^5.61.1", + "copy-to-clipboard": "^3.3.1", + "highlight.js": "^10.7.2", + "insert-text-at-cursor": "^0.3.0", + "katex": "^0.13.11", + "markdown-it": "^12.3.2", + "markdown-it-attrs": "^4.0.0", + "markdown-it-container": "^3.0.0", + "mermaid": "^10.6.1", + "prismjs": "^1.23.0", + "resize-observer-polyfill": "^1.5.1", + "vant": "^3.1.3", + "xss": "^1.0.9" + }, + "peerDependencies": { + "@vue/compiler-sfc": "^3.0.0", + "vue": "^3.0.0" + } + }, + "node_modules/@kangc/v-md-editor/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/@kangc/v-md-editor/node_modules/katex": { + "version": "0.13.24", + "resolved": "https://registry.npmmirror.com/katex/-/katex-0.13.24.tgz", + "integrity": "sha512-jZxYuKCma3VS5UuxOx/rFV1QyGSl3Uy/i0kTJF3HgQ5xMinCQVF8Zd4bMY/9aI9b9A2pjIBOsjSSm68ykTAr8w==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.0.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "license": "MIT", + "dependencies": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.4", + "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", + "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", + "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", + "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", + "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", + "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", + "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", + "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", + "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", + "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", + "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", + "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", + "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", + "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", + "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", + "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", + "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", + "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", + "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", + "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@svgdotjs/svg.draggable.js": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@svgdotjs/svg.draggable.js/-/svg.draggable.js-3.0.6.tgz", + "integrity": "sha512-7iJFm9lL3C40HQcqzEfezK2l+dW2CpoVY3b77KQGqc8GXWa6LhhmX5Ckv7alQfUXBuZbjpICZ+Dvq1czlGx7gA==", + "license": "MIT", + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4" + } + }, + "node_modules/@svgdotjs/svg.filter.js": { + "version": "3.0.9", + "resolved": "https://registry.npmmirror.com/@svgdotjs/svg.filter.js/-/svg.filter.js-3.0.9.tgz", + "integrity": "sha512-/69XMRCDoam2HgC4ldHIaDgeQf1ViHIsa0Ld4uWgiXtZ+E24DWHe/9Ib6kbNiZ7WRIdlVokUDR1Fg0kjIpkfbw==", + "license": "MIT", + "dependencies": { + "@svgdotjs/svg.js": "^3.2.4" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@svgdotjs/svg.js": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/@svgdotjs/svg.js/-/svg.js-3.2.4.tgz", + "integrity": "sha512-BjJ/7vWNowlX3Z8O4ywT58DqbNRyYlkk6Yz/D13aB7hGmfQTvGX4Tkgtm/ApYlu9M7lCQi15xUEidqMUmdMYwg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Fuzzyma" + } + }, + "node_modules/@svgdotjs/svg.resize.js": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@svgdotjs/svg.resize.js/-/svg.resize.js-2.0.5.tgz", + "integrity": "sha512-4heRW4B1QrJeENfi7326lUPYBCevj78FJs8kfeDxn5st0IYPIRXoTtOSYvTzFWgaWWXd3YCDE6ao4fmv91RthA==", + "license": "MIT", + "engines": { + "node": ">= 14.18" + }, + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4", + "@svgdotjs/svg.select.js": "^4.0.1" + } + }, + "node_modules/@svgdotjs/svg.select.js": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/@svgdotjs/svg.select.js/-/svg.select.js-4.0.2.tgz", + "integrity": "sha512-5gWdrvoQX3keo03SCmgaBbD+kFftq0F/f2bzCbNnpkkvW6tk4rl4MakORzFuNjvXPWwB4az9GwuvVxQVnjaK2g==", + "license": "MIT", + "engines": { + "node": ">= 14.18" + }, + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4" + } + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmmirror.com/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "license": "MIT", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmmirror.com/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "3.0.15", + "resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.14.0", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.14.0.tgz", + "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==", + "license": "MIT" + }, + "node_modules/@vant/icons": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/@vant/icons/-/icons-1.8.0.tgz", + "integrity": "sha512-sKfEUo2/CkQFuERxvkuF6mGQZDKu3IQdj5rV9Fm0weJXtchDSSQ+zt8qPCNUEhh9Y8shy5PzxbvAfOOkCwlCXg==", + "license": "MIT" + }, + "node_modules/@vant/popperjs": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/@vant/popperjs/-/popperjs-1.3.0.tgz", + "integrity": "sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==", + "license": "MIT" + }, + "node_modules/@vant/use": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/@vant/use/-/use-1.6.0.tgz", + "integrity": "sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", + "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz", + "integrity": "sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.5.tgz", + "integrity": "sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.6", + "@babel/types": "^7.25.6", + "@vue/babel-helper-vue-transform-on": "1.2.5", + "@vue/babel-plugin-resolve-type": "1.2.5", + "html-tags": "^3.3.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.5.tgz", + "integrity": "sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/parser": "^7.25.6", + "@vue/compiler-sfc": "^3.5.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/devtools-core": { + "version": "7.7.2", + "resolved": "https://registry.npmmirror.com/@vue/devtools-core/-/devtools-core-7.7.2.tgz", + "integrity": "sha512-lexREWj1lKi91Tblr38ntSsy6CvI8ba7u+jmwh2yruib/ltLUcsIzEjCnrkh1yYGGIKXbAuYV2tOG10fGDB9OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.2", + "@vue/devtools-shared": "^7.7.2", + "mitt": "^3.0.1", + "nanoid": "^5.0.9", + "pathe": "^2.0.2", + "vite-hot-client": "^0.2.4" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vue/devtools-core/node_modules/nanoid": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.0.tgz", + "integrity": "sha512-zDAl/llz8Ue/EblwSYwdxGBYfj46IM1dhjVi8dyp9LQffoIGxJEAHj2oeZ4uNcgycSRcQ83CnfcZqEJzVDLcDw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.2", + "resolved": "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-7.7.2.tgz", + "integrity": "sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.2", + "birpc": "^0.2.19", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.1" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.2", + "resolved": "https://registry.npmmirror.com/@vue/devtools-shared/-/devtools-shared-7.7.2.tgz", + "integrity": "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "vue": "3.5.13" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", + "license": "MIT" + }, + "node_modules/@vuepress/markdown": { + "version": "1.9.10", + "resolved": "https://registry.npmmirror.com/@vuepress/markdown/-/markdown-1.9.10.tgz", + "integrity": "sha512-sXTLjeZzH8SQuAL5AEH0hhsMljjNJbzWbBvzaj5yQCCdf+3sp/dJ0kwnBSnQjFPPnzPg5t3tLKGUYHyW0KiKzA==", + "license": "MIT", + "dependencies": { + "@vuepress/shared-utils": "1.9.10", + "markdown-it": "^8.4.1", + "markdown-it-anchor": "^5.0.2", + "markdown-it-chain": "^1.3.0", + "markdown-it-emoji": "^1.4.0", + "markdown-it-table-of-contents": "^0.4.0", + "prismjs": "^1.13.0" + } + }, + "node_modules/@vuepress/markdown/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@vuepress/markdown/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "license": "BSD-2-Clause" + }, + "node_modules/@vuepress/markdown/node_modules/linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "license": "MIT", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/@vuepress/markdown/node_modules/markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/@vuepress/markdown/node_modules/markdown-it-anchor": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", + "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "license": "Unlicense", + "peerDependencies": { + "markdown-it": "*" + } + }, + "node_modules/@vuepress/markdown/node_modules/markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha512-QCz3Hkd+r5gDYtS2xsFXmBYrgw6KuWcJZLCEkdfAuwzZbShCmCfta+hwAMq4NX/4xPzkSHduMKgMkkPUJxSXNg==", + "license": "MIT" + }, + "node_modules/@vuepress/shared-utils": { + "version": "1.9.10", + "resolved": "https://registry.npmmirror.com/@vuepress/shared-utils/-/shared-utils-1.9.10.tgz", + "integrity": "sha512-M9A3DocPih+V8dKK2Zg9FJQ/f3JZrYsdaM/vQ9F48l8bPlzxw5NvqXIYMK4kKcGEyerQNTWCudoCpLL5uiU0hg==", + "license": "MIT", + "dependencies": { + "chalk": "^2.3.2", + "escape-html": "^1.0.3", + "fs-extra": "^7.0.1", + "globby": "^9.2.0", + "gray-matter": "^4.0.1", + "hash-sum": "^1.0.2", + "semver": "^6.0.0", + "toml": "^3.0.0", + "upath": "^1.1.0" + } + }, + "node_modules/@vuepress/shared-utils/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@vuepress/shared-utils/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@vuepress/shared-utils/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "license": "MIT", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@yr/monotone-cubic-spline": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz", + "integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==", + "license": "MIT" + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/apexcharts": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/apexcharts/-/apexcharts-4.5.0.tgz", + "integrity": "sha512-E7ZkrVqPNBUWy/Rmg8DEIqHNBmElzICE/oxOX5Ekvs2ICQUOK/VkEkMH09JGJu+O/EA0NL31hxlmF+wrwrSLaQ==", + "license": "MIT", + "dependencies": { + "@svgdotjs/svg.draggable.js": "^3.0.4", + "@svgdotjs/svg.filter.js": "^3.0.8", + "@svgdotjs/svg.js": "^3.2.4", + "@svgdotjs/svg.resize.js": "^2.0.2", + "@svgdotjs/svg.select.js": "^4.0.1", + "@yr/monotone-cubic-spline": "^1.0.3" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "license": "MIT", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/axios": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.8.1.tgz", + "integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmmirror.com/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "license": "MIT", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/birpc": { + "version": "0.2.19", + "resolved": "https://registry.npmmirror.com/birpc/-/birpc-0.2.19.tgz", + "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-builder": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/buffer-builder/-/buffer-builder-0.2.0.tgz", + "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", + "dev": true, + "license": "MIT/X11" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "license": "MIT", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "license": "MIT" + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001700", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz", + "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmmirror.com/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/codemirror": { + "version": "5.65.19", + "resolved": "https://registry.npmmirror.com/codemirror/-/codemirror-5.65.19.tgz", + "integrity": "sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==", + "license": "MIT" + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "license": "MIT", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/colorjs.io": { + "version": "0.5.2", + "resolved": "https://registry.npmmirror.com/colorjs.io/-/colorjs.io-0.5.2.tgz", + "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssfilter": { + "version": "0.0.10", + "resolved": "https://registry.npmmirror.com/cssfilter/-/cssfilter-0.0.10.tgz", + "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/cytoscape": { + "version": "3.31.2", + "resolved": "https://registry.npmmirror.com/cytoscape/-/cytoscape-3.31.2.tgz", + "integrity": "sha512-/eOXg2uGdMdpGlEes5Sf6zE+jUG+05f3htFNQIxLxduOH/SsaUZiPBfAwP1btVIVzsnhiNOdi+hvDRLYfMZjGw==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmmirror.com/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmmirror.com/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmmirror.com/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.10", + "resolved": "https://registry.npmmirror.com/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz", + "integrity": "sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==", + "license": "MIT", + "dependencies": { + "d3": "^7.8.2", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", + "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "license": "MIT", + "dependencies": { + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dompurify": { + "version": "3.1.6", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", + "license": "(MPL-2.0 OR Apache-2.0)" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.102", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz", + "integrity": "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/element-plus": { + "version": "2.9.5", + "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.5.tgz", + "integrity": "sha512-r+X79oogLbYq8p9L5f9fHSHhUFNM0AL72aikqiZVxSc2/08mK6m/PotiB9e/D90QmWTIHIaFnFmW65AcXmneig==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/elkjs": { + "version": "0.9.3", + "resolved": "https://registry.npmmirror.com/elkjs/-/elkjs-0.9.3.tgz", + "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==", + "license": "EPL-2.0" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-stack-parser-es": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz", + "integrity": "sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.24.2", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/execa": { + "version": "9.5.2", + "resolved": "https://registry.npmmirror.com/execa/-/execa-9.5.2.tgz", + "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.3", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.0", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "license": "MIT", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "license": "MIT", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "license": "MIT", + "dependencies": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filepond": { + "version": "4.32.7", + "resolved": "https://registry.npmmirror.com/filepond/-/filepond-4.32.7.tgz", + "integrity": "sha512-L2idUfC31Qb2ZuFn8yAjX+Km6Ouq0kQn6JHcwhqrl5Ee9cB7xctLa0nkbbAeCML2+a1/cUsd0TqBgVcxYW08GA==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "license": "MIT", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.7", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "function-bind": "^1.1.2", + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "license": "ISC", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==", + "license": "BSD" + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "9.2.0", + "resolved": "https://registry.npmmirror.com/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "license": "MIT", + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gsap": { + "version": "3.12.7", + "resolved": "https://registry.npmmirror.com/gsap/-/gsap-3.12.7.tgz", + "integrity": "sha512-V4GsyVamhmKefvcAKaoy0h6si0xX7ogwBoBSs2CTJwt7luW0oZzC0LhdkyuKV8PJAXr7Yaj8pMjCKD4GJ+eEMg==", + "license": "Standard 'no charge' license: https://gsap.com/standard-license. Club GSAP members get more: https://gsap.com/licensing/. Why GreenSock doesn't employ an MIT license: https://gsap.com/why-license/" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "license": "MIT", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-8.0.0.tgz", + "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "5.0.3", + "resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.0.3.tgz", + "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/insert-text-at-cursor": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/insert-text-at-cursor/-/insert-text-at-cursor-0.3.0.tgz", + "integrity": "sha512-/nPtyeX9xPUvxZf+r0518B7uqNKlP+LqNJqSiXFEaa2T71rWIwTVXGH7hB9xO/EVdwa5/pWlFCPwShOW81XIxQ==", + "license": "MIT" + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmmirror.com/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmmirror.com/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/javascript-stringify": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz", + "integrity": "sha512-fnjC0up+0SjEJtgmmG+teeel68kutkvzfctO/KxE3qJlbunkJYAshgH3boU++gSBHP8z5/r0ts0qRIrHf0RTQQ==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/katex": { + "version": "0.16.21", + "resolved": "https://registry.npmmirror.com/katex/-/katex-0.16.21.tgz", + "integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmmirror.com/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-vue-next": { + "version": "0.483.0", + "resolved": "https://registry.npmmirror.com/lucide-vue-next/-/lucide-vue-next-0.483.0.tgz", + "integrity": "sha512-oMX1hfH7hOAdwaJdddYTSN0Z+WomndF3KXryCP/I6iu+4jZL6a4YyYi1J23EzP3/wOWCaj9mDuVhxgK+xqX8vQ==", + "license": "ISC", + "peerDependencies": { + "vue": ">=3.0.1" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmmirror.com/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "license": "MIT", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-abbr": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz", + "integrity": "sha512-ZeA4Z4SaBbYysZap5iZcxKmlPL6bYA8grqhzJIHB1ikn7njnzaP8uwbtuXc4YXD5LicI4/2Xmc0VwmSiFV04gg==", + "license": "MIT" + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmmirror.com/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "license": "Unlicense", + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/markdown-it-attrs": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/markdown-it-attrs/-/markdown-it-attrs-4.3.1.tgz", + "integrity": "sha512-/ko6cba+H6gdZ0DOw7BbNMZtfuJTRp9g/IrGIuz8lYc/EfnmWRpaR3CFPnNbVz0LDvF8Gf1hFGPqrQqq7De0rg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "markdown-it": ">= 9.0.0" + } + }, + "node_modules/markdown-it-chain": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/markdown-it-chain/-/markdown-it-chain-1.3.0.tgz", + "integrity": "sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ==", + "license": "MIT", + "dependencies": { + "webpack-chain": "^4.9.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "markdown-it": ">=5.0.0" + } + }, + "node_modules/markdown-it-container": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/markdown-it-container/-/markdown-it-container-3.0.0.tgz", + "integrity": "sha512-y6oKTq4BB9OQuY/KLfk/O3ysFhB3IMYoIWhGJEidXt1NQFocFK2sA2t0NYZAMyMShAGL6x5OPIbrmXPIqaN9rw==", + "license": "MIT" + }, + "node_modules/markdown-it-deflist": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/markdown-it-deflist/-/markdown-it-deflist-2.1.0.tgz", + "integrity": "sha512-3OuqoRUlSxJiuQYu0cWTLHNhhq2xtoSFqsZK8plANg91+RJQU1ziQ6lA2LzmFAEes18uPBsHZpcX6We5l76Nzg==", + "license": "MIT" + }, + "node_modules/markdown-it-emoji": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/markdown-it-emoji/-/markdown-it-emoji-2.0.2.tgz", + "integrity": "sha512-zLftSaNrKuYl0kR5zm4gxXjHaOI3FAOEaloKmRA5hijmJZvSjmxcokOLlzycb/HXlUFWzXqpIEoyEMCE4i9MvQ==", + "license": "MIT" + }, + "node_modules/markdown-it-footnote": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz", + "integrity": "sha512-YZMSuCGVZAjzKMn+xqIco9d1cLGxbELHZ9do/TSYVzraooV8ypsppKNmUJ0fVH5ljkCInQAtFpm8Rb3eXSrt5w==", + "license": "MIT" + }, + "node_modules/markdown-it-highlightjs": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/markdown-it-highlightjs/-/markdown-it-highlightjs-3.6.0.tgz", + "integrity": "sha512-ex+Lq3cVkprh0GpGwFyc53A/rqY6GGzopPCG1xMsf8Ya3XtGC8Uw9tChN1rWbpyDae7tBBhVHVcMM29h4Btamw==", + "license": "Unlicense", + "dependencies": { + "highlight.js": "^11.3.1", + "lodash.flow": "^3.5.0" + } + }, + "node_modules/markdown-it-ins": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/markdown-it-ins/-/markdown-it-ins-3.0.1.tgz", + "integrity": "sha512-32SSfZqSzqyAmmQ4SHvhxbFqSzPDqsZgMHDwxqPzp+v+t8RsmqsBZRG+RfRQskJko9PfKC2/oxyOs4Yg/CfiRw==", + "license": "MIT" + }, + "node_modules/markdown-it-katex": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/markdown-it-katex/-/markdown-it-katex-2.0.3.tgz", + "integrity": "sha512-nUkkMtRWeg7OpdflamflE/Ho/pWl64Lk9wNBKOmaj33XkQdumhXAIYhI0WO03GeiycPCsxbmX536V5NEXpC3Ng==", + "license": "MIT", + "dependencies": { + "katex": "^0.6.0" + } + }, + "node_modules/markdown-it-katex/node_modules/katex": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/katex/-/katex-0.6.0.tgz", + "integrity": "sha512-rS4mY3SvHYg5LtQV6RBcK0if7ur6plyEukAOV+jGGPqFImuzu8fHL6M752iBmRGoUyF0bhZbAPoezehn7xYksA==", + "license": "MIT", + "dependencies": { + "match-at": "^0.1.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/markdown-it-mark": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/markdown-it-mark/-/markdown-it-mark-3.0.1.tgz", + "integrity": "sha512-HyxjAu6BRsdt6Xcv6TKVQnkz/E70TdGXEFHRYBGLncRE9lBFwDNLVtFojKxjJWgJ+5XxUwLaHXy+2sGBbDn+4A==", + "license": "MIT" + }, + "node_modules/markdown-it-sub": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz", + "integrity": "sha512-z2Rm/LzEE1wzwTSDrI+FlPEveAAbgdAdPhdWarq/ZGJrGW/uCQbKAnhoCsE4hAbc3SEym26+W2z/VQB0cQiA9Q==", + "license": "MIT" + }, + "node_modules/markdown-it-sup": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz", + "integrity": "sha512-E32m0nV9iyhRR7CrhnzL5msqic7rL1juWre6TQNxsnApg7Uf+F97JOKxUijg5YwXz86lZ0mqfOnutoryyNdntQ==", + "license": "MIT" + }, + "node_modules/markdown-it-table-of-contents": { + "version": "0.4.4", + "resolved": "https://registry.npmmirror.com/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz", + "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==", + "license": "MIT", + "engines": { + "node": ">6.4.0" + } + }, + "node_modules/markdown-it-task-lists": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz", + "integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==", + "license": "ISC" + }, + "node_modules/markdown-it-toc-done-right": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.2.0.tgz", + "integrity": "sha512-UB/IbzjWazwTlNAX0pvWNlJS8NKsOQ4syrXZQ/C72j+jirrsjVRT627lCaylrKJFBQWfRsPmIVQie8x38DEhAQ==", + "license": "MIT" + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/match-at": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/match-at/-/match-at-0.1.1.tgz", + "integrity": "sha512-h4Yd392z9mST+dzc+yjuybOGFNOZjmXIPKWjxBd1Bb23r4SmDOsk2NYCU2BMUBGbSpZqwVsZYNq26QS3xfaT3Q==" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "license": "MIT" + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/mermaid": { + "version": "10.9.3", + "resolved": "https://registry.npmmirror.com/mermaid/-/mermaid-10.9.3.tgz", + "integrity": "sha512-V80X1isSEvAewIL3xhmz/rVmc27CVljcsbWxkxlWJWY/1kQa4XOABqpDl2qQLGKzpKm6WbTfUEKImBlUfFYArw==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^6.0.1", + "@types/d3-scale": "^4.0.3", + "@types/d3-scale-chromatic": "^3.0.0", + "cytoscape": "^3.28.1", + "cytoscape-cose-bilkent": "^4.1.0", + "d3": "^7.4.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.10", + "dayjs": "^1.11.7", + "dompurify": "^3.0.5 <3.1.7", + "elkjs": "^0.9.0", + "katex": "^0.16.9", + "khroma": "^2.0.0", + "lodash-es": "^4.17.21", + "mdast-util-from-markdown": "^1.3.0", + "non-layered-tidy-tree-layout": "^2.0.2", + "stylis": "^4.1.3", + "ts-dedent": "^2.2.0", + "uuid": "^9.0.0", + "web-worker": "^1.2.0" + } + }, + "node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", + "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", + "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "license": "MIT", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmmirror.com/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==", + "license": "MIT" + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "license": "MIT", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "license": "MIT" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "8.5.2", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.2.tgz", + "integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-ms": { + "version": "9.2.0", + "resolved": "https://registry.npmmirror.com/pretty-ms/-/pretty-ms-9.2.0.tgz", + "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/quan": { + "resolved": "", + "link": true + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmmirror.com/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "license": "MIT" + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "license": "MIT" + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmmirror.com/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, + "node_modules/rollup": { + "version": "4.34.8", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.34.8.tgz", + "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.34.8", + "@rollup/rollup-android-arm64": "4.34.8", + "@rollup/rollup-darwin-arm64": "4.34.8", + "@rollup/rollup-darwin-x64": "4.34.8", + "@rollup/rollup-freebsd-arm64": "4.34.8", + "@rollup/rollup-freebsd-x64": "4.34.8", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", + "@rollup/rollup-linux-arm-musleabihf": "4.34.8", + "@rollup/rollup-linux-arm64-gnu": "4.34.8", + "@rollup/rollup-linux-arm64-musl": "4.34.8", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", + "@rollup/rollup-linux-riscv64-gnu": "4.34.8", + "@rollup/rollup-linux-s390x-gnu": "4.34.8", + "@rollup/rollup-linux-x64-gnu": "4.34.8", + "@rollup/rollup-linux-x64-musl": "4.34.8", + "@rollup/rollup-win32-arm64-msvc": "4.34.8", + "@rollup/rollup-win32-ia32-msvc": "4.34.8", + "@rollup/rollup-win32-x64-msvc": "4.34.8", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "license": "MIT", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sass-embedded": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded/-/sass-embedded-1.85.0.tgz", + "integrity": "sha512-x3Vv54g0jv1aPSW8OTA/0GzQCs/HMQOjIkLtZJ3Xsn/I4vnyjKbVTQmFTax9bQjldqLEEkdbvy6ES/cOOnYNwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0", + "buffer-builder": "^0.2.0", + "colorjs.io": "^0.5.0", + "immutable": "^5.0.2", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "sync-child-process": "^1.0.2", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "sass-embedded-android-arm": "1.85.0", + "sass-embedded-android-arm64": "1.85.0", + "sass-embedded-android-ia32": "1.85.0", + "sass-embedded-android-riscv64": "1.85.0", + "sass-embedded-android-x64": "1.85.0", + "sass-embedded-darwin-arm64": "1.85.0", + "sass-embedded-darwin-x64": "1.85.0", + "sass-embedded-linux-arm": "1.85.0", + "sass-embedded-linux-arm64": "1.85.0", + "sass-embedded-linux-ia32": "1.85.0", + "sass-embedded-linux-musl-arm": "1.85.0", + "sass-embedded-linux-musl-arm64": "1.85.0", + "sass-embedded-linux-musl-ia32": "1.85.0", + "sass-embedded-linux-musl-riscv64": "1.85.0", + "sass-embedded-linux-musl-x64": "1.85.0", + "sass-embedded-linux-riscv64": "1.85.0", + "sass-embedded-linux-x64": "1.85.0", + "sass-embedded-win32-arm64": "1.85.0", + "sass-embedded-win32-ia32": "1.85.0", + "sass-embedded-win32-x64": "1.85.0" + } + }, + "node_modules/sass-embedded-android-arm": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-android-arm/-/sass-embedded-android-arm-1.85.0.tgz", + "integrity": "sha512-pPBT7Ad6G8Mlao8ypVNXW2ya7I/Bhcny+RYZ/EmrunEXfhzCNp4PWV2VAweitPO9RnPIJwvUTkLc8Fu6K3nVmw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-arm64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.85.0.tgz", + "integrity": "sha512-4itDzRwezwrW8+YzMLIwHtMeH+qrBNdBsRn9lTVI15K+cNLC8z5JWJi6UCZ8TNNZr9LDBfsh5jUdjSub0yF7jg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-ia32": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.85.0.tgz", + "integrity": "sha512-bwqKq95hzbGbMTeXCMQhH7yEdc2xJVwIXj7rGdD3McvyFWbED6362XRFFPI5YyjfD2wRJd9yWLh/hn+6VyjcYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-riscv64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.85.0.tgz", + "integrity": "sha512-Fgkgay+5EePJXZFHR5Vlkutnsmox2V6nX4U3mfGbSN1xjLRm8F5ST72V2s5Z0mnIFpGvEu/v7hfptgViqMvaxg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-x64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-android-x64/-/sass-embedded-android-x64-1.85.0.tgz", + "integrity": "sha512-/bG3JgTn3eoIDHCiJNVkLeJgUesat4ghxqYmKMZUJx++4e6iKCDj8XwQTJAgm+QDrsPKXHBacHEANJ9LEAuTqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.85.0.tgz", + "integrity": "sha512-plp8TyMz97YFBCB3ndftEvoW29vyfsSBJILM5U84cGzr06SvLh/Npjj8psfUeRw+upEk1zkFtw5u61sRCdgwIw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-x64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.85.0.tgz", + "integrity": "sha512-LP8Zv8DG57Gn6PmSwWzC0gEZUsGdg36Ps3m0i1fVTOelql7N3HZIrlPYRjJvidL8ZlB3ISxNANebTREUHn/wkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.85.0.tgz", + "integrity": "sha512-18xOAEfazJt1MMVS2TRHV94n81VyMnywOoJ7/S7I79qno/zx26OoqqP4XvH107xu8+mZ9Gg54LrUH6ZcgHk08g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.85.0.tgz", + "integrity": "sha512-JRIRKVOY5Y8M1zlUOv9AQGju4P6lj8i5vLJZsVYVN/uY8Cd2dDJZPC8EOhjntp+IpF8AOGIHqCeCkHBceIyIjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-ia32": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.85.0.tgz", + "integrity": "sha512-4JH+h+gLt9So22nNPQtsKojEsLzjld9ol3zWcOtMGclv+HojZGbCuhJUrLUcK72F8adXYsULmWhJPKROLIwYMA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.85.0.tgz", + "integrity": "sha512-Z1j4ageDVFihqNUBnm89fxY46pY0zD/Clp1D3ZdI7S+D280+AEpbm5vMoH8LLhBQfQLf2w7H++SZGpQwrisudQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.85.0.tgz", + "integrity": "sha512-aoQjUjK28bvdw9XKTjQeayn8oWQ2QqvoTD11myklGd3IHH7Jj0nwXUstI4NxDueCKt3wghuZoIQkjOheReQxlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-ia32": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.85.0.tgz", + "integrity": "sha512-/cJCSXOfXmQFH8deE+3U9x+BSz8i0d1Tt9gKV/Gat1Xm43Oumw8pmZgno+cDuGjYQInr9ryW5121pTMlj/PBXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.85.0.tgz", + "integrity": "sha512-l+FJxMXkmg42RZq5RFKXg4InX0IA7yEiPHe4kVSdrczP7z3NLxk+W9wVkPnoRKYIMe1qZPPQ25y0TgI4HNWouA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.85.0.tgz", + "integrity": "sha512-M9ffjcYfFcRvkFA6V3DpOS955AyvmpvPAhL/xNK45d/ma1n1ehTWpd24tVeKiNK5CZkNjjMEfyw2fHa6MpqmEA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.85.0.tgz", + "integrity": "sha512-yqPXQWfM+qiIPkfn++48GOlbmSvUZIyL9nwFstBk0k4x40UhbhilfknqeTUpxoHfQzylTGVhrm5JE7MjM+LNZA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-x64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.85.0.tgz", + "integrity": "sha512-NTDeQFZcuVR7COoaRy8pZD6/+QznwBR8kVFsj7NpmvX9aJ7TX/q+OQZHX7Bfb3tsfKXhf1YZozegPuYxRnMKAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-arm64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.85.0.tgz", + "integrity": "sha512-gO0VAuxC4AdV+uZYJESRWVVHQWCGzNs0C3OKCAdH4r1vGRugooMi7J/5wbwUdXDA1MV9ICfhlKsph2n3GiPdqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-ia32": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.85.0.tgz", + "integrity": "sha512-PCyn6xeFIBUgBceNypuf73/5DWF2VWPlPqPuBprPsTvpZOMUJeBtP+Lf4mnu3dNy1z76mYVnpaCnQmzZ0zHZaA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-x64": { + "version": "1.85.0", + "resolved": "https://registry.npmmirror.com/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.85.0.tgz", + "integrity": "sha512-AknE2jLp6OBwrR5hQ8pDsG94KhJCeSheFJ2xgbnk8RUjZX909JiNbgh2sNt9LG+RXf4xZa55dDL537gZoCx/iw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/section-matter/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/section-matter/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmmirror.com/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "license": "MIT", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "license": "MIT", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "license": "MIT", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmmirror.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "license": "MIT", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "license": "MIT" + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmmirror.com/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "license": "MIT", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmmirror.com/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmmirror.com/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" + }, + "node_modules/superjson": { + "version": "2.2.2", + "resolved": "https://registry.npmmirror.com/superjson/-/superjson-2.2.2.tgz", + "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/sync-child-process": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/sync-child-process/-/sync-child-process-1.0.2.tgz", + "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sync-message-port": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/sync-message-port": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/sync-message-port/-/sync-message-port-1.1.3.tgz", + "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "license": "MIT", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", + "license": "MIT" + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "license": "MIT", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmmirror.com/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "license": "MIT", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "license": "MIT", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "license": "MIT" + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmmirror.com/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/vant": { + "version": "3.6.16", + "resolved": "https://registry.npmmirror.com/vant/-/vant-3.6.16.tgz", + "integrity": "sha512-9pZao0NEeZQ0ZEb6N7SZxtqcdTp24o8IizhZS1G+FtStlXeKOFzCl+Nf1pIWRneQ9Kn+K+mNrfi2eiIZjVVppw==", + "license": "MIT", + "dependencies": { + "@vant/icons": "^1.8.0", + "@vant/popperjs": "^1.2.1", + "@vant/use": "^1.4.2" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "6.1.1", + "resolved": "https://registry.npmmirror.com/vite/-/vite-6.1.1.tgz", + "integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.24.2", + "postcss": "^8.5.2", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-hot-client": { + "version": "0.2.4", + "resolved": "https://registry.npmmirror.com/vite-hot-client/-/vite-hot-client-0.2.4.tgz", + "integrity": "sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0" + } + }, + "node_modules/vite-plugin-inspect": { + "version": "0.8.9", + "resolved": "https://registry.npmmirror.com/vite-plugin-inspect/-/vite-plugin-inspect-0.8.9.tgz", + "integrity": "sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/utils": "^0.7.10", + "@rollup/pluginutils": "^5.1.3", + "debug": "^4.3.7", + "error-stack-parser-es": "^0.1.5", + "fs-extra": "^11.2.0", + "open": "^10.1.0", + "perfect-debounce": "^1.0.0", + "picocolors": "^1.1.1", + "sirv": "^3.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.1" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/vite-plugin-vue-devtools": { + "version": "7.7.2", + "resolved": "https://registry.npmmirror.com/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.7.2.tgz", + "integrity": "sha512-5V0UijQWiSBj32blkyPEqIbzc6HO9c1bwnBhx+ay2dzU0FakH+qMdNUT8nF9BvDE+i6I1U8CqCuJiO20vKEdQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-core": "^7.7.2", + "@vue/devtools-kit": "^7.7.2", + "@vue/devtools-shared": "^7.7.2", + "execa": "^9.5.1", + "sirv": "^3.0.0", + "vite-plugin-inspect": "0.8.9", + "vite-plugin-vue-inspector": "^5.3.1" + }, + "engines": { + "node": ">=v14.21.3" + }, + "peerDependencies": { + "vite": "^3.1.0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0" + } + }, + "node_modules/vite-plugin-vue-inspector": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-5.3.1.tgz", + "integrity": "sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/plugin-proposal-decorators": "^7.23.0", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.22.15", + "@vue/babel-plugin-jsx": "^1.1.5", + "@vue/compiler-dom": "^3.3.4", + "kolorist": "^1.8.0", + "magic-string": "^0.30.4" + }, + "peerDependencies": { + "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0" + } + }, + "node_modules/vue": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-filepond": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/vue-filepond/-/vue-filepond-7.0.4.tgz", + "integrity": "sha512-HvWlCG8qjvyykrpPTDjJ+JqsHTXt5/0zWMX9vu7kU3JXCUODPUkGi9prZcauOnIZ4MqyeSZ9M0sDVwdMATyt1g==", + "license": "MIT", + "peerDependencies": { + "filepond": ">=4.7.4 < 5.x", + "vue": ">=3 < 4" + } + }, + "node_modules/vue-router": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.0.tgz", + "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/vue3-apexcharts": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/vue3-apexcharts/-/vue3-apexcharts-1.8.0.tgz", + "integrity": "sha512-5tSD4mXTBbIJ9ir+58qHE6oNtIe0RNgqIRYMKpcsIaxkKtwUww4JhvPkpUFlmiW4OJbbdklgjleXq1lfcM4gdA==", + "license": "MIT", + "peerDependencies": { + "apexcharts": ">=4.0.0", + "vue": ">=3.0.0" + } + }, + "node_modules/vue3-markdown-it": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/vue3-markdown-it/-/vue3-markdown-it-1.0.10.tgz", + "integrity": "sha512-mTvHu0zl7jrh7ojgaZ+tTpCLiS4CVg4bTgTu4KGhw/cRRY5YgIG8QgFAPu6kCzSW6Znc9a52Beb6hFvF4hSMkQ==", + "license": "MIT", + "dependencies": { + "markdown-it": "^12.3.2", + "markdown-it-abbr": "^1.0.4", + "markdown-it-anchor": "^8.4.1", + "markdown-it-deflist": "^2.1.0", + "markdown-it-emoji": "^2.0.0", + "markdown-it-footnote": "^3.0.3", + "markdown-it-highlightjs": "^3.6.0", + "markdown-it-ins": "^3.0.1", + "markdown-it-mark": "^3.0.1", + "markdown-it-sub": "^1.0.0", + "markdown-it-sup": "^1.0.0", + "markdown-it-task-lists": "^2.1.1", + "markdown-it-toc-done-right": "^4.2.0" + } + }, + "node_modules/vuex": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/vuex/-/vuex-4.0.2.tgz", + "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.0.0-beta.11" + }, + "peerDependencies": { + "vue": "^3.0.2" + } + }, + "node_modules/vuex/node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/web-worker": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/web-worker/-/web-worker-1.5.0.tgz", + "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==", + "license": "Apache-2.0" + }, + "node_modules/webpack-chain": { + "version": "4.12.1", + "resolved": "https://registry.npmmirror.com/webpack-chain/-/webpack-chain-4.12.1.tgz", + "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MPL-2.0", + "dependencies": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^1.6.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xss": { + "version": "1.0.15", + "resolved": "https://registry.npmmirror.com/xss/-/xss-1.0.15.tgz", + "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==", + "license": "MIT", + "dependencies": { + "commander": "^2.20.3", + "cssfilter": "0.0.10" + }, + "bin": { + "xss": "bin/xss" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/xss/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yoctocolors": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/yoctocolors/-/yoctocolors-2.1.1.tgz", + "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "license": "BSD-3-Clause", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + } + } +} diff --git a/quan_frontend-without config/package.json b/quan_frontend-without config/package.json new file mode 100644 index 0000000..7523372 --- /dev/null +++ b/quan_frontend-without config/package.json @@ -0,0 +1,39 @@ +{ + "name": "quan", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@kangc/v-md-editor": "^2.3.18", + "apexcharts": "^4.5.0", + "axios": "^1.8.1", + "echarts": "^5.6.0", + "element-plus": "^2.9.5", + "filepond": "^4.32.7", + "gsap": "^3.12.7", + "highlight.js": "^11.11.1", + "katex": "^0.16.21", + "lucide-vue-next": "^0.483.0", + "markdown-it-katex": "^2.0.3", + "markdown-it-task-lists": "^2.1.1", + "markdown-it-toc-done-right": "^4.2.0", + "quan": "file:", + "vue": "^3.5.13", + "vue-filepond": "^7.0.4", + "vue-router": "^4.5.0", + "vue3-apexcharts": "^1.8.0", + "vue3-markdown-it": "^1.0.10", + "vuex": "^4.0.2" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.2.1", + "sass-embedded": "^1.85.0", + "vite": "^6.1.0", + "vite-plugin-vue-devtools": "^7.7.2" + } +} diff --git a/quan_frontend-without config/public/favicon.ico b/quan_frontend-without config/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/quan_frontend-without config/public/favicon.ico differ diff --git a/quan_frontend-without config/public/images/bg-.jpg b/quan_frontend-without config/public/images/bg-.jpg new file mode 100644 index 0000000..8f6011f Binary files /dev/null and b/quan_frontend-without config/public/images/bg-.jpg differ diff --git a/quan_frontend-without config/public/images/bg.png b/quan_frontend-without config/public/images/bg.png new file mode 100644 index 0000000..3ce1887 Binary files /dev/null and b/quan_frontend-without config/public/images/bg.png differ diff --git a/quan_frontend-without config/public/images/bg2.png b/quan_frontend-without config/public/images/bg2.png new file mode 100644 index 0000000..11dadd0 Binary files /dev/null and b/quan_frontend-without config/public/images/bg2.png differ diff --git a/quan_frontend-without config/public/images/cursor-origin.png b/quan_frontend-without config/public/images/cursor-origin.png new file mode 100644 index 0000000..b74038f Binary files /dev/null and b/quan_frontend-without config/public/images/cursor-origin.png differ diff --git a/quan_frontend-without config/public/images/cursor.png b/quan_frontend-without config/public/images/cursor.png new file mode 100644 index 0000000..70e2ff4 Binary files /dev/null and b/quan_frontend-without config/public/images/cursor.png differ diff --git a/quan_frontend-without config/public/images/email.jpg b/quan_frontend-without config/public/images/email.jpg new file mode 100644 index 0000000..49646eb Binary files /dev/null and b/quan_frontend-without config/public/images/email.jpg differ diff --git a/quan_frontend-without config/public/images/icon/AI.svg b/quan_frontend-without config/public/images/icon/AI.svg new file mode 100644 index 0000000..707f430 --- /dev/null +++ b/quan_frontend-without config/public/images/icon/AI.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/icon/dashboard.svg b/quan_frontend-without config/public/images/icon/dashboard.svg new file mode 100644 index 0000000..d186761 --- /dev/null +++ b/quan_frontend-without config/public/images/icon/dashboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/icon/peerCircle.svg b/quan_frontend-without config/public/images/icon/peerCircle.svg new file mode 100644 index 0000000..8df26e5 --- /dev/null +++ b/quan_frontend-without config/public/images/icon/peerCircle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/icon/resource.svg b/quan_frontend-without config/public/images/icon/resource.svg new file mode 100644 index 0000000..b11c00b --- /dev/null +++ b/quan_frontend-without config/public/images/icon/resource.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/icon/task.svg b/quan_frontend-without config/public/images/icon/task.svg new file mode 100644 index 0000000..6bceaad --- /dev/null +++ b/quan_frontend-without config/public/images/icon/task.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/icon/todayTask.svg b/quan_frontend-without config/public/images/icon/todayTask.svg new file mode 100644 index 0000000..4ae91b3 --- /dev/null +++ b/quan_frontend-without config/public/images/icon/todayTask.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/icon/好友申请.svg b/quan_frontend-without config/public/images/icon/好友申请.svg new file mode 100644 index 0000000..6c7c154 --- /dev/null +++ b/quan_frontend-without config/public/images/icon/好友申请.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/icon/排行榜.svg b/quan_frontend-without config/public/images/icon/排行榜.svg new file mode 100644 index 0000000..59f204e --- /dev/null +++ b/quan_frontend-without config/public/images/icon/排行榜.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/icon/新增.svg b/quan_frontend-without config/public/images/icon/新增.svg new file mode 100644 index 0000000..49f0563 --- /dev/null +++ b/quan_frontend-without config/public/images/icon/新增.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/quan_frontend-without config/public/images/landing-bg.png b/quan_frontend-without config/public/images/landing-bg.png new file mode 100644 index 0000000..dda4ab9 Binary files /dev/null and b/quan_frontend-without config/public/images/landing-bg.png differ diff --git a/quan_frontend-without config/public/images/logo.png b/quan_frontend-without config/public/images/logo.png new file mode 100644 index 0000000..8b5c346 Binary files /dev/null and b/quan_frontend-without config/public/images/logo.png differ diff --git a/quan_frontend-without config/public/images/logo1.png b/quan_frontend-without config/public/images/logo1.png new file mode 100644 index 0000000..d57e6d2 Binary files /dev/null and b/quan_frontend-without config/public/images/logo1.png differ diff --git a/quan_frontend-without config/public/images/src.jpg b/quan_frontend-without config/public/images/src.jpg new file mode 100644 index 0000000..20d10ef Binary files /dev/null and b/quan_frontend-without config/public/images/src.jpg differ diff --git a/quan_frontend-without config/public/images/start_button.png b/quan_frontend-without config/public/images/start_button.png new file mode 100644 index 0000000..4699007 Binary files /dev/null and b/quan_frontend-without config/public/images/start_button.png differ diff --git a/quan_frontend-without config/public/images/user-bg.png b/quan_frontend-without config/public/images/user-bg.png new file mode 100644 index 0000000..aa1cf40 Binary files /dev/null and b/quan_frontend-without config/public/images/user-bg.png differ diff --git a/quan_frontend-without config/public/images/user-bg2.jpg b/quan_frontend-without config/public/images/user-bg2.jpg new file mode 100644 index 0000000..caad0bb Binary files /dev/null and b/quan_frontend-without config/public/images/user-bg2.jpg differ diff --git a/quan_frontend-without config/src/App copy.vue b/quan_frontend-without config/src/App copy.vue new file mode 100644 index 0000000..9b960a5 --- /dev/null +++ b/quan_frontend-without config/src/App copy.vue @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/quan_frontend-without config/src/App.vue b/quan_frontend-without config/src/App.vue new file mode 100644 index 0000000..ba37561 --- /dev/null +++ b/quan_frontend-without config/src/App.vue @@ -0,0 +1,146 @@ + + + + + + + + + + + + + diff --git a/quan_frontend-without config/src/api/aiguide-api.js b/quan_frontend-without config/src/api/aiguide-api.js new file mode 100644 index 0000000..24d2cbc --- /dev/null +++ b/quan_frontend-without config/src/api/aiguide-api.js @@ -0,0 +1,39 @@ +import {axiosClient} from './axios-api' +import store from '@/data/vuex-data'; +import { ElNotification } from 'element-plus' + +const postRequirement= async (data) => { + try { + const response = await axiosClient.post('/obengine/generateFollowup',data); + console.log('响应数据:', response); + store.commit('setQuestion', response); + return response; + } catch (error) { + ElNotification({ + message: '初始化数据失败', + type: 'error', + }) + console.error('请求失败:', error); + return null; + } +}; + +const postAnswer = async(Data)=>{ + try { + const response = await axiosClient.post('/obengine/generateDetailedPlan', Data); + console.log('Post answer successfully ', response); + return response; + } catch (error) { + ElNotification({ + message: '创建目标失败', + type: 'error', + }) + console.error('Error creating obj:', error.response?.data || error.message); + throw error; + } +} + +export default { + postRequirement, + postAnswer +} \ No newline at end of file diff --git a/quan_frontend-without config/src/api/analysis-api.js b/quan_frontend-without config/src/api/analysis-api.js new file mode 100644 index 0000000..78c00f9 --- /dev/null +++ b/quan_frontend-without config/src/api/analysis-api.js @@ -0,0 +1,57 @@ +import { ElNotification } from "element-plus"; +import { axiosClient } from "./axios-api"; + + +const getLast7daysTaskCompletionRate = async () => { + try { + const response = await axiosClient.get("/analysis/completion/task/weekly"); + return response; + } catch (error) { + ElNotification({ + message: "获取近7日任务完成率数据失败", + type: "error", + }); + console.error("获取日历任务数据失败:", error); + return []; + } +}; + + +//个人主页活跃度card +const getUserActivity = async () => { + try { + const response = await axiosClient.get("/analysis/activity"); + console.log("活跃度",response); + return response; + } catch (error) { + ElNotification({ + message: "获取个人活跃度数据失败", + type: "error", + }); + console.error("获取个人活跃度数据失败:", error); + return []; + } +}; + + +// 个人主页社交成就card +const getUserSocialAchievement = async () => { + try { + const response = await axiosClient.get("/analysis/social/achievement"); + console.log("社交成就",response); + return response; + } catch (error) { + ElNotification({ + message: "获取社交成就数据失败", + type: "error", + }); + console.error("获取社交成就数据失败:", error); + return []; + } +}; + +export default{ + getLast7daysTaskCompletionRate, + getUserActivity, + getUserSocialAchievement +}; diff --git a/quan_frontend-without config/src/api/auth.js b/quan_frontend-without config/src/api/auth.js new file mode 100644 index 0000000..19c6b9d --- /dev/null +++ b/quan_frontend-without config/src/api/auth.js @@ -0,0 +1,29 @@ +import {axiosClient} from "@/api/axios-api" + +export const auth = { + // 登录 + login(data) { + return axiosClient.post('/login', data) + }, + + // 注册 + register(data) { + return axiosClient.post('/register', data) + }, + + // 登出 + logout() { + return axiosClient.post('/user/logout') + }, + + // 发送验证码 + sendVerificationCode(email) { + const encodedEmail = encodeURIComponent(email); + return axiosClient.post(`/send-code?email=${encodedEmail}`); + }, + + // 获取用户信息 + getUserInfo() { + return axiosClient.get('/user/user') + } +} \ No newline at end of file diff --git a/quan_frontend-without config/src/api/axios-api.js b/quan_frontend-without config/src/api/axios-api.js new file mode 100644 index 0000000..315221a --- /dev/null +++ b/quan_frontend-without config/src/api/axios-api.js @@ -0,0 +1,85 @@ +import axios from 'axios'; +import { ElNotification } from 'element-plus'; +import router from '@/router'; +// import { config } from '@/config.prod'; +import { config } from '@/config.dev'; + +const serverIp = config.serverIp; +const serverAddress = `http://${serverIp}`; + +const axiosClient = axios.create({ + baseURL: serverAddress, + timeout: 1000 * 30, + headers: { + 'Content-Type': 'application/json' + } +}); + + +// 请求拦截器 +axiosClient.interceptors.request.use( + config => { + // 在发送请求之前添加jwt + const token = localStorage.getItem('token') + if (token) { + config.headers['Authorization'] = `Bearer ${token}` + } + return config + }, + error => { + // 错误请求处理 + return Promise.reject(error) + } +) + +// 响应拦截器 +axiosClient.interceptors.response.use( + response => { + const { code, msg, data } = response.data; + + if (code === 0) { + ElNotification({ + message: msg || '业务异常', + type: "error", + }) + // 业务异常,抛出错误 + return Promise.reject(new Error(msg || '业务异常')); + } else if (code === 1) { + // 正常情况,返回数据 + return data; + } else { + // 其他 code 的处理(可选) + return Promise.reject(new Error('未知的业务状态')); + } + }, + error => { + console.error('响应错误:', error) + // 对响应错误做点什么 + if (error.response) { + switch (error.response.status) { + case 401: + // 未授权,重定向到登录页 + ElNotification({ + message: "登录已过期,请重新登录", + type: "error", + }) + router.push('/login') + break + case 403: + // 权限不足 + console.error('没有权限访问该资源') + break + case 404: + // 资源不存在 + console.error('请求的资源不存在') + break + default: + console.error('服务器错误') + } + } + return Promise.reject(error) + } +) + + +export { axiosClient,serverAddress,serverIp} diff --git a/quan_frontend-without config/src/api/calendar-api.js b/quan_frontend-without config/src/api/calendar-api.js new file mode 100644 index 0000000..e1611dd --- /dev/null +++ b/quan_frontend-without config/src/api/calendar-api.js @@ -0,0 +1,31 @@ +import { ElNotification } from "element-plus"; +import { axiosClient } from "./axios-api"; +import { getUserInfo } from "./userinfo-api"; + +const getCalendarTasks = async (year, month) => { + try { + const response = await axiosClient.get("/analysis/calendar/tasks/month", { + params: { + userId: getUserInfo().id, + // userId: 1, + year, + month, + }, + }); + + // console.log("获取日历任务数据成功:", response); + return response; + + } catch (error) { + ElNotification({ + message: "获取日历任务数据失败", + type: "error", + }); + console.error("获取日历任务数据失败:", error); + return []; + } +}; + +export default { + getCalendarTasks, +}; diff --git a/quan_frontend-without config/src/api/file-api.js b/quan_frontend-without config/src/api/file-api.js new file mode 100644 index 0000000..35a3a44 --- /dev/null +++ b/quan_frontend-without config/src/api/file-api.js @@ -0,0 +1,35 @@ +import {axiosClient} from './axios-api' +import { ElNotification } from 'element-plus' + +const uploadFile = async (file) => { + try { + console.log(file) + const formData = new FormData(); + formData.append("file", file); // 将文件加入 FormData 中 + const response = await axiosClient.post('/files/upload', formData, { + headers: { + 'Content-Type': 'multipart/form-data', // 必须设置为 multipart/form-data + }, + }); + + ElNotification({ + message: '文件上传成功', + type: 'success', + }); + + return response; // 返回服务器响应的数据 + + } catch (error) { + ElNotification({ + message: '文件上传失败,请重试。', + type: 'error', + }); + console.error('Error uploading file:', error.response?.data || error.message); + throw error; // 抛出错误,供调用者处理 + } + }; + + +export default { + uploadFile +} \ No newline at end of file diff --git a/quan_frontend-without config/src/api/heatmap-api.js b/quan_frontend-without config/src/api/heatmap-api.js new file mode 100644 index 0000000..94f7e6c --- /dev/null +++ b/quan_frontend-without config/src/api/heatmap-api.js @@ -0,0 +1,30 @@ +import { ElNotification } from "element-plus"; +import { axiosClient } from "./axios-api"; +import { getUserInfo } from "./userinfo-api"; + +const getHeatmapData = async (year) => { + try { + const response = await axiosClient.get("/analysis/heatmap/tasks", { + params: { + // userId: localStorage.getItem('userId'),//从vuex中获取userId + // userId: 1, + userId: getUserInfo().id, + year, + }, + }); + console.log("获取热力图数据成功:", response); // 检查完整的响应数据结构 + + return response; + } catch (error) { + ElNotification({ + message: "获取数据失败", + type: "error", + }); + console.error("获取热力图数据失败:", error); + return null; + } +}; + +export default { + getHeatmapData, +}; diff --git a/quan_frontend-without config/src/api/objhub-api.ts b/quan_frontend-without config/src/api/objhub-api.ts new file mode 100644 index 0000000..904ffc4 --- /dev/null +++ b/quan_frontend-without config/src/api/objhub-api.ts @@ -0,0 +1,320 @@ +import { axiosClient } from "./axios-api"; +import { ElNotification } from "element-plus"; +import { getUserInfo } from "./userinfo-api"; +import store from "@/data/vuex-data"; + +interface ObjectiveResponse { + id: number; + name: string; + children: any[]; + tasks: any[]; +} + +const getUserObjectives = async (userId) => { + try { + const response = await axiosClient.get(`/objectives/user/${userId}`); + console.log("user objs:", response); + store.commit("setObjList", response); + return response; + } catch (error) { + ElNotification({ + message: "初始化数据失败", + type: "error", + }); + console.error("Error get user objs", error); + return null; + } +}; + +const getPeerObjectives = async (userId) => { + try { + const response = await axiosClient.get(`/objectives/user/${userId}`); + console.log("peer objs:", response); + return response; + } catch (error) { + ElNotification({ + message: "获取好友近期目标失效", + type: "error", + }); + console.error("Error get user objs", error); + return null; + } +}; + +const getSingleObjectiveDetails = async (ObjId) => { + try { + const response = await axiosClient.get(`/objectives/${ObjId}`); + return response; + } catch (error) { + ElNotification({ + message: "获取当前目标详情失败", + type: "error", + }); + console.error("Error get ", error); + return null; + } +}; + +const getUserTodayTasks = async (userId) => { + try { + const response = await axiosClient.get(`/tasks/user/${userId}/today`); + console.log("user today tasks:", response); + store.commit("setTodayTaskList", response); + return response; + } catch (error) { + ElNotification({ + message: "获取用户今日任务失败", + type: "error", + }) + } +} + +const postObj = async (objData) => { + try { + const response = await axiosClient.post("/objectives", objData); + console.log("Obj created successfully:", response); + + getUserObjectives(getUserInfo().id); + + return response; + } catch (error) { + ElNotification({ + message: "创建目标失败", + type: "error", + }); + console.error("Error creating obj:", error.response?.data || error.message); + throw error; + } +}; + +const getSingleTaskDetails = async (taskId) => { + try { + const response = await axiosClient.get(`/tasks/${taskId}`); + return response; + }catch (error) { + ElNotification({ + message: "获取任务详情失败", + type: "error", + }) + } +} + +const postSingleTask = async (taskData, objId) => { + try { + const response = await axiosClient.post("/tasks/single", taskData); + console.log("SingleTask created successfully:", response); + getSingleObjectiveDetails(objId); + return response; + } catch (error) { + ElNotification({ + message: "创建单次任务失败", + type: "error", + }); + console.error( + "Error creating task:", + error.response?.data || error.message + ); + throw error; + } +}; + +const postRecurringTask = async (taskData, objId) => { + try { + const response = await axiosClient.post("/tasks/recurring", taskData); + console.log("RecurringTask created successfully:", response); + getSingleObjectiveDetails(objId); + return response; + } catch (error) { + ElNotification({ + message: "创建周期任务失败", + type: "error", + }); + console.error( + "Error creating task:", + error.response?.data || error.message + ); + throw error; + } +}; + +const deleteObj = async (objId) => { + try { + const response = await axiosClient.delete(`/objectives/${objId}`); + console.log("delete obj successfully", objId); + getUserObjectives(getUserInfo().id) + return response; + } catch (error) { + ElNotification({ + message: "删除目标失败", + type: "error", + }); + console.error("Error deleting obj:", error.response?.data || error.message); + throw error; + } +}; + +const deleteTask = async (taskId) => { + origin = taskId; + try { + const response = await axiosClient.delete(`/tasks/${taskId}`); + console.log("delete task successfully", origin); + return response; + } catch (error) { + ElNotification({ + message: "删除目标失败", + type: "error", + }); + throw error; + } +}; + +const createChildObj = async (parentId,data) => { + try { + const response = await axiosClient.post(`/objectives/parent/${parentId}/children`, data); + console.log("create child objsuccessfully", data); + }catch (error) { + ElNotification({ + message: "创建子目标失败", + type: "error", + }); + } +} +const associateObj = async (fatherId, data) => { + try { + origin = fatherId; + const response = await axiosClient.post( + `/objectives/${fatherId}/children`, + data + ); + console.log( + "associate child " + + data.childObjectiveId + + " and father " + + origin + + " successfully" + ); + return response; + } catch (error) { + ElNotification({ + message: "关联目标失败", + type: "error", + }); + console.error( + "Error associating obj and task:", + error.response?.data || error.message + ); + throw error; + } +}; + +const updateObj = async (objId, data) => { + try { + origin = objId; + const response = await axiosClient.put(`/objectives/${objId}`, data); + return response; + } catch (error) { + ElNotification({ + message: "修改目标失败", + type: "error", + }); + console.error("Error changing obj:", error.response?.data || error.message); + throw error; + } +}; + +const updateSingleTask = async (taskId, data) => { + try { + origin = taskId; + const response = await axiosClient.put(`/tasks/single/${taskId}`, data); + console.log("change single task " + origin + " successfully"); + return response; + } catch (error) { + ElNotification({ + message: "修改单次任务失败", + type: "error", + }); + console.error( + "Error changing single task:", + error.response?.data || error.message + ); + throw error; + } +}; + +const updateRecurringTask = async (taskId, data) => { + try { + origin = taskId; + const response = await axiosClient.put(`/tasks/recurring/${taskId}`, data); + console.log("change recurring task " + origin + " successfully"); + return response; + } catch (error) { + ElNotification({ + message: "修改周期任务失败", + type: "error", + }); + console.error( + "Error changing recrring task:", + error.response?.data || error.message + ); + throw error; + } +}; + +const completeTask = async (data) => { + try { + const response = await axiosClient.post('/tasks/completion', data); + console.log("complete task " + data.id + " successfully"); + return response; + } catch (error) { + ElNotification({ + message: "完成任务失败", + type: "error", + }) + } +} + +const cancelCompleteTask = async (taskId) => { + try { + const response = await axiosClient.delete(`/tasks/completion/${taskId}`); + console.log("cancel complete task " + taskId + " successfully"); + return response; + } catch (error) { + ElNotification({ + message: "取消完成任务失败", + type: "error", + }) + } +} + +const getAiGuidanceForObjective = async (objectiveId) => { + try { + const response = await axiosClient.get(`/objectives/${objectiveId}/ai-guide`); + return response; + } catch (error) { + ElNotification({ + message: "取消完成任务失败", + type: "error", + }) + } +} + +export default { + getUserObjectives, + getPeerObjectives, + getSingleObjectiveDetails, + getUserTodayTasks, + postObj, + postSingleTask, + postRecurringTask, + deleteObj, + deleteTask, + associateObj, + updateObj, + updateSingleTask, + updateRecurringTask, + completeTask, + cancelCompleteTask, + getAiGuidanceForObjective, + getSingleTaskDetails, + createChildObj +}; diff --git a/quan_frontend-without config/src/api/peer-api.js b/quan_frontend-without config/src/api/peer-api.js new file mode 100644 index 0000000..d7f0d60 --- /dev/null +++ b/quan_frontend-without config/src/api/peer-api.js @@ -0,0 +1,354 @@ +import { LayoutList } from "lucide-vue-next"; +import { axiosClient } from "./axios-api"; +import { ElNotification } from "element-plus"; + +// 获取好友列表√ +const getFriends = async () => { + try { + const response = await axiosClient.get("/friends/list"); + console.log("friendlist", response); + return response; + } catch (error) { + ElNotification({ + message: "获取好友列表失败", + type: "error", + }); + console.error("获取好友列表失败", error); + return null; + } +}; + +//生成好友数组 +const loadFriends = async () => { + try { + const response = await getFriends(); + + return Array.isArray(response) ? response : []; + } catch (error) { + console.error("Failed to fetch friends", error); + return []; + } +}; + +// 获取好友详细信息 +const getFriendProfile = async (friendId) => { + try { + const response = await axiosClient.get("/friends/profile", { + params: { friendId }, + }); + console.log("friendprofile", response); + return response; + } catch (error) { + ElNotification({ + message: "获取好友详细信息失败", + type: "error", + }); + console.error("Failed to get friend profile", error); + return null; + } +}; + +const searchUsers = async (id) => { + try { + const response = await axiosClient.get(`/friends/search?id=${id}`); ; + console.log("搜索用户", response); + return response; + } catch (error) { + console.error("Failed to search user", error); + throw error; + } +}; + +// 发送好友请求√ +const postAddFriend = async (friendId) => { + try { + const response = await axiosClient.post("/friends/request", { + friendId, + }); + console.log("post addfriendRequest Successfully", response); + return response; + } catch (error) { + console.error("Failed to add friend", error); + throw error; + } +}; + +// 接受好友请求√ +const postAcceptFriend = async (userId) => { + try { + const response = await axiosClient.post("/friends/accept", { + userId, + }); + console.log("post acceptfriendRequest Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "接受好友请求失败", + type: "error", + }); + console.error("Failed to accept friend", error); + throw error; + } +}; + +// 删除好友√ +const postRemoveFriend = async (friendId) => { + try { + const response = await axiosClient.post("/friends/remove", { + friendId, + }); + console.log("post removefriendRequest Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "删除好友失败", + type: "error", + }); + console.error("Failed to remove friend", error); + throw error; + } +}; + +// 获取朋友圈动态√ +const getFriendCircle = async (page, pageSize) => { + try { + const response = await axiosClient.get("/feed", { + params: { page, pageSize }, + }); + return response; + } catch (error) { + ElNotification({ + message: "获取好友圈列表失败", + type: "error", + }); + console.error("Failed to get friend circle", error); + return null; + } +}; + +// 获取好友申请列表√ +const getFriendRequestList = async () => { + try { + const response = await axiosClient.get("/friends/requestlist"); + console.log("get friendRequestList Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "获取好友申请列表失败", + type: "error", + }); + console.error("Failed to get friend request list", error); + return null; + } +}; + +// 发布帖子 +const postMessage = async (content) => { + try { + const response = await axiosClient.post("/feed/post", { + content, + }); + console.log("post message Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "发布帖子失败", + type: "error", + }); + console.error("Failed to post message", error); + throw error; + } +}; + +// 点赞帖子 +const postThumbsUp = async (feed_id) => { + try { + const response = await axiosClient.post("/feed/like", { feed_id }); + console.log("post thumbsUp Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "点赞帖子失败", + type: "error", + }); + console.error("Failed to thumbsUp message", error); + throw error; + } +}; + +// 取消点赞 +const deleteThumbsUp = async (feedId) => { + try { + const response = await axiosClient.delete(`/feed/${feedId}/like`); + console.log("delete thumbsUp Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "取消点赞失败", + type: "error", + }); + console.error("Failed to delete thumbsUp", error); + throw error; + } +}; + +// 评论帖子 +const postComment = async (feedId, content) => { + try { + const response = await axiosClient.post("/feed/comment", { + feedId, + content, + }); + console.log("post comment Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "评论帖子失败", + type: "error", + }); + console.error("Failed to comment message", error); + throw error; + } +}; + +// 获取评论 +const getComments = async (feedId) => { + try { + const response = await axiosClient.get("/feed/comments", { + params: { feedId }, + }); + console.log("get commentList Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "获取评论失败", + type: "error", + }); + console.error("Failed to get commentList", error); + return null; + } +}; + +// 获取任务排行榜 +const getTaskRankList = async (period) => { + try { + const response = await axiosClient.get("/analysis/leaderboard/task", { + params: { period }, + }); + console.log("get TaskRankList Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "获取目标排行榜失败", + type: "error", + }); + console.error("Failed to get TaskRankList", error); + return null; + } +}; + +// 获取目标排行榜 +const getObjRankList = async (period) => { + try { + const response = await axiosClient.get("/analysis/leaderboard/objective", { + params: { period }, + }); + console.log("get ObjRankList Successfully", response); + return response; + } catch (error) { + ElNotification({ + message: "获取任务排行榜失败", + type: "error", + }); + return null; + } + }; + + + //获取好友界面-好友完成情况 + const getObjHubStatus = async (userId) => { + try { + const response = await axiosClient.get(`/analysis/friend/${userId}/objhubstatus`); + return response; + } catch (error) { + ElNotification({ + message: "获取好友目标完成情况失败", + type: "error", + }); + return null; + } + }; + +const pushLocation = async (latitude, longitude) => { + try { + console.log("push location",latitude,longitude) + const response = await axiosClient.put("/user/location", { + latitude,longitude + }) + console.log("push location Successfully", response); + }catch (error) { + console.error("Failed to push location", error); + ElNotification({ + message: "上传用户位置失败", + type: "error", + }); + } +} + +const getPeerNearby = async () => { + try { + const response = await axiosClient.get("/friends/nearby",{}); + console.log("get nearby Successfully", response); + + if(response==null){ + ElNotification({ + message: "附近暂时没有用户", + type: "info", + }); + } + return response; + }catch (error) { + ElNotification({ + message: "获取附近的人失败", + type: "error", + }); + } +}; + + +const getRecentFeed = async () => { + try { + const response = await axiosClient.get("/feed/recent",{}); + console.log("get recent feed Successfully", response); + return response; + }catch (error) { + ElNotification({ + message: "获取动态推荐", + type: "error", + }); + } + +}; + +export default { + getFriends, + getFriendProfile, + postAddFriend, + searchUsers, + postAcceptFriend, + postRemoveFriend, + getFriendCircle, + getFriendRequestList, + postMessage, + postThumbsUp, + deleteThumbsUp, + postComment, + getComments, + getTaskRankList, + getObjRankList, + loadFriends, + getObjHubStatus, + pushLocation, + getPeerNearby, + getRecentFeed, +}; diff --git a/quan_frontend-without config/src/api/resource-center.js b/quan_frontend-without config/src/api/resource-center.js new file mode 100644 index 0000000..2c27e8e --- /dev/null +++ b/quan_frontend-without config/src/api/resource-center.js @@ -0,0 +1,246 @@ +import { axiosClient } from './axios-api'; +import { ElNotification } from 'element-plus'; +// 创建资源 +const createResource = async (data) => { + try { + const response = await axiosClient.post('/resources', data); + console.log('资源创建成功:', response); + return response; + } catch (error) { + ElNotification({ + message: '资源创建失败', + type: 'error', + }); + console.error('资源创建失败:', error.response?.data || error.message); + return null; + } +}; + +// 获取资源详情 +const getResourceDetail = async (id) => { + try { + const response = await axiosClient.get(`/resources/${id}`); + return response; + } catch (error) { + ElNotification({ + message: '无法获取资源详情', + type: 'error', + }); + console.error('获取资源失败:', error.response?.data || error.message); + return null; + } +}; + +// 获取资源列表 +const getResourcesList = async ( page, pageSize, category ) => { + try { + const response = await axiosClient.get('/resources', { + params: { + page, + pageSize, + category + } + }); + console.log('获取资源列表:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法加载资源列表', + type: 'error', + }); + console.error('获取资源列表失败:', error.response?.data || error.message); + return null; + } +}; + +// 获取资源列表 +const getUserResourcesList = async ( userId, page, pageSize, category ) => { + try { + const response = await axiosClient.get(`/resources/user/${userId}`, { + params: { + page, + pageSize, + category + } + }); + console.log('获取用户资源列表:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法加载资源列表', + type: 'error', + }); + console.error('获取资源列表失败:', error.response?.data || error.message); + return null; + } +}; + +// 删除资源 +const deleteResource = async (id) => { + try { + const response = await axiosClient.delete(`/resources/${id}`); + console.log('资源删除成功:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法删除资源', + type: 'error', + }); + console.error('删除资源失败:', error.response?.data || error.message); + return null; + } +}; + +// 点赞资源 +const likeResource = async (id) => { + try { + const response = await axiosClient.post(`/resources/${id}/like`); + console.log('资源点赞成功:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法点赞资源', + type: 'error', + }); + console.error('资源点赞失败:', error.response?.data || error.message); + return null; + } +}; + +// 取消点赞 +const unlikeResource = async (id) => { + try { + const response = await axiosClient.delete(`/resources/${id}/like`); + console.log('取消点赞成功:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法取消点赞', + type: 'error', + }); + console.error('取消点赞失败:', error.response?.data || error.message); + return null; + } +}; + +// 评论资源 +const commentOnResource = async (id, data) => { + try { + const response = await axiosClient.post(`/resources/${id}/comments`, data); + console.log('评论成功:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法发表评论', + type: 'error', + }); + console.error('评论失败:', error.response?.data || error.message); + return null; + } +}; + +// 获取资源评论 +const getResourceComments = async (id) => { + try { + const response = await axiosClient.get(`/resources/${id}/comments`); + console.log('获取资源评论:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法加载评论', + type: 'error', + }); + console.error('获取评论失败:', error.response?.data || error.message); + return null; + } +}; + +const getResourceFavorites = async (page, pageSize, category) => { + try { + const response = await axiosClient.get(`/resources/favorite`, { + params: { + page, pageSize, category + } + }); + console.log('获取资源收藏:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法加载收藏', + type: 'error', + }); + } +} + +// 收藏资源 +const favoriteResource = async (id) => { + try { + const response = await axiosClient.post(`/resources/${id}/favorite`); + console.log('资源收藏成功:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法收藏资源', + type: 'error', + }); + console.error('资源收藏失败:', error.response?.data || error.message); + return null; + } +}; + +// 取消收藏 +const unfavoriteResource = async (id) => { + try { + const response = await axiosClient.delete(`/resources/${id}/favorite`); + console.log('取消收藏成功:', response); + return response; + } catch (error) { + ElNotification({ + message: '无法取消收藏', + type: 'error', + }); + console.error('取消收藏失败:', error.response?.data || error.message); + return null; + } +}; + +const getRecommendResources = async()=>{ + try { + const response = await axiosClient.get(`/resources/recommend`); + console.log('获取推荐资源:', response); + return response; + } catch (error) { + ElNotification({ + message: "获取推荐资源失败", + type: 'error', + }); + } +}; + +const getExternalImage = async (url) => { + try { + const response = await axiosClient.get(`/img-proxy`, { + params: { url } + }); + return response; + } catch (error) { + return null; + } +}; + +export default { + createResource, + getResourceDetail, + getResourcesList, + getUserResourcesList, + deleteResource, + likeResource, + unlikeResource, + commentOnResource, + getResourceComments, + getResourceFavorites, + favoriteResource, + unfavoriteResource, + getRecommendResources, + getExternalImage +}; diff --git a/quan_frontend-without config/src/api/useAuth.js b/quan_frontend-without config/src/api/useAuth.js new file mode 100644 index 0000000..8b43129 --- /dev/null +++ b/quan_frontend-without config/src/api/useAuth.js @@ -0,0 +1,119 @@ +import { ref } from 'vue' +import { useRouter } from 'vue-router' +import { auth } from '@/api/auth' +import store from '@/data/vuex-data' + +export function useAuth() { + const router = useRouter() + const loading = ref(false) + const errorMessage = ref('') + const isCodeSent = ref(false) + const codeCountdown = ref(0) + let countdownTimer = null + + // 邮箱格式验证 + const validateEmail = (email) => { + const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ + return emailRegex.test(email) + } + + // 登录方法 + const login = async (credentials) => { + try { + loading.value = true + errorMessage.value = '' + const response = await auth.login(credentials) + // 将用户信息存储到本地存储中 + localStorage.setItem('userInfos', JSON.stringify(response.userVO)) + localStorage.setItem('token', response.token) + router.push('/home') + } catch (error) { + throw error + } finally { + loading.value = false + } + } + + // 注册方法 + const register = async (userData) => { + if (!validateEmail(userData.email)) { + errorMessage.value = '请输入有效的邮箱地址' + return Promise.reject(new Error('Invalid email')) + } + + if (userData.password !== userData.confirmPassword) { + errorMessage.value = '两次输入的密码不一致' + return Promise.reject(new Error('Passwords do not match')) + } + + try { + loading.value = true + errorMessage.value = '' + + await auth.register({ + username: userData.username, + email: userData.email, + nickname: userData.nickname, + password: userData.password, + captcha: userData.verificationCode, // 需要用户输入的验证码 + avatarUrl: "666" // 暂时忽略此字段 + }) + + // 注册成功后自动登录 + await login({ + email: userData.email, + password: userData.password + }) + } catch (error) { + throw error + } finally { + loading.value = false + } + } + + // 发送邮箱验证码 + const sendVerificationCode = async (email) => { + if (!validateEmail(email.email)) { + errorMessage.value = '请输入正确的邮箱格式' + return Promise.reject(new Error('Invalid email')) + } + + if (isCodeSent.value) { + return Promise.reject(new Error('请稍后再试')) + } + + try { + loading.value = true + errorMessage.value = '' + + await auth.sendVerificationCode(email.email) + + isCodeSent.value = true + codeCountdown.value = 60 + + countdownTimer = setInterval(() => { + if (codeCountdown.value > 0) { + codeCountdown.value-- + } else { + clearInterval(countdownTimer) + isCodeSent.value = false + } + }, 1000) + } catch (error) { + throw error + } finally { + loading.value = false + } + } + + return { + loading, + errorMessage, + login, + register, + validateEmail, + sendVerificationCode, + isCodeSent, + codeCountdown + } +} diff --git a/quan_frontend-without config/src/api/userinfo-api.js b/quan_frontend-without config/src/api/userinfo-api.js new file mode 100644 index 0000000..bf585d3 --- /dev/null +++ b/quan_frontend-without config/src/api/userinfo-api.js @@ -0,0 +1,73 @@ +import store from "@/data/vuex-data"; +import { axiosClient } from "./axios-api"; + +const getUserInfo = () => { + // 获取本地信息 + const info = localStorage.getItem("userInfos"); + var userInfo = null; + if (info) { + userInfo = JSON.parse(info); + } else { + console.error("No user info found in local storage"); + } + return userInfo; +}; + +const updateUserInfo = async (nickname, avatar) => { + //Step1. 进行数据库更新 + var response; + try { + const data = { + id: getUserInfo().id, + nickname: nickname, + avatarUrl: avatar, + }; + response = await axiosClient.put("/user", data); + console.log("Updated user info Successfully"); + } catch (error) { + ElNotification.error({ + title: "更新失败", + message: error, + }); + throw error; + } + + //Step2. 进行本地存储量的更新 + const stored = localStorage.getItem("userInfos"); + if (!stored) { + console.error("No userInfos found in localStorage."); + return; + } + + let userInfo; + try { + userInfo = JSON.parse(stored); + } catch (e) { + console.error("Failed to parse userInfos from localStorage:", e); + return; + } + + // 更新 nickname 和 avatarUrl,保留其他字段 + const updatedUserInfo = { + id: userInfo.id, + email: userInfo.email, + nickname: nickname, + avatarUrl: avatar, + }; + + // 写回 localStorage + localStorage.setItem("userInfos", JSON.stringify(updatedUserInfo)); + return response; +}; + +const getUserAchievements = async () => { + try { + const response = await axiosClient.get("/achievement"); + return response; + } catch (error) { + console.error("Failed to get user achievements:", error); + throw error; + } +}; + +export { getUserInfo, updateUserInfo, getUserAchievements }; diff --git a/quan_frontend-without config/src/assets/styles/global.css b/quan_frontend-without config/src/assets/styles/global.css new file mode 100644 index 0000000..4c2e1ca --- /dev/null +++ b/quan_frontend-without config/src/assets/styles/global.css @@ -0,0 +1,225 @@ +@import url("https://fonts.googleapis.com/css2?family=Ma+Shan+Zheng&display=swap"); + +:root { + --ink-black: #262626; + --ink-gray: #4a4a4a; + --paper-white: #f5f5f5; + --paper-gray: #e8e8e8; +} + +/* 去掉主页滚动条 */ +html, +body { + overflow: hidden; + height: 100%; +} + +body { + background-color: var(--paper-white); + color: var(--ink-black); + font-family: 'Times New Roman', "Ma Shan Zheng", serif; + font-size: 22px; + /* cursor: url("/images/cursor.png"), auto; */ +} + + +.ink-button { + background-color: var(--ink-grey); + /* color: var(--paper-white); */ + color: #2C2C2C; + border: 1px solid var(--ink-black); + padding: 8px 16px; + border-radius: 4px; + transition: all 0.3s ease; + font-family: 'Times New Roman', "Ma Shan Zheng", serif; + cursor: pointer; + font-size: 18px; +} + +.ink-drawer-button { + background-color: var(--ink-black); + color: var(--ink-black); + border: 1px solid var(--ink-black); + padding: 20px; + margin: 20px; + border-radius: 4px; + transition: all 0.3s ease; + cursor: pointer; + font-family: 'Times New Roman', "Ma Shan Zheng", serif; + + font-size: 18px; +} + +.ink-button:hover { + background-color: var(--paper-white); + color: var(--ink-black); + border: 1px solid #2C2C2C; +} + +.ink-input { + background-color: var(--paper-white); + border: 1px solid var(--ink-gray); + padding: 8px 12px; + border-radius: 4px; + font-family: 'Times New Roman', "Ma Shan Zheng", serif; + +} + +.ink-input:focus { + outline: none; + border-color: var(--ink-black); + box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); +} + +.ink-card { + background-color: var(--paper-white); + border: 1px solid var(--ink-gray); + border-radius: 8px; + padding: 20px; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); +} + +.ink-title { + color: var(--ink-black); + font-family: 'Times New Roman', "Ma Shan Zheng", serif; + + border-bottom: 2px solid var(--ink-black); + padding-bottom: 10px; + margin-bottom: 20px; +} + +.el-button, +.el-menu, +.el-menu-item { + /* background-color: transparent !important; */ + backdrop-filter: blur(2px); + /* 设置磨砂效果的强度 */ + background: rgba(255, 255, 255, 0.3); + /* 半透明背景 */ + border-radius: 10px; +} + + + +/* .el-menu-item:hover{ + background-color: gray; + color:var(--ink-gray); +} + +.el-menu-item.is-active{ + background-color: #4a4a4a; + color: white; +} */ + +/* 卡片总样式 */ +.el-card { + margin-bottom: 15px; + cursor: pointer; + padding: 12px 16px; + border-radius: 3px; + background: rgba(255, 255, 255, 0.5); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s, box-shadow 0.3s; +} + +/* 1. Drawer 容器整体样式 */ +.el-drawer { + /* background: rgba(255, 255, 255, 0.7); */ + background-image: url("/images/bg-.jpg"); + /* 半透明 */ + backdrop-filter: blur(20px); + /* 毛玻璃模糊 */ + /* border-left: 6px solid rgba(0, 0, 0, 0.05); */ + /* 墨痕边界 */ + border-radius: 2px 0 0 2px; + /* 左边圆角 */ + box-shadow: -4px 0 20px rgba(0, 0, 0, 0.1); + overflow: hidden; + /* position: relative; */ + font-family: "STKaiti", "仿宋", "Noto Serif SC", serif; +} + +/* 3. 内容容器样式微调 */ +.el-drawer__body { + padding: 20px; + z-index: 1; + position: relative; + color: #2f2f2f; +} + +/* 4. 标题样式(如使用 el-drawer title 插槽) */ +.el-drawer__header { + font-size: 20px; + font-weight: bold; + border-bottom: 1px dashed rgba(0, 0, 0, 0.1); + margin-bottom: 16px; + color: #1f1f1f; +} + +/* 5. 关闭按钮手绘感 */ +.el-drawer__close-btn { + background-color: rgba(255, 255, 255, 0.6); + border-radius: 50%; + border: 1px solid rgba(0, 0, 0, 0.1); + transition: all 0.2s ease; +} +.el-drawer__close-btn:hover { + transform: scale(1.1); + background-color: rgba(240, 240, 240, 0.9); +} + +.el-progress-bar__inner{ + background-color: #3A6E64; +} + +/* menu-item图标样式 */ +.icon-menu { + margin-top: 20px; + display: flex; + flex-direction: column; + align-items: center; +} + + +/* 按钮通用类:图标在上,文字在下 */ +.sidebar-icon-btn { + display: flex; + flex-direction: column; + align-items: center; + /* border: none; */ + border-color: black; + background: transparent; + box-shadow: none; + padding: 10px; + margin-right: 70px; + height: 60px; + width: 60px; + /* color: var(--el-color-primary); */ +} + +.icon-text-column { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.icon-text-column .el-icon { + font-size: 22px; + margin-bottom: 4px; +} + +.icon-text-column .btn-text { + font-size: 14px; + color: #333; +} +.el-checkbox__inner { + color: #3A6E64; + border-radius: 7px +} + +.el-checkbox{ + --el-checkbox-checked-bg-color: #3A6E64; + --el-checkbox-checked-text-color: #3A6E64; + --el-checkbox-checked-input-border-color: #3A6E64; +} \ No newline at end of file diff --git a/quan_frontend-without config/src/components/AiGuide/AiGuidanceBox.vue b/quan_frontend-without config/src/components/AiGuide/AiGuidanceBox.vue new file mode 100644 index 0000000..dc5c880 --- /dev/null +++ b/quan_frontend-without config/src/components/AiGuide/AiGuidanceBox.vue @@ -0,0 +1,111 @@ + + + {{ displayedText }} + + + + + + diff --git a/quan_frontend-without config/src/components/AiGuide/AiGuideBar.vue b/quan_frontend-without config/src/components/AiGuide/AiGuideBar.vue new file mode 100644 index 0000000..81e4f6e --- /dev/null +++ b/quan_frontend-without config/src/components/AiGuide/AiGuideBar.vue @@ -0,0 +1,127 @@ + + + + + + + + {{ questionList[active]?.question }} + + + + {{ item }} + + + + + 上一个问题 + 下一个问题 + 提交答案 + + + + + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/AiGuide/AiGuideButton.vue b/quan_frontend-without config/src/components/AiGuide/AiGuideButton.vue new file mode 100644 index 0000000..c222806 --- /dev/null +++ b/quan_frontend-without config/src/components/AiGuide/AiGuideButton.vue @@ -0,0 +1,56 @@ + + + + + 智能规划 + + + + + + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/AiGuide/AiGuideFront.vue b/quan_frontend-without config/src/components/AiGuide/AiGuideFront.vue new file mode 100644 index 0000000..c0d0d1f --- /dev/null +++ b/quan_frontend-without config/src/components/AiGuide/AiGuideFront.vue @@ -0,0 +1,87 @@ + + + 目标名称 + + + 目标描述 + + + 目标时间 + + + + 生成任务 + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/Analysis/Calendar.vue b/quan_frontend-without config/src/components/Analysis/Calendar.vue new file mode 100644 index 0000000..b7b62d8 --- /dev/null +++ b/quan_frontend-without config/src/components/Analysis/Calendar.vue @@ -0,0 +1,252 @@ + + + + + + {{ date }} + + + 先岁 + + + 先月 + + 今旦 + + 来月 + + + 来岁 + + + + + + + + + + {{ data.day.split("-")[2] }} + + + + + + + + + + diff --git a/quan_frontend-without config/src/components/Analysis/Heatmap.vue b/quan_frontend-without config/src/components/Analysis/Heatmap.vue new file mode 100644 index 0000000..a345e1a --- /dev/null +++ b/quan_frontend-without config/src/components/Analysis/Heatmap.vue @@ -0,0 +1,244 @@ + + + + + + + + + + + {{ errorMessage }} + + + + + + + + + + 上一年 + 下一年 + + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/Analysis/Last7daysTaskCompeletion.vue b/quan_frontend-without config/src/components/Analysis/Last7daysTaskCompeletion.vue new file mode 100644 index 0000000..c47d9f2 --- /dev/null +++ b/quan_frontend-without config/src/components/Analysis/Last7daysTaskCompeletion.vue @@ -0,0 +1,109 @@ + + + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/Analysis/MonthHeatmap.vue b/quan_frontend-without config/src/components/Analysis/MonthHeatmap.vue new file mode 100644 index 0000000..c4ef8f4 --- /dev/null +++ b/quan_frontend-without config/src/components/Analysis/MonthHeatmap.vue @@ -0,0 +1,210 @@ + + + + + 上个月 + 下个月 + + + + + + + + + {{ errorMessage }} + + + + + + + + + + + diff --git a/quan_frontend-without config/src/components/Analysis/OldCalendar.vue b/quan_frontend-without config/src/components/Analysis/OldCalendar.vue new file mode 100644 index 0000000..37cfd11 --- /dev/null +++ b/quan_frontend-without config/src/components/Analysis/OldCalendar.vue @@ -0,0 +1,253 @@ + + + + + Custom header content + {{ date }} + + + Previous Year + + + Previous Month + + Today + + Next Month + + + Next Year + + + + + + + + + + {{ data.day.split("-").slice(2).join("-") }} + + + + + {{ todo.name }} + + + + + + + + + + diff --git a/quan_frontend-without config/src/components/Common/InkedCursor.vue b/quan_frontend-without config/src/components/Common/InkedCursor.vue new file mode 100644 index 0000000..f515250 --- /dev/null +++ b/quan_frontend-without config/src/components/Common/InkedCursor.vue @@ -0,0 +1,142 @@ + + + + + + + + + diff --git a/quan_frontend-without config/src/components/Common/MarkdownView.vue b/quan_frontend-without config/src/components/Common/MarkdownView.vue new file mode 100644 index 0000000..6994e47 --- /dev/null +++ b/quan_frontend-without config/src/components/Common/MarkdownView.vue @@ -0,0 +1,129 @@ + + + + + + + diff --git a/quan_frontend-without config/src/components/Common/ObjRelationMap.vue b/quan_frontend-without config/src/components/Common/ObjRelationMap.vue new file mode 100644 index 0000000..439b8f8 --- /dev/null +++ b/quan_frontend-without config/src/components/Common/ObjRelationMap.vue @@ -0,0 +1,157 @@ + + 目标关系图 + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/Common/UploadPictureButton.vue b/quan_frontend-without config/src/components/Common/UploadPictureButton.vue new file mode 100644 index 0000000..5230536 --- /dev/null +++ b/quan_frontend-without config/src/components/Common/UploadPictureButton.vue @@ -0,0 +1,137 @@ + + + 上传图片 + + + + + + + + + + + {{ "复制链接" }} + + + + + + + + + 图片{{ index + 1 + }} + + + + + + + + + + diff --git a/quan_frontend-without config/src/components/Common/UserResourceList.vue b/quan_frontend-without config/src/components/Common/UserResourceList.vue new file mode 100644 index 0000000..072ae86 --- /dev/null +++ b/quan_frontend-without config/src/components/Common/UserResourceList.vue @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + 没有更多资源了 + + + + + + diff --git a/quan_frontend-without config/src/components/Common/WebSocket.vue b/quan_frontend-without config/src/components/Common/WebSocket.vue new file mode 100644 index 0000000..e2b0e23 --- /dev/null +++ b/quan_frontend-without config/src/components/Common/WebSocket.vue @@ -0,0 +1,92 @@ + + + + diff --git a/quan_frontend-without config/src/components/Common/test.vue b/quan_frontend-without config/src/components/Common/test.vue new file mode 100644 index 0000000..d1ca104 --- /dev/null +++ b/quan_frontend-without config/src/components/Common/test.vue @@ -0,0 +1,136 @@ + + + + hello + + + + + + diff --git a/quan_frontend-without config/src/components/Dashboard/PeerFeed.vue b/quan_frontend-without config/src/components/Dashboard/PeerFeed.vue new file mode 100644 index 0000000..b8a66d2 --- /dev/null +++ b/quan_frontend-without config/src/components/Dashboard/PeerFeed.vue @@ -0,0 +1,92 @@ + + + 👫 好友动态 + + + + {{ item.user.username || '匿名用户' }}: + {{ item.content }} + + + + 暂无好友动态 + + + + + + diff --git a/quan_frontend-without config/src/components/Dashboard/Pie.vue b/quan_frontend-without config/src/components/Dashboard/Pie.vue new file mode 100644 index 0000000..7025944 --- /dev/null +++ b/quan_frontend-without config/src/components/Dashboard/Pie.vue @@ -0,0 +1,119 @@ + + + + + + + diff --git a/quan_frontend-without config/src/components/Dashboard/Ranking.vue b/quan_frontend-without config/src/components/Dashboard/Ranking.vue new file mode 100644 index 0000000..2cb2909 --- /dev/null +++ b/quan_frontend-without config/src/components/Dashboard/Ranking.vue @@ -0,0 +1,127 @@ + + + 🏆 任务完成数月榜 + + + + + + {{ user.username }} + + + {{ user.completeCount }} + + + + + + + + + + + + diff --git a/quan_frontend-without config/src/components/Dashboard/ResOverview.vue b/quan_frontend-without config/src/components/Dashboard/ResOverview.vue new file mode 100644 index 0000000..8b32873 --- /dev/null +++ b/quan_frontend-without config/src/components/Dashboard/ResOverview.vue @@ -0,0 +1,94 @@ + + + 📚 资源推荐 + + + + {{ item.userVO?.username || '匿名用户' }}: + + {{ item.title }} - {{ item.description }} + + + + + 暂无推荐资源 + + + + + + diff --git a/quan_frontend-without config/src/components/Dashboard/TaskProgress.vue b/quan_frontend-without config/src/components/Dashboard/TaskProgress.vue new file mode 100644 index 0000000..e48a6b4 --- /dev/null +++ b/quan_frontend-without config/src/components/Dashboard/TaskProgress.vue @@ -0,0 +1,55 @@ + + + 🎯 目标进度 + + + {{ obj.name }} + + + + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/Landing/BackToLandingButton.vue b/quan_frontend-without config/src/components/Landing/BackToLandingButton.vue new file mode 100644 index 0000000..815c071 --- /dev/null +++ b/quan_frontend-without config/src/components/Landing/BackToLandingButton.vue @@ -0,0 +1,48 @@ + + + + + 返回首页 + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/Landing/LoginRegister.vue b/quan_frontend-without config/src/components/Landing/LoginRegister.vue new file mode 100644 index 0000000..26b3228 --- /dev/null +++ b/quan_frontend-without config/src/components/Landing/LoginRegister.vue @@ -0,0 +1,333 @@ + + + + + + + {{ isLogin ? '登录' : '注册' }} + {{ errorMessage }} + + + + 用户名 + + + + + 邮箱 + + + + + + 验证码 + + + + {{ isCodeSent ? `重新获取(${codeCountdown}s)` : '获取验证码' }} + + + + + + + + 昵称 + + + + + 密码 + + + + 确认密码 + + + + {{ loading ? '处理中...' : (isLogin ? '行启' : '启名') }} + + + {{ isLogin ? '没有账号?注册' : '已有账号?登录' }} + + + + + diff --git a/quan_frontend-without config/src/components/Landing/Quan.vue b/quan_frontend-without config/src/components/Landing/Quan.vue new file mode 100644 index 0000000..897c607 --- /dev/null +++ b/quan_frontend-without config/src/components/Landing/Quan.vue @@ -0,0 +1,109 @@ + + + 开始使用 + 尚未构建 + 卷 + 尚未构建 + 关于我们 + + + + + + diff --git a/quan_frontend-without config/src/components/Landing/calligraphy-buttons.vue b/quan_frontend-without config/src/components/Landing/calligraphy-buttons.vue new file mode 100644 index 0000000..0860e4a --- /dev/null +++ b/quan_frontend-without config/src/components/Landing/calligraphy-buttons.vue @@ -0,0 +1,154 @@ + + + + 卷 + + + + + {{ stroke.label }} + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/ObjHub/CheckButton.vue b/quan_frontend-without config/src/components/ObjHub/CheckButton.vue new file mode 100644 index 0000000..6a3e77e --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/CheckButton.vue @@ -0,0 +1,90 @@ + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/ObjHub/CreateObjButton.vue b/quan_frontend-without config/src/components/ObjHub/CreateObjButton.vue new file mode 100644 index 0000000..f328d25 --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/CreateObjButton.vue @@ -0,0 +1,75 @@ + + + + + + + + {{text}} + + + + + + + + + + + + + + diff --git a/quan_frontend-without config/src/components/ObjHub/CreateObjPage.vue b/quan_frontend-without config/src/components/ObjHub/CreateObjPage.vue new file mode 100644 index 0000000..bae6dd5 --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/CreateObjPage.vue @@ -0,0 +1,121 @@ + + + 目标名称 + + + + 目标描述 + + + 目标时间 + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/ObjHub/CreateSubObjButton.vue b/quan_frontend-without config/src/components/ObjHub/CreateSubObjButton.vue new file mode 100644 index 0000000..8f827de --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/CreateSubObjButton.vue @@ -0,0 +1,109 @@ + + + + + + + {{ text }} + + + + + + + + + + + + + + + diff --git a/quan_frontend-without config/src/components/ObjHub/CreateTaskButton.vue b/quan_frontend-without config/src/components/ObjHub/CreateTaskButton.vue new file mode 100644 index 0000000..41849af --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/CreateTaskButton.vue @@ -0,0 +1,42 @@ + + + + + + + {{ objId }} + + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/ObjHub/CreateTaskPage.vue b/quan_frontend-without config/src/components/ObjHub/CreateTaskPage.vue new file mode 100644 index 0000000..19ae617 --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/CreateTaskPage.vue @@ -0,0 +1,204 @@ + + + 任务名称 + + {{ props.objId }} + + 任务类型 + + + + + 任务内容 + + + + 任务周期 + + + + + 任务时间 + + + + + 结束时间 + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/ObjHub/DeleteButton.vue b/quan_frontend-without config/src/components/ObjHub/DeleteButton.vue new file mode 100644 index 0000000..8f0d52b --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/DeleteButton.vue @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/ObjHub/ObjHeader.vue b/quan_frontend-without config/src/components/ObjHub/ObjHeader.vue new file mode 100644 index 0000000..e91e058 --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/ObjHeader.vue @@ -0,0 +1,145 @@ + + + + + + {{ objName }} + + + 时间: {{ startDateString }} : {{ endDateString }} + + + 主要内容: {{ textArea }} + + + + + + + 完成进度 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/quan_frontend-without config/src/components/ObjHub/ObjMainPage.vue b/quan_frontend-without config/src/components/ObjHub/ObjMainPage.vue new file mode 100644 index 0000000..51afbb2 --- /dev/null +++ b/quan_frontend-without config/src/components/ObjHub/ObjMainPage.vue @@ -0,0 +1,221 @@ + + + + + + 星枢台 + + + + + + + + + + + + 今日任务 + + + + + + + 目标列表 + + + +
阁下台鉴:
您的验证码为:
有效期5分钟,请及时研磨书写。
{{ errorMessage }}
没有更多资源了
hello
暂无好友动态
暂无推荐资源
{{ obj.name }}
{{ isLogin ? '没有账号?注册' : '已有账号?登录' }}
{{ objId }}
{{ props.objId }}
时间: {{ startDateString }} : {{ endDateString }}
主要内容: {{ textArea }}