大修,改为使用SpringBoot框架

master
cxy 7 days ago
parent 5c1d75781c
commit 35dfdcb693

@ -10,10 +10,14 @@
<module name="backend" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel>
<module name="backendtest (1) (org.example)" target="17" />
</bytecodeTargetLevel>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="backend" options="-parameters" />
<module name="backend" options="" />
<module name="backendtest (1) (org.example)" options="-parameters" />
</option>
</component>
</project>

@ -2,5 +2,7 @@
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/backend/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/backend/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/backendtest/src/main/java" charset="UTF-8" />
</component>
</project>

@ -5,8 +5,14 @@
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/backend/pom.xml" />
<option value="$PROJECT_DIR$/backendtest/pom.xml" />
</list>
</option>
<option name="ignoredFiles">
<set>
<option value="$PROJECT_DIR$/backendtest/pom.xml" />
</set>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_20" default="true" project-jdk-name="20" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WebContextManager">
<option name="state">
<map>
<entry key="file://$PROJECT_DIR$/backend/src/main/webapp/index.jsp" value="file://$PROJECT_DIR$/backend/src/main/webapp" />
</map>
</option>
</component>
</project>

@ -5,43 +5,27 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/> <!-- lookup parent from repository -->
<version>3.1.5</version>
<relativePath/>
</parent>
<groupId>org.example</groupId>
<groupId>com</groupId>
<artifactId>backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>backend</name>
<description>backend</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version> <!-- 请根据需要选择适合的版本 -->
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
@ -49,20 +33,47 @@
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
</dependencies>
<build>

@ -0,0 +1,11 @@
package com.backend;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

@ -0,0 +1,25 @@
package com.backend.config;
import com.backend.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@Configuration
public class WebConfig implements WebMvcConfigurer {
private static final List<String> BYPASS_PATHS = List.of(
"/user/login",
"/user/register");
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(final InterceptorRegistry registry) {
// For login and register, not intercept.
registry.addInterceptor(loginInterceptor).excludePathPatterns(BYPASS_PATHS);
}
}

@ -0,0 +1,119 @@
package com.backend.controller;
import com.backend.pojo.Result;
import com.backend.pojo.User;
import com.backend.service.UserService;
import com.backend.utils.JwtUtil;
import com.backend.utils.Md5Util;
import com.backend.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.Duration;
import java.util.Map;
import static com.backend.interceptor.LoginInterceptor.AUTHORIZATION_HEADER;
@RestController
@RequestMapping("/user")
@Validated
public class UserController {
@Autowired
private UserService userService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@PostMapping("/register")
public Result<User> register(@Pattern(regexp = "^\\S{5,16}$") final String username, @Pattern(regexp = "^\\S{5,16}$") final String password) {
final User existingUser = userService.findByUsername(username);
if (existingUser == null) {
userService.register(username, password);
return Result.success();
} else {
return Result.error("用户名已被占用");
}
}
@PostMapping("/login")
public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") final String username, @Pattern(regexp = "^\\S{5,16}$") final String password) {
final User existingUser = userService.findByUsername(username);
if (existingUser == null) {
return Result.error("用户不存在");
}
if (Md5Util.getMD5String(password).equals(existingUser.getPassword())) {
final Map<String, Object> map = Map.of("id", existingUser.getId(),
"username", existingUser.getUsername());
final String token = JwtUtil.genToken(map);
// Save token to redis
final ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
// If key is token, and when we validate, and the token doesn't exist, then it has expired.
operations.set(token, token, Duration.ofHours(12));
// Return JWT token
return Result.success(token);
} else {
return Result.error("密码错误");
}
}
@GetMapping("/userInfo")
public Result<User> userInfo() {
final Map<String, Object> map = ThreadLocalUtil.get();
final String username = (String) map.get("username");
final User user = userService.findByUsername(username);
return Result.success(user);
}
@PutMapping("/update")
public Result<String> update(@RequestBody @Validated final User user) {
final Map<String, Object> map = ThreadLocalUtil.get();
final Integer id = (Integer) map.get("id");
if (user.getId().equals(id)) {
userService.update(user);
return Result.success();
} else {
return Result.error("非本人id");
}
}
@PatchMapping("/updateAvatar")
public Result<String> updateAvatar(@RequestParam @URL final String avatarUrl) {
userService.updateAvatar(avatarUrl);
return Result.success();
}
@PatchMapping("/updatePwd")
public Result<String> updatePwd(@RequestBody Map<String, String> params, @RequestHeader(AUTHORIZATION_HEADER) final String token) {
final String oldPwd = params.get("old_pwd");
final String newPwd = params.get("new_pwd");
final String rePwd = params.get("re_pwd");
if (!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)) {
return Result.error("缺少必要的参数");
}
final Map<String, Object> map = ThreadLocalUtil.get();
final String username = (String) map.get("username");
final User user = userService.findByUsername(username);
if (!rePwd.equals(newPwd)) {
return Result.error("两次结果不一样");
}
if (!user.getPassword().equals(Md5Util.getMD5String(oldPwd))) {
return Result.error("密码填写不正确");
}
userService.updatePwd(newPwd);
// Delete token in redis.
final ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
operations.getOperations().delete(token);
return Result.success();
}
}

@ -0,0 +1,16 @@
package com.backend.exception;
import com.backend.pojo.Result;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler({Exception.class})
public <T> Result<T> handleException(final Exception exception) {
exception.printStackTrace();
return Result.error(StringUtils.hasLength(exception.getMessage()) ? exception.getMessage() : "操作失败");
}
}

@ -0,0 +1,45 @@
package com.backend.interceptor;
import com.backend.utils.JwtUtil;
import com.backend.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Map;
@Component
public class LoginInterceptor implements HandlerInterceptor {
public static final String AUTHORIZATION_HEADER = "Authorization";
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) {
final String token = request.getHeader(AUTHORIZATION_HEADER);
try {
// Get same token from redis.
final ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
final String redisToken = operations.get(token);
if (redisToken == null) { // Token has expired
throw new RuntimeException("过期或未登录");
}
final Map<String, Object> map = JwtUtil.parseToken(token);
ThreadLocalUtil.set(map);
return true;
} catch (Exception e) {
response.setStatus(401);
return false;
}
}
@Override
public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final Exception ex) throws Exception {
ThreadLocalUtil.remove();
}
}

@ -0,0 +1,24 @@
package com.backend.mapper;
import com.backend.pojo.User;
import org.apache.ibatis.annotations.*;
@Mapper
public interface UserMapper {
@Insert("insert into user(username, password, create_time, update_time) " +
"values(#{username},#{md5String},now(),now())")
void add(final String username, final String md5String);
@Select("select * from user where username=#{username}")
User findByUsername(final String username);
@Update("update user set nickname=#{nickname}, update_time=now() where id=#{id}")
void update(final User user);
@Update("update user set user_pic=#{url}, update_time=now() where id=#{id}")
void updateAvatar(final String url, final Integer id);
@Update("update user set password=#{md5String}, update_time=now() where id=#{id}")
void updatePwd(final String md5String, final Integer id);
}

@ -0,0 +1,28 @@
package com.backend.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {
private Integer code;//业务状态码 0-成功 1-失败
private String message;//提示信息
private T data;//响应数据
//快速返回操作成功响应结果(带响应数据)
public static <T> Result<T> success(T data) {
return new Result<>(0, "操作成功", data);
}
//快速返回操作成功响应结果
public static <T> Result<T> success() {
return new Result<>(0, "操作成功", null);
}
public static <T> Result<T> error(String message) {
return new Result<>(1, message, null);
}
}

@ -0,0 +1,26 @@
package com.backend.pojo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class User {
@NotNull
private Integer id;//主键ID
private String username;//用户名
@JsonIgnore // let springmvc ignore password when converting object to json
private String password;//密码
@NotEmpty
@Pattern(regexp = "^\\S{1,10}$")
private String nickname;//昵称
private String userPic;//用户头像地址
private LocalDateTime createTime;//创建时间
private LocalDateTime updateTime;//更新时间
}

@ -0,0 +1,15 @@
package com.backend.service;
import com.backend.pojo.User;
public interface UserService {
User findByUsername(final String username);
void register(final String username, final String password);
void update(final User user);
void updateAvatar(final String url);
void updatePwd(final String newPwd);
}

@ -0,0 +1,49 @@
package com.backend.service.impl;
import com.backend.mapper.UserMapper;
import com.backend.pojo.User;
import com.backend.service.UserService;
import com.backend.utils.Md5Util;
import com.backend.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByUsername(final String username) {
return userMapper.findByUsername(username);
}
@Override
public void register(final String username, final String password) {
final String md5String = Md5Util.getMD5String(password);
userMapper.add(username, md5String);
}
@Override
public void update(final User user) {
userMapper.update(user);
}
@Override
public void updateAvatar(final String url) {
final Map<String, Object> map = ThreadLocalUtil.get();
final Integer id = (Integer) map.get("id");
userMapper.updateAvatar(url, id);
}
@Override
public void updatePwd(final String newPwd) {
final String md5String = Md5Util.getMD5String(newPwd);
final Map<String, Object> map = ThreadLocalUtil.get();
final Integer id = (Integer) map.get("id");
userMapper.updatePwd(md5String, id);
}
}

@ -0,0 +1,46 @@
package com.backend.utils;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import java.io.InputStream;
public class AliOssUtil {
private static final String ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";
public static final String ACCESS_KEY_ID = System.getenv("ALIYUN_ACCESSKEY_ID");
private static final String SECRET_ACCESS_KEY = System.getenv("ALIYUN_ACCESSKEY_SECRET");
private static final String BUCKET_NAME = "big-event-1";
//上传文件,返回文件的公网访问地址
public static String uploadFile(String objectName, InputStream inputStream) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, SECRET_ACCESS_KEY);
//公文访问地址
String url = "";
try {
// 创建存储空间。
ossClient.createBucket(BUCKET_NAME);
ossClient.putObject(BUCKET_NAME, objectName, inputStream);
url = "https://" + BUCKET_NAME + "." + ENDPOINT.substring(ENDPOINT.lastIndexOf("/") + 1) + "/" + objectName;
} 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();
}
}
return url;
}
}

@ -0,0 +1,29 @@
package com.backend.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
private static final String KEY = "express-jwt-secret";
//接收业务数据,生成token并返回
public static String genToken(Map<String, Object> claims) {
return JWT.create()
.withClaim("claims", claims)
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
.sign(Algorithm.HMAC256(KEY));
}
//接收token,验证token,并返回业务数据
public static Map<String, Object> parseToken(String token) {
return JWT.require(Algorithm.HMAC256(KEY))
.build()
.verify(token)
.getClaim("claims")
.asMap();
}
}

@ -0,0 +1,73 @@
package com.backend.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Util {
/**
* 16 ,apache
*/
protected static char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
protected static MessageDigest messagedigest = null;
static {
try {
messagedigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsaex) {
System.err.println(Md5Util.class.getName() + "初始化失败MessageDigest不支持MD5Util。");
nsaex.printStackTrace();
}
}
/**
* md5
*
* @param s
* @return
*/
public static String getMD5String(String s) {
return getMD5String(s.getBytes());
}
/**
* md5md5
*
* @param password
* @param md5PwdStr md5
* @return
*/
public static boolean checkPassword(String password, String md5PwdStr) {
String s = getMD5String(password);
return s.equals(md5PwdStr);
}
public static String getMD5String(byte[] bytes) {
messagedigest.update(bytes);
return bufferToHex(messagedigest.digest());
}
private static String bufferToHex(byte[] bytes) {
return bufferToHex(bytes, 0, bytes.length);
}
private static String bufferToHex(byte[] bytes, int m, int n) {
StringBuffer stringbuffer = new StringBuffer(2 * n);
int k = m + n;
for (int l = m; l < k; l++) {
appendHexPair(bytes[l], stringbuffer);
}
return stringbuffer.toString();
}
private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>>
// 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同
char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换
stringbuffer.append(c0);
stringbuffer.append(c1);
}
}

@ -0,0 +1,26 @@
package com.backend.utils;
/**
* ThreadLocal
*/
@SuppressWarnings("all")
public class ThreadLocalUtil {
//提供ThreadLocal对象,
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
//根据键获取值
public static <T> T get() {
return (T) THREAD_LOCAL.get();
}
//存储键值对
public static void set(Object value) {
THREAD_LOCAL.set(value);
}
//清除ThreadLocal 防止内存泄漏
public static void remove() {
THREAD_LOCAL.remove();
}
}

@ -1,20 +0,0 @@
package org.example.backend;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class BackendApplication {
@RequestMapping("/")
public String hello() {
return "Hello, World!";
}
public static void main(String[] args) {
SpringApplication.run(BackendApplication.class, args);
}
}

@ -0,0 +1,16 @@
spring:
datasource:
url: jdbc:mysql://localhost:3306/express_management
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
data:
redis:
host: 47.115.225.58
port: 6379
mybatis:
configuration:
map-underscore-to-camel-case: true
#mybatis:
# mapper-locations: classpath:./mapper/*.xml
# type-aliases-package: com.backend.pojo

@ -1,7 +0,0 @@
spring.application.name=backend
server.port=8888
spring.datasource.url=jdbc:mysql://localhost:3306/express_management
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

@ -0,0 +1,3 @@
spring:
profiles:
active: dev

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.backend.mapper.UserMapper">
<insert id="add">
INSERT INTO user (username, password, create_time, update_time)
VALUES (#{username}, #{md5String}, NOW(), NOW())
</insert>
<select id="findByUsername" resultType="User">
SELECT * FROM user WHERE username = #{username}
</select>
<update id="update">
UPDATE user
SET nickname = #{nickname},
update_time = NOW()
WHERE id = #{id}
</update>
<update id="updateAvatar">
UPDATE user
SET user_pic = #{url},
update_time = NOW()
WHERE id = #{id}
</update>
<update id="updatePwd">
UPDATE user
SET password = #{md5String},
update_time = NOW()
WHERE id = #{id}
</update>
</mapper>

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.backend.mapper.UserMapper">
<insert id="add">
INSERT INTO user (username, password, create_time, update_time)
VALUES (#{username}, #{md5String}, NOW(), NOW())
</insert>
<select id="findByUsername" resultType="User">
SELECT * FROM user WHERE username = #{username}
</select>
<update id="update">
UPDATE user
SET nickname = #{nickname},
update_time = NOW()
WHERE id = #{id}
</update>
<update id="updateAvatar">
UPDATE user
SET user_pic = #{url},
update_time = NOW()
WHERE id = #{id}
</update>
<update id="updatePwd">
UPDATE user
SET password = #{md5String},
update_time = NOW()
WHERE id = #{id}
</update>
</mapper>

@ -1,10 +1,10 @@
package org.example.backend;
package com.backend;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class BackendBackendApplicationTests {
class BackendApplicationTests {
@Test
void contextLoads() {

@ -1,5 +1,5 @@
{
"name": "lesson1_vite",
"name": "express",
"private": true,
"version": "0.0.0",
"type": "module",
@ -9,16 +9,21 @@
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@vueup/vue-quill": "^1.2.0",
"axios": "1.2.1",
"element-plus": "^2.8.6",
"express": "^4.21.1",
"pinia": "2.0.27",
"pinia-persistedstate-plugin": "^0.1.0",
"save": "^2.9.0",
"scss": "^0.2.4",
"vue": "^3.4.37",
"vue-router": "4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.2",
"sass": "^1.81.0",
"vite": "^5.4.1"
}
}

@ -8,16 +8,5 @@
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

@ -1,9 +1,11 @@
<script setup>
</script>
<template>
<h1>页面2</h1>
</template>
<script setup>
</script>
<style scoped>
<style>
</style>

@ -1,72 +1,177 @@
<template>
<div class="login-container">
<h2>登录</h2>
<form @submit.prevent="handleLogin">
<div>
<label for="username">用户名</label>
<input type="text" id="username" v-model="username" required />
</div>
<div>
<label for="password">密码</label>
<input type="password" id="password" v-model="password" required />
</div>
<button type="submit">登录</button>
</form>
<div @click="toRegister"></div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const username = ref('');
const password = ref('');
const handleLogin = () => {
const storedUser = JSON.parse(localStorage.getItem(username.value));
if (storedUser && storedUser.password === password.value) {
alert('登录成功!');
// user/index.vue
router.push('/user');
} else {
alert('用户名或密码错误');
}
};
const toRegister = () => {
router.push({ name: 'Register' });
};
</script>
import {Lock, User} from "@element-plus/icons-vue"
import {ref} from "vue";
import {userLoginService, userRegisterService} from "@/api/user";
import {ElMessage} from "element-plus";
import {useRouter} from "vue-router";
import {useTokenStore} from "@/stores/token";
// Register page and Login page use the same view.
// By default, show login.
const isRegister = ref(false);
const registerData = ref({
username: '',
password: '',
rePassword: ''
});
<style scoped>
.login-container {
width: 300px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
const checkRePassword = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次确认密码'))
} else if (value !== registerData.value.password) {
callback(new Error('两次密码不一样'))
} else {
callback()
}
}
const rules = {
username: [
{required: true, message: '请输入用户名', trigger: 'blur'},
{min: 5, max: 16, message: '长度为5-16位', trigger: 'blur'},
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 5, max: 16, message: '长度为5-16位', trigger: 'blur'},
],
rePassword: [
{required: true, message: '请输入密码', trigger: 'blur'},
{validator: checkRePassword, trigger: 'blur'},
]
}
h2 {
text-align: center;
const register = async () => {
const valid = await form.value.validate();
if (valid) {
const result = await userRegisterService(registerData.value);
ElMessage.success(result.message ? result.message : '注册成功')
}
}
form div {
margin-bottom: 10px;
const router = useRouter()
const tokenStore = useTokenStore();
const form = ref(null)
const login = async () => {
// HM
const valid = await form.value.validate();
if (valid) {
const result = await userLoginService(registerData.value);
ElMessage.success(result.message ? result.message : '登录成功')
tokenStore.setToken(result.data)
router.push('/')
}
}
button {
width: 100%;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
const clearRegisterData = () => {
registerData.value = {
username: '',
password: '',
rePassword: ''
}
}
button:hover {
background-color: #45a049;
</script>
<template>
<el-row class="login-page">
<el-col :span="12" class="bg"></el-col>
<el-col :span="6" :offset="3" class="form">
<!-- 注册表单 -->
<el-form ref="form" size="large" autocomplete="on" v-if="isRegister" :model="registerData" :rules="rules">
<el-form-item>
<h1>注册</h1>
</el-form-item>
<el-form-item prop="username">
<el-input :prefix-icon="User" placeholder="请输入用户名" v-model="registerData.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input :prefix-icon="Lock" type="password" placeholder="请输入密码"
v-model="registerData.password"></el-input>
</el-form-item>
<el-form-item prop="rePassword">
<el-input :prefix-icon="Lock" type="password" placeholder="请输入再次密码"
v-model="registerData.rePassword"></el-input>
</el-form-item>
<!-- 注册按钮 -->
<el-form-item>
<el-button class="button" type="primary" auto-insert-space @click="register">
注册
</el-button>
</el-form-item>
<el-form-item class="flex">
<el-link type="info" :underline="false" @click="isRegister = false;clearRegisterData()">
返回
</el-link>
</el-form-item>
</el-form>
<!-- 登录表单 -->
<el-form ref="form" size="large" autocomplete="off" v-else :model="registerData" :rules="rules">
<el-form-item>
<h1>登录</h1>
</el-form-item>
<el-form-item prop="username">
<el-input :prefix-icon="User" placeholder="请输入用户名" v-model="registerData.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input name="password" :prefix-icon="Lock" type="password" placeholder="请输入密码"
v-model="registerData.password"></el-input>
</el-form-item>
<el-form-item class="flex">
<div class="flex">
<el-checkbox>记住我</el-checkbox>
<el-link type="primary" :underline="false">忘记密码</el-link>
</div>
</el-form-item>
<!-- 登录按钮 -->
<el-form-item>
<el-button class="button" type="primary" auto-insert-space @click="login">
登录
</el-button>
</el-form-item>
<el-form-item class="flex">
<el-link type="info" :underline="false" @click="isRegister = true;clearRegisterData()">
注册
</el-link>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<style lang="scss" scoped>
/* 样式 */
.login-page {
height: 100vh;
background-color: #fff;
.bg {
background: url('@/assets/logo2.png') no-repeat 60% center / 240px auto,
url('@/assets/login_bg.jpg') no-repeat center / cover;
border-radius: 0 20px 20px 0;
}
.form {
display: flex;
flex-direction: column;
justify-content: center;
user-select: none;
.title {
margin: 0 auto;
}
.button {
width: 100%;
}
.flex {
width: 100%;
display: flex;
justify-content: space-between;
}
}
}
</style>

@ -1,9 +0,0 @@
<template>
<h1>页面1</h1>
</template>
<script setup>
</script>
<style>
</style>

@ -1,86 +0,0 @@
<template>
<div class="register-container">
<h2>注册</h2>
<form @submit.prevent="handleRegister">
<div>
<label for="username">用户名</label>
<input type="text" id="username" v-model="username" required />
</div>
<div>
<label for="password">密码</label>
<input type="password" id="password" v-model="password" required />
</div>
<div>
<label for="confirmPassword">确认密码</label>
<input type="password" id="confirmPassword" v-model="confirmPassword" required />
</div>
<button type="submit">注册</button>
</form>
<div @click="toLogin"></div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
const username = ref('');
const password = ref('');
const confirmPassword = ref('');
const router = useRouter();
const handleRegister = () => {
if (password.value !== confirmPassword.value) {
alert('密码不一致,请重新输入');
return;
}
if (localStorage.getItem(username.value)) {
alert('用户名已存在,请选择其他用户名');
return;
}
const newUser = {
username: username.value,
password: password.value
};
localStorage.setItem(username.value, JSON.stringify(newUser));
alert('注册成功!');
router.push('/');
};
const toLogin = () => {
router.push({ name: "Login" });
};
</script>
<style scoped>
.register-container {
width: 300px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
h2 {
text-align: center;
}
form div {
margin-bottom: 10px;
}
button {
width: 100%;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
</style>

@ -1,3 +1,4 @@
<template>
<div>
<el-row class="top">

@ -0,0 +1,98 @@
<script setup>
import {Plus, Upload} from '@element-plus/icons-vue'
import {ref} from 'vue'
import {useUserInfoStore} from "@/stores/userInfo.js";
import {useTokenStore} from "@/stores/token";
import {ElMessage} from "element-plus";
import {userAvatarUpdateService} from "@/api/user";
const uploadRef = ref()
const userInfoStore = useUserInfoStore();
//
const imgUrl = ref(userInfoStore.userInfo.userPic)
const tokenStore = useTokenStore();
const uploadSuccess = (result) => {
imgUrl.value = result.data;
ElMessage.success("图片上传成功")
}
const updateAvatar = async () => {
await userAvatarUpdateService(imgUrl.value)
ElMessage.success("修改成功")
userInfoStore.setUserInfo({
...userInfoStore.userInfo,
userPic: imgUrl.value
})
}
</script>
<template>
<el-card class="page-container">
<template #header>
<div class="header">
<span>更换头像</span>
</div>
</template>
<el-row>
<el-col :span="12">
<el-upload
ref="uploadRef"
class="avatar-uploader"
:show-file-list="false"
:auto-upload="true"
action="/api/upload"
name="file"
:headers="{'Authorization':tokenStore.token}"
:on-success="uploadSuccess"
>
<el-image v-if="imgUrl" :src="imgUrl" class="avatar"/>
<el-image v-else src="avatar" width="278"/>
</el-upload>
<br/>
<el-button type="primary" :icon="Plus" size="large" @click="uploadRef.$el.querySelector('input').click()">
选择图片
</el-button>
<el-button type="success" :icon="Upload" size="large" @click="updateAvatar">
上传头像
</el-button>
</el-col>
</el-row>
</el-card>
</template>
<style lang="scss" scoped>
.avatar-uploader {
:deep {
.avatar {
width: 278px;
height: 278px;
display: block;
}
.el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 278px;
height: 278px;
text-align: center;
}
}
}
</style>

@ -0,0 +1,61 @@
<template>
<el-card class="page-container">
<template #header>
<div class="header">
<span>基本资料</span>
</div>
</template>
<el-row>
<el-col :span="12">
<el-form :model="userInfo" :rules="rules" label-width="100px" size="large">
<el-form-item label="登录名称">
<el-input v-model="userInfo.username" disabled></el-input>
</el-form-item>
<el-form-item label="用户昵称" prop="nickname">
<el-input v-model="userInfo.nickname"></el-input>
</el-form-item>
<el-form-item label="用户邮箱" prop="email">
<el-input v-model="userInfo.email"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="updateUserInfo"></el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-card>
</template>
<script setup>
import {ref} from 'vue'
import {useUserInfoStore} from "@/stores/userInfo.js";
import {userInfoUpdateService} from "@/api/user";
import {ElMessage} from "element-plus";
const userInfoStore = useUserInfoStore();
const userInfo = ref({
...userInfoStore.userInfo
})
const rules = {
nickname: [
{required: true, message: '请输入用户昵称', trigger: 'blur'},
{
pattern: /^\S{2,10}$/,
message: '昵称必须是2-10位的非空字符串',
trigger: 'blur'
}
],
email: [
{required: true, message: '请输入用户邮箱', trigger: 'blur'},
{type: 'email', message: '邮箱格式不正确', trigger: 'blur'}
]
}
const updateUserInfo = () => {
userInfoUpdateService(userInfo.value);
ElMessage.success('修改成功')
userInfoStore.setUserInfo(userInfo.value)
}
</script>

@ -0,0 +1,74 @@
<template>
<el-card class="page-container">
<template #header>
<div class="header">
<span>重置密码</span>
</div>
</template>
<el-row>
<el-col :span="12">
<el-form :model="pwdData" :rules="rules" label-width="100px" size="large">
<el-form-item label="旧密码" prop="old_pwd">
<el-input v-model="pwdData.old_pwd" type="password" placeholder="请输入旧密码"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="new_pwd">
<el-input v-model="pwdData.new_pwd" type="password" placeholder="请输入新密码"></el-input>
</el-form-item>
<el-form-item label="确认新密码" prop="re_pwd">
<el-input v-model="pwdData.re_pwd" type="password" placeholder="请输入再次新密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="updatePwdData"></el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-card>
</template>
<script setup>
import {ref} from 'vue'
import {userPwdUpdateService} from "@/api/user";
import {ElMessage} from "element-plus";
const pwdData = ref({
old_pwd: '',
new_pwd: '',
re_pwd: ''
})
const updatePwdData = async () => {
await userPwdUpdateService(pwdData.value);
ElMessage.success('修改成功')
pwdData.value = {
old_pwd: '',
new_pwd: '',
re_pwd: ''
}
}
const checkRePassword = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次确认密码'))
} else if (value !== pwdData.value.new_pwd) {
callback(new Error('两次密码不一样'))
} else {
callback()
}
}
const rules = {
old_pwd: [
{required: true, message: '请输入旧密码?', trigger: 'blur'},
{min: 5, max: 16, message: '长度为5-16位', trigger: 'blur'},
],
new_pwd: [
{required: true, message: '请输入新密码', trigger: 'blur'},
{min: 5, max: 16, message: '长度为5-16位', trigger: 'blur'},
],
re_pwd: [
{required: true, message: '请输入确认新密码', trigger: 'blur'},
{validator: checkRePassword, trigger: 'blur'},
]
}
</script>

@ -0,0 +1,36 @@
import request from "@/utils/request";
export const userRegisterService = (registerData) => {
const params = new URLSearchParams();
for (const key in registerData) {
params.append(key, registerData[key])
}
return request.post('/user/register', params)
}
export const userLoginService = (loginData) => {
const params = new URLSearchParams();
for (const key in loginData) {
params.append(key, loginData[key])
}
return request.post('/user/login', params)
}
export const userInfoService = () => {
return request.get('/user/userInfo')
}
export const userInfoUpdateService = (userInfoData) => {
return request.put('/user/update', userInfoData)
}
export const userAvatarUpdateService = (avatarUrl) => {
const urlSearchParams = new URLSearchParams();
urlSearchParams.append('avatarUrl', avatarUrl)
return request.patch('/user/updateAvatar', urlSearchParams)
}
export const userPwdUpdateService = (pwdData) => {
return request.patch('/user/updatePwd', pwdData)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -0,0 +1,20 @@
body {
margin: 0;
background-color: #f5f5f5;
}
/* fade-slide */
.fade-slide-leave-active,
.fade-slide-enter-active {
transition: all 0.3s;
}
.fade-slide-enter-from {
transform: translateX(-30px);
opacity: 0;
}
.fade-slide-leave-to {
transform: translateX(30px);
opacity: 0;
}

@ -6,7 +6,7 @@ import 'element-plus/dist/index.css'
// 引入 App 根组件
import App from './App.vue'
// 引入路由器
import router from './router'
import router from "./router/index.js";
import { createPinia } from 'pinia'
// 创建一个应用

@ -1,5 +0,0 @@
import axios from "axios";
const request=axios.create({
timeout:2000
})
export default request

@ -2,7 +2,7 @@ import {
createRouter,
createWebHashHistory
} from "vue-router"
import {userStore} from "./store"
import {userStore} from "./stores"
import {storeToRefs} from "pinia"
const router = createRouter({
@ -17,11 +17,6 @@ const router = createRouter({
name: 'Home',
component: () => import('./View/Home.vue')
},
{
path: '/register',
name: 'Register',
component: () => import('./View/Register.vue')
},
{
path: '/login',
name: 'Login',

@ -0,0 +1,56 @@
import {createRouter, createWebHistory} from "vue-router";
import Login from "../view/Login.vue";
import Layout from "../view/Layout.vue";
import Home from "../view/Home.vue";
import Index from "../view/user/Index.vue";
import MyInfo from "../view/user/MyInfo.vue";
import ExpressList from "../view/user/ExpressList.vue";
import ExpressForm from "../view/user/ExpressForm.vue";
import UserInfo from "../view/user/UserInfo.vue";
import UserAvatar from "../view/user/UserAvatar.vue";
import UserResetPassword from "../view/user/UserResetPassword.vue";
const routes = [
{
path: '/',
redirect: 'Home'
},
{
path: '/home',
name: 'Home',
component: Home,
},
{
path: '/login',
name: 'Login',
component: Login,
},
{
path: '/user',
name: 'User',
component: Index,
redirect: "myInfo",
children: [
{
path: '/myInfo',
component: MyInfo
},
{
path: '/expressList',
component: ExpressList
},
{
path: '/expressForm',
component: ExpressForm
}
]
},
]
const router = createRouter({
history: createWebHistory(),
routes: routes
})
export default router

@ -1,37 +0,0 @@
// 引入 Express
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
// 中间件
app.use(bodyParser.json());
// 登录
app.post('/View/login', (req, res) => {
const { username, password } = req.body;
// 验证用户名和密码
if (username === 'test' && password === '123456') {
res.json({ success: true });
} else {
res.json({ success: false, message: '用户名或密码错误' });
}
});
// 注册
app.post('/View/register', (req, res) => {
const { username, email, password } = req.body;
// 进行用户名、邮箱的检查并保存用户
if (username && email && password) {
res.json({ success: true });
} else {
res.json({ success: false, message: '信息不完整' });
}
});
// 启动服务器
app.listen(port, () => {
console.log(`服务器正在运行在 http://localhost:${port}`);
});

@ -0,0 +1,22 @@
import {defineStore} from "pinia";
import {ref} from "vue";
export const useTokenStore = defineStore('token',
() => {
const token = ref('')
const setToken = (newToken) => {
token.value = newToken
}
const removeToken = () => {
token.value = ''
}
return {
token, setToken, removeToken
}
},
{
persist: true
});

@ -0,0 +1,22 @@
import {defineStore} from "pinia";
import {ref} from "vue";
export const useUserInfoStore = defineStore('userInfo',
() => {
const userInfo = ref({})
const setUserInfo = (newUserInfo) => {
userInfo.value = newUserInfo
}
const removeUserInfo = () => {
userInfo.value = {}
}
return {
userInfo, setUserInfo, removeUserInfo
}
},
{
persist: true
});

@ -1,79 +0,0 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

@ -0,0 +1,43 @@
import axios from "axios";
import {ElMessage} from "element-plus";
import {useTokenStore} from "@/stores/token";
import router from "@/router";
const instance = axios.create({baseURL: '/api'});
instance.interceptors.request.use(
config => {
const tokenStore = useTokenStore();
if (tokenStore.token) {
config.headers.Authorization = tokenStore.token
}
return config
},
error => {
return Promise.reject(error)
}
)
instance.interceptors.response.use(
result => {
if (result.data.code === 0) {
return result.data
}
ElMessage.error(result.data.message ? result.data.message : '服务异常')
return Promise.reject(result.data)
},
error => {
if (error.response.status === 401) {
ElMessage.error("请先登录")
// Have problems here
router.push('/login')
} else {
ElMessage.error('服务异常')
}
return Promise.reject(error)
}
)
export default instance

@ -1,7 +1,26 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/,'')
}
}
}
})

@ -35,7 +35,7 @@
"@element-plus/icons-vue@^2.3.1":
version "2.3.1"
resolved "https://registry.yarnpkg.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a"
resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a"
integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==
"@esbuild/aix-ppc64@0.21.5":
@ -178,6 +178,95 @@
resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a"
integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
"@parcel/watcher-android-arm64@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz#e32d3dda6647791ee930556aee206fcd5ea0fb7a"
integrity sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==
"@parcel/watcher-darwin-arm64@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz#0d9e680b7e9ec1c8f54944f1b945aa8755afb12f"
integrity sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==
"@parcel/watcher-darwin-x64@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz#f9f1d5ce9d5878d344f14ef1856b7a830c59d1bb"
integrity sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==
"@parcel/watcher-freebsd-x64@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz#2b77f0c82d19e84ff4c21de6da7f7d096b1a7e82"
integrity sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==
"@parcel/watcher-linux-arm-glibc@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz#92ed322c56dbafa3d2545dcf2803334aee131e42"
integrity sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==
"@parcel/watcher-linux-arm-musl@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz#cd48e9bfde0cdbbd2ecd9accfc52967e22f849a4"
integrity sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==
"@parcel/watcher-linux-arm64-glibc@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz#7b81f6d5a442bb89fbabaf6c13573e94a46feb03"
integrity sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==
"@parcel/watcher-linux-arm64-musl@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz#dcb8ff01077cdf59a18d9e0a4dff7a0cfe5fd732"
integrity sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==
"@parcel/watcher-linux-x64-glibc@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz#2e254600fda4e32d83942384d1106e1eed84494d"
integrity sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==
"@parcel/watcher-linux-x64-musl@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz#01fcea60fedbb3225af808d3f0a7b11229792eef"
integrity sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==
"@parcel/watcher-win32-arm64@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz#87cdb16e0783e770197e52fb1dc027bb0c847154"
integrity sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==
"@parcel/watcher-win32-ia32@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz#778c39b56da33e045ba21c678c31a9f9d7c6b220"
integrity sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==
"@parcel/watcher-win32-x64@2.5.0":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz#33873876d0bbc588aacce38e90d1d7480ce81cb7"
integrity sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==
"@parcel/watcher@^2.4.1":
version "2.5.0"
resolved "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.0.tgz#5c88818b12b8de4307a9d3e6dc3e28eba0dfbd10"
integrity sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==
dependencies:
detect-libc "^1.0.3"
is-glob "^4.0.3"
micromatch "^4.0.5"
node-addon-api "^7.0.0"
optionalDependencies:
"@parcel/watcher-android-arm64" "2.5.0"
"@parcel/watcher-darwin-arm64" "2.5.0"
"@parcel/watcher-darwin-x64" "2.5.0"
"@parcel/watcher-freebsd-x64" "2.5.0"
"@parcel/watcher-linux-arm-glibc" "2.5.0"
"@parcel/watcher-linux-arm-musl" "2.5.0"
"@parcel/watcher-linux-arm64-glibc" "2.5.0"
"@parcel/watcher-linux-arm64-musl" "2.5.0"
"@parcel/watcher-linux-x64-glibc" "2.5.0"
"@parcel/watcher-linux-x64-musl" "2.5.0"
"@parcel/watcher-win32-arm64" "2.5.0"
"@parcel/watcher-win32-ia32" "2.5.0"
"@parcel/watcher-win32-x64" "2.5.0"
"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7":
version "2.11.7"
resolved "https://registry.yarnpkg.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671"
@ -268,6 +357,11 @@
resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
"@types/js-cookie@^3.0.1":
version "3.0.6"
resolved "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-3.0.6.tgz#a04ca19e877687bd449f5ad37d33b104b71fdf95"
integrity sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==
"@types/lodash-es@^4.17.6":
version "4.17.12"
resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b"
@ -332,7 +426,7 @@
"@vue/compiler-dom" "3.4.38"
"@vue/shared" "3.4.38"
"@vue/devtools-api@^6.4.5", "@vue/devtools-api@^6.6.4":
"@vue/devtools-api@^6.4.5", "@vue/devtools-api@^6.6.3", "@vue/devtools-api@^6.6.4":
version "6.6.4"
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343"
integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==
@ -375,6 +469,14 @@
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.4.38.tgz#552a6770098bfd556fa3e2c686c9d3b4f4cd94c2"
integrity sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==
"@vueup/vue-quill@^1.2.0":
version "1.2.0"
resolved "https://registry.npmmirror.com/@vueup/vue-quill/-/vue-quill-1.2.0.tgz#cd0d93559256d069f639723dd91c044e8162c72a"
integrity sha512-kd5QPSHMDpycklojPXno2Kw2JSiKMYduKYQckTm1RJoVDA557MnyUXgcuuDpry4HY/Rny9nGNcK+m3AHk94wag==
dependencies:
quill "^1.3.7"
quill-delta "^4.2.2"
"@vueuse/core@^9.1.0":
version "9.13.0"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
@ -452,12 +554,19 @@ body-parser@1.20.3:
type-is "~1.6.18"
unpipe "1.0.0"
braces@^3.0.3:
version "3.0.3"
resolved "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
fill-range "^7.1.1"
bytes@3.1.2:
version "3.1.2"
resolved "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
call-bind@^1.0.7:
call-bind@^1.0.2, call-bind@^1.0.7:
version "1.0.7"
resolved "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
@ -468,6 +577,18 @@ call-bind@^1.0.7:
get-intrinsic "^1.2.4"
set-function-length "^1.2.1"
chokidar@^4.0.0:
version "4.0.1"
resolved "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.1.tgz#4a6dff66798fb0f72a94f616abbd7e1a19f31d41"
integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==
dependencies:
readdirp "^4.0.1"
clone@^2.1.1:
version "2.1.2"
resolved "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@ -514,7 +635,19 @@ debug@2.6.9:
dependencies:
ms "2.0.0"
define-data-property@^1.1.4:
deep-equal@^1.0.1:
version "1.1.2"
resolved "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.1.2.tgz#78a561b7830eef3134c7f6f3a3d6af272a678761"
integrity sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==
dependencies:
is-arguments "^1.1.1"
is-date-object "^1.0.5"
is-regex "^1.1.4"
object-is "^1.1.5"
object-keys "^1.1.1"
regexp.prototype.flags "^1.5.1"
define-data-property@^1.0.1, define-data-property@^1.1.4:
version "1.1.4"
resolved "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
@ -523,6 +656,15 @@ define-data-property@^1.1.4:
es-errors "^1.3.0"
gopd "^1.0.1"
define-properties@^1.2.1:
version "1.2.1"
resolved "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c"
integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
dependencies:
define-data-property "^1.0.1"
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@ -538,6 +680,11 @@ destroy@1.2.0:
resolved "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
duplexer@^0.1.1, duplexer@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
@ -653,6 +800,11 @@ event-stream@^4.0.1:
stream-combiner "^0.2.2"
through "^2.3.8"
eventemitter3@^2.0.3:
version "2.0.3"
resolved "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
integrity sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==
express@^4.21.1:
version "4.21.1"
resolved "https://registry.npmmirror.com/express/-/express-4.21.1.tgz#9dae5dda832f16b4eec941a4e44aa89ec481b281"
@ -690,6 +842,28 @@ express@^4.21.1:
utils-merge "1.0.1"
vary "~1.1.2"
extend@^3.0.2:
version "3.0.2"
resolved "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
fast-diff@1.1.2:
version "1.1.2"
resolved "https://registry.npmmirror.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154"
integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==
fast-diff@1.2.0:
version "1.2.0"
resolved "https://registry.npmmirror.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"
finalhandler@1.3.1:
version "1.3.1"
resolved "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019"
@ -742,6 +916,11 @@ function-bind@^1.1.2:
resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
functions-have-names@^1.2.3:
version "1.2.3"
resolved "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
version "1.2.4"
resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
@ -760,7 +939,7 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
has-property-descriptors@^1.0.2:
has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
@ -777,6 +956,13 @@ has-symbols@^1.0.3:
resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
has-tostringtag@^1.0.0:
version "1.0.2"
resolved "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
dependencies:
has-symbols "^1.0.3"
hasown@^2.0.0:
version "2.0.2"
resolved "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
@ -802,6 +988,11 @@ iconv-lite@0.4.24:
dependencies:
safer-buffer ">= 2.1.2 < 3"
immutable@^5.0.2:
version "5.0.3"
resolved "https://registry.npmmirror.com/immutable/-/immutable-5.0.3.tgz#aa037e2313ea7b5d400cd9298fa14e404c933db1"
integrity sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==
inherits@2.0.4:
version "2.0.4"
resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
@ -812,6 +1003,46 @@ ipaddr.js@1.9.1:
resolved "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
is-arguments@^1.1.1:
version "1.1.1"
resolved "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
dependencies:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
is-date-object@^1.0.5:
version "1.0.5"
resolved "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
dependencies:
has-tostringtag "^1.0.0"
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-glob@^4.0.3:
version "4.0.3"
resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-regex@^1.1.4:
version "1.1.4"
resolved "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
dependencies:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
@ -827,6 +1058,16 @@ lodash.assign@^4.2.0:
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
integrity sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==
lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
@ -864,6 +1105,14 @@ methods@~1.1.2:
resolved "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
micromatch@^4.0.5:
version "4.0.8"
resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
dependencies:
braces "^3.0.3"
picomatch "^2.3.1"
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
@ -906,6 +1155,11 @@ negotiator@0.6.3:
resolved "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
node-addon-api@^7.0.0:
version "7.1.1"
resolved "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
normalize-wheel-es@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e"
@ -916,6 +1170,24 @@ object-inspect@^1.13.1:
resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a"
integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==
object-is@^1.1.5:
version "1.1.6"
resolved "https://registry.npmmirror.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07"
integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==
dependencies:
call-bind "^1.0.7"
define-properties "^1.2.1"
object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
ometa@0.2.2:
version "0.2.2"
resolved "https://registry.npmmirror.com/ometa/-/ometa-0.2.2.tgz#f53c4735ba6d56af5a46b04dfb7c4334c596d44e"
integrity sha512-LZuoK/yjU3FvrxPjUXUlZ1bavCfBPqauA7fsNdwi+AVhRdyk2IzgP3JRnevvjzQ6fKHdUw8YISshf53FmpHrng==
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
@ -923,6 +1195,11 @@ on-finished@2.4.1:
dependencies:
ee-first "1.1.1"
parchment@^1.1.4:
version "1.1.4"
resolved "https://registry.npmmirror.com/parchment/-/parchment-1.1.4.tgz#aeded7ab938fe921d4c34bc339ce1168bc2ffde5"
integrity sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@ -945,6 +1222,19 @@ picocolors@^1.0.1:
resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pinia-persistedstate-plugin@^0.1.0:
version "0.1.0"
resolved "https://registry.npmmirror.com/pinia-persistedstate-plugin/-/pinia-persistedstate-plugin-0.1.0.tgz#37f0c8a0e93e7ff529d8867e536365274b4bb8d4"
integrity sha512-ToKR/EJzhhXElQ5YL8PVVY4CqLJjywxszAJjOCgprjmIVkTrPBsEOY4b/ATOzHQc1TtuaJs/3MJuoCpA3pv8Ew==
dependencies:
"@types/js-cookie" "^3.0.1"
pinia "^2.0.12"
pinia@2.0.27:
version "2.0.27"
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.27.tgz#cf13a8dca2792a613c1d8bb8ef50707756e5a6ef"
@ -953,6 +1243,14 @@ pinia@2.0.27:
"@vue/devtools-api" "^6.4.5"
vue-demi "*"
pinia@^2.0.12:
version "2.2.6"
resolved "https://registry.npmmirror.com/pinia/-/pinia-2.2.6.tgz#ff93f35b8c02033eaedc8c92ad5f10f215d6c804"
integrity sha512-vIsR8JkDN5Ga2vAxqOE2cJj4VtsHnzpR1Fz30kClxlh0yCHfec6uoMeM3e/ddqmwFUejK3NlrcQa/shnpyT4hA==
dependencies:
"@vue/devtools-api" "^6.6.3"
vue-demi "^0.14.10"
postcss@^8.4.40, postcss@^8.4.41:
version "8.4.41"
resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681"
@ -982,6 +1280,36 @@ qs@6.13.0:
dependencies:
side-channel "^1.0.6"
quill-delta@^3.6.2:
version "3.6.3"
resolved "https://registry.npmmirror.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032"
integrity sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==
dependencies:
deep-equal "^1.0.1"
extend "^3.0.2"
fast-diff "1.1.2"
quill-delta@^4.2.2:
version "4.2.2"
resolved "https://registry.npmmirror.com/quill-delta/-/quill-delta-4.2.2.tgz#015397d046e0a3bed087cd8a51f98c11a1b8f351"
integrity sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg==
dependencies:
fast-diff "1.2.0"
lodash.clonedeep "^4.5.0"
lodash.isequal "^4.5.0"
quill@^1.3.7:
version "1.3.7"
resolved "https://registry.npmmirror.com/quill/-/quill-1.3.7.tgz#da5b2f3a2c470e932340cdbf3668c9f21f9286e8"
integrity sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==
dependencies:
clone "^2.1.1"
deep-equal "^1.0.1"
eventemitter3 "^2.0.3"
extend "^3.0.2"
parchment "^1.1.4"
quill-delta "^3.6.2"
range-parser@~1.2.1:
version "1.2.1"
resolved "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
@ -997,6 +1325,21 @@ raw-body@2.5.2:
iconv-lite "0.4.24"
unpipe "1.0.0"
readdirp@^4.0.1:
version "4.0.2"
resolved "https://registry.npmmirror.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a"
integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==
regexp.prototype.flags@^1.5.1:
version "1.5.3"
resolved "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42"
integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==
dependencies:
call-bind "^1.0.7"
define-properties "^1.2.1"
es-errors "^1.3.0"
set-function-name "^2.0.2"
rollup@^4.20.0:
version "4.21.1"
resolved "https://registry.npmmirror.com/rollup/-/rollup-4.21.1.tgz#65b9b9e9de9a64604fab083fb127f3e9eac2935d"
@ -1032,6 +1375,17 @@ safe-buffer@5.2.1:
resolved "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sass@^1.81.0:
version "1.81.0"
resolved "https://registry.npmmirror.com/sass/-/sass-1.81.0.tgz#a9010c0599867909dfdbad057e4a6fbdd5eec941"
integrity sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==
dependencies:
chokidar "^4.0.0"
immutable "^5.0.2"
source-map-js ">=0.6.2 <2.0.0"
optionalDependencies:
"@parcel/watcher" "^2.4.1"
save@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/save/-/save-2.9.0.tgz#6659375fadeaf58e4abc6a90ec6b0fb2e2232e0f"
@ -1042,6 +1396,13 @@ save@^2.9.0:
lodash.assign "^4.2.0"
mingo "^6.1.0"
scss@^0.2.4:
version "0.2.4"
resolved "https://registry.npmmirror.com/scss/-/scss-0.2.4.tgz#040d903ed37c5d4fa4ad33ae1fd389ac12a4e065"
integrity sha512-4u8V87F+Q/upVhUmhPnB4C1R11xojkRkWjExL2v0CX2EXTg18VrKd+9JWoeyCp2VEMdSpJsyAvVU+rVjogh51A==
dependencies:
ometa "0.2.2"
send@0.19.0:
version "0.19.0"
resolved "https://registry.npmmirror.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
@ -1083,6 +1444,16 @@ set-function-length@^1.2.1:
gopd "^1.0.1"
has-property-descriptors "^1.0.2"
set-function-name@^2.0.2:
version "2.0.2"
resolved "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985"
integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==
dependencies:
define-data-property "^1.1.4"
es-errors "^1.3.0"
functions-have-names "^1.2.3"
has-property-descriptors "^1.0.2"
setprototypeof@1.2.0:
version "1.2.0"
resolved "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
@ -1098,6 +1469,11 @@ side-channel@^1.0.6:
get-intrinsic "^1.2.4"
object-inspect "^1.13.1"
"source-map-js@>=0.6.2 <2.0.0":
version "1.2.1"
resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
@ -1133,6 +1509,13 @@ to-fast-properties@^2.0.0:
resolved "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
toidentifier@1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
@ -1172,7 +1555,7 @@ vite@^5.4.1:
optionalDependencies:
fsevents "~2.3.3"
vue-demi@*:
vue-demi@*, vue-demi@^0.14.10:
version "0.14.10"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==

Loading…
Cancel
Save