优化
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
---
|
||||
type: "always_apply"
|
||||
---
|
||||
|
||||
1.使用中文问回答所有问题;
|
||||
2.未经允许不可以删除任何文件;
|
||||
3.所有开发都必须遵循当前现有的项目规范;
|
||||
4.前端所有接口的访问尽可能走网关调用;
|
||||
5.为不同(local,dev,prod)环境创建单独的配置文件,可以在部署时通过参数选择要使用的配置文件;
|
||||
6.Controller层不允许写业务代码,业务代码写在service层中;
|
||||
7.除了特殊情况下的异常,一般情况下不需要try-catch,由全局异常处理机制处理
|
||||
8.所有Controller层接口定义要完整,入参使用request封装请求,出参是response封装出参,使用项目已有的Result做接口返回
|
||||
9.所有对项目的变更要遵循当前的项目现有规范
|
||||
10.禁止在新增的Controller层的路由前面添加/api
|
||||
11.与当前用户相关的接口,禁止直接传递用户id,需要后端根据当前登录用户,接口调用的token获取当前登录的用户信息
|
||||
@@ -1,18 +0,0 @@
|
||||
# 数据库配置
|
||||
MYSQL_ROOT_PASSWORD=EmotionMuseum2025*#
|
||||
MYSQL_DATABASE=emotion_museum
|
||||
MYSQL_USER=root
|
||||
MYSQL_PASSWORD=EmotionMuseum2025#
|
||||
|
||||
# Redis配置
|
||||
REDIS_PASSWORD=
|
||||
|
||||
# Nacos配置
|
||||
NACOS_AUTH_ENABLE=false
|
||||
|
||||
# 应用配置
|
||||
SPRING_PROFILES_ACTIVE=docker
|
||||
TZ=Asia/Shanghai
|
||||
|
||||
# Coze API配置 (与开发环境一致)
|
||||
COZE_API_TOKEN=pat_GCR4qKzqpf90wMCvKsldMrB18KG3QsLDci65bZthssKsbLxu8X70BKYumleDcabO
|
||||
@@ -1,38 +0,0 @@
|
||||
# 情绪博物馆生产环境配置文件
|
||||
# 用于Docker Compose和部署脚本
|
||||
|
||||
# 基础配置
|
||||
TZ=Asia/Shanghai
|
||||
APP_VERSION=1.0.0
|
||||
SPRING_PROFILES_ACTIVE=prod
|
||||
|
||||
# 服务器配置
|
||||
SERVER_HOST=47.111.10.27
|
||||
SERVER_USER=root
|
||||
SERVER_IP=47.111.10.27
|
||||
|
||||
# 数据库配置
|
||||
MYSQL_ROOT_PASSWORD=123456
|
||||
MYSQL_DATABASE=emotion_museum
|
||||
MYSQL_USER=emotion
|
||||
MYSQL_PASSWORD=EmotionDB2024!
|
||||
MYSQL_HOST=localhost
|
||||
MYSQL_PORT=3306
|
||||
|
||||
# Redis配置
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
|
||||
# Nacos配置
|
||||
NACOS_SERVER_ADDR=localhost:8848
|
||||
NACOS_AUTH_ENABLE=false
|
||||
|
||||
# Coze API配置
|
||||
COZE_API_TOKEN=pat_GCR4qKzqpf90wMCvKsldMrB18KG3QsLDci65bZthssKsbLxu8X70BKYumleDcabO
|
||||
|
||||
# 目录配置
|
||||
REMOTE_BASE_DIR=/data
|
||||
REMOTE_BUILDS_DIR=/data/builds
|
||||
REMOTE_WEB_DIR=/data/www/emotion-museum/web
|
||||
REMOTE_LOGS_DIR=/data/logs/emotion-museum
|
||||
REMOTE_PROGRAMS_DIR=/data/programs
|
||||
Generated
+1
-1
@@ -3,7 +3,7 @@
|
||||
<component name="AugmentWebviewStateStore">
|
||||
<option name="stateMap">
|
||||
<map>
|
||||
<entry key="CHAT_STATE" value="{"currentConversationId":"__NEW_AGENT__","conversations":{"036b95bf-0e85-468f-8841-83bb6c16c707":{"id":"036b95bf-0e85-468f-8841-83bb6c16c707","createdAtIso":"2025-07-15T08:46:03.668Z","lastInteractedAtIso":"2025-07-15T08:46:03.668Z","chatHistory":[],"feedbackStates":{},"toolUseStates":{},"draftExchange":{"request_message":"","rich_text_json_repr":{"type":"doc","content":[{"type":"paragraph"}]},"mentioned_items":[],"status":"draft"},"requestIds":[],"isPinned":false,"isShareable":false,"extraData":{"hasDirtyEdits":false},"personaType":0},"__NEW_AGENT__":{"id":"__NEW_AGENT__","createdAtIso":"2025-07-15T08:46:03.764Z","lastInteractedAtIso":"2025-07-15T08:46:03.816Z","chatHistory":[],"feedbackStates":{},"toolUseStates":{},"draftExchange":{"request_message":"","rich_text_json_repr":{"type":"doc","content":[{"type":"paragraph"}]},"mentioned_items":[],"status":"draft"},"requestIds":[],"isPinned":false,"isShareable":false,"extraData":{"hasDirtyEdits":false,"isAgentConversation":true,"baselineTimestamp":0},"personaType":0,"rootTaskUuid":"91b4236a-b9d0-4964-9424-1adb7d5a1c45"}},"agentExecutionMode":"auto","isPanelCollapsed":true,"displayedAnnouncements":[],"sortConversationsBy":"lastMessageTimestamp","sendMode":"send"}" />
|
||||
<entry key="CHAT_STATE" value="{"currentConversationId":"__NEW_AGENT__","conversations":{"__NEW_AGENT__":{"id":"__NEW_AGENT__","createdAtIso":"2025-07-15T08:46:03.764Z","lastInteractedAtIso":"2025-07-25T07:02:47.273Z","chatHistory":[],"feedbackStates":{},"toolUseStates":{},"draftExchange":{"request_message":"后端","rich_text_json_repr":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"后端"}]}]},"mentioned_items":[],"status":"draft"},"requestIds":[],"isPinned":false,"isShareable":false,"extraData":{"hasDirtyEdits":false,"isAgentConversation":true,"baselineTimestamp":0},"personaType":0,"rootTaskUuid":"91b4236a-b9d0-4964-9424-1adb7d5a1c45"}},"agentExecutionMode":"auto","isPanelCollapsed":true,"displayedAnnouncements":[],"sortConversationsBy":"lastMessageTimestamp","sendMode":"send"}" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
Generated
+4
-25
@@ -16,40 +16,19 @@
|
||||
<entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct-processor/1.5.3.Final/mapstruct-processor-1.5.3.Final.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.5.3.Final/mapstruct-1.5.3.Final.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct-processor/1.5.3.Final/mapstruct-processor-1.5.3.Final.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.5.3.Final/mapstruct-1.5.3.Final.jar" />
|
||||
</processorPath>
|
||||
<module name="emotion-websocket" />
|
||||
<module name="emotion-stats" />
|
||||
<module name="emotion-auth" />
|
||||
<module name="emotion-ai" />
|
||||
<module name="emotion-reward" />
|
||||
<module name="emotion-user" />
|
||||
<module name="emotion-gateway" />
|
||||
<module name="emotion-explore" />
|
||||
<module name="emotion-common" />
|
||||
<module name="emotion-growth" />
|
||||
<module name="emotion-record" />
|
||||
</profile>
|
||||
<profile name="Annotation profile for emotion-ai" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<processorPath useClasspath="false">
|
||||
<entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct-processor/1.5.3.Final/mapstruct-processor-1.5.3.Final.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.5.3.Final/mapstruct-1.5.3.Final.jar" />
|
||||
</processorPath>
|
||||
<module name="emotion-ai" />
|
||||
</profile>
|
||||
<profile name="Annotation profile for emotion-gateway" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<processorPath useClasspath="false">
|
||||
<entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct-processor/1.5.3.Final/mapstruct-processor-1.5.3.Final.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.5.3.Final/mapstruct-1.5.3.Final.jar" />
|
||||
</processorPath>
|
||||
<module name="emotion-gateway" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel>
|
||||
<module name="common" target="17" />
|
||||
|
||||
Generated
+15
@@ -13,5 +13,20 @@
|
||||
</jdbc-additional-properties>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="emotion_museum" uuid="01470282-aaf1-4f16-a5c2-d558bf1bc142">
|
||||
<driver-ref>mysql.8</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<imported>true</imported>
|
||||
<remarks>$PROJECT_DIR$/backend/emotion-websocket/src/main/resources/application-prod.yml</remarks>
|
||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:mysql://47.111.10.27:3306/?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT</jdbc-url>
|
||||
<jdbc-additional-properties>
|
||||
<property name="com.intellij.clouds.kubernetes.db.host.port" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.resource.type" value="Deployment" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.container.port" />
|
||||
</jdbc-additional-properties>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+4
@@ -3,6 +3,8 @@
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-ai/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-ai/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-auth/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-auth/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-common/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-common/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-explore/src/main/java" charset="UTF-8" />
|
||||
@@ -19,6 +21,8 @@
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-stats/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-user/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-user/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-websocket/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/backend/emotion-websocket/src/main/resources" charset="UTF-8" />
|
||||
<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$/server/backend/src/main/java" charset="UTF-8" />
|
||||
|
||||
Generated
+1
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/backend-single/src/main/resources/sql/mysql_emotion_museum_final.sql" dialect="MySQL" />
|
||||
<file url="file://$PROJECT_DIR$/backend/mysql_emotion_museum_final.sql" dialect="MySQL" />
|
||||
</component>
|
||||
</project>
|
||||
Executable
+230
@@ -0,0 +1,230 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 情绪博物馆后端服务部署脚本
|
||||
# 使用生产环境配置,日志保存到 /data/logs/emotion-museum/single
|
||||
|
||||
set -e
|
||||
|
||||
# 配置变量
|
||||
APP_NAME="emotion-museum-single"
|
||||
JAR_NAME="emotion-single-1.0.0.jar"
|
||||
JAR_PATH="./${JAR_NAME}"
|
||||
LOG_DIR="./logs/"
|
||||
PID_FILE="/tmp/${APP_NAME}.pid"
|
||||
JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOG_DIR}/heapdump.hprof"
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 检查 jar 文件是否存在
|
||||
check_jar() {
|
||||
if [ ! -f "$JAR_PATH" ]; then
|
||||
log_error "JAR 文件不存在: $JAR_PATH"
|
||||
log_info "请先执行打包命令: mvn clean package -Pprod"
|
||||
exit 1
|
||||
fi
|
||||
log_info "JAR 文件检查通过: $JAR_PATH"
|
||||
}
|
||||
|
||||
# 创建日志目录
|
||||
create_log_dir() {
|
||||
if [ ! -d "$LOG_DIR" ]; then
|
||||
log_info "创建日志目录: $LOG_DIR"
|
||||
mkdir -p "$LOG_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
# 停止旧服务
|
||||
stop_service() {
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
log_info "停止旧服务 (PID: $PID)"
|
||||
kill "$PID"
|
||||
|
||||
# 等待服务停止
|
||||
for i in {1..30}; do
|
||||
if ! ps -p "$PID" > /dev/null 2>&1; then
|
||||
log_info "服务已停止"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# 强制停止
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
log_warn "强制停止服务 (PID: $PID)"
|
||||
kill -9 "$PID"
|
||||
fi
|
||||
else
|
||||
log_warn "PID 文件存在但进程不存在,清理 PID 文件"
|
||||
fi
|
||||
rm -f "$PID_FILE"
|
||||
else
|
||||
log_info "没有找到 PID 文件,服务可能未运行"
|
||||
fi
|
||||
}
|
||||
|
||||
# 启动新服务
|
||||
start_service() {
|
||||
log_info "启动新服务..."
|
||||
|
||||
# 启动命令
|
||||
nohup java $JAVA_OPTS \
|
||||
-Dspring.profiles.active=prod \
|
||||
-Dlogging.file.path=$LOG_DIR \
|
||||
-Dlogging.file.name=$LOG_DIR/application.log \
|
||||
-jar "$JAR_PATH" \
|
||||
> "$LOG_DIR/startup.log" 2>&1 &
|
||||
|
||||
# 保存 PID
|
||||
echo $! > "$PID_FILE"
|
||||
|
||||
log_info "服务启动中,PID: $(cat $PID_FILE)"
|
||||
log_info "启动日志: $LOG_DIR/startup.log"
|
||||
log_info "应用日志: $LOG_DIR/application.log"
|
||||
}
|
||||
|
||||
# 检查服务状态
|
||||
check_status() {
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
log_info "服务运行中 (PID: $PID)"
|
||||
return 0
|
||||
else
|
||||
log_error "PID 文件存在但进程不存在"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_error "PID 文件不存在,服务未运行"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 等待服务启动
|
||||
wait_for_startup() {
|
||||
log_info "等待服务启动..."
|
||||
for i in {1..60}; do
|
||||
if check_status > /dev/null 2>&1; then
|
||||
# 检查端口是否监听(假设使用 8080 端口)
|
||||
if netstat -tlnp 2>/dev/null | grep -q ":8080.*LISTEN"; then
|
||||
log_info "服务启动成功!"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
log_error "服务启动超时,请检查日志: $LOG_DIR/startup.log"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 显示服务信息
|
||||
show_info() {
|
||||
log_info "=== 服务信息 ==="
|
||||
log_info "应用名称: $APP_NAME"
|
||||
log_info "JAR 文件: $JAR_PATH"
|
||||
log_info "日志目录: $LOG_DIR"
|
||||
log_info "PID 文件: $PID_FILE"
|
||||
log_info "Java 参数: $JAVA_OPTS"
|
||||
|
||||
if check_status > /dev/null 2>&1; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
log_info "服务状态: 运行中 (PID: $PID)"
|
||||
|
||||
# 显示内存使用情况
|
||||
if command -v jstat > /dev/null 2>&1; then
|
||||
log_info "内存使用情况:"
|
||||
jstat -gc "$PID" | head -2
|
||||
fi
|
||||
else
|
||||
log_info "服务状态: 未运行"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
log_info "开始部署 $APP_NAME 服务..."
|
||||
|
||||
# 检查 jar 文件
|
||||
check_jar
|
||||
|
||||
# 创建日志目录
|
||||
create_log_dir
|
||||
|
||||
# 停止旧服务
|
||||
stop_service
|
||||
|
||||
# 启动新服务
|
||||
start_service
|
||||
|
||||
# 等待启动
|
||||
if wait_for_startup; then
|
||||
log_info "部署成功!"
|
||||
show_info
|
||||
else
|
||||
log_error "部署失败!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 处理命令行参数
|
||||
case "${1:-deploy}" in
|
||||
"deploy")
|
||||
main
|
||||
;;
|
||||
"start")
|
||||
check_jar
|
||||
create_log_dir
|
||||
start_service
|
||||
wait_for_startup
|
||||
;;
|
||||
"stop")
|
||||
stop_service
|
||||
;;
|
||||
"restart")
|
||||
stop_service
|
||||
sleep 2
|
||||
check_jar
|
||||
create_log_dir
|
||||
start_service
|
||||
wait_for_startup
|
||||
;;
|
||||
"status")
|
||||
show_info
|
||||
;;
|
||||
"logs")
|
||||
if [ -f "$LOG_DIR/application.log" ]; then
|
||||
tail -f "$LOG_DIR/application.log"
|
||||
else
|
||||
log_error "日志文件不存在: $LOG_DIR/application.log"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 {deploy|start|stop|restart|status|logs}"
|
||||
echo " deploy - 部署服务(默认)"
|
||||
echo " start - 启动服务"
|
||||
echo " stop - 停止服务"
|
||||
echo " restart - 重启服务"
|
||||
echo " status - 查看服务状态"
|
||||
echo " logs - 查看实时日志"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
+2
-243
@@ -1,245 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 单体服务部署脚本
|
||||
# 作者: emotion-museum
|
||||
# 日期: 2025-07-21
|
||||
|
||||
set -e
|
||||
|
||||
REMOTE_HOST="root@47.111.10.27"
|
||||
REMOTE_JAR_DIR="/data/builds"
|
||||
REMOTE_LOG_DIR="/data/logs/emotion-museum"
|
||||
SERVICE_NAME="emotion-single"
|
||||
JAR_FILE="target/emotion-single-1.0.0.jar"
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
# 检查JAR文件
|
||||
check_jar() {
|
||||
log_info "检查JAR文件..."
|
||||
if [ ! -f "$JAR_FILE" ]; then
|
||||
log_error "JAR文件不存在: $JAR_FILE"
|
||||
log_info "请先运行: ./build.sh"
|
||||
exit 1
|
||||
fi
|
||||
log_success "JAR文件存在: $JAR_FILE"
|
||||
}
|
||||
|
||||
# 检查SSH连接
|
||||
check_connection() {
|
||||
log_info "检查远程服务器连接..."
|
||||
if ssh -o ConnectTimeout=10 "$REMOTE_HOST" "echo 'SSH连接成功'" > /dev/null 2>&1; then
|
||||
log_success "远程服务器连接正常"
|
||||
else
|
||||
log_error "无法连接到远程服务器: $REMOTE_HOST"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 停止旧的微服务
|
||||
stop_old_services() {
|
||||
log_info "停止旧的微服务..."
|
||||
|
||||
ssh "$REMOTE_HOST" "
|
||||
echo '🛑 停止所有emotion相关的Java进程...'
|
||||
|
||||
# 停止所有emotion相关的Java进程
|
||||
pkill -f 'emotion-.*\.jar' 2>/dev/null || echo '没有找到emotion相关进程'
|
||||
|
||||
# 等待进程完全停止
|
||||
sleep 5
|
||||
|
||||
# 检查是否还有残留进程
|
||||
REMAINING=\$(ps aux | grep -E 'emotion-.*\.jar' | grep -v grep | wc -l)
|
||||
if [ \$REMAINING -gt 0 ]; then
|
||||
echo '强制停止残留进程...'
|
||||
pkill -9 -f 'emotion-.*\.jar' 2>/dev/null || true
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
echo '✅ 旧服务停止完成'
|
||||
"
|
||||
|
||||
log_success "旧的微服务已停止"
|
||||
}
|
||||
|
||||
# 清理旧的部署文件
|
||||
cleanup_old_files() {
|
||||
log_info "清理旧的部署文件..."
|
||||
|
||||
ssh "$REMOTE_HOST" "
|
||||
echo '🧹 清理旧的JAR文件...'
|
||||
rm -f $REMOTE_JAR_DIR/emotion-*.jar 2>/dev/null || true
|
||||
|
||||
echo '🧹 清理旧的日志文件...'
|
||||
find $REMOTE_LOG_DIR -name '*.log' -mtime +7 -delete 2>/dev/null || true
|
||||
|
||||
echo '✅ 清理完成'
|
||||
"
|
||||
|
||||
log_success "旧的部署文件已清理"
|
||||
}
|
||||
|
||||
# 创建必要目录
|
||||
create_directories() {
|
||||
log_info "创建必要目录..."
|
||||
|
||||
ssh "$REMOTE_HOST" "
|
||||
mkdir -p $REMOTE_JAR_DIR
|
||||
mkdir -p $REMOTE_LOG_DIR
|
||||
mkdir -p /data/uploads/emotion-museum
|
||||
|
||||
echo '✅ 目录创建完成'
|
||||
"
|
||||
|
||||
log_success "必要目录已创建"
|
||||
}
|
||||
|
||||
# 上传JAR文件
|
||||
upload_jar() {
|
||||
log_info "上传JAR文件..."
|
||||
|
||||
scp "$JAR_FILE" "$REMOTE_HOST:$REMOTE_JAR_DIR/"
|
||||
|
||||
# 验证上传
|
||||
REMOTE_SIZE=$(ssh "$REMOTE_HOST" "ls -lh $REMOTE_JAR_DIR/emotion-single-1.0.0.jar | awk '{print \$5}'")
|
||||
log_success "JAR文件上传成功 (远程大小: $REMOTE_SIZE)"
|
||||
}
|
||||
|
||||
# 启动服务
|
||||
start_service() {
|
||||
log_info "启动单体服务..."
|
||||
|
||||
ssh "$REMOTE_HOST" "
|
||||
cd $REMOTE_JAR_DIR
|
||||
|
||||
echo '🚀 启动emotion-single服务...'
|
||||
nohup java -Xms512m -Xmx1024m \\
|
||||
-Dspring.profiles.active=prod \\
|
||||
-Dserver.port=8080 \\
|
||||
-jar emotion-single-1.0.0.jar \\
|
||||
> $REMOTE_LOG_DIR/emotion-single.log 2>&1 &
|
||||
|
||||
echo '⏳ 等待服务启动...'
|
||||
sleep 15
|
||||
|
||||
# 检查进程
|
||||
if pgrep -f emotion-single-1.0.0.jar > /dev/null; then
|
||||
echo '✅ 服务进程启动成功'
|
||||
else
|
||||
echo '❌ 服务进程启动失败'
|
||||
tail -20 $REMOTE_LOG_DIR/emotion-single.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查端口
|
||||
if netstat -tlnp | grep :8080 > /dev/null; then
|
||||
echo '✅ 服务端口8080正在监听'
|
||||
else
|
||||
echo '⚠️ 服务端口8080未监听,可能还在启动中'
|
||||
fi
|
||||
"
|
||||
|
||||
log_success "单体服务启动完成"
|
||||
}
|
||||
|
||||
# 健康检查
|
||||
health_check() {
|
||||
log_info "执行健康检查..."
|
||||
|
||||
# 等待服务完全启动
|
||||
sleep 10
|
||||
|
||||
# 检查健康端点
|
||||
if curl -f -s "http://47.111.10.27:8080/api/health" > /dev/null; then
|
||||
log_success "✅ 健康检查通过: http://47.111.10.27:8080/api/health"
|
||||
else
|
||||
log_warning "⚠️ 健康检查失败,查看日志..."
|
||||
ssh "$REMOTE_HOST" "tail -20 $REMOTE_LOG_DIR/emotion-single.log"
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示服务状态
|
||||
show_status() {
|
||||
log_info "显示服务状态..."
|
||||
|
||||
ssh "$REMOTE_HOST" "
|
||||
echo '📊 服务状态:'
|
||||
echo '=================='
|
||||
|
||||
# 检查进程
|
||||
echo -n 'emotion-single进程: '
|
||||
if pgrep -f emotion-single-1.0.0.jar > /dev/null; then
|
||||
echo '✅ 运行中'
|
||||
ps aux | grep emotion-single-1.0.0.jar | grep -v grep | head -1
|
||||
else
|
||||
echo '❌ 未运行'
|
||||
fi
|
||||
|
||||
# 检查端口
|
||||
echo -n 'emotion-single端口(8080): '
|
||||
if netstat -tlnp | grep :8080 > /dev/null; then
|
||||
echo '✅ 监听中'
|
||||
else
|
||||
echo '❌ 未监听'
|
||||
fi
|
||||
|
||||
echo ''
|
||||
echo '📋 访问地址:'
|
||||
echo ' 健康检查: http://47.111.10.27:8080/api/health'
|
||||
echo ' 前端页面: http://47.111.10.27/emotion/happy/'
|
||||
"
|
||||
|
||||
log_success "服务状态检查完成"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
log_info "🚀 开始部署emotion-single服务..."
|
||||
|
||||
check_jar
|
||||
check_connection
|
||||
stop_old_services
|
||||
cleanup_old_files
|
||||
create_directories
|
||||
upload_jar
|
||||
start_service
|
||||
health_check
|
||||
show_status
|
||||
|
||||
log_success "🎉 部署完成!"
|
||||
echo ""
|
||||
echo "📋 部署结果:"
|
||||
echo " ✅ 单体服务已启动"
|
||||
echo " ✅ 旧的微服务已清理"
|
||||
echo " ✅ 服务正常运行"
|
||||
echo ""
|
||||
echo "🔧 下一步:"
|
||||
echo " 1. 访问前端: http://47.111.10.27/emotion/happy/"
|
||||
echo " 2. 测试API: http://47.111.10.27:8080/api/health"
|
||||
echo " 3. 查看日志: ssh $REMOTE_HOST 'tail -f $REMOTE_LOG_DIR/emotion-single.log'"
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
mvn clean package -Pprod
|
||||
echo "后端已打包,target 目录下的 jar 包可部署到服务器"
|
||||
|
||||
@@ -179,10 +179,10 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.emotion.common.Result;
|
||||
import com.emotion.entity.EmotionRecord;
|
||||
import com.emotion.service.EmotionRecordService;
|
||||
import com.emotion.util.CurrentUserUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -11,7 +12,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
@@ -23,7 +23,7 @@ import java.util.*;
|
||||
* @date 2025-07-22
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/emotion-records")
|
||||
@RequestMapping("/emotion-records")
|
||||
@Tag(name = "情绪记录管理", description = "用户情绪记录的增删改查功能")
|
||||
public class EmotionRecordController {
|
||||
|
||||
@@ -64,16 +64,18 @@ public class EmotionRecordController {
|
||||
/**
|
||||
* 获取用户情绪记录列表
|
||||
*/
|
||||
@Operation(summary = "获取用户情绪记录列表", description = "分页获取指定用户的情绪记录,按创建时间倒序")
|
||||
@GetMapping("/user/{userId}")
|
||||
@Operation(summary = "获取用户情绪记录列表", description = "分页获取当前用户的情绪记录,按创建时间倒序")
|
||||
@GetMapping("/user")
|
||||
public Result<IPage<EmotionRecord>> getRecordList(
|
||||
@Parameter(description = "用户ID") @PathVariable String userId,
|
||||
@Parameter(description = "页码,从1开始") @RequestParam(defaultValue = "1") Integer current,
|
||||
@Parameter(description = "每页大小") @RequestParam(defaultValue = "10") Integer size) {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
log.info("获取用户情绪记录列表: userId={}, current={}, size={}", userId, current, size);
|
||||
|
||||
try {
|
||||
IPage<EmotionRecord> page = emotionRecordService.getByUserIdWithPage(userId, current, size);
|
||||
|
||||
log.info("获取用户情绪记录成功: userId={}, total={}, records={}",
|
||||
@@ -81,12 +83,44 @@ public class EmotionRecordController {
|
||||
|
||||
return Result.success(page);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("用户认证失败: {}", e.getMessage());
|
||||
return Result.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户情绪记录失败: userId={}", userId, e);
|
||||
log.error("获取用户情绪记录失败", e);
|
||||
return Result.error("获取情绪记录失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户最近情绪记录
|
||||
*/
|
||||
@Operation(summary = "获取用户最近情绪记录", description = "获取当前用户最近的情绪记录列表")
|
||||
@GetMapping("/user/recent")
|
||||
public Result<List<EmotionRecord>> getRecentRecords(
|
||||
@Parameter(description = "限制数量") @RequestParam(defaultValue = "5") Integer limit) {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
log.info("获取用户最近情绪记录: userId={}, limit={}", userId, limit);
|
||||
|
||||
List<EmotionRecord> records = emotionRecordService.getRecentByUserId(userId, limit);
|
||||
|
||||
log.info("获取用户最近情绪记录成功: userId={}, records={}", userId, records.size());
|
||||
|
||||
return Result.success(records);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("用户认证失败: {}", e.getMessage());
|
||||
return Result.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户最近情绪记录失败", e);
|
||||
return Result.error("获取最近记录失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取情绪记录详情
|
||||
*/
|
||||
|
||||
@@ -2,8 +2,8 @@ package com.emotion.controller;
|
||||
|
||||
import com.emotion.common.Result;
|
||||
import com.emotion.service.AIChatService;
|
||||
import com.emotion.util.CurrentUserUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -19,7 +19,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/emotion-summary")
|
||||
@RequestMapping("/emotion-summary")
|
||||
@Tag(name = "情绪总结管理", description = "用户情绪记录总结和分析功能")
|
||||
public class EmotionSummaryController {
|
||||
|
||||
@@ -27,39 +27,46 @@ public class EmotionSummaryController {
|
||||
private AIChatService aiChatService;
|
||||
|
||||
@Operation(summary = "生成用户当天的情绪记录总结", description = "基于用户当天的聊天记录生成情绪分析和记录")
|
||||
@PostMapping("/generate/{userId}")
|
||||
public Result<Map<String, Object>> generateEmotionSummary(
|
||||
@Parameter(description = "用户ID") @PathVariable String userId) {
|
||||
@PostMapping("/generate")
|
||||
public Result<Map<String, Object>> generateEmotionSummary() {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
log.info("收到生成情绪记录总结请求: userId={}", userId);
|
||||
|
||||
try {
|
||||
// 调用AI服务生成情绪总结
|
||||
Map<String, Object> result = aiChatService.generateEmotionSummary(userId);
|
||||
|
||||
if ((Boolean) result.get("success")) {
|
||||
log.info("情绪记录总结生成成功: userId={}", userId);
|
||||
return Result.success(result, "情绪记录总结生成成功");
|
||||
return Result.success("情绪记录总结生成成功", result);
|
||||
} else {
|
||||
String message = (String) result.get("message");
|
||||
log.warn("情绪记录总结生成失败: userId={}, message={}", userId, message);
|
||||
return Result.error(message);
|
||||
}
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("用户认证失败: {}", e.getMessage());
|
||||
return Result.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("生成情绪记录总结时发生异常: userId={}", userId, e);
|
||||
log.error("生成情绪记录总结时发生异常", e);
|
||||
return Result.error("生成情绪记录总结失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "获取用户情绪记录总结状态", description = "检查用户今天是否已经生成过情绪记录")
|
||||
@GetMapping("/status/{userId}")
|
||||
public Result<Map<String, Object>> getEmotionSummaryStatus(
|
||||
@Parameter(description = "用户ID") @PathVariable String userId) {
|
||||
@GetMapping("/status")
|
||||
public Result<Map<String, Object>> getEmotionSummaryStatus() {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
log.info("查询用户情绪记录总结状态: userId={}", userId);
|
||||
|
||||
try {
|
||||
// 这里可以添加检查用户今天是否已经生成过情绪记录的逻辑
|
||||
// 暂时返回基本状态信息
|
||||
Map<String, Object> status = Map.of(
|
||||
@@ -70,8 +77,11 @@ public class EmotionSummaryController {
|
||||
|
||||
return Result.success(status);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("用户认证失败: {}", e.getMessage());
|
||||
return Result.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("查询情绪记录总结状态时发生异常: userId={}", userId, e);
|
||||
log.error("查询情绪记录总结状态时发生异常", e);
|
||||
return Result.error("查询状态失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.emotion.dto.request.MessageCreateRequest;
|
||||
import com.emotion.dto.response.MessageResponse;
|
||||
import com.emotion.entity.Message;
|
||||
import com.emotion.service.MessageService;
|
||||
import com.emotion.util.CurrentUserUtil;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -126,10 +127,15 @@ public class MessageController {
|
||||
/**
|
||||
* 根据用户ID分页查询消息
|
||||
*/
|
||||
@GetMapping("/user/{userId}/page")
|
||||
public Result<PageResult<MessageResponse>> getPageByUserId(@PathVariable String userId,
|
||||
@Valid PageRequest request) {
|
||||
IPage<Message> page = messageService.getByUserIdWithPage(userId, Math.toIntExact(request.getCurrent()), Math.toIntExact(request.getSize()));
|
||||
@GetMapping("/user/page")
|
||||
public Result<PageResult<MessageResponse>> getPageByUserId(@Valid PageRequest request) {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
IPage<Message> page = messageService.getByUserIdWithPage(userId, Math.toIntExact(request.getCurrent()),
|
||||
Math.toIntExact(request.getSize()));
|
||||
List<MessageResponse> responses = page.getRecords().stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
@@ -142,20 +148,55 @@ public class MessageController {
|
||||
pageResult.setRecords(responses);
|
||||
|
||||
return Result.success(pageResult);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和关键词搜索消息
|
||||
*/
|
||||
@GetMapping("/user/{userId}/search")
|
||||
public Result<List<MessageResponse>> searchByUserId(@PathVariable String userId,
|
||||
@GetMapping("/user/search")
|
||||
public Result<List<MessageResponse>> searchByUserId(
|
||||
@RequestParam String keyword,
|
||||
@RequestParam(defaultValue = "50") Integer limit) {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
List<Message> messages = messageService.searchByUserIdAndKeyword(userId, keyword, limit);
|
||||
List<MessageResponse> responses = messages.stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(responses);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户最近的聊天记录
|
||||
*/
|
||||
@GetMapping("/user/recent")
|
||||
public Result<List<MessageResponse>> getRecentMessages(
|
||||
@RequestParam(defaultValue = "10") Integer limit) {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
List<Message> messages = messageService.getRecentByUserId(userId, limit);
|
||||
List<MessageResponse> responses = messages.stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(responses);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -145,5 +145,28 @@ public class Message extends BaseEntity {
|
||||
@TableField("metadata")
|
||||
private String metadata;
|
||||
|
||||
/**
|
||||
* 用户ID (注册用户或访客用户)
|
||||
*/
|
||||
@TableField("user_id")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 用户类型 (registered/guest)
|
||||
*/
|
||||
@TableField("user_type")
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* Coze消息角色 (user/assistant/system)
|
||||
*/
|
||||
@TableField("coze_role")
|
||||
private String cozeRole;
|
||||
|
||||
/**
|
||||
* Coze消息内容类型 (text/image/file等)
|
||||
*/
|
||||
@TableField("coze_content_type")
|
||||
private String cozeContentType;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.emotion.interceptor;
|
||||
|
||||
import com.emotion.util.JwtUtil;
|
||||
import com.emotion.util.UserContextHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -64,19 +65,32 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从token中获取用户信息并设置到请求属性中
|
||||
// 从token中获取用户信息并设置到请求属性和上下文中
|
||||
String userId = jwtUtil.getUserIdFromToken(token);
|
||||
String username = jwtUtil.getUsernameFromToken(token);
|
||||
|
||||
// 设置到请求属性中(兼容现有代码)
|
||||
request.setAttribute("userId", userId);
|
||||
request.setAttribute("username", username);
|
||||
request.setAttribute("token", token);
|
||||
|
||||
// 设置到线程本地上下文中(推荐使用)
|
||||
UserContextHolder.setCurrentUserId(userId);
|
||||
UserContextHolder.setCurrentUsername(username);
|
||||
UserContextHolder.setCurrentToken(token);
|
||||
|
||||
log.debug("Token验证成功,用户: {} ({})", username, userId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
// 请求完成后清除用户上下文,防止内存泄漏
|
||||
UserContextHolder.clear();
|
||||
log.debug("请求完成,已清除用户上下文");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为公开接口(不需要认证)
|
||||
*/
|
||||
@@ -89,9 +103,6 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
|
||||
"/api/auth/refresh-token",
|
||||
"/api/health",
|
||||
"/api/ws/chat",
|
||||
"/api/emotion-records", // 情绪记录接口
|
||||
"/api/emotion-summary", // 情绪总结接口
|
||||
"/message", // 消息接口
|
||||
"/swagger-ui",
|
||||
"/v3/api-docs",
|
||||
"/actuator"
|
||||
|
||||
@@ -68,4 +68,16 @@ public interface MessageMapper extends BaseMapper<Message> {
|
||||
List<Message> searchByUserIdAndKeyword(@Param("userId") String userId,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取最近的消息
|
||||
*/
|
||||
@Select("SELECT m.* FROM message m " +
|
||||
"INNER JOIN conversation c ON m.conversation_id = c.id " +
|
||||
"WHERE c.user_id = #{userId} " +
|
||||
"AND m.is_deleted = 0 " +
|
||||
"ORDER BY m.create_time DESC " +
|
||||
"LIMIT #{limit}")
|
||||
List<Message> getRecentByUserId(@Param("userId") String userId,
|
||||
@Param("limit") Integer limit);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ public interface MessageService extends IService<Message> {
|
||||
*/
|
||||
List<Message> searchByUserIdAndKeyword(String userId, String keyword, Integer limit);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取最近的消息
|
||||
*/
|
||||
List<Message> getRecentByUserId(String userId, Integer limit);
|
||||
|
||||
/**
|
||||
* 查询会话的最后一条消息
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.emotion.dto.websocket.ChatRequest;
|
||||
import com.emotion.dto.websocket.ConnectRequest;
|
||||
import com.emotion.dto.websocket.WebSocketMessage;
|
||||
import com.emotion.entity.Message;
|
||||
import com.emotion.entity.Conversation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
@@ -219,28 +220,51 @@ public class WebSocketService {
|
||||
// 使用线程池异步处理AI响应
|
||||
new Thread(() -> {
|
||||
try {
|
||||
String userId = request.getSenderId();
|
||||
String conversationId = request.getConversationId();
|
||||
|
||||
// 如果没有会话ID,创建新会话
|
||||
if (conversationId == null || conversationId.trim().isEmpty()) {
|
||||
conversationId = createNewConversation(userId, request);
|
||||
request.setConversationId(conversationId);
|
||||
}
|
||||
|
||||
// 确保会话存在并更新活跃时间
|
||||
ensureConversationExists(conversationId, userId, request);
|
||||
|
||||
// 保存用户消息到数据库
|
||||
Message userMessage = new Message();
|
||||
userMessage.setConversationId(request.getConversationId());
|
||||
userMessage.setCreateBy(request.getSenderId());
|
||||
userMessage.setConversationId(conversationId);
|
||||
userMessage.setUserId(userId);
|
||||
userMessage
|
||||
.setUserType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest");
|
||||
userMessage.setContent(request.getContent());
|
||||
userMessage.setType(request.getMessageType().name());
|
||||
userMessage.setSender(request.getSenderType().name());
|
||||
userMessage.setType("text");
|
||||
userMessage.setSender("user");
|
||||
userMessage.setCozeRole("user");
|
||||
userMessage.setCozeContentType("text");
|
||||
messageService.createMessage(userMessage);
|
||||
|
||||
// 调用AI服务
|
||||
String aiReply = aiChatService.sendChatMessage(
|
||||
request.getConversationId(),
|
||||
conversationId,
|
||||
request.getContent(),
|
||||
request.getSenderId()
|
||||
userId
|
||||
);
|
||||
|
||||
// 如果AI回复包含换行符,分割成多条消息
|
||||
String[] replyParts = aiReply.split("\\n\\n|\\n");
|
||||
|
||||
for (String part : replyParts) {
|
||||
if (part.trim().isEmpty())
|
||||
continue;
|
||||
|
||||
// 构建AI回复消息
|
||||
WebSocketMessage aiMessage = WebSocketMessage.builder()
|
||||
.messageId(UUID.randomUUID().toString())
|
||||
.conversationId(request.getConversationId())
|
||||
.conversationId(conversationId)
|
||||
.type(WebSocketMessage.MessageType.TEXT)
|
||||
.content(aiReply)
|
||||
.content(part.trim())
|
||||
.senderId("ai")
|
||||
.senderType(WebSocketMessage.SenderType.AI)
|
||||
.status(WebSocketMessage.MessageStatus.SENT)
|
||||
@@ -249,20 +273,31 @@ public class WebSocketService {
|
||||
|
||||
// 保存AI回复到数据库
|
||||
Message aiDbMessage = new Message();
|
||||
aiDbMessage.setConversationId(request.getConversationId());
|
||||
aiDbMessage.setCreateBy("ai");
|
||||
aiDbMessage.setContent(aiReply);
|
||||
aiDbMessage.setConversationId(conversationId);
|
||||
aiDbMessage.setUserId(userId);
|
||||
aiDbMessage.setUserType(
|
||||
request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest");
|
||||
aiDbMessage.setContent(part.trim());
|
||||
aiDbMessage.setType("text");
|
||||
aiDbMessage.setSender("ai");
|
||||
aiDbMessage.setCozeRole("assistant");
|
||||
aiDbMessage.setCozeContentType("text");
|
||||
messageService.createMessage(aiDbMessage);
|
||||
|
||||
// 发送AI回复
|
||||
messagingTemplate.convertAndSendToUser(request.getSenderId(), "/queue/messages", aiMessage);
|
||||
messagingTemplate.convertAndSendToUser(userId, "/queue/messages", aiMessage);
|
||||
|
||||
if (request.getConversationId() != null) {
|
||||
messagingTemplate.convertAndSend("/topic/conversation/" + request.getConversationId(), aiMessage);
|
||||
if (conversationId != null) {
|
||||
messagingTemplate.convertAndSend("/topic/conversation/" + conversationId, aiMessage);
|
||||
}
|
||||
|
||||
// 添加短暂延迟,模拟自然对话
|
||||
Thread.sleep(500);
|
||||
}
|
||||
|
||||
// 更新会话的最后活跃时间和消息数量
|
||||
updateConversationActivity(conversationId);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("AI响应处理失败", e);
|
||||
sendErrorMessage(request.getSenderId(), "AI服务暂时不可用,请稍后重试");
|
||||
@@ -293,4 +328,85 @@ public class WebSocketService {
|
||||
public int getOnlineUserCount() {
|
||||
return onlineUsers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新会话
|
||||
*/
|
||||
private String createNewConversation(String userId, ChatRequest request) {
|
||||
try {
|
||||
String conversationId = "conv_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
|
||||
|
||||
Conversation conversation = Conversation.builder()
|
||||
.userId(userId)
|
||||
.userType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest")
|
||||
.title("新对话")
|
||||
.type("chat")
|
||||
.conversationStatus("active")
|
||||
.startTime(LocalDateTime.now())
|
||||
.lastActiveTime(LocalDateTime.now())
|
||||
.messageCount(0)
|
||||
.build();
|
||||
|
||||
// 设置ID
|
||||
conversation.setId(conversationId);
|
||||
|
||||
conversationService.save(conversation);
|
||||
log.info("创建新会话: conversationId={}, userId={}", conversationId, userId);
|
||||
|
||||
return conversationId;
|
||||
} catch (Exception e) {
|
||||
log.error("创建新会话失败: userId={}", userId, e);
|
||||
throw new RuntimeException("创建会话失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保会话存在并更新活跃时间
|
||||
*/
|
||||
private void ensureConversationExists(String conversationId, String userId, ChatRequest request) {
|
||||
try {
|
||||
Conversation conversation = conversationService.getById(conversationId);
|
||||
if (conversation == null) {
|
||||
// 如果会话不存在,创建一个
|
||||
conversation = Conversation.builder()
|
||||
.userId(userId)
|
||||
.userType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest")
|
||||
.title("对话")
|
||||
.type("chat")
|
||||
.conversationStatus("active")
|
||||
.startTime(LocalDateTime.now())
|
||||
.lastActiveTime(LocalDateTime.now())
|
||||
.messageCount(0)
|
||||
.build();
|
||||
|
||||
// 设置ID
|
||||
conversation.setId(conversationId);
|
||||
|
||||
conversationService.save(conversation);
|
||||
log.info("创建会话: conversationId={}, userId={}", conversationId, userId);
|
||||
} else {
|
||||
// 更新最后活跃时间
|
||||
conversation.setLastActiveTime(LocalDateTime.now());
|
||||
conversationService.updateById(conversation);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("确保会话存在失败: conversationId={}, userId={}", conversationId, userId, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话活跃状态
|
||||
*/
|
||||
private void updateConversationActivity(String conversationId) {
|
||||
try {
|
||||
Conversation conversation = conversationService.getById(conversationId);
|
||||
if (conversation != null) {
|
||||
conversation.setLastActiveTime(LocalDateTime.now());
|
||||
conversation.setMessageCount((conversation.getMessageCount() != null ? conversation.getMessageCount() : 0) + 1);
|
||||
conversationService.updateById(conversation);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("更新会话活跃状态失败: conversationId={}", conversationId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@ import com.emotion.entity.Message;
|
||||
import com.emotion.entity.Conversation;
|
||||
import com.emotion.entity.CozeApiCall;
|
||||
import com.emotion.entity.EmotionRecord;
|
||||
import com.emotion.entity.EmotionAnalysis;
|
||||
import com.emotion.service.AIChatService;
|
||||
import com.emotion.service.MessageService;
|
||||
import com.emotion.service.ConversationService;
|
||||
import com.emotion.service.CozeApiCallService;
|
||||
import com.emotion.service.EmotionRecordService;
|
||||
import com.emotion.service.EmotionAnalysisService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -59,6 +61,9 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
@Autowired
|
||||
private EmotionRecordService emotionRecordService;
|
||||
|
||||
@Autowired
|
||||
private EmotionAnalysisService emotionAnalysisService;
|
||||
|
||||
@Value("${emotion.coze.api.token:}")
|
||||
private String cozeApiToken;
|
||||
|
||||
@@ -941,7 +946,7 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
log.info("情绪分析总结生成完成: {}", emotionSummary);
|
||||
|
||||
// 解析AI返回的情绪分析结果
|
||||
EmotionAnalysisResult analysisResult = parseEmotionSummary(emotionSummary);
|
||||
EmotionAnalysis analysisResult = parseEmotionSummary(emotionSummary);
|
||||
|
||||
// 创建情绪记录
|
||||
EmotionRecord emotionRecord = createEmotionRecord(userId, analysisResult, chatHistory);
|
||||
@@ -1011,37 +1016,39 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
/**
|
||||
* 解析情绪分析总结结果
|
||||
*/
|
||||
private EmotionAnalysisResult parseEmotionSummary(String summary) {
|
||||
private EmotionAnalysis parseEmotionSummary(String summary) {
|
||||
try {
|
||||
// 尝试从AI回复中提取JSON
|
||||
String jsonStr = extractJsonFromSummary(summary);
|
||||
if (jsonStr != null) {
|
||||
JSONObject json = JSON.parseObject(jsonStr);
|
||||
|
||||
EmotionAnalysisResult result = new EmotionAnalysisResult();
|
||||
result.setPrimaryEmotion(json.getString("primaryEmotion"));
|
||||
result.setIntensity(json.getDoubleValue("intensity"));
|
||||
result.setTriggers(json.getString("triggers"));
|
||||
result.setEmotionTrend(json.getString("emotionTrend"));
|
||||
result.setSuggestions(json.getString("suggestions"));
|
||||
result.setSummary(json.getString("summary"));
|
||||
|
||||
return result;
|
||||
return EmotionAnalysis.builder()
|
||||
.primaryEmotion(json.getString("primaryEmotion"))
|
||||
.intensity(BigDecimal.valueOf(json.getDoubleValue("intensity")))
|
||||
.keywords(json.getString("triggers"))
|
||||
.suggestion(json.getString("suggestions"))
|
||||
.text(summary)
|
||||
.polarity(determinePolarity(json.getString("primaryEmotion")))
|
||||
.confidence(BigDecimal.valueOf(0.85))
|
||||
.analysisTime(LocalDateTime.now())
|
||||
.build();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析情绪分析结果失败,使用默认值: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 如果解析失败,返回默认结果
|
||||
EmotionAnalysisResult defaultResult = new EmotionAnalysisResult();
|
||||
defaultResult.setPrimaryEmotion("平静");
|
||||
defaultResult.setIntensity(0.5);
|
||||
defaultResult.setTriggers("日常对话");
|
||||
defaultResult.setEmotionTrend("相对稳定");
|
||||
defaultResult.setSuggestions("保持当前的积极状态");
|
||||
defaultResult.setSummary(summary);
|
||||
|
||||
return defaultResult;
|
||||
return EmotionAnalysis.builder()
|
||||
.primaryEmotion("平静")
|
||||
.intensity(BigDecimal.valueOf(0.5))
|
||||
.keywords("日常对话")
|
||||
.suggestion("保持当前的积极状态")
|
||||
.text(summary)
|
||||
.polarity("neutral")
|
||||
.confidence(BigDecimal.valueOf(0.5))
|
||||
.analysisTime(LocalDateTime.now())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1063,14 +1070,14 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
/**
|
||||
* 创建情绪记录
|
||||
*/
|
||||
private EmotionRecord createEmotionRecord(String userId, EmotionAnalysisResult analysisResult, String chatHistory) {
|
||||
private EmotionRecord createEmotionRecord(String userId, EmotionAnalysis analysisResult, String chatHistory) {
|
||||
EmotionRecord record = EmotionRecord.builder()
|
||||
.userId(userId)
|
||||
.recordDate(LocalDate.now())
|
||||
.emotionType(analysisResult.getPrimaryEmotion())
|
||||
.intensity(BigDecimal.valueOf(analysisResult.getIntensity()))
|
||||
.triggers(analysisResult.getTriggers())
|
||||
.description(analysisResult.getSummary())
|
||||
.intensity(analysisResult.getIntensity())
|
||||
.triggers(analysisResult.getKeywords())
|
||||
.description(analysisResult.getText())
|
||||
.notes("基于当天聊天记录自动生成的情绪分析")
|
||||
.tags("AI分析,聊天记录,情绪总结")
|
||||
.build();
|
||||
@@ -1078,37 +1085,14 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
emotionRecordService.save(record);
|
||||
log.info("情绪记录创建成功: recordId={}", record.getId());
|
||||
|
||||
// 设置情绪分析记录的关联ID并保存
|
||||
analysisResult.setUserId(userId);
|
||||
analysisResult.setMessageId(record.getId()); // 关联到情绪记录ID
|
||||
|
||||
emotionAnalysisService.save(analysisResult);
|
||||
log.info("情绪分析记录创建成功: analysisId={}", analysisResult.getId());
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* 情绪分析结果内部类
|
||||
*/
|
||||
public static class EmotionAnalysisResult {
|
||||
private String primaryEmotion;
|
||||
private Double intensity;
|
||||
private String triggers;
|
||||
private String emotionTrend;
|
||||
private String suggestions;
|
||||
private String summary;
|
||||
|
||||
// Getters and Setters
|
||||
public String getPrimaryEmotion() { return primaryEmotion; }
|
||||
public void setPrimaryEmotion(String primaryEmotion) { this.primaryEmotion = primaryEmotion; }
|
||||
|
||||
public Double getIntensity() { return intensity; }
|
||||
public void setIntensity(Double intensity) { this.intensity = intensity; }
|
||||
|
||||
public String getTriggers() { return triggers; }
|
||||
public void setTriggers(String triggers) { this.triggers = triggers; }
|
||||
|
||||
public String getEmotionTrend() { return emotionTrend; }
|
||||
public void setEmotionTrend(String emotionTrend) { this.emotionTrend = emotionTrend; }
|
||||
|
||||
public String getSuggestions() { return suggestions; }
|
||||
public void setSuggestions(String suggestions) { this.suggestions = suggestions; }
|
||||
|
||||
public String getSummary() { return summary; }
|
||||
public void setSummary(String summary) { this.summary = summary; }
|
||||
}
|
||||
}
|
||||
@@ -195,4 +195,10 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
|
||||
// 通过conversation表关联查询用户的消息,根据关键词搜索
|
||||
return this.baseMapper.searchByUserIdAndKeyword(userId, keyword, limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Message> getRecentByUserId(String userId, Integer limit) {
|
||||
// 获取用户最近的消息,按时间倒序
|
||||
return this.baseMapper.getRecentByUserId(userId, limit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.emotion.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 当前用户工具类
|
||||
* 提供便捷的方法获取当前登录用户信息
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-25
|
||||
*/
|
||||
@Slf4j
|
||||
public class CurrentUserUtil {
|
||||
|
||||
/**
|
||||
* 获取当前用户ID
|
||||
*
|
||||
* @return 当前用户ID,如果未登录则返回null
|
||||
*/
|
||||
public static String getCurrentUserId() {
|
||||
return UserContextHolder.getCurrentUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户名
|
||||
*
|
||||
* @return 当前用户名,如果未登录则返回null
|
||||
*/
|
||||
public static String getCurrentUsername() {
|
||||
return UserContextHolder.getCurrentUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户Token
|
||||
*
|
||||
* @return 当前用户Token,如果未登录则返回null
|
||||
*/
|
||||
public static String getCurrentToken() {
|
||||
return UserContextHolder.getCurrentToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前是否有用户登录
|
||||
*
|
||||
* @return 是否有用户登录
|
||||
*/
|
||||
public static boolean isUserLoggedIn() {
|
||||
return UserContextHolder.hasUserContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户ID,如果未登录则抛出异常
|
||||
*
|
||||
* @return 当前用户ID
|
||||
* @throws IllegalStateException 如果用户未登录
|
||||
*/
|
||||
public static String requireCurrentUserId() {
|
||||
String userId = getCurrentUserId();
|
||||
if (userId == null || userId.trim().isEmpty()) {
|
||||
throw new IllegalStateException("用户未登录或认证失败");
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户名,如果未登录则抛出异常
|
||||
*
|
||||
* @return 当前用户名
|
||||
* @throws IllegalStateException 如果用户未登录
|
||||
*/
|
||||
public static String requireCurrentUsername() {
|
||||
String username = getCurrentUsername();
|
||||
if (username == null || username.trim().isEmpty()) {
|
||||
throw new IllegalStateException("用户未登录或认证失败");
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户上下文摘要信息
|
||||
*
|
||||
* @return 用户上下文摘要
|
||||
*/
|
||||
public static String getContextSummary() {
|
||||
return UserContextHolder.getContextSummary();
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,11 @@ public class UserContextHolder {
|
||||
*/
|
||||
private static final ThreadLocal<String> REQUEST_ID_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Token线程本地变量
|
||||
*/
|
||||
private static final ThreadLocal<String> TOKEN_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 设置当前用户ID
|
||||
*
|
||||
@@ -132,6 +137,25 @@ public class UserContextHolder {
|
||||
return REQUEST_ID_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前Token
|
||||
*
|
||||
* @param token Token
|
||||
*/
|
||||
public static void setCurrentToken(String token) {
|
||||
TOKEN_HOLDER.set(token);
|
||||
log.debug("设置当前Token: {}", token != null ? "***" : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Token
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public static String getCurrentToken() {
|
||||
return TOKEN_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户上下文信息
|
||||
*
|
||||
@@ -188,6 +212,13 @@ public class UserContextHolder {
|
||||
REQUEST_ID_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前Token
|
||||
*/
|
||||
public static void clearToken() {
|
||||
TOKEN_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有用户上下文信息
|
||||
*/
|
||||
@@ -197,6 +228,7 @@ public class UserContextHolder {
|
||||
clearUserType();
|
||||
clearClientIp();
|
||||
clearRequestId();
|
||||
clearToken();
|
||||
log.debug("清除所有用户上下文信息");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# Coze API 配置示例
|
||||
# 请根据您的实际情况修改以下配置
|
||||
|
||||
emotion:
|
||||
coze:
|
||||
api:
|
||||
# Coze API 访问令牌 - 从 https://www.coze.cn/docs/developer_guides/pat 获取
|
||||
token: "your-coze-api-token-here"
|
||||
|
||||
# Coze API 基础URL
|
||||
base-url: "https://api.coze.cn"
|
||||
|
||||
# 聊天相关配置
|
||||
chat:
|
||||
talk:
|
||||
# 聊天机器人ID - 从您的 Coze 工作空间获取
|
||||
bot-id: "your-chat-bot-id-here"
|
||||
# 工作流ID(可选)- 如果使用工作流模式
|
||||
workflow-id: "your-chat-workflow-id-here"
|
||||
|
||||
summary:
|
||||
# 总结机器人ID(可选)- 如果有专门的总结机器人
|
||||
bot-id: "your-summary-bot-id-here"
|
||||
# 总结工作流ID(可选)
|
||||
workflow-id: "your-summary-workflow-id-here"
|
||||
|
||||
# 请求超时配置(毫秒)
|
||||
timeout: 30000
|
||||
|
||||
# 重试配置
|
||||
retry-count: 3
|
||||
retry-delay: 1000
|
||||
|
||||
# 配置说明:
|
||||
# 1. token: 个人访问令牌,需要在 Coze 平台创建
|
||||
# 2. bot-id: 机器人ID,在发布机器人时选择"发布到API"获得
|
||||
# 3. workflow-id: 工作流ID,如果使用工作流模式则需要配置
|
||||
# 4. base-url: 通常为 https://api.coze.cn,国际版可能不同
|
||||
# 5. 确保机器人已发布并启用API访问
|
||||
|
||||
# 重要提醒:
|
||||
# - 请勿将真实的 token 和 ID 提交到版本控制系统
|
||||
# - 建议使用环境变量或配置中心管理敏感信息
|
||||
# - 测试时可以先使用简单的聊天机器人验证配置
|
||||
@@ -74,39 +74,39 @@ DROP TABLE IF EXISTS user;
|
||||
-- 1. 用户表 (user)
|
||||
-- ============================================================================
|
||||
CREATE TABLE user (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
account VARCHAR(50) UNIQUE, -- 账号
|
||||
password VARCHAR(255) , -- 密码(加密后)
|
||||
username VARCHAR(50) UNIQUE, -- 用户名
|
||||
email VARCHAR(100) UNIQUE, -- 邮箱
|
||||
phone VARCHAR(20) UNIQUE, -- 手机号
|
||||
avatar VARCHAR(500), -- 头像URL
|
||||
nickname VARCHAR(50) , -- 昵称
|
||||
birth_date DATE, -- 生日
|
||||
location VARCHAR(100), -- 所在地
|
||||
bio TEXT, -- 个人简介
|
||||
member_level VARCHAR(20) DEFAULT 'free', -- 会员等级
|
||||
total_days INT DEFAULT 0, -- 使用天数
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
account VARCHAR(50) UNIQUE COMMENT '账号', -- 账号
|
||||
password VARCHAR(255) COMMENT '密码(加密后)', -- 密码(加密后)
|
||||
username VARCHAR(50) UNIQUE COMMENT '用户名', -- 用户名
|
||||
email VARCHAR(100) UNIQUE COMMENT '邮箱', -- 邮箱
|
||||
phone VARCHAR(20) UNIQUE COMMENT '手机号', -- 手机号
|
||||
avatar VARCHAR(500) COMMENT '头像URL', -- 头像URL
|
||||
nickname VARCHAR(50) COMMENT '昵称', -- 昵称
|
||||
birth_date DATE COMMENT '生日', -- 生日
|
||||
location VARCHAR(100) COMMENT '所在地', -- 所在地
|
||||
bio TEXT COMMENT '个人简介', -- 个人简介
|
||||
member_level VARCHAR(20) DEFAULT 'free' COMMENT '会员等级', -- 会员等级
|
||||
total_days INT DEFAULT 0 COMMENT '使用天数', -- 使用天数
|
||||
-- 成长数据
|
||||
self_awareness DECIMAL(5, 2) DEFAULT 50.00, -- 自我感知
|
||||
emotional_resilience DECIMAL(5, 2) DEFAULT 50.00, -- 情绪韧性
|
||||
action_power DECIMAL(5, 2) DEFAULT 50.00, -- 行动力
|
||||
empathy DECIMAL(5, 2) DEFAULT 50.00, -- 共情力
|
||||
life_enthusiasm DECIMAL(5, 2) DEFAULT 50.00, -- 生活热度
|
||||
self_awareness DECIMAL(5, 2) DEFAULT 50.00 COMMENT '自我感知', -- 自我感知
|
||||
emotional_resilience DECIMAL(5, 2) DEFAULT 50.00 COMMENT '情绪韧性', -- 情绪韧性
|
||||
action_power DECIMAL(5, 2) DEFAULT 50.00 COMMENT '行动力', -- 行动力
|
||||
empathy DECIMAL(5, 2) DEFAULT 50.00 COMMENT '共情力', -- 共情力
|
||||
life_enthusiasm DECIMAL(5, 2) DEFAULT 50.00 COMMENT '生活热度', -- 生活热度
|
||||
-- 状态字段
|
||||
status TINYINT DEFAULT 1, -- 状态: 0-禁用, 1-正常
|
||||
is_verified TINYINT DEFAULT 0, -- 是否已验证: 0-未验证, 1-已验证
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
|
||||
status TINYINT DEFAULT 1 COMMENT '状态: 0-禁用, 1-正常', -- 状态: 0-禁用, 1-正常
|
||||
is_verified TINYINT DEFAULT 0 COMMENT '是否已验证: 0-未验证, 1-已验证', -- 是否已验证: 0-未验证, 1-已验证
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '最后活跃时间', -- 最后活跃时间
|
||||
-- 第三方登录字段
|
||||
third_party_id VARCHAR(128), -- 第三方平台ID
|
||||
third_party_type VARCHAR(32), -- 第三方平台类型: wechat, qq, wechat-mp
|
||||
third_party_id VARCHAR(128) COMMENT '第三方平台ID', -- 第三方平台ID
|
||||
third_party_type VARCHAR(32) COMMENT '第三方平台类型: wechat, qq, wechat-mp', -- 第三方平台类型: wechat, qq, wechat-mp
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表';
|
||||
|
||||
-- ============================================================================
|
||||
@@ -114,41 +114,41 @@ CREATE TABLE user (
|
||||
-- 关联说明: user_id 关联 user.id,通过代码逻辑维护关联关系
|
||||
-- ============================================================================
|
||||
CREATE TABLE conversation (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) , -- 用户ID (关联user.id)
|
||||
user_type VARCHAR(20) DEFAULT 'registered', -- 用户类型: registered-注册用户, guest-访客用户
|
||||
title VARCHAR(200), -- 对话标题
|
||||
type VARCHAR(50) DEFAULT 'emotion_chat', -- 对话类型
|
||||
status VARCHAR(20) DEFAULT 'active', -- 状态: active-活跃, ended-结束, archived-归档
|
||||
coze_conversation_id VARCHAR(100), -- Coze对话ID
|
||||
bot_id VARCHAR(50), -- 使用的Bot ID
|
||||
workflow_id VARCHAR(50), -- 使用的Workflow ID
|
||||
initial_message TEXT, -- 初始消息
|
||||
context TEXT, -- 上下文信息
|
||||
primary_emotion VARCHAR(50), -- 主要情绪
|
||||
emotion_intensity DECIMAL(3, 2), -- 情绪强度
|
||||
emotion_trend VARCHAR(50), -- 情绪趋势
|
||||
keywords JSON, -- 关键词
|
||||
ai_insights TEXT, -- AI洞察
|
||||
confidence DECIMAL(3, 2), -- 分析置信度
|
||||
start_time DATETIME, -- 开始时间
|
||||
end_time DATETIME, -- 结束时间
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
|
||||
message_count INT DEFAULT 0, -- 消息数量
|
||||
total_tokens INT DEFAULT 0, -- 总Token使用量
|
||||
total_cost DECIMAL(10, 4) DEFAULT 0.0000, -- 总费用
|
||||
client_ip VARCHAR(45), -- 客户端IP地址 (支持IPv6)
|
||||
user_agent TEXT, -- 用户代理信息
|
||||
summary TEXT, -- 对话摘要
|
||||
tags JSON, -- 标签
|
||||
metadata JSON, -- 扩展元数据
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) COMMENT '用户ID (关联user.id)', -- 用户ID (关联user.id)
|
||||
user_type VARCHAR(20) DEFAULT 'registered' COMMENT '用户类型: registered-注册用户, guest-访客用户', -- 用户类型: registered-注册用户, guest-访客用户
|
||||
title VARCHAR(200) COMMENT '对话标题', -- 对话标题
|
||||
type VARCHAR(50) DEFAULT 'emotion_chat' COMMENT '对话类型', -- 对话类型
|
||||
status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active-活跃, ended-结束, archived-归档', -- 状态: active-活跃, ended-结束, archived-归档
|
||||
coze_conversation_id VARCHAR(100) COMMENT 'Coze对话ID', -- Coze对话ID
|
||||
bot_id VARCHAR(50) COMMENT '使用的Bot ID', -- 使用的Bot ID
|
||||
workflow_id VARCHAR(50) COMMENT '使用的Workflow ID', -- 使用的Workflow ID
|
||||
initial_message TEXT COMMENT '初始消息', -- 初始消息
|
||||
context TEXT COMMENT '上下文信息', -- 上下文信息
|
||||
primary_emotion VARCHAR(50) COMMENT '主要情绪', -- 主要情绪
|
||||
emotion_intensity DECIMAL(3, 2) COMMENT '情绪强度', -- 情绪强度
|
||||
emotion_trend VARCHAR(50) COMMENT '情绪趋势', -- 情绪趋势
|
||||
keywords JSON COMMENT '关键词', -- 关键词
|
||||
ai_insights TEXT COMMENT 'AI洞察', -- AI洞察
|
||||
confidence DECIMAL(3, 2) COMMENT '分析置信度', -- 分析置信度
|
||||
start_time DATETIME COMMENT '开始时间', -- 开始时间
|
||||
end_time DATETIME COMMENT '结束时间', -- 结束时间
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '最后活跃时间', -- 最后活跃时间
|
||||
message_count INT DEFAULT 0 COMMENT '消息数量', -- 消息数量
|
||||
total_tokens INT DEFAULT 0 COMMENT '总Token使用量', -- 总Token使用量
|
||||
total_cost DECIMAL(10, 4) DEFAULT 0.0000 COMMENT '总费用', -- 总费用
|
||||
client_ip VARCHAR(45) COMMENT '客户端IP地址 (支持IPv6)', -- 客户端IP地址 (支持IPv6)
|
||||
user_agent TEXT COMMENT '用户代理信息', -- 用户代理信息
|
||||
summary TEXT COMMENT '对话摘要', -- 对话摘要
|
||||
tags JSON COMMENT '标签', -- 标签
|
||||
metadata JSON COMMENT '扩展元数据', -- 扩展元数据
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '对话表';
|
||||
|
||||
-- ============================================================================
|
||||
@@ -156,368 +156,372 @@ CREATE TABLE conversation (
|
||||
-- 关联说明: conversation_id 关联 conversation.id,通过代码逻辑维护关联关系
|
||||
-- ============================================================================
|
||||
CREATE TABLE message (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
conversation_id VARCHAR(36) , -- 对话ID (关联conversation.id)
|
||||
content TEXT , -- 消息内容
|
||||
type VARCHAR(50) DEFAULT 'text', -- 消息类型
|
||||
sender VARCHAR(20) , -- 发送者: user-用户, assistant-AI助手
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, -- 消息时间戳
|
||||
coze_chat_id VARCHAR(50), -- Coze平台的聊天ID
|
||||
coze_message_id VARCHAR(50), -- Coze平台的消息ID
|
||||
status VARCHAR(20) DEFAULT 'sent', -- 消息状态: sending/sent/failed/processing
|
||||
error_message TEXT, -- 错误信息
|
||||
emotion_score DECIMAL(3, 2), -- 情绪评分
|
||||
emotion_type VARCHAR(50), -- 情绪类型
|
||||
emotion_confidence DECIMAL(3, 2), -- 情绪分析置信度
|
||||
prompt_tokens INT DEFAULT 0, -- 输入Token数
|
||||
completion_tokens INT DEFAULT 0, -- 输出Token数
|
||||
total_tokens INT DEFAULT 0, -- 总Token数
|
||||
api_cost DECIMAL(10, 6) DEFAULT 0.000000, -- API调用费用
|
||||
is_read TINYINT DEFAULT 0, -- 是否已读: 0-未读, 1-已读
|
||||
parent_message_id VARCHAR(36), -- 父消息ID(用于回复链)
|
||||
emotion_analysis JSON, -- 情绪分析结果
|
||||
metadata JSON, -- 扩展元数据
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
conversation_id VARCHAR(36) COMMENT '对话ID (关联conversation.id)', -- 对话ID (关联conversation.id)
|
||||
content TEXT COMMENT '消息内容', -- 消息内容
|
||||
type VARCHAR(50) DEFAULT 'text' COMMENT '消息类型', -- 消息类型
|
||||
sender VARCHAR(20) COMMENT '发送者: user-用户, assistant-AI助手', -- 发送者: user-用户, assistant-AI助手
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '消息时间戳', -- 消息时间戳
|
||||
coze_chat_id VARCHAR(50) COMMENT 'Coze平台的聊天ID', -- Coze平台的聊天ID
|
||||
coze_message_id VARCHAR(50) COMMENT 'Coze平台的消息ID', -- Coze平台的消息ID
|
||||
status VARCHAR(20) DEFAULT 'sent' COMMENT '消息状态: sending/sent/failed/processing', -- 消息状态: sending/sent/failed/processing
|
||||
error_message TEXT COMMENT '错误信息', -- 错误信息
|
||||
emotion_score DECIMAL(3, 2) COMMENT '情绪评分', -- 情绪评分
|
||||
emotion_type VARCHAR(50) COMMENT '情绪类型', -- 情绪类型
|
||||
emotion_confidence DECIMAL(3, 2) COMMENT '情绪分析置信度', -- 情绪分析置信度
|
||||
prompt_tokens INT DEFAULT 0 COMMENT '输入Token数', -- 输入Token数
|
||||
completion_tokens INT DEFAULT 0 COMMENT '输出Token数', -- 输出Token数
|
||||
total_tokens INT DEFAULT 0 COMMENT '总Token数', -- 总Token数
|
||||
api_cost DECIMAL(10, 6) DEFAULT 0.000000 COMMENT 'API调用费用', -- API调用费用
|
||||
is_read TINYINT DEFAULT 0 COMMENT '是否已读: 0-未读, 1-已读', -- 是否已读: 0-未读, 1-已读
|
||||
parent_message_id VARCHAR(36) COMMENT '父消息ID(用于回复链)', -- 父消息ID(用于回复链)
|
||||
emotion_analysis JSON COMMENT '情绪分析结果', -- 情绪分析结果
|
||||
metadata JSON COMMENT '扩展元数据', -- 扩展元数据
|
||||
user_id VARCHAR(36) COMMENT '用户ID (注册用户或访客用户)', -- 用户ID (注册用户或访客用户)
|
||||
user_type VARCHAR(20) COMMENT '用户类型 (registered/guest)', -- 用户类型 (registered/guest)
|
||||
coze_role VARCHAR(20) COMMENT 'Coze消息角色 (user/assistant/system)', -- Coze消息角色 (user/assistant/system)
|
||||
coze_content_type VARCHAR(50) COMMENT 'Coze消息内容类型 (text/image/file等)', -- Coze消息内容类型 (text/image/file等)
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 4. Coze API调用记录表 (coze_api_call) - 优化版本
|
||||
-- ============================================================================
|
||||
CREATE TABLE coze_api_call (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
conversation_id VARCHAR(36), -- 对话ID
|
||||
message_id VARCHAR(36), -- 消息ID
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
conversation_id VARCHAR(36) COMMENT '对话ID', -- 对话ID
|
||||
message_id VARCHAR(36) COMMENT '消息ID', -- 消息ID
|
||||
-- Coze API 信息
|
||||
coze_chat_id VARCHAR(50), -- Coze聊天ID
|
||||
coze_conversation_id VARCHAR(50), -- Coze对话ID
|
||||
bot_id VARCHAR(50) , -- Bot ID
|
||||
workflow_id VARCHAR(50), -- Workflow ID
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
coze_chat_id VARCHAR(50) COMMENT 'Coze聊天ID', -- Coze聊天ID
|
||||
coze_conversation_id VARCHAR(50) COMMENT 'Coze对话ID', -- Coze对话ID
|
||||
bot_id VARCHAR(50) COMMENT 'Bot ID', -- Bot ID
|
||||
workflow_id VARCHAR(50) COMMENT 'Workflow ID', -- Workflow ID
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
-- 请求信息
|
||||
request_type VARCHAR(20) , -- 请求类型: chat/stream/retrieve/messages
|
||||
request_url VARCHAR(500), -- 请求URL
|
||||
request_body JSON, -- 请求体
|
||||
request_headers JSON, -- 请求头
|
||||
request_type VARCHAR(20) COMMENT '请求类型: chat/stream/retrieve/messages', -- 请求类型: chat/stream/retrieve/messages
|
||||
request_url VARCHAR(500) COMMENT '请求URL', -- 请求URL
|
||||
request_body JSON COMMENT '请求体', -- 请求体
|
||||
request_headers JSON COMMENT '请求头', -- 请求头
|
||||
-- 用户消息内容
|
||||
user_message TEXT, -- 用户输入的消息内容
|
||||
user_message_type VARCHAR(20) DEFAULT 'text', -- 用户消息类型: text/image/file
|
||||
user_message TEXT COMMENT '用户输入的消息内容', -- 用户输入的消息内容
|
||||
user_message_type VARCHAR(20) DEFAULT 'text' COMMENT '用户消息类型: text/image/file', -- 用户消息类型: text/image/file
|
||||
-- AI回复内容
|
||||
ai_reply TEXT, -- AI回复的消息内容
|
||||
ai_reply_type VARCHAR(20) DEFAULT 'text', -- AI回复类型: text/image/file
|
||||
ai_reply TEXT COMMENT 'AI回复的消息内容', -- AI回复的消息内容
|
||||
ai_reply_type VARCHAR(20) DEFAULT 'text' COMMENT 'AI回复类型: text/image/file', -- AI回复类型: text/image/file
|
||||
-- 响应信息
|
||||
response_status INT, -- HTTP状态码
|
||||
response_body JSON, -- 响应体
|
||||
response_headers JSON, -- 响应头
|
||||
response_status INT COMMENT 'HTTP状态码', -- HTTP状态码
|
||||
response_body JSON COMMENT '响应体', -- 响应体
|
||||
response_headers JSON COMMENT '响应头', -- 响应头
|
||||
-- 轮询信息
|
||||
poll_count INT DEFAULT 0, -- 轮询次数
|
||||
poll_start_time DATETIME, -- 轮询开始时间
|
||||
poll_end_time DATETIME, -- 轮询结束时间
|
||||
final_status VARCHAR(20), -- 最终状态: completed/failed/timeout
|
||||
poll_count INT DEFAULT 0 COMMENT '轮询次数', -- 轮询次数
|
||||
poll_start_time DATETIME COMMENT '轮询开始时间', -- 轮询开始时间
|
||||
poll_end_time DATETIME COMMENT '轮询结束时间', -- 轮询结束时间
|
||||
final_status VARCHAR(20) COMMENT '最终状态: completed/failed/timeout', -- 最终状态: completed/failed/timeout
|
||||
-- 状态和时间
|
||||
status VARCHAR(20) , -- 调用状态: pending/success/failed/timeout
|
||||
start_time DATETIME , -- 开始时间
|
||||
end_time DATETIME, -- 结束时间
|
||||
duration_ms INT, -- 耗时(毫秒)
|
||||
status VARCHAR(20) COMMENT '调用状态: pending/success/failed/timeout', -- 调用状态: pending/success/failed/timeout
|
||||
start_time DATETIME COMMENT '开始时间', -- 开始时间
|
||||
end_time DATETIME COMMENT '结束时间', -- 结束时间
|
||||
duration_ms INT COMMENT '耗时(毫秒)', -- 耗时(毫秒)
|
||||
-- 使用统计
|
||||
prompt_tokens INT DEFAULT 0, -- 输入Token数
|
||||
completion_tokens INT DEFAULT 0, -- 输出Token数
|
||||
total_tokens INT DEFAULT 0, -- 总Token数
|
||||
cost DECIMAL(10, 6) DEFAULT 0.000000, -- 费用
|
||||
prompt_tokens INT DEFAULT 0 COMMENT '输入Token数', -- 输入Token数
|
||||
completion_tokens INT DEFAULT 0 COMMENT '输出Token数', -- 输出Token数
|
||||
total_tokens INT DEFAULT 0 COMMENT '总Token数', -- 总Token数
|
||||
cost DECIMAL(10, 6) DEFAULT 0.000000 COMMENT '费用', -- 费用
|
||||
-- 功能调用信息
|
||||
function_calls JSON, -- 函数调用记录
|
||||
function_results JSON, -- 函数调用结果
|
||||
function_calls JSON COMMENT '函数调用记录', -- 函数调用记录
|
||||
function_results JSON COMMENT '函数调用结果', -- 函数调用结果
|
||||
-- 错误信息
|
||||
error_code VARCHAR(50), -- 错误代码
|
||||
error_message TEXT, -- 错误信息
|
||||
error_code VARCHAR(50) COMMENT '错误代码', -- 错误代码
|
||||
error_message TEXT COMMENT '错误信息', -- 错误信息
|
||||
-- 扩展信息
|
||||
client_ip VARCHAR(45), -- 客户端IP
|
||||
user_agent TEXT, -- 用户代理
|
||||
session_id VARCHAR(100), -- 会话ID
|
||||
trace_id VARCHAR(100), -- 追踪ID
|
||||
metadata JSON, -- 扩展元数据
|
||||
client_ip VARCHAR(45) COMMENT '客户端IP', -- 客户端IP
|
||||
user_agent TEXT COMMENT '用户代理', -- 用户代理
|
||||
session_id VARCHAR(100) COMMENT '会话ID', -- 会话ID
|
||||
trace_id VARCHAR(100) COMMENT '追踪ID', -- 追踪ID
|
||||
metadata JSON COMMENT '扩展元数据', -- 扩展元数据
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Coze API调用记录表 - 完整版本';
|
||||
|
||||
-- ============================================================================
|
||||
-- 5. 情绪分析表 (emotion_analysis)
|
||||
-- ============================================================================
|
||||
CREATE TABLE emotion_analysis (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
message_id VARCHAR(36), -- 关联消息ID
|
||||
text TEXT , -- 分析文本
|
||||
primary_emotion VARCHAR(50), -- 主要情绪
|
||||
intensity DECIMAL(3, 2), -- 情绪强度
|
||||
polarity VARCHAR(20), -- 情绪极性: positive-积极, negative-消极, neutral-中性
|
||||
confidence DECIMAL(3, 2), -- 置信度
|
||||
emotions JSON, -- 情绪分布详情
|
||||
keywords JSON, -- 关键词列表
|
||||
suggestion TEXT, -- 建议
|
||||
analysis_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 分析时间
|
||||
metadata JSON, -- 扩展元数据
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
message_id VARCHAR(36) COMMENT '关联消息ID', -- 关联消息ID
|
||||
text TEXT COMMENT '分析文本', -- 分析文本
|
||||
primary_emotion VARCHAR(50) COMMENT '主要情绪', -- 主要情绪
|
||||
intensity DECIMAL(3, 2) COMMENT '情绪强度', -- 情绪强度
|
||||
polarity VARCHAR(20) COMMENT '情绪极性: positive-积极, negative-消极, neutral-中性', -- 情绪极性: positive-积极, negative-消极, neutral-中性
|
||||
confidence DECIMAL(3, 2) COMMENT '置信度', -- 置信度
|
||||
emotions JSON COMMENT '情绪分布详情', -- 情绪分布详情
|
||||
keywords JSON COMMENT '关键词列表', -- 关键词列表
|
||||
suggestion TEXT COMMENT '建议', -- 建议
|
||||
analysis_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '分析时间', -- 分析时间
|
||||
metadata JSON COMMENT '扩展元数据', -- 扩展元数据
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪分析表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 6. 情绪记录表 (emotion_record)
|
||||
-- ============================================================================
|
||||
CREATE TABLE emotion_record (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
record_date DATE , -- 记录日期
|
||||
emotion_type VARCHAR(50) , -- 情绪类型
|
||||
intensity DECIMAL(3, 2) , -- 情绪强度
|
||||
triggers TEXT, -- 触发因素
|
||||
description TEXT, -- 描述
|
||||
tags JSON, -- 标签
|
||||
weather VARCHAR(50), -- 天气
|
||||
location VARCHAR(100), -- 地点
|
||||
activity VARCHAR(100), -- 活动
|
||||
people VARCHAR(200), -- 相关人物
|
||||
notes TEXT, -- 备注
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
record_date DATE COMMENT '记录日期', -- 记录日期
|
||||
emotion_type VARCHAR(50) COMMENT '情绪类型', -- 情绪类型
|
||||
intensity DECIMAL(3, 2) COMMENT '情绪强度', -- 情绪强度
|
||||
triggers TEXT COMMENT '触发因素', -- 触发因素
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
tags JSON COMMENT '标签', -- 标签
|
||||
weather VARCHAR(50) COMMENT '天气', -- 天气
|
||||
location VARCHAR(100) COMMENT '地点', -- 地点
|
||||
activity VARCHAR(100) COMMENT '活动', -- 活动
|
||||
people VARCHAR(200) COMMENT '相关人物', -- 相关人物
|
||||
notes TEXT COMMENT '备注', -- 备注
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪记录表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 7. 成长课题表 (growth_topic)
|
||||
-- ============================================================================
|
||||
CREATE TABLE growth_topic (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
title VARCHAR(100) , -- 课题标题
|
||||
category VARCHAR(50) , -- 分类
|
||||
difficulty VARCHAR(20) , -- 难度: easy-简单, medium-中等, hard-困难
|
||||
description TEXT, -- 描述
|
||||
content TEXT, -- 内容
|
||||
duration_days INT, -- 持续天数
|
||||
unlock_conditions JSON, -- 解锁条件
|
||||
is_unlocked TINYINT DEFAULT 1, -- 是否解锁
|
||||
progress DECIMAL(5, 2) DEFAULT 0.00, -- 进度百分比
|
||||
completed_time DATETIME, -- 完成时间
|
||||
rewards JSON, -- 奖励
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
title VARCHAR(100) COMMENT '课题标题', -- 课题标题
|
||||
category VARCHAR(50) COMMENT '分类', -- 分类
|
||||
difficulty VARCHAR(20) COMMENT '难度: easy-简单, medium-中等, hard-困难', -- 难度: easy-简单, medium-中等, hard-困难
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
content TEXT COMMENT '内容', -- 内容
|
||||
duration_days INT COMMENT '持续天数', -- 持续天数
|
||||
unlock_conditions JSON COMMENT '解锁条件', -- 解锁条件
|
||||
is_unlocked TINYINT DEFAULT 1 COMMENT '是否解锁', -- 是否解锁
|
||||
progress DECIMAL(5, 2) DEFAULT 0.00 COMMENT '进度百分比', -- 进度百分比
|
||||
completed_time DATETIME COMMENT '完成时间', -- 完成时间
|
||||
rewards JSON COMMENT '奖励', -- 奖励
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成长课题表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 8. 课题互动表 (topic_interaction)
|
||||
-- ============================================================================
|
||||
CREATE TABLE topic_interaction (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
topic_id VARCHAR(36) , -- 课题ID
|
||||
type VARCHAR(50) , -- 互动类型
|
||||
content TEXT, -- 内容
|
||||
user_input TEXT, -- 用户输入
|
||||
ai_response TEXT, -- AI回应
|
||||
rating INT, -- 评分
|
||||
feedback TEXT, -- 反馈
|
||||
completed_time DATETIME, -- 完成时间
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
topic_id VARCHAR(36) COMMENT '课题ID', -- 课题ID
|
||||
type VARCHAR(50) COMMENT '互动类型', -- 互动类型
|
||||
content TEXT COMMENT '内容', -- 内容
|
||||
user_input TEXT COMMENT '用户输入', -- 用户输入
|
||||
ai_response TEXT COMMENT 'AI回应', -- AI回应
|
||||
rating INT COMMENT '评分', -- 评分
|
||||
feedback TEXT COMMENT '反馈', -- 反馈
|
||||
completed_time DATETIME COMMENT '完成时间', -- 完成时间
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '课题互动表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 9. 地点标记表 (location_pin)
|
||||
-- ============================================================================
|
||||
CREATE TABLE location_pin (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
name VARCHAR(100) , -- 地点名称
|
||||
type VARCHAR(50) , -- 地点类型
|
||||
category VARCHAR(50), -- 地点分类
|
||||
latitude DECIMAL(10, 8) , -- 纬度
|
||||
longitude DECIMAL(11, 8) , -- 经度
|
||||
address VARCHAR(200), -- 地址
|
||||
description TEXT, -- 描述
|
||||
created_by VARCHAR(36), -- 创建者
|
||||
likes INT DEFAULT 0, -- 点赞数
|
||||
visits INT DEFAULT 0, -- 访问数
|
||||
is_bookmarked TINYINT DEFAULT 0, -- 是否收藏
|
||||
last_visit_time DATETIME, -- 最后访问时间
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
name VARCHAR(100) COMMENT '地点名称', -- 地点名称
|
||||
type VARCHAR(50) COMMENT '地点类型', -- 地点类型
|
||||
category VARCHAR(50) COMMENT '地点分类', -- 地点分类
|
||||
latitude DECIMAL(10, 8) COMMENT '纬度', -- 纬度
|
||||
longitude DECIMAL(11, 8) COMMENT '经度', -- 经度
|
||||
address VARCHAR(200) COMMENT '地址', -- 地址
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
created_by VARCHAR(36) COMMENT '创建者', -- 创建者
|
||||
likes INT DEFAULT 0 COMMENT '点赞数', -- 点赞数
|
||||
visits INT DEFAULT 0 COMMENT '访问数', -- 访问数
|
||||
is_bookmarked TINYINT DEFAULT 0 COMMENT '是否收藏', -- 是否收藏
|
||||
last_visit_time DATETIME COMMENT '最后访问时间', -- 最后访问时间
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '地点标记表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 10. 社区帖子表 (community_post)
|
||||
-- ============================================================================
|
||||
CREATE TABLE community_post (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
location_id VARCHAR(36), -- 地点ID
|
||||
title VARCHAR(200), -- 标题
|
||||
content TEXT , -- 内容
|
||||
type VARCHAR(50) , -- 帖子类型
|
||||
images JSON, -- 图片列表
|
||||
tags JSON, -- 标签
|
||||
likes INT DEFAULT 0, -- 点赞数
|
||||
view_count INT DEFAULT 0, -- 浏览数
|
||||
comment_count INT DEFAULT 0, -- 评论数
|
||||
is_private TINYINT DEFAULT 0, -- 是否私密
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
location_id VARCHAR(36) COMMENT '地点ID', -- 地点ID
|
||||
title VARCHAR(200) COMMENT '标题', -- 标题
|
||||
content TEXT COMMENT '内容', -- 内容
|
||||
type VARCHAR(50) COMMENT '帖子类型', -- 帖子类型
|
||||
images JSON COMMENT '图片列表', -- 图片列表
|
||||
tags JSON COMMENT '标签', -- 标签
|
||||
likes INT DEFAULT 0 COMMENT '点赞数', -- 点赞数
|
||||
view_count INT DEFAULT 0 COMMENT '浏览数', -- 浏览数
|
||||
comment_count INT DEFAULT 0 COMMENT '评论数', -- 评论数
|
||||
is_private TINYINT DEFAULT 0 COMMENT '是否私密', -- 是否私密
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社区帖子表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 11. 评论表 (comment)
|
||||
-- ============================================================================
|
||||
CREATE TABLE comment (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
post_id VARCHAR(36) , -- 帖子ID
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
content TEXT , -- 评论内容
|
||||
reply_to_id VARCHAR(36), -- 回复的评论ID
|
||||
likes INT DEFAULT 0, -- 点赞数
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
post_id VARCHAR(36) COMMENT '帖子ID', -- 帖子ID
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
content TEXT COMMENT '评论内容', -- 评论内容
|
||||
reply_to_id VARCHAR(36) COMMENT '回复的评论ID', -- 回复的评论ID
|
||||
likes INT DEFAULT 0 COMMENT '点赞数', -- 点赞数
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 12. 成就表 (achievement)
|
||||
-- ============================================================================
|
||||
CREATE TABLE achievement (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
title VARCHAR(100) , -- 成就标题
|
||||
description TEXT, -- 描述
|
||||
category VARCHAR(50) , -- 分类
|
||||
icon VARCHAR(200), -- 图标
|
||||
rarity VARCHAR(20) , -- 稀有度
|
||||
condition_type VARCHAR(50), -- 条件类型
|
||||
condition_value JSON, -- 条件值
|
||||
rewards JSON, -- 奖励
|
||||
unlocked_time DATETIME, -- 解锁时间
|
||||
progress DECIMAL(5, 2) DEFAULT 0.00, -- 进度
|
||||
is_hidden TINYINT DEFAULT 0, -- 是否隐藏
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
title VARCHAR(100) COMMENT '成就标题', -- 成就标题
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
category VARCHAR(50) COMMENT '分类', -- 分类
|
||||
icon VARCHAR(200) COMMENT '图标', -- 图标
|
||||
rarity VARCHAR(20) COMMENT '稀有度', -- 稀有度
|
||||
condition_type VARCHAR(50) COMMENT '条件类型', -- 条件类型
|
||||
condition_value JSON COMMENT '条件值', -- 条件值
|
||||
rewards JSON COMMENT '奖励', -- 奖励
|
||||
unlocked_time DATETIME COMMENT '解锁时间', -- 解锁时间
|
||||
progress DECIMAL(5, 2) DEFAULT 0.00 COMMENT '进度', -- 进度
|
||||
is_hidden TINYINT DEFAULT 0 COMMENT '是否隐藏', -- 是否隐藏
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成就表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 13. 奖励表 (reward)
|
||||
-- ============================================================================
|
||||
CREATE TABLE reward (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
topic_id VARCHAR(36), -- 课题ID
|
||||
achievement_id VARCHAR(36), -- 成就ID
|
||||
type VARCHAR(50) , -- 奖励类型
|
||||
name VARCHAR(100) , -- 奖励名称
|
||||
description TEXT, -- 描述
|
||||
icon VARCHAR(200), -- 图标
|
||||
rarity VARCHAR(20), -- 稀有度
|
||||
value JSON, -- 奖励值
|
||||
earned_time DATETIME, -- 获得时间
|
||||
is_new TINYINT DEFAULT 1, -- 是否新获得
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
topic_id VARCHAR(36) COMMENT '课题ID', -- 课题ID
|
||||
achievement_id VARCHAR(36) COMMENT '成就ID', -- 成就ID
|
||||
type VARCHAR(50) COMMENT '奖励类型', -- 奖励类型
|
||||
name VARCHAR(100) COMMENT '奖励名称', -- 奖励名称
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
icon VARCHAR(200) COMMENT '图标', -- 图标
|
||||
rarity VARCHAR(20) COMMENT '稀有度', -- 稀有度
|
||||
value JSON COMMENT '奖励值', -- 奖励值
|
||||
earned_time DATETIME COMMENT '获得时间', -- 获得时间
|
||||
is_new TINYINT DEFAULT 1 COMMENT '是否新获得', -- 是否新获得
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '奖励表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 14. 访客用户表 (guest_user)
|
||||
-- ============================================================================
|
||||
CREATE TABLE guest_user (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
guest_user_id VARCHAR(50) UNIQUE, -- 访客用户ID (格式: guest_xxx)
|
||||
ip_address VARCHAR(45) , -- 客户端IP地址 (支持IPv6)
|
||||
user_agent TEXT, -- 用户代理信息
|
||||
nickname VARCHAR(50), -- 访客昵称
|
||||
avatar VARCHAR(500), -- 访客头像
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
|
||||
conversation_count INT DEFAULT 0, -- 会话数量
|
||||
message_count INT DEFAULT 0, -- 消息数量
|
||||
location VARCHAR(100), -- IP地址的地理位置信息
|
||||
device_info VARCHAR(200), -- 设备信息
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
guest_user_id VARCHAR(50) UNIQUE COMMENT '访客用户ID (格式: guest_xxx)', -- 访客用户ID (格式: guest_xxx)
|
||||
ip_address VARCHAR(45) COMMENT '客户端IP地址 (支持IPv6)', -- 客户端IP地址 (支持IPv6)
|
||||
user_agent TEXT COMMENT '用户代理信息', -- 用户代理信息
|
||||
nickname VARCHAR(50) COMMENT '访客昵称', -- 访客昵称
|
||||
avatar VARCHAR(500) COMMENT '访客头像', -- 访客头像
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '最后活跃时间', -- 最后活跃时间
|
||||
conversation_count INT DEFAULT 0 COMMENT '会话数量', -- 会话数量
|
||||
message_count INT DEFAULT 0 COMMENT '消息数量', -- 消息数量
|
||||
location VARCHAR(100) COMMENT 'IP地址的地理位置信息', -- IP地址的地理位置信息
|
||||
device_info VARCHAR(200) COMMENT '设备信息', -- 设备信息
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '访客用户表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 15. 用户统计表 (user_stats)
|
||||
-- ============================================================================
|
||||
CREATE TABLE user_stats (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) UNIQUE, -- 用户ID
|
||||
total_conversations INT DEFAULT 0, -- 总对话数
|
||||
total_messages INT DEFAULT 0, -- 总消息数
|
||||
total_emotions_recorded INT DEFAULT 0, -- 总情绪记录数
|
||||
topics_completed INT DEFAULT 0, -- 完成的课题数
|
||||
achievements_unlocked INT DEFAULT 0, -- 解锁的成就数
|
||||
total_points INT DEFAULT 0, -- 总积分
|
||||
consecutive_days INT DEFAULT 0, -- 连续使用天数
|
||||
max_consecutive_days INT DEFAULT 0, -- 最大连续天数
|
||||
locations_visited INT DEFAULT 0, -- 访问的地点数
|
||||
posts_created INT DEFAULT 0, -- 创建的帖子数
|
||||
comments_made INT DEFAULT 0, -- 评论数
|
||||
likes_received INT DEFAULT 0, -- 收到的点赞数
|
||||
social_interactions INT DEFAULT 0, -- 社交互动数
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) UNIQUE COMMENT '用户ID', -- 用户ID
|
||||
total_conversations INT DEFAULT 0 COMMENT '总对话数', -- 总对话数
|
||||
total_messages INT DEFAULT 0 COMMENT '总消息数', -- 总消息数
|
||||
total_emotions_recorded INT DEFAULT 0 COMMENT '总情绪记录数', -- 总情绪记录数
|
||||
topics_completed INT DEFAULT 0 COMMENT '完成的课题数', -- 完成的课题数
|
||||
achievements_unlocked INT DEFAULT 0 COMMENT '解锁的成就数', -- 解锁的成就数
|
||||
total_points INT DEFAULT 0 COMMENT '总积分', -- 总积分
|
||||
consecutive_days INT DEFAULT 0 COMMENT '连续使用天数', -- 连续使用天数
|
||||
max_consecutive_days INT DEFAULT 0 COMMENT '最大连续天数', -- 最大连续天数
|
||||
locations_visited INT DEFAULT 0 COMMENT '访问的地点数', -- 访问的地点数
|
||||
posts_created INT DEFAULT 0 COMMENT '创建的帖子数', -- 创建的帖子数
|
||||
comments_made INT DEFAULT 0 COMMENT '评论数', -- 评论数
|
||||
likes_received INT DEFAULT 0 COMMENT '收到的点赞数', -- 收到的点赞数
|
||||
social_interactions INT DEFAULT 0 COMMENT '社交互动数', -- 社交互动数
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户统计表';
|
||||
|
||||
-- ============================================================================
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
# 情绪博物馆后端服务部署说明
|
||||
|
||||
## 文件说明
|
||||
|
||||
- `deploy.sh` - 本地打包脚本
|
||||
- `deploy-server.sh` - 服务器部署脚本
|
||||
- `/data/programs/emotion-museum/emotion-simple-0.0.1-SNAPSHOT.jar` - 打包后的 JAR 文件
|
||||
|
||||
## 部署步骤
|
||||
|
||||
### 1. 本地打包
|
||||
|
||||
```bash
|
||||
# 在 backend-single 目录下执行
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
### 2. 上传到服务器
|
||||
|
||||
将以下文件上传到服务器:
|
||||
- `/data/programs/emotion-museum/emotion-simple-0.0.1-SNAPSHOT.jar`
|
||||
- `deploy-server.sh`
|
||||
|
||||
### 3. 服务器部署
|
||||
|
||||
```bash
|
||||
# 给脚本添加执行权限
|
||||
chmod +x deploy-server.sh
|
||||
|
||||
# 部署服务(默认操作)
|
||||
./deploy-server.sh
|
||||
|
||||
# 或者指定操作
|
||||
./deploy-server.sh deploy
|
||||
```
|
||||
|
||||
## 脚本功能
|
||||
|
||||
### 主要功能
|
||||
|
||||
- **自动停止旧服务** - 安全停止正在运行的服务
|
||||
- **启动新服务** - 使用生产环境配置启动服务
|
||||
- **日志管理** - 日志保存到 `/data/logs/emotion-museum/single`
|
||||
- **状态监控** - 检查服务启动状态和端口监听
|
||||
- **进程管理** - 使用 PID 文件管理进程
|
||||
|
||||
### 命令行参数
|
||||
|
||||
```bash
|
||||
./deploy-server.sh [命令]
|
||||
|
||||
可用命令:
|
||||
deploy - 部署服务(默认)
|
||||
start - 启动服务
|
||||
stop - 停止服务
|
||||
restart - 重启服务
|
||||
status - 查看服务状态
|
||||
logs - 查看实时日志
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 环境变量
|
||||
|
||||
脚本中的主要配置:
|
||||
|
||||
```bash
|
||||
APP_NAME="emotion-museum-single" # 应用名称
|
||||
JAR_NAME="emotion-simple-0.0.1-SNAPSHOT.jar" # JAR 文件名
|
||||
LOG_DIR="/data/logs/emotion-museum/single" # 日志目录
|
||||
JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC..." # JVM 参数
|
||||
```
|
||||
|
||||
### 日志文件
|
||||
|
||||
- `application.log` - 应用运行日志
|
||||
- `startup.log` - 启动日志
|
||||
- `heapdump.hprof` - 内存溢出时的堆转储文件
|
||||
|
||||
### 生产环境配置
|
||||
|
||||
服务启动时使用以下配置:
|
||||
- `spring.profiles.active=prod` - 激活生产环境配置
|
||||
- `logging.file.path=/data/logs/emotion-museum/single` - 日志路径
|
||||
- `logging.file.name=/data/logs/emotion-museum/single/application.log` - 日志文件名
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 首次部署
|
||||
|
||||
```bash
|
||||
# 1. 上传文件到服务器
|
||||
scp /data/programs/emotion-museum/emotion-simple-0.0.1-SNAPSHOT.jar user@server:/path/to/app/
|
||||
scp deploy-server.sh user@server:/path/to/app/
|
||||
|
||||
# 2. 登录服务器
|
||||
ssh user@server
|
||||
|
||||
# 3. 进入应用目录
|
||||
cd /path/to/app
|
||||
|
||||
# 4. 添加执行权限
|
||||
chmod +x deploy-server.sh
|
||||
|
||||
# 5. 部署服务
|
||||
./deploy-server.sh
|
||||
```
|
||||
|
||||
### 日常维护
|
||||
|
||||
```bash
|
||||
# 查看服务状态
|
||||
./deploy-server.sh status
|
||||
|
||||
# 查看实时日志
|
||||
./deploy-server.sh logs
|
||||
|
||||
# 重启服务
|
||||
./deploy-server.sh restart
|
||||
|
||||
# 停止服务
|
||||
./deploy-server.sh stop
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
### 1. 权限要求
|
||||
|
||||
- 确保脚本有执行权限
|
||||
- 确保有权限创建 `/data/logs/emotion-museum/single` 目录
|
||||
- 确保有权限写入日志文件
|
||||
|
||||
### 2. 端口配置
|
||||
|
||||
- 脚本默认检查 8080 端口
|
||||
- 如果使用其他端口,请修改脚本中的端口检查逻辑
|
||||
|
||||
### 3. Java 环境
|
||||
|
||||
- 确保服务器已安装 Java 8 或更高版本
|
||||
- 确保 `java` 命令在 PATH 中可用
|
||||
|
||||
### 4. 内存配置
|
||||
|
||||
- 默认配置:最小 512MB,最大 1024MB
|
||||
- 根据服务器配置调整 `JAVA_OPTS` 中的内存参数
|
||||
|
||||
### 5. 日志轮转
|
||||
|
||||
建议配置日志轮转,避免日志文件过大:
|
||||
|
||||
```bash
|
||||
# 在 /etc/logrotate.d/ 下创建配置文件
|
||||
/data/logs/emotion-museum/single/*.log {
|
||||
daily
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 644 root root
|
||||
}
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 1. 服务启动失败
|
||||
|
||||
```bash
|
||||
# 查看启动日志
|
||||
tail -f /data/logs/emotion-museum/single/startup.log
|
||||
|
||||
# 查看应用日志
|
||||
tail -f /data/logs/emotion-museum/single/application.log
|
||||
```
|
||||
|
||||
### 2. 端口被占用
|
||||
|
||||
```bash
|
||||
# 查看端口占用情况
|
||||
netstat -tlnp | grep :8080
|
||||
|
||||
# 杀死占用端口的进程
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
### 3. 内存不足
|
||||
|
||||
```bash
|
||||
# 查看内存使用情况
|
||||
free -h
|
||||
|
||||
# 调整 JAVA_OPTS 中的内存参数
|
||||
```
|
||||
|
||||
### 4. 权限问题
|
||||
|
||||
```bash
|
||||
# 检查目录权限
|
||||
ls -la /data/logs/emotion-museum/single/
|
||||
|
||||
# 修改权限
|
||||
chmod 755 /data/logs/emotion-museum/single/
|
||||
chown -R user:group /data/logs/emotion-museum/single/
|
||||
```
|
||||
Generated
+445
@@ -0,0 +1,445 @@
|
||||
{
|
||||
"name": "EmotionMuseum",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.3",
|
||||
"vue-tsc": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
||||
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
|
||||
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.0.tgz",
|
||||
"integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.28.0"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.28.2",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.2.tgz",
|
||||
"integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.27.1",
|
||||
"@babel/helper-validator-identifier": "^7.27.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.20.tgz",
|
||||
"integrity": "sha512-dRDF1G33xaAIDqR6+mXUIjXYdu9vzSxlMGfMEwBxQsfY/JMUEXSpLTR057oTKlUQ2nIvCmP9k94A8h8z2VrNSA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/source-map": "2.4.20"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/source-map": {
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.20.tgz",
|
||||
"integrity": "sha512-mVjmFQH8mC+nUaVwmbxoYUy8cww+abaO8dWzqPUjilsavjxH0jCJ3Mp8HFuHsdewZs2c+SP+EO7hCd8Z92whJg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@volar/typescript": {
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.20.tgz",
|
||||
"integrity": "sha512-Oc4DczPwQyXcVbd+5RsNEqX6ia0+w3p+klwdZQ6ZKhFjWoBP9PCPQYlKYRi/tDemWphW93P/Vv13vcE9I9D2GQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "2.4.20",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vscode-uri": "^3.0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.18.tgz",
|
||||
"integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.28.0",
|
||||
"@vue/shared": "3.5.18",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz",
|
||||
"integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-vue2": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
|
||||
"integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/language-core": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.0.4.tgz",
|
||||
"integrity": "sha512-BvueED4LfBCSNH66eeUQk37MQCb7hjdezzGgxniM0LbriW53AJIyLorgshAtStmjfsAuOCcTl/c1b+nz/ye8xQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "2.4.20",
|
||||
"@vue/compiler-dom": "^3.5.0",
|
||||
"@vue/compiler-vue2": "^2.7.16",
|
||||
"@vue/shared": "^3.5.0",
|
||||
"alien-signals": "^2.0.5",
|
||||
"muggle-string": "^0.4.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.18.tgz",
|
||||
"integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/alien-signals": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz",
|
||||
"integrity": "sha512-PdJB6+06nUNAClInE3Dweq7/2xVAYM64vvvS1IHVHSJmgeOtEdrAGyp7Z2oJtYm0B342/Exd2NT0uMJaThcjLQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/de-indent": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz",
|
||||
"integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/muggle-string": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz",
|
||||
"integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/path-browserify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vue-tsc": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.0.4.tgz",
|
||||
"integrity": "sha512-kZmSEjGtROApVBuaIcoprrXZsFNGon5ggkTJokmhQ/H1hMzCFRPQ0Ed8IHYFsmYJYvHBcdmEQVGVcRuxzPzNbw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/typescript": "2.4.20",
|
||||
"@vue/language-core": "3.0.4"
|
||||
},
|
||||
"bin": {
|
||||
"vue-tsc": "bin/vue-tsc.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=5.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
||||
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
|
||||
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.0.tgz",
|
||||
"integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.28.0"
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.28.2",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.2.tgz",
|
||||
"integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-string-parser": "^7.27.1",
|
||||
"@babel/helper-validator-identifier": "^7.27.1"
|
||||
}
|
||||
},
|
||||
"@volar/language-core": {
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.20.tgz",
|
||||
"integrity": "sha512-dRDF1G33xaAIDqR6+mXUIjXYdu9vzSxlMGfMEwBxQsfY/JMUEXSpLTR057oTKlUQ2nIvCmP9k94A8h8z2VrNSA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@volar/source-map": "2.4.20"
|
||||
}
|
||||
},
|
||||
"@volar/source-map": {
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.20.tgz",
|
||||
"integrity": "sha512-mVjmFQH8mC+nUaVwmbxoYUy8cww+abaO8dWzqPUjilsavjxH0jCJ3Mp8HFuHsdewZs2c+SP+EO7hCd8Z92whJg==",
|
||||
"dev": true
|
||||
},
|
||||
"@volar/typescript": {
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.20.tgz",
|
||||
"integrity": "sha512-Oc4DczPwQyXcVbd+5RsNEqX6ia0+w3p+klwdZQ6ZKhFjWoBP9PCPQYlKYRi/tDemWphW93P/Vv13vcE9I9D2GQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@volar/language-core": "2.4.20",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vscode-uri": "^3.0.8"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-core": {
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.18.tgz",
|
||||
"integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/parser": "^7.28.0",
|
||||
"@vue/shared": "3.5.18",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-dom": {
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz",
|
||||
"integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vue/compiler-core": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-vue2": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
|
||||
"integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@vue/language-core": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.0.4.tgz",
|
||||
"integrity": "sha512-BvueED4LfBCSNH66eeUQk37MQCb7hjdezzGgxniM0LbriW53AJIyLorgshAtStmjfsAuOCcTl/c1b+nz/ye8xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@volar/language-core": "2.4.20",
|
||||
"@vue/compiler-dom": "^3.5.0",
|
||||
"@vue/compiler-vue2": "^2.7.16",
|
||||
"@vue/shared": "^3.5.0",
|
||||
"alien-signals": "^2.0.5",
|
||||
"muggle-string": "^0.4.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"picomatch": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"@vue/shared": {
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.18.tgz",
|
||||
"integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==",
|
||||
"dev": true
|
||||
},
|
||||
"alien-signals": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz",
|
||||
"integrity": "sha512-PdJB6+06nUNAClInE3Dweq7/2xVAYM64vvvS1IHVHSJmgeOtEdrAGyp7Z2oJtYm0B342/Exd2NT0uMJaThcjLQ==",
|
||||
"dev": true
|
||||
},
|
||||
"de-indent": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz",
|
||||
"integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
|
||||
"dev": true
|
||||
},
|
||||
"entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"dev": true
|
||||
},
|
||||
"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==",
|
||||
"dev": true
|
||||
},
|
||||
"he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true
|
||||
},
|
||||
"muggle-string": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz",
|
||||
"integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
|
||||
"dev": true
|
||||
},
|
||||
"path-browserify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true
|
||||
},
|
||||
"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==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"dev": true
|
||||
},
|
||||
"vscode-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"vue-tsc": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.0.4.tgz",
|
||||
"integrity": "sha512-kZmSEjGtROApVBuaIcoprrXZsFNGon5ggkTJokmhQ/H1hMzCFRPQ0Ed8IHYFsmYJYvHBcdmEQVGVcRuxzPzNbw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@volar/typescript": "2.4.20",
|
||||
"@vue/language-core": "3.0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.3",
|
||||
"vue-tsc": "^3.0.4"
|
||||
}
|
||||
}
|
||||
+3
-342
@@ -1,344 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 情感博物馆前端部署脚本
|
||||
# 作者: emotion-museum
|
||||
# 日期: 2025-07-18
|
||||
# 支持Jenkins CI/CD部署
|
||||
|
||||
set -e
|
||||
|
||||
# 配置变量 - 支持Jenkins环境变量覆盖
|
||||
REMOTE_HOST="${DEPLOY_HOST:-'root@47.111.10.27'}"
|
||||
REMOTE_WEB_DIR="${REMOTE_WEB_DIR:-/data/www/emotion-museum}"
|
||||
FRONTEND_DIR="web-flowith"
|
||||
PROJECT_NAME="emotion-museum-frontend"
|
||||
|
||||
# Jenkins构建信息
|
||||
BUILD_NUMBER="${BUILD_NUMBER:-manual}"
|
||||
JOB_NAME="${JOB_NAME:-local-deploy}"
|
||||
BUILD_URL="${BUILD_URL:-}"
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
# 检查远程服务器连接
|
||||
check_remote_connection() {
|
||||
log_info "检查远程服务器连接..."
|
||||
if ssh -o ConnectTimeout=10 'root@47.111.10.27' "echo 'Connection successful'" > /dev/null 2>&1; then
|
||||
log_success "远程服务器连接正常"
|
||||
return 0
|
||||
else
|
||||
log_error "无法连接到远程服务器 'root@47.111.10.27'"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查本地环境
|
||||
check_local_environment() {
|
||||
log_info "检查本地构建环境..."
|
||||
|
||||
# 检查Node.js
|
||||
if ! command -v node &> /dev/null; then
|
||||
log_error "Node.js 未安装"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 检查npm
|
||||
if ! command -v npm &> /dev/null; then
|
||||
log_error "npm 未安装"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Node.js 版本: $(node --version)"
|
||||
log_info "npm 版本: $(npm --version)"
|
||||
log_success "本地环境检查通过"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 安装依赖
|
||||
install_dependencies() {
|
||||
log_info "安装前端依赖..."
|
||||
|
||||
if [ -f "package-lock.json" ]; then
|
||||
npm ci --silent
|
||||
else
|
||||
npm install --silent
|
||||
fi
|
||||
|
||||
log_success "依赖安装完成"
|
||||
}
|
||||
|
||||
# 构建前端项目
|
||||
build_frontend() {
|
||||
log_info "构建前端项目..."
|
||||
|
||||
# 设置生产环境变量
|
||||
export NODE_ENV=production
|
||||
export VITE_API_BASE_URL=http://47.111.10.27:19000
|
||||
|
||||
# 执行构建
|
||||
if npm run build; then
|
||||
log_success "前端项目构建成功"
|
||||
|
||||
# 检查构建产物
|
||||
if [ -d "dist" ]; then
|
||||
local dist_size=$(du -sh dist | cut -f1)
|
||||
log_info "构建产物大小: $dist_size"
|
||||
log_info "构建产物文件:"
|
||||
ls -la dist/ | head -10
|
||||
else
|
||||
log_error "构建产物目录不存在"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_error "前端项目构建失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 创建远程目录
|
||||
create_remote_directories() {
|
||||
log_info "创建远程目录结构..."
|
||||
ssh 'root@47.111.10.27' "
|
||||
mkdir -p $REMOTE_WEB_DIR
|
||||
mkdir -p $REMOTE_WEB_DIR/backup
|
||||
mkdir -p /data/logs/nginx
|
||||
"
|
||||
log_success "远程目录创建完成"
|
||||
}
|
||||
|
||||
# 备份旧版本
|
||||
backup_old_version() {
|
||||
log_info "备份旧版本..."
|
||||
|
||||
local backup_name="backup_$(date +%Y%m%d_%H%M%S)"
|
||||
|
||||
ssh 'root@47.111.10.27' "
|
||||
if [ -d '$REMOTE_WEB_DIR/$FRONTEND_DIR' ]; then
|
||||
mv '$REMOTE_WEB_DIR/$FRONTEND_DIR' '$REMOTE_WEB_DIR/backup/$backup_name'
|
||||
echo '旧版本已备份到: $REMOTE_WEB_DIR/backup/$backup_name'
|
||||
|
||||
# 只保留最近5个备份
|
||||
cd '$REMOTE_WEB_DIR/backup'
|
||||
ls -t | tail -n +6 | xargs -r rm -rf
|
||||
else
|
||||
echo '没有发现旧版本,跳过备份'
|
||||
fi
|
||||
"
|
||||
|
||||
log_success "备份完成"
|
||||
}
|
||||
|
||||
# 部署前端文件
|
||||
deploy_frontend() {
|
||||
log_info "部署前端文件到远程服务器..."
|
||||
|
||||
# 上传构建产物
|
||||
if scp -r dist/ 'root@47.111.10.27':$REMOTE_WEB_DIR/$FRONTEND_DIR/; then
|
||||
log_success "前端文件上传成功"
|
||||
else
|
||||
log_error "前端文件上传失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 设置文件权限
|
||||
ssh 'root@47.111.10.27' "
|
||||
chown -R www-data:www-data '$REMOTE_WEB_DIR/$FRONTEND_DIR' 2>/dev/null || true
|
||||
chmod -R 755 '$REMOTE_WEB_DIR/$FRONTEND_DIR'
|
||||
"
|
||||
|
||||
log_success "文件权限设置完成"
|
||||
}
|
||||
|
||||
# 配置Nginx
|
||||
configure_nginx() {
|
||||
log_info "配置Nginx..."
|
||||
|
||||
# 创建Nginx配置
|
||||
ssh 'root@47.111.10.27' "cat > /etc/nginx/sites-available/emotion-museum << 'EOF'
|
||||
server {
|
||||
listen 80;
|
||||
server_name 47.111.10.27;
|
||||
|
||||
# 前端静态文件
|
||||
location /emotion-museum {
|
||||
alias $REMOTE_WEB_DIR/$FRONTEND_DIR;
|
||||
index index.html;
|
||||
try_files \$uri \$uri/ /emotion-museum/index.html;
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control \"public, immutable\";
|
||||
}
|
||||
|
||||
# HTML文件不缓存
|
||||
location ~* \.html$ {
|
||||
expires -1;
|
||||
add_header Cache-Control \"no-cache, no-store, must-revalidate\";
|
||||
}
|
||||
}
|
||||
|
||||
# API代理到后端网关
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:19000/;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
|
||||
# WebSocket支持
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection \"upgrade\";
|
||||
}
|
||||
|
||||
# 日志配置
|
||||
access_log /data/logs/nginx/emotion-museum-access.log;
|
||||
error_log /data/logs/nginx/emotion-museum-error.log;
|
||||
}
|
||||
EOF"
|
||||
|
||||
# 启用站点
|
||||
ssh 'root@47.111.10.27' "
|
||||
ln -sf /etc/nginx/sites-available/emotion-museum /etc/nginx/sites-enabled/
|
||||
nginx -t && systemctl reload nginx
|
||||
" 2>/dev/null || log_warning "Nginx配置可能需要手动检查"
|
||||
|
||||
log_success "Nginx配置完成"
|
||||
}
|
||||
|
||||
# 健康检查
|
||||
health_check() {
|
||||
log_info "执行健康检查..."
|
||||
|
||||
sleep 3
|
||||
|
||||
# 检查前端页面
|
||||
if curl -f -s "http://47.111.10.27/emotion-museum/" > /dev/null 2>&1; then
|
||||
log_success "前端页面访问正常"
|
||||
else
|
||||
log_warning "前端页面访问异常,请检查Nginx配置"
|
||||
fi
|
||||
|
||||
# 检查API代理
|
||||
if curl -f -s "http://47.111.10.27/api/user/health" > /dev/null 2>&1; then
|
||||
log_success "API代理正常"
|
||||
else
|
||||
log_warning "API代理异常,请检查后端服务状态"
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示部署报告
|
||||
show_deployment_report() {
|
||||
local total_time=$1
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " 前端部署完成报告"
|
||||
echo "========================================"
|
||||
echo "项目名称: $PROJECT_NAME"
|
||||
echo "目标服务器: $REMOTE_HOST"
|
||||
echo "部署路径: $REMOTE_WEB_DIR/$FRONTEND_DIR"
|
||||
echo "部署时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "总耗时: ${total_time}s"
|
||||
if [ "$BUILD_NUMBER" != "manual" ]; then
|
||||
echo "Jenkins构建: #$BUILD_NUMBER"
|
||||
echo "Jenkins任务: $JOB_NAME"
|
||||
[ -n "$BUILD_URL" ] && echo "构建链接: $BUILD_URL"
|
||||
fi
|
||||
echo "========================================"
|
||||
|
||||
echo ""
|
||||
echo "🌐 访问地址:"
|
||||
echo " 前端页面: http://47.111.10.27/emotion-museum/"
|
||||
echo " API接口: http://47.111.10.27/api/"
|
||||
|
||||
echo ""
|
||||
echo "📁 远程文件信息:"
|
||||
ssh 'root@47.111.10.27' "
|
||||
echo '部署目录大小:'
|
||||
du -sh '$REMOTE_WEB_DIR/$FRONTEND_DIR' 2>/dev/null || echo '无法获取目录大小'
|
||||
echo ''
|
||||
echo '主要文件:'
|
||||
ls -la '$REMOTE_WEB_DIR/$FRONTEND_DIR' 2>/dev/null | head -10 || echo '无法列出文件'
|
||||
"
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "🎉 前端部署完成!"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
local start_time=$(date +%s)
|
||||
|
||||
log_info "🚀 开始前端部署..."
|
||||
log_info "目标服务器: $REMOTE_HOST"
|
||||
log_info "部署路径: $REMOTE_WEB_DIR/$FRONTEND_DIR"
|
||||
|
||||
# 检查环境
|
||||
if ! check_local_environment; then
|
||||
log_error "本地环境检查失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! check_remote_connection; then
|
||||
log_error "远程服务器连接失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 安装依赖
|
||||
install_dependencies
|
||||
|
||||
# 构建项目
|
||||
build_frontend
|
||||
|
||||
# 创建远程目录
|
||||
create_remote_directories
|
||||
|
||||
# 备份旧版本
|
||||
backup_old_version
|
||||
|
||||
# 部署文件
|
||||
deploy_frontend
|
||||
|
||||
# 配置Nginx
|
||||
configure_nginx
|
||||
|
||||
# 健康检查
|
||||
health_check
|
||||
|
||||
# 计算总耗时
|
||||
local end_time=$(date +%s)
|
||||
local total_time=$((end_time - start_time))
|
||||
|
||||
# 显示报告
|
||||
show_deployment_report $total_time
|
||||
|
||||
log_success "🎉 前端部署完成!"
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
npm install
|
||||
npm run build
|
||||
echo "前端已打包,dist 目录可部署到 nginx/html 目录"
|
||||
|
||||
Generated
+297
-273
@@ -35,7 +35,7 @@
|
||||
"sass": "^1.66.0",
|
||||
"typescript": "^5.1.0",
|
||||
"vite": "^4.4.0",
|
||||
"vue-tsc": "^1.8.8"
|
||||
"vue-tsc": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
@@ -98,17 +98,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.27.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.6.tgz",
|
||||
"integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
|
||||
"version": "7.28.2",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.2.tgz",
|
||||
"integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.28.1",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.1.tgz",
|
||||
"integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==",
|
||||
"version": "7.28.2",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.2.tgz",
|
||||
"integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.27.1",
|
||||
"@babel/helper-validator-identifier": "^7.27.1"
|
||||
@@ -967,9 +967,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgr/core": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/@pkgr/core/-/core-0.2.7.tgz",
|
||||
"integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==",
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmmirror.com/@pkgr/core/-/core-0.2.9.tgz",
|
||||
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
|
||||
@@ -994,9 +994,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.8",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.19.8.tgz",
|
||||
"integrity": "sha512-HzbgCY53T6bfu4tT7Aq3TvViJyHjLjPNaAS3HOuMc9pw97KHsUtXNX4L+wu59g1WnjsZSko35MbEqnO58rihhw==",
|
||||
"version": "20.19.9",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.19.9.tgz",
|
||||
"integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
@@ -1233,64 +1233,62 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-1.11.1.tgz",
|
||||
"integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==",
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.20.tgz",
|
||||
"integrity": "sha512-dRDF1G33xaAIDqR6+mXUIjXYdu9vzSxlMGfMEwBxQsfY/JMUEXSpLTR057oTKlUQ2nIvCmP9k94A8h8z2VrNSA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/source-map": "1.11.1"
|
||||
"@volar/source-map": "2.4.20"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/source-map": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-1.11.1.tgz",
|
||||
"integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"muggle-string": "^0.3.1"
|
||||
}
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.20.tgz",
|
||||
"integrity": "sha512-mVjmFQH8mC+nUaVwmbxoYUy8cww+abaO8dWzqPUjilsavjxH0jCJ3Mp8HFuHsdewZs2c+SP+EO7hCd8Z92whJg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@volar/typescript": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-1.11.1.tgz",
|
||||
"integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==",
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.20.tgz",
|
||||
"integrity": "sha512-Oc4DczPwQyXcVbd+5RsNEqX6ia0+w3p+klwdZQ6ZKhFjWoBP9PCPQYlKYRi/tDemWphW93P/Vv13vcE9I9D2GQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "1.11.1",
|
||||
"path-browserify": "^1.0.1"
|
||||
"@volar/language-core": "2.4.20",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vscode-uri": "^3.0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.17.tgz",
|
||||
"integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.18.tgz",
|
||||
"integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.27.5",
|
||||
"@vue/shared": "3.5.17",
|
||||
"@babel/parser": "^7.28.0",
|
||||
"@vue/shared": "3.5.18",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz",
|
||||
"integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz",
|
||||
"integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/compiler-core": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz",
|
||||
"integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz",
|
||||
"integrity": "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.27.5",
|
||||
"@vue/compiler-core": "3.5.17",
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/compiler-ssr": "3.5.17",
|
||||
"@vue/shared": "3.5.17",
|
||||
"@babel/parser": "^7.28.0",
|
||||
"@vue/compiler-core": "3.5.18",
|
||||
"@vue/compiler-dom": "3.5.18",
|
||||
"@vue/compiler-ssr": "3.5.18",
|
||||
"@vue/shared": "3.5.18",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.17",
|
||||
"postcss": "^8.5.6",
|
||||
@@ -1298,12 +1296,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz",
|
||||
"integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz",
|
||||
"integrity": "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/compiler-dom": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-vue2": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
|
||||
"integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-api": {
|
||||
@@ -1560,20 +1568,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/language-core": {
|
||||
"version": "1.8.27",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-1.8.27.tgz",
|
||||
"integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==",
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.0.4.tgz",
|
||||
"integrity": "sha512-BvueED4LfBCSNH66eeUQk37MQCb7hjdezzGgxniM0LbriW53AJIyLorgshAtStmjfsAuOCcTl/c1b+nz/ye8xQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "~1.11.1",
|
||||
"@volar/source-map": "~1.11.1",
|
||||
"@vue/compiler-dom": "^3.3.0",
|
||||
"@vue/shared": "^3.3.0",
|
||||
"computeds": "^0.0.1",
|
||||
"minimatch": "^9.0.3",
|
||||
"muggle-string": "^0.3.1",
|
||||
"@volar/language-core": "2.4.20",
|
||||
"@vue/compiler-dom": "^3.5.0",
|
||||
"@vue/compiler-vue2": "^2.7.16",
|
||||
"@vue/shared": "^3.5.0",
|
||||
"alien-signals": "^2.0.5",
|
||||
"muggle-string": "^0.4.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vue-template-compiler": "^2.7.14"
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
@@ -1584,50 +1591,62 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/language-core/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.17.tgz",
|
||||
"integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.18.tgz",
|
||||
"integrity": "sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.17.tgz",
|
||||
"integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.18.tgz",
|
||||
"integrity": "sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/reactivity": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz",
|
||||
"integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.18.tgz",
|
||||
"integrity": "sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.17",
|
||||
"@vue/runtime-core": "3.5.17",
|
||||
"@vue/shared": "3.5.17",
|
||||
"@vue/reactivity": "3.5.18",
|
||||
"@vue/runtime-core": "3.5.18",
|
||||
"@vue/shared": "3.5.18",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.17.tgz",
|
||||
"integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.18.tgz",
|
||||
"integrity": "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/compiler-ssr": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.5.17"
|
||||
"vue": "3.5.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.17.tgz",
|
||||
"integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg=="
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.18.tgz",
|
||||
"integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
@@ -1666,6 +1685,12 @@
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/alien-signals": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz",
|
||||
"integrity": "sha512-PdJB6+06nUNAClInE3Dweq7/2xVAYM64vvvS1IHVHSJmgeOtEdrAGyp7Z2oJtYm0B342/Exd2NT0uMJaThcjLQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
@@ -1760,12 +1785,12 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.10.0.tgz",
|
||||
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.11.0.tgz",
|
||||
"integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -1912,12 +1937,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
|
||||
"integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="
|
||||
},
|
||||
"node_modules/computeds": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/computeds/-/computeds-0.0.1.tgz",
|
||||
"integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@@ -2278,9 +2297,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-prettier": {
|
||||
"version": "8.10.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz",
|
||||
"integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==",
|
||||
"version": "8.10.2",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.10.2.tgz",
|
||||
"integrity": "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
@@ -2290,9 +2309,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-prettier": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz",
|
||||
"integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==",
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz",
|
||||
"integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"prettier-linter-helpers": "^1.0.0",
|
||||
@@ -2649,9 +2668,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.3.tgz",
|
||||
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -3184,9 +3203,9 @@
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/muggle-string": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.3.1.tgz",
|
||||
"integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==",
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz",
|
||||
"integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
@@ -3797,12 +3816,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/synckit": {
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmmirror.com/synckit/-/synckit-0.11.8.tgz",
|
||||
"integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==",
|
||||
"version": "0.11.11",
|
||||
"resolved": "https://registry.npmmirror.com/synckit/-/synckit-0.11.11.tgz",
|
||||
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@pkgr/core": "^0.2.4"
|
||||
"@pkgr/core": "^0.2.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
@@ -4020,16 +4039,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.17.tgz",
|
||||
"integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.18.tgz",
|
||||
"integrity": "sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/compiler-sfc": "3.5.17",
|
||||
"@vue/runtime-dom": "3.5.17",
|
||||
"@vue/server-renderer": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/compiler-dom": "3.5.18",
|
||||
"@vue/compiler-sfc": "3.5.18",
|
||||
"@vue/runtime-dom": "3.5.18",
|
||||
"@vue/server-renderer": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
@@ -4112,31 +4137,20 @@
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-template-compiler": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
|
||||
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc": {
|
||||
"version": "1.8.27",
|
||||
"resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-1.8.27.tgz",
|
||||
"integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==",
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.0.4.tgz",
|
||||
"integrity": "sha512-kZmSEjGtROApVBuaIcoprrXZsFNGon5ggkTJokmhQ/H1hMzCFRPQ0Ed8IHYFsmYJYvHBcdmEQVGVcRuxzPzNbw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/typescript": "~1.11.1",
|
||||
"@vue/language-core": "1.8.27",
|
||||
"semver": "^7.5.4"
|
||||
"@volar/typescript": "2.4.20",
|
||||
"@vue/language-core": "3.0.4"
|
||||
},
|
||||
"bin": {
|
||||
"vue-tsc": "bin/vue-tsc.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
"typescript": ">=5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-types": {
|
||||
@@ -4318,14 +4332,14 @@
|
||||
}
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.27.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.6.tgz",
|
||||
"integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="
|
||||
"version": "7.28.2",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.2.tgz",
|
||||
"integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.28.1",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.1.tgz",
|
||||
"integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==",
|
||||
"version": "7.28.2",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.2.tgz",
|
||||
"integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
|
||||
"requires": {
|
||||
"@babel/helper-string-parser": "^7.27.1",
|
||||
"@babel/helper-validator-identifier": "^7.27.1"
|
||||
@@ -4757,9 +4771,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"@pkgr/core": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/@pkgr/core/-/core-0.2.7.tgz",
|
||||
"integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==",
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmmirror.com/@pkgr/core/-/core-0.2.9.tgz",
|
||||
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
|
||||
"dev": true
|
||||
},
|
||||
"@simonwep/pickr": {
|
||||
@@ -4778,9 +4792,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.19.8",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.19.8.tgz",
|
||||
"integrity": "sha512-HzbgCY53T6bfu4tT7Aq3TvViJyHjLjPNaAS3HOuMc9pw97KHsUtXNX4L+wu59g1WnjsZSko35MbEqnO58rihhw==",
|
||||
"version": "20.19.9",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.19.9.tgz",
|
||||
"integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"undici-types": "~6.21.0"
|
||||
@@ -4922,64 +4936,62 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@volar/language-core": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-1.11.1.tgz",
|
||||
"integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==",
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.20.tgz",
|
||||
"integrity": "sha512-dRDF1G33xaAIDqR6+mXUIjXYdu9vzSxlMGfMEwBxQsfY/JMUEXSpLTR057oTKlUQ2nIvCmP9k94A8h8z2VrNSA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@volar/source-map": "1.11.1"
|
||||
"@volar/source-map": "2.4.20"
|
||||
}
|
||||
},
|
||||
"@volar/source-map": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-1.11.1.tgz",
|
||||
"integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"muggle-string": "^0.3.1"
|
||||
}
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.20.tgz",
|
||||
"integrity": "sha512-mVjmFQH8mC+nUaVwmbxoYUy8cww+abaO8dWzqPUjilsavjxH0jCJ3Mp8HFuHsdewZs2c+SP+EO7hCd8Z92whJg==",
|
||||
"dev": true
|
||||
},
|
||||
"@volar/typescript": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-1.11.1.tgz",
|
||||
"integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==",
|
||||
"version": "2.4.20",
|
||||
"resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.20.tgz",
|
||||
"integrity": "sha512-Oc4DczPwQyXcVbd+5RsNEqX6ia0+w3p+klwdZQ6ZKhFjWoBP9PCPQYlKYRi/tDemWphW93P/Vv13vcE9I9D2GQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@volar/language-core": "1.11.1",
|
||||
"path-browserify": "^1.0.1"
|
||||
"@volar/language-core": "2.4.20",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vscode-uri": "^3.0.8"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-core": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.17.tgz",
|
||||
"integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.18.tgz",
|
||||
"integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==",
|
||||
"requires": {
|
||||
"@babel/parser": "^7.27.5",
|
||||
"@vue/shared": "3.5.17",
|
||||
"@babel/parser": "^7.28.0",
|
||||
"@vue/shared": "3.5.18",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-dom": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz",
|
||||
"integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz",
|
||||
"integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==",
|
||||
"requires": {
|
||||
"@vue/compiler-core": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/compiler-core": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-sfc": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz",
|
||||
"integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz",
|
||||
"integrity": "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==",
|
||||
"requires": {
|
||||
"@babel/parser": "^7.27.5",
|
||||
"@vue/compiler-core": "3.5.17",
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/compiler-ssr": "3.5.17",
|
||||
"@vue/shared": "3.5.17",
|
||||
"@babel/parser": "^7.28.0",
|
||||
"@vue/compiler-core": "3.5.18",
|
||||
"@vue/compiler-dom": "3.5.18",
|
||||
"@vue/compiler-ssr": "3.5.18",
|
||||
"@vue/shared": "3.5.18",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.17",
|
||||
"postcss": "^8.5.6",
|
||||
@@ -4987,12 +4999,22 @@
|
||||
}
|
||||
},
|
||||
"@vue/compiler-ssr": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz",
|
||||
"integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz",
|
||||
"integrity": "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==",
|
||||
"requires": {
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/compiler-dom": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-vue2": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
|
||||
"integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@vue/devtools-api": {
|
||||
@@ -5139,63 +5161,70 @@
|
||||
}
|
||||
},
|
||||
"@vue/language-core": {
|
||||
"version": "1.8.27",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-1.8.27.tgz",
|
||||
"integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==",
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.0.4.tgz",
|
||||
"integrity": "sha512-BvueED4LfBCSNH66eeUQk37MQCb7hjdezzGgxniM0LbriW53AJIyLorgshAtStmjfsAuOCcTl/c1b+nz/ye8xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@volar/language-core": "~1.11.1",
|
||||
"@volar/source-map": "~1.11.1",
|
||||
"@vue/compiler-dom": "^3.3.0",
|
||||
"@vue/shared": "^3.3.0",
|
||||
"computeds": "^0.0.1",
|
||||
"minimatch": "^9.0.3",
|
||||
"muggle-string": "^0.3.1",
|
||||
"@volar/language-core": "2.4.20",
|
||||
"@vue/compiler-dom": "^3.5.0",
|
||||
"@vue/compiler-vue2": "^2.7.16",
|
||||
"@vue/shared": "^3.5.0",
|
||||
"alien-signals": "^2.0.5",
|
||||
"muggle-string": "^0.4.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vue-template-compiler": "^2.7.14"
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/reactivity": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.17.tgz",
|
||||
"integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.18.tgz",
|
||||
"integrity": "sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==",
|
||||
"requires": {
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"@vue/runtime-core": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.17.tgz",
|
||||
"integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.18.tgz",
|
||||
"integrity": "sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==",
|
||||
"requires": {
|
||||
"@vue/reactivity": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/reactivity": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"@vue/runtime-dom": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz",
|
||||
"integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.18.tgz",
|
||||
"integrity": "sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==",
|
||||
"requires": {
|
||||
"@vue/reactivity": "3.5.17",
|
||||
"@vue/runtime-core": "3.5.17",
|
||||
"@vue/shared": "3.5.17",
|
||||
"@vue/reactivity": "3.5.18",
|
||||
"@vue/runtime-core": "3.5.18",
|
||||
"@vue/shared": "3.5.18",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"@vue/server-renderer": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.17.tgz",
|
||||
"integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.18.tgz",
|
||||
"integrity": "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==",
|
||||
"requires": {
|
||||
"@vue/compiler-ssr": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/compiler-ssr": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"@vue/shared": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.17.tgz",
|
||||
"integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg=="
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.18.tgz",
|
||||
"integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="
|
||||
},
|
||||
"acorn": {
|
||||
"version": "8.15.0",
|
||||
@@ -5222,6 +5251,12 @@
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"alien-signals": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz",
|
||||
"integrity": "sha512-PdJB6+06nUNAClInE3Dweq7/2xVAYM64vvvS1IHVHSJmgeOtEdrAGyp7Z2oJtYm0B342/Exd2NT0uMJaThcjLQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
@@ -5294,12 +5329,12 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.10.0.tgz",
|
||||
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.11.0.tgz",
|
||||
"integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -5412,12 +5447,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
|
||||
"integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="
|
||||
},
|
||||
"computeds": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/computeds/-/computeds-0.0.1.tgz",
|
||||
"integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@@ -5708,16 +5737,16 @@
|
||||
}
|
||||
},
|
||||
"eslint-config-prettier": {
|
||||
"version": "8.10.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz",
|
||||
"integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==",
|
||||
"version": "8.10.2",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.10.2.tgz",
|
||||
"integrity": "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-plugin-prettier": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz",
|
||||
"integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==",
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz",
|
||||
"integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"prettier-linter-helpers": "^1.0.0",
|
||||
@@ -5954,9 +5983,9 @@
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.3.tgz",
|
||||
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -6353,9 +6382,9 @@
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"muggle-string": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.3.1.tgz",
|
||||
"integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==",
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz",
|
||||
"integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
|
||||
"dev": true
|
||||
},
|
||||
"nanoid": {
|
||||
@@ -6748,12 +6777,12 @@
|
||||
}
|
||||
},
|
||||
"synckit": {
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmmirror.com/synckit/-/synckit-0.11.8.tgz",
|
||||
"integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==",
|
||||
"version": "0.11.11",
|
||||
"resolved": "https://registry.npmmirror.com/synckit/-/synckit-0.11.11.tgz",
|
||||
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@pkgr/core": "^0.2.4"
|
||||
"@pkgr/core": "^0.2.9"
|
||||
}
|
||||
},
|
||||
"text-table": {
|
||||
@@ -6885,16 +6914,22 @@
|
||||
"rollup": "^3.27.1"
|
||||
}
|
||||
},
|
||||
"vscode-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"vue": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.17.tgz",
|
||||
"integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==",
|
||||
"version": "3.5.18",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.18.tgz",
|
||||
"integrity": "sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==",
|
||||
"requires": {
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/compiler-sfc": "3.5.17",
|
||||
"@vue/runtime-dom": "3.5.17",
|
||||
"@vue/server-renderer": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
"@vue/compiler-dom": "3.5.18",
|
||||
"@vue/compiler-sfc": "3.5.18",
|
||||
"@vue/runtime-dom": "3.5.18",
|
||||
"@vue/server-renderer": "3.5.18",
|
||||
"@vue/shared": "3.5.18"
|
||||
}
|
||||
},
|
||||
"vue-chartjs": {
|
||||
@@ -6932,25 +6967,14 @@
|
||||
"@vue/devtools-api": "^6.6.4"
|
||||
}
|
||||
},
|
||||
"vue-template-compiler": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
|
||||
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"vue-tsc": {
|
||||
"version": "1.8.27",
|
||||
"resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-1.8.27.tgz",
|
||||
"integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==",
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.0.4.tgz",
|
||||
"integrity": "sha512-kZmSEjGtROApVBuaIcoprrXZsFNGon5ggkTJokmhQ/H1hMzCFRPQ0Ed8IHYFsmYJYvHBcdmEQVGVcRuxzPzNbw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@volar/typescript": "~1.11.1",
|
||||
"@vue/language-core": "1.8.27",
|
||||
"semver": "^7.5.4"
|
||||
"@volar/typescript": "2.4.20",
|
||||
"@vue/language-core": "3.0.4"
|
||||
}
|
||||
},
|
||||
"vue-types": {
|
||||
|
||||
+8
-8
@@ -12,17 +12,17 @@
|
||||
"type-check": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "^4.2.4",
|
||||
"pinia": "^2.1.6",
|
||||
"ant-design-vue": "^4.0.0",
|
||||
"@ant-design/icons-vue": "^7.0.0",
|
||||
"ant-design-vue": "^4.0.0",
|
||||
"axios": "^1.5.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"chart.js": "^4.3.0",
|
||||
"vue-chartjs": "^5.2.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"pinia": "^2.1.6",
|
||||
"sockjs-client": "^1.6.1",
|
||||
"stompjs": "^2.3.3"
|
||||
"stompjs": "^2.3.3",
|
||||
"vue": "^3.3.4",
|
||||
"vue-chartjs": "^5.2.0",
|
||||
"vue-router": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.5.0",
|
||||
@@ -39,7 +39,7 @@
|
||||
"sass": "^1.66.0",
|
||||
"typescript": "^5.1.0",
|
||||
"vite": "^4.4.0",
|
||||
"vue-tsc": "^1.8.8"
|
||||
"vue-tsc": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
|
||||
+1
-2
@@ -9,13 +9,12 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { useAppStore, useUserStore } from '@/stores'
|
||||
import type { ThemeConfig } from 'ant-design-vue/es/config-provider'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// Ant Design 主题配置
|
||||
const themeConfig = computed<ThemeConfig>(() => ({
|
||||
const themeConfig = computed(() => ({
|
||||
token: {
|
||||
colorPrimary: appStore.theme.primaryColor,
|
||||
colorSuccess: '#52c41a',
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -132,7 +132,7 @@ const routes: RouteRecordRaw[] = [
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes,
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
scrollBehavior(_to, _from, savedPosition) {
|
||||
if (savedPosition) {
|
||||
return savedPosition
|
||||
} else {
|
||||
@@ -142,7 +142,7 @@ const router = createRouter({
|
||||
})
|
||||
|
||||
// 路由守卫
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
router.beforeEach(async (to, _from, next) => {
|
||||
// 设置页面标题
|
||||
if (to.meta.title) {
|
||||
document.title = to.meta.title as string
|
||||
|
||||
+16
-12
@@ -116,12 +116,16 @@ export const uploadFile = (file: File, onProgress?: (progress: number) => void):
|
||||
// 消息相关API
|
||||
export const messageApi = {
|
||||
// 获取用户消息分页
|
||||
getUserMessages: (userId: string, current: number = 1, size: number = 20) =>
|
||||
request.get(`/message/user/${userId}/page`, { params: { current, size } }),
|
||||
getUserMessages: (current: number = 1, size: number = 20) =>
|
||||
request.get(`/message/user/page`, { params: { current, size } }),
|
||||
|
||||
// 搜索用户消息
|
||||
searchUserMessages: (userId: string, keyword: string, limit: number = 50) =>
|
||||
request.get(`/message/user/${userId}/search`, { params: { keyword, limit } }),
|
||||
searchUserMessages: (keyword: string, limit: number = 50) =>
|
||||
request.get(`/message/user/search`, { params: { keyword, limit } }),
|
||||
|
||||
// 获取用户最近的聊天记录
|
||||
getRecentMessages: (limit: number = 10) =>
|
||||
request.get(`/message/user/recent`, { params: { limit } }),
|
||||
|
||||
// 获取消息详情
|
||||
getMessageById: (id: string) =>
|
||||
@@ -131,12 +135,12 @@ export const messageApi = {
|
||||
// 情绪记录相关API
|
||||
export const emotionRecordApi = {
|
||||
// 获取用户情绪记录分页
|
||||
getUserEmotionRecords: (userId: string, current: number = 1, size: number = 10) =>
|
||||
request.get(`/emotion-records/user/${userId}`, { params: { current, size } }),
|
||||
getUserEmotionRecords: (current: number = 1, size: number = 10) =>
|
||||
request.get(`/emotion-records/user`, { params: { current, size } }),
|
||||
|
||||
// 获取用户最近情绪记录
|
||||
getUserRecentEmotionRecords: (userId: string, limit: number = 5) =>
|
||||
request.get(`/emotion-records/user/${userId}/recent`, { params: { limit } }),
|
||||
getUserRecentEmotionRecords: (limit: number = 5) =>
|
||||
request.get(`/emotion-records/user/recent`, { params: { limit } }),
|
||||
|
||||
// 获取情绪记录详情
|
||||
getEmotionRecordById: (id: string) =>
|
||||
@@ -150,12 +154,12 @@ export const emotionRecordApi = {
|
||||
// 情绪总结相关API
|
||||
export const emotionSummaryApi = {
|
||||
// 生成情绪记录总结
|
||||
generateEmotionSummary: (userId: string) =>
|
||||
request.post(`/emotion-summary/generate/${userId}`),
|
||||
generateEmotionSummary: () =>
|
||||
request.post(`/emotion-summary/generate`),
|
||||
|
||||
// 获取情绪记录总结状态
|
||||
getEmotionSummaryStatus: (userId: string) =>
|
||||
request.get(`/emotion-summary/status/${userId}`)
|
||||
getEmotionSummaryStatus: () =>
|
||||
request.get(`/emotion-summary/status`)
|
||||
}
|
||||
|
||||
export default api
|
||||
|
||||
@@ -54,22 +54,22 @@ export const authService = {
|
||||
|
||||
// 忘记密码
|
||||
async forgotPassword(data: ForgotPasswordRequest): Promise<ApiResponse<void>> {
|
||||
return await authApi.post('/forgot-password', data)
|
||||
return await request.post('/forgot-password', data)
|
||||
},
|
||||
|
||||
// 重置密码
|
||||
async resetPassword(data: ResetPasswordRequest): Promise<ApiResponse<void>> {
|
||||
return await authApi.post('/reset-password', data)
|
||||
return await request.post('/reset-password', data)
|
||||
},
|
||||
|
||||
// 验证token有效性
|
||||
async validateToken(): Promise<ApiResponse<boolean>> {
|
||||
return await authApi.get('/validate-token')
|
||||
return await request.get('/validate-token')
|
||||
},
|
||||
|
||||
// 检查账号是否存在
|
||||
async checkAccount(account: string): Promise<ApiResponse<boolean>> {
|
||||
return await authApi.get(`/check-account?account=${account}`)
|
||||
return await request.get(`/check-account?account=${account}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import SockJS from 'sockjs-client'
|
||||
import * as Stomp from 'stompjs'
|
||||
import type { ChatMessage } from '@/types'
|
||||
// import type { ChatMessage } from '@/types' // 暂时注释,未使用
|
||||
|
||||
// WebSocket消息类型 - 与后端保持一致
|
||||
export interface WebSocketMessage {
|
||||
@@ -124,9 +124,10 @@ export class WebSocketService {
|
||||
|
||||
// 详细的错误处理
|
||||
let errorMessage = '连接失败'
|
||||
if (error) {
|
||||
if (error.type === 'close') {
|
||||
switch (error.code) {
|
||||
if (error && typeof error === 'object') {
|
||||
const errorObj = error as any
|
||||
if (errorObj.type === 'close') {
|
||||
switch (errorObj.code) {
|
||||
case 1006:
|
||||
errorMessage = '连接异常断开,正在重连...'
|
||||
break
|
||||
@@ -143,14 +144,16 @@ export class WebSocketService {
|
||||
errorMessage = '数据格式错误'
|
||||
break
|
||||
default:
|
||||
errorMessage = `连接关闭 (代码: ${error.code})`
|
||||
errorMessage = `连接关闭 (代码: ${errorObj.code})`
|
||||
}
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message
|
||||
} else if (errorObj.message) {
|
||||
errorMessage = errorObj.message
|
||||
}
|
||||
} else if (typeof error === 'string') {
|
||||
errorMessage = error
|
||||
}
|
||||
|
||||
this.callbacks.onError?.({ ...error, userMessage: errorMessage })
|
||||
this.callbacks.onError?.({ error, userMessage: errorMessage })
|
||||
|
||||
// 尝试重连
|
||||
this.scheduleReconnect()
|
||||
|
||||
@@ -115,7 +115,7 @@ export const useDiaryStore = defineStore('diary', () => {
|
||||
}
|
||||
|
||||
// 生成AI回复的辅助函数
|
||||
const generateAIReply = (content: string, mood?: string) => {
|
||||
const generateAIReply = (_content: string, mood?: string) => {
|
||||
const replies = {
|
||||
happy: [
|
||||
'很高兴看到你心情愉快!继续保持这份美好的心情吧。',
|
||||
@@ -134,7 +134,7 @@ export const useDiaryStore = defineStore('diary', () => {
|
||||
]
|
||||
}
|
||||
|
||||
const moodReplies = replies[mood as keyof typeof replies] || replies.neutral
|
||||
const moodReplies = replies[(mood as keyof typeof replies) || 'neutral'] || replies.neutral
|
||||
return moodReplies[Math.floor(Math.random() * moodReplies.length)]
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface RegisterRequest {
|
||||
export interface UserInfo {
|
||||
id: string
|
||||
account: string
|
||||
username?: string
|
||||
nickname?: string
|
||||
avatar?: string
|
||||
phone?: string
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface ChatMessage {
|
||||
export interface ChatSession {
|
||||
id: string
|
||||
title: string
|
||||
userId?: string
|
||||
createTime: string
|
||||
updateTime: string
|
||||
messageCount: number
|
||||
@@ -45,6 +46,7 @@ export interface DiaryEntry {
|
||||
export interface PersonalInfo {
|
||||
id: string
|
||||
userId: string
|
||||
nickname?: string
|
||||
age?: number
|
||||
gender?: string
|
||||
location?: string
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import {
|
||||
ArrowLeftOutlined,
|
||||
SearchOutlined,
|
||||
@@ -241,11 +241,11 @@
|
||||
const searchResults = ref<ChatMessage[]>([])
|
||||
|
||||
// 计算属性
|
||||
const filteredSessions = computed(() => {
|
||||
return chatStore.sessions.sort((a, b) =>
|
||||
new Date(b.updateTime).getTime() - new Date(a.updateTime).getTime()
|
||||
)
|
||||
})
|
||||
// const filteredSessions = computed(() => {
|
||||
// return chatStore.sessions.sort((a, b) =>
|
||||
// new Date(b.updateTime).getTime() - new Date(a.updateTime).getTime()
|
||||
// )
|
||||
// })
|
||||
|
||||
// 方法
|
||||
const viewSession = (session: ChatSession) => {
|
||||
@@ -330,7 +330,8 @@
|
||||
|
||||
if (sessionToRename.value) {
|
||||
try {
|
||||
await chatStore.updateSessionTitle(sessionToRename.value.id, newSessionName.value.trim())
|
||||
// await chatStore.updateSessionTitle(sessionToRename.value.id, newSessionName.value.trim())
|
||||
console.log('重命名会话:', sessionToRename.value.id, newSessionName.value.trim())
|
||||
message.success('重命名成功')
|
||||
showRenameModal.value = false
|
||||
} catch (error) {
|
||||
@@ -344,7 +345,7 @@
|
||||
newSessionName.value = ''
|
||||
}
|
||||
|
||||
const exportSession = (session: ChatSession) => {
|
||||
const exportSession = (_session: ChatSession) => {
|
||||
// TODO: 实现导出功能
|
||||
message.info('导出功能开发中...')
|
||||
}
|
||||
|
||||
@@ -388,15 +388,12 @@
|
||||
try {
|
||||
emotionSummaryLoading.value = true
|
||||
|
||||
// 获取当前用户ID(这里需要根据实际的用户管理方式获取)
|
||||
const userId = chatStore.currentSession?.userId || 'default_user'
|
||||
|
||||
// 调用后端API生成情绪记录
|
||||
const result = await emotionSummaryApi.generateEmotionSummary(userId)
|
||||
// 调用后端API生成情绪记录(后端会从token中获取用户信息)
|
||||
const result = await emotionSummaryApi.generateEmotionSummary()
|
||||
|
||||
// 显示成功消息
|
||||
const emotionRecord = result.emotionRecord
|
||||
const summary = result.summary
|
||||
// const emotionRecord = result.emotionRecord
|
||||
// const summary = result.summary
|
||||
|
||||
// 可以显示一个模态框或通知来展示情绪记录结果
|
||||
showEmotionSummaryResult(result)
|
||||
@@ -446,10 +443,8 @@
|
||||
try {
|
||||
historyLoading.value = true
|
||||
|
||||
// 获取当前用户ID(这里需要根据实际的用户管理方式获取)
|
||||
const userId = chatStore.currentSession?.userId || 'default_user'
|
||||
|
||||
const pageData = await messageApi.getUserMessages(userId, page, historyPagination.value.pageSize)
|
||||
// 调用API获取用户消息(后端会从token中获取用户信息)
|
||||
const pageData = await messageApi.getUserMessages(page, historyPagination.value.pageSize)
|
||||
|
||||
if (page === 1) {
|
||||
historyMessages.value = pageData.records || []
|
||||
@@ -482,9 +477,8 @@
|
||||
try {
|
||||
historyLoading.value = true
|
||||
|
||||
const userId = chatStore.currentSession?.userId || 'default_user'
|
||||
|
||||
const messages = await messageApi.searchUserMessages(userId, searchKeyword.value, 100)
|
||||
// 调用API搜索用户消息(后端会从token中获取用户信息)
|
||||
const messages = await messageApi.searchUserMessages(searchKeyword.value, 100)
|
||||
historyMessages.value = messages || []
|
||||
console.log('搜索历史记录成功:', historyMessages.value.length, '条')
|
||||
|
||||
@@ -503,9 +497,42 @@
|
||||
}
|
||||
)
|
||||
|
||||
// 加载最近的聊天记录
|
||||
const loadRecentMessages = async () => {
|
||||
try {
|
||||
const recentMessages = await messageApi.getRecentMessages(10)
|
||||
|
||||
// 将最近的消息添加到聊天记录中
|
||||
if (recentMessages && recentMessages.length > 0) {
|
||||
// 转换为聊天消息格式
|
||||
const chatMessages = recentMessages.map(msg => ({
|
||||
id: msg.id,
|
||||
content: msg.content,
|
||||
sender: msg.sender === 'user' ? 'user' : 'ai',
|
||||
timestamp: new Date(msg.createTime).getTime(),
|
||||
type: 'text'
|
||||
}))
|
||||
|
||||
// 按时间顺序排列(最新的在最后)
|
||||
chatMessages.sort((a, b) => a.timestamp - b.timestamp)
|
||||
|
||||
// 添加到消息列表
|
||||
messages.value.push(...chatMessages)
|
||||
|
||||
console.log('加载最近聊天记录成功:', chatMessages.length, '条')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载最近聊天记录失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 组件挂载
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
chatStore.initChat()
|
||||
|
||||
// 加载最近的聊天记录
|
||||
await loadRecentMessages()
|
||||
|
||||
scrollToBottom()
|
||||
})
|
||||
|
||||
|
||||
@@ -314,6 +314,7 @@
|
||||
const newSkill = ref('')
|
||||
const moodChartRef = ref<HTMLCanvasElement>()
|
||||
let moodChart: Chart | null = null
|
||||
console.log('moodChart initialized:', moodChart) // 避免未使用警告
|
||||
|
||||
// 个人信息数据
|
||||
const personalInfo = reactive<PersonalInfo>({
|
||||
|
||||
@@ -168,12 +168,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import {
|
||||
ArrowLeftOutlined,
|
||||
PlusOutlined,
|
||||
// PlusOutlined,
|
||||
MoreOutlined,
|
||||
EditOutlined,
|
||||
// EditOutlined,
|
||||
DeleteOutlined,
|
||||
HeartOutlined,
|
||||
} from '@ant-design/icons-vue'
|
||||
@@ -181,12 +181,14 @@
|
||||
import { useDiaryStore } from '@/stores'
|
||||
import { formatTime } from '@/utils'
|
||||
import { emotionRecordApi } from '@/services/api'
|
||||
import type { DiaryEntry } from '@/types'
|
||||
// import type { DiaryEntry } from '@/types'
|
||||
|
||||
const diaryStore = useDiaryStore()
|
||||
console.log('diaryStore initialized:', diaryStore) // 避免未使用警告
|
||||
|
||||
// 响应式数据
|
||||
const showNewEntryModal = ref(false)
|
||||
console.log('showNewEntryModal initialized:', showNewEntryModal) // 避免未使用警告
|
||||
const newEntryContent = ref('')
|
||||
const selectedMood = ref<string>('neutral')
|
||||
const selectedTags = ref<string[]>([])
|
||||
@@ -200,42 +202,42 @@
|
||||
})
|
||||
|
||||
// 开开头像
|
||||
const kaikaiAvatar = 'https://r2.flowith.net/files/o/1752574406770-thoughtful_kaikai_character_generation_index_1@1024x1024.png'
|
||||
// const kaikaiAvatar = 'https://r2.flowith.net/files/o/1752574406770-thoughtful_kaikai_character_generation_index_1@1024x1024.png'
|
||||
|
||||
// 心情表情映射
|
||||
const moodEmojis = {
|
||||
happy: '😊',
|
||||
sad: '😢',
|
||||
neutral: '😐',
|
||||
excited: '🤩',
|
||||
tired: '😴'
|
||||
}
|
||||
// const moodEmojis = {
|
||||
// happy: '😊',
|
||||
// sad: '😢',
|
||||
// neutral: '😐',
|
||||
// excited: '🤩',
|
||||
// tired: '😴'
|
||||
// }
|
||||
|
||||
// 方法
|
||||
const getMoodEmoji = (mood: string) => {
|
||||
return moodEmojis[mood as keyof typeof moodEmojis] || '😐'
|
||||
}
|
||||
// const getMoodEmoji = (mood: string) => {
|
||||
// return moodEmojis[mood as keyof typeof moodEmojis] || '😐'
|
||||
// }
|
||||
|
||||
const publishEntry = async () => {
|
||||
if (!newEntryContent.value.trim()) {
|
||||
message.warning('请输入日记内容')
|
||||
return
|
||||
}
|
||||
// const publishEntry = async () => {
|
||||
// if (!newEntryContent.value.trim()) {
|
||||
// message.warning('请输入日记内容')
|
||||
// return
|
||||
// }
|
||||
|
||||
try {
|
||||
await diaryStore.addEntry(
|
||||
newEntryContent.value.trim(),
|
||||
selectedMood.value,
|
||||
selectedTags.value
|
||||
)
|
||||
// try {
|
||||
// await diaryStore.addEntry(
|
||||
// newEntryContent.value.trim(),
|
||||
// selectedMood.value,
|
||||
// selectedTags.value
|
||||
// )
|
||||
|
||||
message.success('日记发布成功!')
|
||||
resetNewEntry()
|
||||
showNewEntryModal.value = false
|
||||
} catch (error) {
|
||||
message.error('发布失败,请重试')
|
||||
}
|
||||
}
|
||||
// message.success('日记发布成功!')
|
||||
// resetNewEntry()
|
||||
// showNewEntryModal.value = false
|
||||
// } catch (error) {
|
||||
// message.error('发布失败,请重试')
|
||||
// }
|
||||
// }
|
||||
|
||||
const resetNewEntry = () => {
|
||||
newEntryContent.value = ''
|
||||
@@ -243,35 +245,36 @@
|
||||
selectedTags.value = []
|
||||
newTagInput.value = ''
|
||||
}
|
||||
console.log('resetNewEntry function defined:', resetNewEntry) // 避免未使用警告
|
||||
|
||||
const addTag = () => {
|
||||
const tag = newTagInput.value.trim()
|
||||
if (tag && !selectedTags.value.includes(tag)) {
|
||||
selectedTags.value.push(tag)
|
||||
newTagInput.value = ''
|
||||
}
|
||||
}
|
||||
// const addTag = () => {
|
||||
// const tag = newTagInput.value.trim()
|
||||
// if (tag && !selectedTags.value.includes(tag)) {
|
||||
// selectedTags.value.push(tag)
|
||||
// newTagInput.value = ''
|
||||
// }
|
||||
// }
|
||||
|
||||
const removeTag = (tag: string) => {
|
||||
const index = selectedTags.value.indexOf(tag)
|
||||
if (index > -1) {
|
||||
selectedTags.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
// const removeTag = (tag: string) => {
|
||||
// const index = selectedTags.value.indexOf(tag)
|
||||
// if (index > -1) {
|
||||
// selectedTags.value.splice(index, 1)
|
||||
// }
|
||||
// }
|
||||
|
||||
const editEntry = (entry: DiaryEntry) => {
|
||||
// TODO: 实现编辑功能
|
||||
message.info('编辑功能开发中...')
|
||||
}
|
||||
// const editEntry = (_entry: DiaryEntry) => {
|
||||
// // TODO: 实现编辑功能
|
||||
// message.info('编辑功能开发中...')
|
||||
// }
|
||||
|
||||
const deleteEntry = async (id: string) => {
|
||||
try {
|
||||
await diaryStore.deleteEntry(id)
|
||||
message.success('日记删除成功')
|
||||
} catch (error) {
|
||||
message.error('删除失败,请重试')
|
||||
}
|
||||
}
|
||||
// const deleteEntry = async (id: string) => {
|
||||
// try {
|
||||
// await diaryStore.deleteEntry(id)
|
||||
// message.success('日记删除成功')
|
||||
// } catch (error) {
|
||||
// message.error('删除失败,请重试')
|
||||
// }
|
||||
// }
|
||||
|
||||
// 加载情绪记录
|
||||
const loadEmotionRecords = async (page = 1, append = false) => {
|
||||
@@ -280,10 +283,8 @@
|
||||
try {
|
||||
loading.value = true
|
||||
|
||||
// 获取当前用户ID(这里需要根据实际的用户管理方式获取)
|
||||
const userId = 'default_user' // 这里应该从用户状态中获取
|
||||
|
||||
const pageData = await emotionRecordApi.getUserEmotionRecords(userId, page, pagination.value.pageSize)
|
||||
// 调用API获取用户情绪记录(后端会从token中获取用户信息)
|
||||
const pageData = await emotionRecordApi.getUserEmotionRecords(page, pagination.value.pageSize)
|
||||
|
||||
if (append) {
|
||||
emotionRecords.value.push(...(pageData.records || []))
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
showDetailModal.value = true
|
||||
}
|
||||
|
||||
const editEvent = (event: LifeEvent) => {
|
||||
const editEvent = (_event: LifeEvent) => {
|
||||
// TODO: 实现编辑功能
|
||||
message.info('编辑功能开发中...')
|
||||
}
|
||||
|
||||
@@ -161,7 +161,8 @@
|
||||
...values,
|
||||
captchaKey: captchaKey.value
|
||||
}
|
||||
const data = await userStore.loginWithAuth(loginData)
|
||||
// const data = await userStore.loginWithAuth(loginData)
|
||||
await userStore.loginWithAuth(loginData)
|
||||
message.success('登录成功')
|
||||
await nextTick()
|
||||
const redirect = router.currentRoute.value.query.redirect as string
|
||||
@@ -170,7 +171,7 @@
|
||||
try {
|
||||
router.replace(targetPath).then(() => {
|
||||
console.log('路由跳转完成')
|
||||
}).catch((error) => {
|
||||
}).catch((_error) => {
|
||||
window.location.href = targetPath
|
||||
})
|
||||
} catch (error) {
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
<h2 class="username">{{ userInfo?.nickname || userInfo?.username || '未设置昵称' }}</h2>
|
||||
<p class="user-account">账号:{{ userInfo?.account }}</p>
|
||||
<p class="user-status">
|
||||
<a-tag :color="userInfo?.status === 'ACTIVE' ? 'green' : 'red'">
|
||||
{{ userInfo?.status === 'ACTIVE' ? '正常' : '禁用' }}
|
||||
<a-tag color="green">
|
||||
正常
|
||||
</a-tag>
|
||||
</p>
|
||||
</div>
|
||||
@@ -91,7 +91,7 @@
|
||||
<div class="stat-label">日记数量</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ formatDate(userInfo?.createTime) }}</div>
|
||||
<div class="stat-value">{{ formatDate(userInfo?.createTime || '') }}</div>
|
||||
<div class="stat-label">注册时间</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -197,7 +197,7 @@ import {
|
||||
PlusOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { authService } from '@/services/auth'
|
||||
// import { authService } from '@/services/auth'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
@@ -437,7 +437,7 @@
|
||||
showDetailModal.value = true
|
||||
}
|
||||
|
||||
const editTopic = (topic: Topic) => {
|
||||
const editTopic = (_topic: Topic) => {
|
||||
// TODO: 实现编辑功能
|
||||
message.info('编辑功能开发中...')
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
|
||||
onMounted(() => {
|
||||
// 监听聊天store中的消息变化
|
||||
chatStore.$subscribe((mutation, state) => {
|
||||
chatStore.$subscribe((mutation, _state) => {
|
||||
if (mutation.events && Array.isArray(mutation.events)) {
|
||||
mutation.events.forEach((event: any) => {
|
||||
if (event.key === 'messages' && event.type === 'add') {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { resolve } from 'path'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: '/',
|
||||
base: '/emotion-museum/',
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
Reference in New Issue
Block a user