diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 63da4213..e0053cfb 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -1,7 +1,10 @@ { "permissions": { "allow": [ - "Bash(ls:*)" + "Bash(ls:*)", + "Bash(tree:*)", + "Bash(find:*)", + "Bash(dir:*)" ] } } diff --git a/.kiro/specs/urbanlifeline-to-pigx-migration/database-migration-script.md b/.kiro/specs/urbanlifeline-to-pigx-migration/database-migration-script.md index 82467a78..7def8695 100644 --- a/.kiro/specs/urbanlifeline-to-pigx-migration/database-migration-script.md +++ b/.kiro/specs/urbanlifeline-to-pigx-migration/database-migration-script.md @@ -210,8 +210,6 @@ CREATE TABLE IF NOT EXISTS `tb_customer_service` ( `status` varchar(20) NOT NULL DEFAULT 'offline' COMMENT '状态:online-在线 busy-忙碌 offline-离线', `skill_tags` json DEFAULT NULL COMMENT '技能标签', `max_concurrent` int NOT NULL DEFAULT 5 COMMENT '最大并发接待数', - `current_workload` int NOT NULL DEFAULT 0 COMMENT '当前工作量', - `total_served` int NOT NULL DEFAULT 0 COMMENT '累计服务次数', `avg_response_time` int DEFAULT NULL COMMENT '平均响应时间(秒)', `satisfaction_score` decimal(3,2) DEFAULT NULL COMMENT '满意度评分(0-5)', `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID', @@ -221,7 +219,6 @@ CREATE TABLE IF NOT EXISTS `tb_customer_service` ( `delete_time` datetime DEFAULT NULL COMMENT '删除时间', `deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', PRIMARY KEY (`user_id`), - KEY `idx_status_workload` (`status`, `current_workload`), KEY `idx_tenant_id` (`tenant_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客服人员配置表'; diff --git a/ai-management-dify b/ai-management-dify index aa57f855..f1b32d51 160000 --- a/ai-management-dify +++ b/ai-management-dify @@ -1 +1 @@ -Subproject commit aa57f8551a32fdf666c65ee61b2b7a9c51465378 +Subproject commit f1b32d51cbce89e4876a9ba9defe638c0d0f3aea diff --git a/ai-management-platform b/ai-management-platform index 410de71b..bfea48fa 160000 --- a/ai-management-platform +++ b/ai-management-platform @@ -1 +1 @@ -Subproject commit 410de71bf2e4b1d4878de04f07edaad378b214e6 +Subproject commit bfea48fa67f304cd29a3e755dab0adc68acb1b8d diff --git a/docker/kkfileView/.env.example b/docker/kkfileView/.env.example new file mode 100644 index 00000000..53d879af --- /dev/null +++ b/docker/kkfileView/.env.example @@ -0,0 +1,33 @@ +# ================================================ +# KKFileView 配置 +# 复制此文件为 .env 并修改配置 +# ================================================ +# 新增:KKFileView代理后的完整基础URL(HTTPS+域名,无端口、无末尾斜杠) +KKFILEVIEW_BASE_URL=https://org.xyzh.yslg.kkfileview +# ------------------------------ +# 端口配置 +# ------------------------------ +KKFILEVIEW_PORT=8012 + +# ------------------------------ +# 数据目录 +# ------------------------------ +DATA_ROOT=../volumes + +# ------------------------------ +# 存储配置(可选) +# ------------------------------ +# STORAGE_TYPE=local +# STORAGE_PATH=/data + +# ------------------------------ +# 其他配置(可选) +# ------------------------------ +# 预览服务地址(如果需要外部访问) +# KKFILEVIEW_EXTERNAL_URL=http://localhost:8012 + +# 最大文件大小(默认 50M) +# MAX_FILE_SIZE=52428800 + +# 转换超时时间(默认 60s) +# CONVERT_TIMEOUT=60 \ No newline at end of file diff --git a/docker/kkfileView/docker-compose.yml b/docker/kkfileView/docker-compose.yml new file mode 100644 index 00000000..8a1581bc --- /dev/null +++ b/docker/kkfileView/docker-compose.yml @@ -0,0 +1,43 @@ +# ================================================ +# KKFileView 文档预览服务 +# ================================================ +name: urbanlifeline + +services: + +# ====================== KKFileView 文档预览 ====================== + kkfileview: + image: keking/kkfileview:latest + container_name: urban-lifeline-kkfileview + restart: unless-stopped + env_file: + - .env + networks: + - urban-lifeline + ports: + - "${KKFILEVIEW_PORT:-8012}:8012" + environment: + # 基础配置 + KKFILEVIEW_PORT: 8012 + # 新增:核心预览路径(从.env读取,代理后的KKFileView完整域名) + KK_BASE_URL: ${KKFILEVIEW_BASE_URL} + # 新增:允许外部访问(固定值0.0.0.0,无需修改) + SERVER_HOST: 0.0.0.0 + # 存储配置(如果需要) + # STORAGE_TYPE: local + # STORAGE_PATH: /data + TZ: Asia/Shanghai + volumes: + - ${DATA_ROOT:-../volumes}/kkfileview/data:/data + - ${DATA_ROOT:-../volumes}/kkfileview/log:/opt/kkfileview/log + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8012/onlinePreview"] + interval: 30s + timeout: 20s + retries: 3 + start_period: 30s + +networks: + urban-lifeline: + external: true + name: urban-lifeline \ No newline at end of file diff --git a/pigx-ai-app b/pigx-ai-app deleted file mode 160000 index f1588359..00000000 --- a/pigx-ai-app +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f1588359101450ff35b165f9c6d0ee9874a87022 diff --git a/urbanLifelineServ/.bin/database/postgres/bin.sh b/urbanLifelineServ/.bin/database/postgres/bin.sh deleted file mode 100644 index 672ba116..00000000 --- a/urbanLifelineServ/.bin/database/postgres/bin.sh +++ /dev/null @@ -1,290 +0,0 @@ - -#!/bin/bash - -# 定义颜色输出 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# 设置脚本所在目录为工作目录 -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -SQL_DIR="${SCRIPT_DIR}/sql" - -# 打印带时间戳的日志 -log() { - local level=$1 - local message=$2 - local color=$NC - - case $level in - "INFO") color=$BLUE;; - "SUCCESS") color=$GREEN;; - "WARN") color=$YELLOW;; - "ERROR") color=$RED;; - esac - - echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] ${color}${level}${NC}: ${message}" -} - -# 数据库连接信息(可通过环境变量覆盖) -DB_HOST=${POSTGRES_HOST:-"localhost"} -DB_PORT=${POSTGRES_PORT:-"5432"} -DB_NAME=${POSTGRES_DB:-"urban_lifeline"} -DB_USER=${POSTGRES_USER:-"postgres"} -DB_PASSWORD=${POSTGRES_PASSWORD:-"postgres"} - -# 设置 PSQL 环境变量以支持中文 -export PGCLIENTENCODING=UTF8 - -# 检查psql命令是否可用 -check_psql() { - if ! command -v psql &> /dev/null; then - echo -e "${RED}Error: psql command not found. Please install PostgreSQL client.${NC}" - exit 1 - fi -} - -# 检查并创建数据库用户 -check_and_create_user() { - local new_user=$1 - local new_password=$2 - - # 使用 postgres 用户执行 - if sudo -u postgres psql -c "SELECT 1 FROM pg_roles WHERE rolname = '$new_user'" | grep -q 1; then - echo -e "${GREEN}User $new_user already exists${NC}" - else - echo -e "${YELLOW}Creating user $new_user...${NC}" - sudo -u postgres psql -c "CREATE USER $new_user WITH PASSWORD '$new_password' CREATEDB;" - if [ $? -eq 0 ]; then - echo -e "${GREEN}User $new_user created successfully${NC}" - else - echo -e "${RED}Failed to create user $new_user${NC}" - exit 1 - fi - fi -} - -# 检查数据库连接 -check_db_connection() { - # 首先尝试以当前用户身份连接 - if ! psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "postgres" -c '\q' &> /dev/null; then - echo -e "${YELLOW}Could not connect with current settings, attempting to create user...${NC}" - # 创建用户并设置权限 - check_and_create_user "$DB_USER" "$DB_PASSWORD" - - # 再次检查连接 - if ! psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "postgres" -c '\q' &> /dev/null; then - echo -e "${RED}Error: Could not connect to PostgreSQL server.${NC}" - echo "Please check your connection settings:" - echo "Host: $DB_HOST" - echo "Port: $DB_PORT" - echo "User: $DB_USER" - exit 1 - fi - fi -} - -# 执行SQL文件 -execute_sql_file() { - local sql_file=$1 - if [ ! -f "$sql_file" ]; then - echo -e "${RED}Error: SQL file not found: $sql_file${NC}" - return 1 - fi - - echo -e "${YELLOW}Executing SQL file: $sql_file${NC}" - PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -f "$sql_file" - local status=$? - if [ $status -eq 0 ]; then - echo -e "${GREEN}Successfully executed: $sql_file${NC}" - else - echo -e "${RED}Failed to execute: $sql_file${NC}" - return $status - fi -} - -# 初始化数据库 -init() { - echo -e "${YELLOW}Initializing database...${NC}" - - # 执行完整的初始化脚本 - log "INFO" "Executing initialization script..." - # Run from inside the SQL_DIR so relative \i includes in initAll.sql (like createDB.sql) - # resolve relative to the SQL directory. - ( - if [ ! -d "$SQL_DIR" ]; then - echo -e "${RED}Error: SQL directory not found: $SQL_DIR${NC}" - exit 1 - fi - cd "$SQL_DIR" || exit 1 - PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "postgres" -v ON_ERROR_STOP=1 -f "initAll.sql" - ) - - if [ $? -eq 0 ]; then - log "SUCCESS" "Database initialization completed successfully" - else - log "ERROR" "Database initialization failed" - return 1 - fi - - if [ $? -ne 0 ]; then - echo -e "${RED}Failed to create database.${NC}" - return 1 - fi - - # 2. 创建扩展和设置搜索路径 - echo -e "${YELLOW}Creating extensions...${NC}" - check_extensions_availability() { - # 检查服务器上是否存在需创建的扩展 - local missing=() - local exts=("uuid-ossp" "pg_trgm" "btree_gist") - for ext in "${exts[@]}"; do - # 查询 pg_available_extensions 来判断扩展是否已安装到服务器目录 - if ! PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -tAc "SELECT 1 FROM pg_available_extensions WHERE name = '$ext';" | grep -q 1; then - missing+=("$ext") - fi - done - - if [ ${#missing[@]} -ne 0 ]; then - echo -e "${RED}Error: The following server-side extensions are not available: ${missing[*]}${NC}" - echo "If you compiled PostgreSQL from source, you need to build and install the contrib modules into the server's installation prefix. Example steps:" - echo " # 在 PostgreSQL 源码目录下运行:" - echo " cd /path/to/postgresql-source/contrib" - echo " make" - echo " sudo make install" - echo "或者只安装缺失的模块(例如 uuid-ossp):" - echo " cd /path/to/postgresql-source/contrib/uuid-ossp" - echo " make" - echo " sudo make install" - echo "安装完成后,重启 PostgreSQL 服务并重新运行此脚本:" - echo " sudo systemctl restart postgresql" - echo "如果你使用的是容器或自定义路径,请确保将编译安装的扩展安装到 PostgreSQL 的 \$(pg_config --sharedir)/extension 目录下。" - return 1 - fi - return 0 - } - - # 检查扩展可用性,若缺失则给出建议并退出 - if ! check_extensions_availability; then - return 1 - fi - - PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c " - CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"; - CREATE EXTENSION IF NOT EXISTS \"pg_trgm\"; - CREATE EXTENSION IF NOT EXISTS \"btree_gist\";" - - if [ $? -ne 0 ]; then - echo -e "${RED}Failed to create extensions.${NC}" - return 1 - fi - - # 3. 逐个执行初始化SQL文件 - echo -e "${YELLOW}Initializing tables...${NC}" - while IFS= read -r line || [[ -n "$line" ]]; do - # 跳过注释和空行 - [[ $line =~ ^--.*$ ]] && continue - [[ -z "${line// }" ]] && continue - - # 从 \i 命令中提取文件名 - if [[ $line =~ \\i[[:space:]]+([^[:space:]]+) ]]; then - sql_file="${SQL_DIR}/${BASH_REMATCH[1]}" - if [[ $sql_file != *"createDB.sql"* ]]; then # 跳过createDB.sql - echo -e "${YELLOW}Executing: $sql_file${NC}" - PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -f "$sql_file" - if [ $? -ne 0 ]; then - echo -e "${RED}Failed to execute: $sql_file${NC}" - return 1 - fi - fi - fi - done < "${SQL_DIR}/initAll.sql" - - # 4. 设置搜索路径 - echo -e "${YELLOW}Setting search path...${NC}" - PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c " - ALTER DATABASE $DB_NAME SET search_path TO sys, public;" - - echo -e "${GREEN}Database initialization completed successfully.${NC}" - return 0 -} - -# 重新初始化数据库 -reinit() { - echo -e "${YELLOW}Reinitializing database...${NC}" - delete - init -} - -# 删除数据库 -delete() { - echo -e "${YELLOW}Deleting database...${NC}" - - # 多次尝试终止连接(因为某些连接可能会立即重连) - for i in {1..3}; do - log "INFO" "Terminating database connections (attempt $i/3)..." - PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "postgres" -c " - SELECT pg_terminate_backend(pg_stat_activity.pid) - FROM pg_stat_activity - WHERE pg_stat_activity.datname = '$DB_NAME' - AND pid <> pg_backend_pid();" > /dev/null 2>&1 - - # 等待连接完全关闭 - sleep 1 - done - - # 尝试删除数据库,最多重试3次 - for i in {1..3}; do - log "INFO" "Attempting to drop database (attempt $i/3)..." - if PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "postgres" -c "DROP DATABASE IF EXISTS $DB_NAME;" 2>&1; then - log "SUCCESS" "Database deleted successfully" - return 0 - else - log "WARN" "Failed to drop database, retrying after 2 seconds..." - sleep 2 - fi - done - - log "ERROR" "Failed to delete database after 3 attempts" - log "ERROR" "Please ensure all connections to the database are closed, including:" - log "ERROR" " - Running application servers" - log "ERROR" " - IDE database connections" - log "ERROR" " - pgAdmin or other database tools" - return 1 -} - -# 显示帮助信息 -show_help() { - echo "Usage: $0 {init|reinit|delete}" - echo "Commands:" - echo " init Initialize the database" - echo " reinit Reinitialize the database (delete and create)" - echo " delete Delete the database" -} - -# 主函数 -main() { - check_psql - check_db_connection - - case "$1" in - "init") - init - ;; - "reinit") - reinit - ;; - "delete") - delete - ;; - *) - show_help - exit 1 - ;; - esac -} - -# Call main with all passed arguments so the script runs when invoked -main "$@" \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createDB.sql b/urbanLifelineServ/.bin/database/postgres/sql/createDB.sql deleted file mode 100644 index c5ce72b7..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createDB.sql +++ /dev/null @@ -1,27 +0,0 @@ - --- 删除已存在的数据库(如果存在) -DROP DATABASE IF EXISTS urban_lifeline; - --- 创建新数据库,使用 UTF8 编码,并设置适合中文的排序规则 --- 使用 template0 确保干净的数据库模板 --- zh_CN.UTF-8 支持中文字符排序和比较 -CREATE DATABASE urban_lifeline - ENCODING 'UTF8' - TEMPLATE template0 - LC_COLLATE 'zh_CN.UTF-8' - LC_CTYPE 'zh_CN.UTF-8'; - --- 连接到新创建的数据库 -\c urban_lifeline; - --- -- 创建扩展(如果需要) -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID 支持 -CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- 文本搜索支持 -CREATE EXTENSION IF NOT EXISTS "btree_gist"; -- GiST 索引支持 - --- 设置搜索路径(可选,但建议设置) --- ALTER DATABASE urban-lifeline SET search_path TO sys, public; - --- sudo ./configure --prefix=/opt/postgres/postgres-17.6 --- --with-uuid=ossp --with-openssl --with-libxml --with-pam --- && sudo make && sudo make install diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableAI.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableAI.sql deleted file mode 100644 index 3752bd0b..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableAI.sql +++ /dev/null @@ -1,188 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS ai; - --- AI智能体配置 -DROP TABLE IF EXISTS ai.tb_agent CASCADE; -CREATE TABLE ai.tb_agent( - optsn VARCHAR(50) NOT NULL, -- 流水号 - agent_id VARCHAR(50) NOT NULL, -- 智能体ID - name VARCHAR(50) NOT NULL, -- 智能体名称 - description VARCHAR(500) DEFAULT NULL, -- 智能体描述 - link VARCHAR(500) DEFAULT NULL, -- 智能体url - api_key VARCHAR(500) NOT NULL, -- dify智能体APIKEY - is_outer BOOLEAN DEFAULT false, -- 是否是对外智能体,未登录可用 - introduce VARCHAR(500) NOT NULL, -- 引导词 - prompt_cards JSONB DEFAULT '[]'::jsonb, -- 提示卡片数组 [{file_id:'', prompt:''}] - category VARCHAR(50) NOT NULL, -- 分类 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (agent_id), - UNIQUE (optsn), - UNIQUE (api_key) -); - --- AI智能体对话 -DROP TABLE IF EXISTS ai.tb_chat CASCADE; -CREATE TABLE ai.tb_chat( - optsn VARCHAR(50) NOT NULL, -- 流水号 - chat_id VARCHAR(50) NOT NULL, -- 对话ID - agent_id VARCHAR(50) NOT NULL, -- 智能体ID - user_id VARCHAR(50) NOT NULL, -- 用户ID - user_type BOOLEAN NOT NULL DEFAULT true, -- 用户类型 true-系统内部人员 false-系统外部人员 - title VARCHAR(500) NOT NULL, -- 对话标题 - channel VARCHAR(50) DEFAULT 'agent', -- 对话渠道 agent、wechat - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (chat_id), - UNIQUE (optsn) -); - --- AI智能体对话消息 -DROP TABLE IF EXISTS ai.tb_chat_message CASCADE; -CREATE TABLE ai.tb_chat_message( - optsn VARCHAR(50) NOT NULL, -- 流水号 - message_id VARCHAR(50) NOT NULL, -- 消息ID - dify_message_id VARCHAR(100) DEFAULT NULL, -- Dify消息ID - chat_id VARCHAR(50) NOT NULL, -- 对话ID - role VARCHAR(50) NOT NULL, -- 角色:user-用户/ai-智能体/recipient-来客 - content TEXT NOT NULL, -- 消息内容 - files VARCHAR(50)[] DEFAULT NULL, -- 文件id数组 - comment VARCHAR(50) DEFAULT NULL, -- 评价 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (message_id), - UNIQUE (optsn) -); - - --- 知识库配置 bidding和workcase2个服务使用 -DROP TABLE IF EXISTS ai.tb_knowledge CASCADE; -CREATE TABLE ai.tb_knowledge( - -- 知识库dify相关配置 - optsn VARCHAR(50) NOT NULL, -- 流水号 - knowledge_id VARCHAR(50) NOT NULL, -- 知识库ID - title VARCHAR(255) NOT NULL, -- 知识库标题 - avatar VARCHAR(255) DEFAULT NULL, -- 知识库头像 - description VARCHAR(500) DEFAULT NULL, -- 知识库描述 - dify_dataset_id VARCHAR(100) DEFAULT NULL, -- Dify知识库ID(Dataset ID) - dify_indexing_technique VARCHAR(50) DEFAULT 'high_quality', -- Dify索引方式(high_quality/economy) - embedding_model VARCHAR(100) DEFAULT NULL, -- 向量模型名称 - embedding_model_provider VARCHAR(100) DEFAULT NULL, -- 向量模型提供商 - rerank_model VARCHAR(100) DEFAULT NULL, -- Rerank模型名称 - rerank_model_provider VARCHAR(100) DEFAULT NULL, -- Rerank模型提供商 - reranking_enable BOOLEAN DEFAULT false, -- 是否启用Rerank - retrieval_top_k INTEGER DEFAULT 2, -- 检索Top K(返回前K个结果) - retrieval_score_threshold DECIMAL(3,2) DEFAULT 0.00, -- 检索分数阈值(0.00-1.00) - document_count INTEGER DEFAULT 0, -- 文档数量 - total_chunks INTEGER DEFAULT 0, -- 总分段数 - -- 下面是服务使用 - service VARCHAR(50) DEFAULT NULL, -- 所属服务 workcase、bidding - project_id VARCHAR(50) DEFAULT NULL, -- bidding所属项目ID - category VARCHAR(50) DEFAULT NULL, -- 所属分类 workcase 内部知识库、外部知识库 - creator VARCHAR(50) NOT NULL, -- 创建者(用户ID) - dept_path VARCHAR(50) DEFAULT NULL, -- 创建者部门路径 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (optsn), - UNIQUE (knowledge_id), - UNIQUE (dify_dataset_id) -); - --- 知识库配置表字段注释 -COMMENT ON TABLE ai.tb_knowledge IS '知识库配置表'; -COMMENT ON COLUMN ai.tb_knowledge.optsn IS '流水号'; -COMMENT ON COLUMN ai.tb_knowledge.knowledge_id IS '知识库ID'; -COMMENT ON COLUMN ai.tb_knowledge.title IS '知识库标题'; -COMMENT ON COLUMN ai.tb_knowledge.avatar IS '知识库头像'; -COMMENT ON COLUMN ai.tb_knowledge.description IS '知识库描述'; -COMMENT ON COLUMN ai.tb_knowledge.dify_dataset_id IS 'Dify知识库ID(Dataset ID)'; -COMMENT ON COLUMN ai.tb_knowledge.dify_indexing_technique IS 'Dify索引方式(high_quality/economy)'; -COMMENT ON COLUMN ai.tb_knowledge.embedding_model IS '向量模型名称'; -COMMENT ON COLUMN ai.tb_knowledge.embedding_model_provider IS '向量模型提供商'; -COMMENT ON COLUMN ai.tb_knowledge.rerank_model IS 'Rerank模型名称'; -COMMENT ON COLUMN ai.tb_knowledge.rerank_model_provider IS 'Rerank模型提供商'; -COMMENT ON COLUMN ai.tb_knowledge.reranking_enable IS '是否启用Rerank'; -COMMENT ON COLUMN ai.tb_knowledge.retrieval_top_k IS '检索Top K(返回前K个结果)'; -COMMENT ON COLUMN ai.tb_knowledge.retrieval_score_threshold IS '检索分数阈值(0.00-1.00)'; -COMMENT ON COLUMN ai.tb_knowledge.document_count IS '文档数量'; -COMMENT ON COLUMN ai.tb_knowledge.total_chunks IS '总分段数'; -COMMENT ON COLUMN ai.tb_knowledge.service IS '所属服务 workcase、bidding'; -COMMENT ON COLUMN ai.tb_knowledge.project_id IS 'bidding所属项目ID'; -COMMENT ON COLUMN ai.tb_knowledge.category IS '所属分类 workcase 内部知识库、外部知识库'; -COMMENT ON COLUMN ai.tb_knowledge.creator IS '创建者(用户ID)'; -COMMENT ON COLUMN ai.tb_knowledge.dept_path IS '创建者部门路径'; -COMMENT ON COLUMN ai.tb_knowledge.updater IS '更新者'; -COMMENT ON COLUMN ai.tb_knowledge.create_time IS '创建时间'; -COMMENT ON COLUMN ai.tb_knowledge.update_time IS '更新时间'; -COMMENT ON COLUMN ai.tb_knowledge.delete_time IS '删除时间'; -COMMENT ON COLUMN ai.tb_knowledge.deleted IS '是否删除'; --- bidding知识库根据project等变化 --- workcase知识库固定8个 --- workcase外部知识库:4个知识库: --- 1. 设备操作指南 --- 2. 常见故障解决方案 --- 3. 三包外服务政策 --- 4. 配件咨询话术 --- workcase内部知识库:4个知识库: --- 1. 技术维修手册 --- 2. 产品参数明细 --- 3. 内部服务流程规范 --- 4. 客户服务话术模板 - --- 知识库文件 文件上传dify知识库,对dify内的文件修改不生成新版本, 只有重新上传才生成新版本 -DROP TABLE IF EXISTS ai.tb_knowledge_file CASCADE; -CREATE TABLE ai.tb_knowledge_file( - optsn VARCHAR(50) NOT NULL, -- 流水号 - knowledge_id VARCHAR(50) NOT NULL, -- 知识库ID - file_root_id VARCHAR(50) NOT NULL, -- 文件根ID - file_id VARCHAR(50) NOT NULL, -- 文件ID - dify_file_id VARCHAR(50) NOT NULL, -- dify文件ID - version INTEGER NOT NULL DEFAULT 1, -- 文件版本 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (optsn), - UNIQUE (knowledge_id, file_id) -); - --- 知识库文件表字段注释 -COMMENT ON TABLE ai.tb_knowledge_file IS '知识库文件表'; -COMMENT ON COLUMN ai.tb_knowledge_file.optsn IS '流水号'; -COMMENT ON COLUMN ai.tb_knowledge_file.knowledge_id IS '知识库ID'; -COMMENT ON COLUMN ai.tb_knowledge_file.file_root_id IS '文件根ID'; -COMMENT ON COLUMN ai.tb_knowledge_file.file_id IS '文件ID'; -COMMENT ON COLUMN ai.tb_knowledge_file.dify_file_id IS 'dify文件ID'; -COMMENT ON COLUMN ai.tb_knowledge_file.version IS '文件版本'; -COMMENT ON COLUMN ai.tb_knowledge_file.create_time IS '创建时间'; -COMMENT ON COLUMN ai.tb_knowledge_file.update_time IS '更新时间'; -COMMENT ON COLUMN ai.tb_knowledge_file.delete_time IS '删除时间'; -COMMENT ON COLUMN ai.tb_knowledge_file.deleted IS '是否删除'; - -DROP TABLE IF EXISTS ai.tb_knowledge_file_log CASCADE; -CREATE TABLE ai.tb_knowledge_file_log( - optsn VARCHAR(50) NOT NULL, -- 流水号 - log_id VARCHAR(50) NOT NULL, -- 日志ID - knowledge_id VARCHAR(50) NOT NULL, -- 知识库ID - file_root_id VARCHAR(50) NOT NULL, -- 文件根ID - file_id VARCHAR(50) NOT NULL, -- 文件ID - file_name VARCHAR(100) NOT NULL, -- 文件名 - service VARCHAR(50) NOT NULL, -- 所属服务 workcase、bidding - version INTEGER NOT NULL DEFAULT 1, -- 文件版本 - action VARCHAR(50) NOT NULL, -- 操作类型 upload、update、delete - creator VARCHAR(50) NOT NULL, -- 创建者(用户ID) - creator_name VARCHAR(100) NOT NULL, -- 创建者姓名 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - PRIMARY KEY (optsn), - UNIQUE (knowledge_id, file_id) -); diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableBidding.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableBidding.sql deleted file mode 100644 index 4818df60..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableBidding.sql +++ /dev/null @@ -1,264 +0,0 @@ --- ============================= --- 招投标智能体业务模块 --- 支持:招标文件管理、投标文件生成、评分分析、流程跟踪 --- ============================= -CREATE SCHEMA IF NOT EXISTS bidding; - --- 招标项目表 -DROP TABLE IF EXISTS bidding.tb_bidding_project CASCADE; -CREATE TABLE bidding.tb_bidding_project ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - project_id VARCHAR(50) NOT NULL, -- 项目ID - project_no VARCHAR(100) NOT NULL, -- 项目编号 - project_name VARCHAR(500) NOT NULL, -- 项目名称 - project_type VARCHAR(50) NOT NULL, -- 项目类型:public-公开招标/invitation-邀请招标/competitive_negotiation-竞争性谈判 - industry VARCHAR(100), -- 所属行业 - source_platform VARCHAR(100), -- 来源平台(如:政府采购网、企业官网等) - source_url VARCHAR(500), -- 来源URL - publish_date TIMESTAMPTZ, -- 发布日期 - deadline TIMESTAMPTZ, -- 投标截止日期 - opening_date TIMESTAMPTZ, -- 开标日期 - budget_amount DECIMAL(18,2), -- 预算金额 - currency VARCHAR(10) DEFAULT 'CNY', -- 货币单位 - project_status VARCHAR(30) NOT NULL DEFAULT 'collecting', -- 项目状态:collecting-收集中/analyzing-分析中/preparing-准备投标/submitted-已提交/opened-已开标/won-中标/lost-未中标/abandoned-放弃 - winning_status VARCHAR(30), -- 中标状态:pending-待定/won-中标/lost-未中标 - winning_amount DECIMAL(18,2), -- 中标金额 - client_name VARCHAR(255), -- 客户名称 - client_contact VARCHAR(100), -- 客户联系方式 - contact_person VARCHAR(100), -- 联系人 - project_location VARCHAR(500), -- 项目地点 - description TEXT, -- 项目描述 - keywords TEXT[], -- 关键词数组 - metadata JSONB DEFAULT NULL, -- 项目元数据 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - responsible_user VARCHAR(50), -- 负责人 - team_members VARCHAR(50)[], -- 团队成员数组 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (project_id), - UNIQUE (optsn), - UNIQUE (project_no) -); - -CREATE INDEX idx_project_status ON bidding.tb_bidding_project(project_status) WHERE deleted = false; -CREATE INDEX idx_project_deadline ON bidding.tb_bidding_project(deadline) WHERE deleted = false; -CREATE INDEX idx_project_dept ON bidding.tb_bidding_project(dept_path) WHERE deleted = false; -CREATE INDEX idx_project_responsible ON bidding.tb_bidding_project(responsible_user) WHERE deleted = false; - -COMMENT ON TABLE bidding.tb_bidding_project IS '招标项目表'; -COMMENT ON COLUMN bidding.tb_bidding_project.project_status IS '项目状态:collecting/analyzing/preparing/submitted/opened/won/lost/abandoned'; - --- 招标文件表 -DROP TABLE IF EXISTS bidding.tb_bidding_document CASCADE; -CREATE TABLE bidding.tb_bidding_document ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - doc_id VARCHAR(50) NOT NULL, -- 文档ID - project_id VARCHAR(50) NOT NULL, -- 所属项目ID - doc_type VARCHAR(50) NOT NULL, -- 文档类型:tender-招标文件/technical-技术标/commercial-商务标/clarification-澄清文件/other-其他 - doc_name VARCHAR(500) NOT NULL, -- 文档名称 - file_id VARCHAR(50), -- 关联文件表ID - file_path VARCHAR(500), -- 文件路径 - file_size BIGINT, -- 文件大小 - mime_type VARCHAR(100), -- MIME类型 - version INTEGER DEFAULT 1, -- 版本号 - language VARCHAR(20) DEFAULT 'zh-CN', -- 语言 - page_count INTEGER, -- 页数 - parse_status VARCHAR(30) DEFAULT 'pending', -- 解析状态:pending-待解析/parsing-解析中/completed-已完成/failed-失败 - parse_result JSONB, -- 解析结果(JSON格式:提取的要素、表格、图纸等) - extraction_data JSONB, -- 提取的结构化数据 - ai_analysis TEXT, -- AI分析结果 - upload_date TIMESTAMPTZ DEFAULT now(), -- 上传日期 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (doc_id), - UNIQUE (optsn), - FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id) -); - -CREATE INDEX idx_doc_project ON bidding.tb_bidding_document(project_id) WHERE deleted = false; -CREATE INDEX idx_doc_type ON bidding.tb_bidding_document(doc_type) WHERE deleted = false; - -COMMENT ON TABLE bidding.tb_bidding_document IS '招标文件表'; -COMMENT ON COLUMN bidding.tb_bidding_document.parse_status IS '解析状态:pending/parsing/completed/failed'; - --- 招标要素提取表 -DROP TABLE IF EXISTS bidding.tb_bidding_requirement CASCADE; -CREATE TABLE bidding.tb_bidding_requirement ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - req_id VARCHAR(50) NOT NULL, -- 要素ID - project_id VARCHAR(50) NOT NULL, -- 所属项目ID - doc_id VARCHAR(50), -- 来源文档ID - req_category VARCHAR(50) NOT NULL, -- 要素类别:commercial-商务要素/technical-技术参数/veto-否决项/qualification-资质要求/delivery-交付要求/payment-付款条件/scoring-评分标准 - req_name VARCHAR(255) NOT NULL, -- 要素名称 - req_content TEXT NOT NULL, -- 要素内容 - req_value VARCHAR(500), -- 要素值 - is_mandatory BOOLEAN DEFAULT false, -- 是否必填 - is_veto BOOLEAN DEFAULT false, -- 是否为否决项 - priority INTEGER DEFAULT 0, -- 优先级 - extraction_method VARCHAR(30) DEFAULT 'ai', -- 提取方式:ai-AI提取/manual-人工录入 - confidence_score DECIMAL(5,4), -- 置信度分数(0-1) - source_location JSONB, -- 来源位置(页码、段落等) - compliance_status VARCHAR(30), -- 合规状态:compliant-符合/non_compliant-不符合/pending-待确认 - response_content TEXT, -- 响应内容(我方的应答) - notes TEXT, -- 备注 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (req_id), - UNIQUE (optsn), - FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id) -); - -CREATE INDEX idx_req_project ON bidding.tb_bidding_requirement(project_id) WHERE deleted = false; -CREATE INDEX idx_req_category ON bidding.tb_bidding_requirement(req_category) WHERE deleted = false; -CREATE INDEX idx_req_veto ON bidding.tb_bidding_requirement(is_veto) WHERE deleted = false AND is_veto = true; - -COMMENT ON TABLE bidding.tb_bidding_requirement IS '招标要素提取表'; -COMMENT ON COLUMN bidding.tb_bidding_requirement.req_category IS '要素类别:commercial/technical/veto/qualification/delivery/payment/scoring'; - --- 投标文件生成表 -DROP TABLE IF EXISTS bidding.tb_bid_response CASCADE; -CREATE TABLE bidding.tb_bid_response ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - response_id VARCHAR(50) NOT NULL, -- 响应文件ID - project_id VARCHAR(50) NOT NULL, -- 所属项目ID - response_type VARCHAR(50) NOT NULL, -- 响应类型:technical-技术标/commercial-商务标/comprehensive-综合标 - doc_name VARCHAR(500) NOT NULL, -- 文档名称 - outline TEXT, -- 文档大纲(JSON格式) - content TEXT, -- 文档内容 - generation_method VARCHAR(30) DEFAULT 'ai', -- 生成方式:ai-AI生成/template-模板生成/manual-人工编写 - template_id VARCHAR(50), -- 使用的模板ID - ai_model VARCHAR(100), -- 使用的AI模型 - generation_status VARCHAR(30) DEFAULT 'draft', -- 生成状态:draft-草稿/reviewing-审核中/approved-已批准/rejected-已拒绝/submitted-已提交 - file_id VARCHAR(50), -- 生成的文件ID - file_path VARCHAR(500), -- 文件路径 - version INTEGER DEFAULT 1, -- 版本号 - parent_version_id VARCHAR(50), -- 父版本ID - review_comments TEXT, -- 审核意见 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (response_id), - UNIQUE (optsn), - FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id) -); - -CREATE INDEX idx_response_project ON bidding.tb_bid_response(project_id) WHERE deleted = false; -CREATE INDEX idx_response_status ON bidding.tb_bid_response(generation_status) WHERE deleted = false; - -COMMENT ON TABLE bidding.tb_bid_response IS '投标文件生成表'; -COMMENT ON COLUMN bidding.tb_bid_response.generation_status IS '生成状态:draft/reviewing/approved/rejected/submitted'; - --- 评分规则表 -DROP TABLE IF EXISTS bidding.tb_bidding_scoring_rule CASCADE; -CREATE TABLE bidding.tb_bidding_scoring_rule ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - rule_id VARCHAR(50) NOT NULL, -- 规则ID - project_id VARCHAR(50) NOT NULL, -- 所属项目ID - rule_category VARCHAR(50) NOT NULL, -- 规则类别:technical-技术分/commercial-商务分/price-价格分/credit-信誉分 - rule_name VARCHAR(255) NOT NULL, -- 规则名称 - rule_description TEXT, -- 规则描述 - max_score DECIMAL(10,2) NOT NULL, -- 最高分值 - weight DECIMAL(5,4), -- 权重(0-1) - scoring_method VARCHAR(50), -- 评分方法:fixed-固定分值/range-区间评分/formula-公式计算 - calculation_formula TEXT, -- 计算公式 - evaluation_criteria TEXT, -- 评分标准 - our_score DECIMAL(10,2), -- 我方得分(预估) - score_analysis TEXT, -- 得分分析 - optimization_advice TEXT, -- 优化建议 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (rule_id), - UNIQUE (optsn), - FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id) -); - -CREATE INDEX idx_rule_project ON bidding.tb_bidding_scoring_rule(project_id) WHERE deleted = false; - -COMMENT ON TABLE bidding.tb_bidding_scoring_rule IS '评分规则表'; - --- 项目流程节点表 -DROP TABLE IF EXISTS bidding.tb_bidding_process CASCADE; -CREATE TABLE bidding.tb_bidding_process ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - process_id VARCHAR(50) NOT NULL, -- 流程节点ID - project_id VARCHAR(50) NOT NULL, -- 所属项目ID - node_name VARCHAR(255) NOT NULL, -- 节点名称 - node_type VARCHAR(50) NOT NULL, -- 节点类型:collection-文件收集/analysis-需求分析/preparation-文件准备/review-内部审核/submission-投标提交/opening-开标/result-结果通知 - node_order INTEGER NOT NULL, -- 节点顺序 - node_status VARCHAR(30) DEFAULT 'pending', -- 节点状态:pending-待处理/in_progress-进行中/completed-已完成/skipped-已跳过 - planned_start_time TIMESTAMPTZ, -- 计划开始时间 - planned_end_time TIMESTAMPTZ, -- 计划结束时间 - actual_start_time TIMESTAMPTZ, -- 实际开始时间 - actual_end_time TIMESTAMPTZ, -- 实际结束时间 - responsible_user VARCHAR(50), -- 负责人 - participants VARCHAR(50)[], -- 参与人员数组 - notes TEXT, -- 节点备注 - attachments VARCHAR(50)[], -- 附件ID数组 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (process_id), - UNIQUE (optsn), - FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id) -); - -CREATE INDEX idx_process_project ON bidding.tb_bidding_process(project_id, node_order) WHERE deleted = false; - -COMMENT ON TABLE bidding.tb_bidding_process IS '项目流程节点表'; -COMMENT ON COLUMN bidding.tb_bidding_process.node_type IS '节点类型:collection/analysis/preparation/review/submission/opening/result'; - --- 投标模板表 -DROP TABLE IF EXISTS bidding.tb_bid_template CASCADE; -CREATE TABLE bidding.tb_bid_template ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - template_id VARCHAR(50) NOT NULL, -- 模板ID - template_name VARCHAR(255) NOT NULL, -- 模板名称 - template_type VARCHAR(50) NOT NULL, -- 模板类型:technical-技术标/commercial-商务标/comprehensive-综合标 - industry VARCHAR(100), -- 适用行业 - template_content TEXT, -- 模板内容 - outline_structure JSONB, -- 大纲结构(JSON格式) - file_id VARCHAR(50), -- 模板文件ID - usage_count INTEGER DEFAULT 0, -- 使用次数 - is_default BOOLEAN DEFAULT false, -- 是否默认模板 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - status VARCHAR(20) DEFAULT 'active', -- 状态:active-激活/inactive-停用 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (template_id), - UNIQUE (optsn) -); - -CREATE INDEX idx_template_type ON bidding.tb_bid_template(template_type) WHERE deleted = false; - -COMMENT ON TABLE bidding.tb_bid_template IS '投标模板表'; diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableConfig.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableConfig.sql deleted file mode 100644 index f3bd68d4..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableConfig.sql +++ /dev/null @@ -1,51 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS config; -DROP TABLE IF EXISTS config.tb_sys_config CASCADE; -CREATE TABLE config.tb_sys_config ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - config_id VARCHAR(50) NOT NULL, -- 配置ID - key VARCHAR(255) NOT NULL, -- 配置键 - name VARCHAR(255) NOT NULL, -- 配置名称 - value VARCHAR(255) NOT NULL, -- 配置值 - config_type VARCHAR(50) NOT NULL, -- 数据类型(String, INTEGER, BOOLEAN, Float, Double) - render_type VARCHAR(50) NOT NULL, -- 配置渲染类型(select, input, textarea, checkbox, radio, switch) - description VARCHAR(255) NOT NULL, -- 配置描述 - re JSON DEFAULT NULL, -- 正则表达式校验规则 - options JSON DEFAULT NULL, -- 可选项,render_type为select、checkbox、radio时使用 - "group" VARCHAR(255) NOT NULL, -- 配置组 - module_id VARCHAR(255) NOT NULL, -- 模块id - order_num INT NOT NULL, -- 配置顺序 - status INT NOT NULL DEFAULT 0, -- 配置状态 0:启用 1:禁用 - remark VARCHAR(255) NOT NULL, -- 配置备注 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径,支持like递归(如/1/2/3/) - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 配置创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 配置更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 配置删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (config_id), - UNIQUE (optsn) -); -COMMENT ON TABLE config.tb_sys_config IS '系统配置表'; -COMMENT ON COLUMN config.tb_sys_config.optsn IS '流水号'; -COMMENT ON COLUMN config.tb_sys_config.config_id IS '配置ID'; -COMMENT ON COLUMN config.tb_sys_config.key IS '配置键'; -COMMENT ON COLUMN config.tb_sys_config.name IS '配置名称'; -COMMENT ON COLUMN config.tb_sys_config.value IS '配置值'; -COMMENT ON COLUMN config.tb_sys_config.config_type IS '数据类型'; -COMMENT ON COLUMN config.tb_sys_config.render_type IS '数据渲染类型'; -COMMENT ON COLUMN config.tb_sys_config.description IS '配置描述'; -COMMENT ON COLUMN config.tb_sys_config.re IS '正则表达式校验规则'; -COMMENT ON COLUMN config.tb_sys_config.options IS '可选项'; -COMMENT ON COLUMN config.tb_sys_config.group IS'配置组名称'; -COMMENT ON COLUMN config.tb_sys_config.module_id IS '模块id'; -COMMENT ON COLUMN config.tb_sys_config.order_num IS '配置顺序'; -COMMENT ON COLUMN config.tb_sys_config.status IS '配置状态'; -COMMENT ON COLUMN config.tb_sys_config.remark IS '配置备注'; -COMMENT ON COLUMN config.tb_sys_config.creator IS '创建者'; -COMMENT ON COLUMN config.tb_sys_config.dept_path IS '部门全路径'; -COMMENT ON COLUMN config.tb_sys_config.updater IS '更新者'; -COMMENT ON COLUMN config.tb_sys_config.create_time IS '配置创建时间'; -COMMENT ON COLUMN config.tb_sys_config.update_time IS '配置更新时间'; -COMMENT ON COLUMN config.tb_sys_config.delete_time IS '配置删除时间'; -COMMENT ON COLUMN config.tb_sys_config.deleted IS '是否删除'; \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableCrontab.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableCrontab.sql deleted file mode 100644 index 1dfc5e72..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableCrontab.sql +++ /dev/null @@ -1,153 +0,0 @@ --- ==================================================== --- 定时任务表 --- ==================================================== -CREATE SCHEMA IF NOT EXISTS crontab; -DROP TABLE IF EXISTS crontab.tb_crontab_task CASCADE; -CREATE TABLE crontab.tb_crontab_task ( - id VARCHAR(64) NOT NULL, - task_id VARCHAR(64) NOT NULL, - task_name VARCHAR(100) NOT NULL, - task_group VARCHAR(50) NOT NULL DEFAULT 'DEFAULT', - meta_id VARCHAR(64) NOT NULL, - default_recipient SMALLINT NOT NULL DEFAULT 0, -- 是否使用默认接收人(0:否 1:是) - bean_name VARCHAR(100) NOT NULL, - method_name VARCHAR(100) NOT NULL, - method_params VARCHAR(500) DEFAULT NULL, - cron_expression VARCHAR(100) NOT NULL, - status SMALLINT NOT NULL DEFAULT 0, -- 任务状态(0:暂停 1:运行中) - description VARCHAR(500) DEFAULT NULL, - concurrent SMALLINT NOT NULL DEFAULT 0, -- 是否允许并发执行(0:否 1:是) - misfire_policy SMALLINT NOT NULL DEFAULT 1, -- 错过执行策略(1:立即执行 2:执行一次 3:放弃执行) - creator VARCHAR(64) DEFAULT NULL, - updater VARCHAR(64) DEFAULT NULL, - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), - update_time TIMESTAMPTZ DEFAULT NULL, - delete_time TIMESTAMPTZ DEFAULT NULL, - deleted SMALLINT NOT NULL DEFAULT 0, -- 是否删除(0:否 1:是) - PRIMARY KEY (id) -); - -CREATE INDEX IF NOT EXISTS idx_task_name ON crontab.tb_crontab_task(task_name); -CREATE INDEX IF NOT EXISTS idx_bean_name ON crontab.tb_crontab_task(bean_name); -CREATE INDEX IF NOT EXISTS idx_status ON crontab.tb_crontab_task(status); -CREATE INDEX IF NOT EXISTS idx_deleted ON crontab.tb_crontab_task(deleted); - -COMMENT ON TABLE crontab.tb_crontab_task IS '定时任务配置表'; -COMMENT ON COLUMN crontab.tb_crontab_task.id IS '主键ID'; -COMMENT ON COLUMN crontab.tb_crontab_task.task_id IS '任务ID'; -COMMENT ON COLUMN crontab.tb_crontab_task.task_name IS '任务名称'; -COMMENT ON COLUMN crontab.tb_crontab_task.task_group IS '任务分组'; -COMMENT ON COLUMN crontab.tb_crontab_task.meta_id IS '任务元数据ID'; -COMMENT ON COLUMN crontab.tb_crontab_task.default_recipient IS '是否使用默认接收人(0:否 1:是)'; -COMMENT ON COLUMN crontab.tb_crontab_task.bean_name IS 'Bean名称'; -COMMENT ON COLUMN crontab.tb_crontab_task.method_name IS '方法名称'; -COMMENT ON COLUMN crontab.tb_crontab_task.method_params IS '方法参数'; -COMMENT ON COLUMN crontab.tb_crontab_task.cron_expression IS 'Cron表达式'; -COMMENT ON COLUMN crontab.tb_crontab_task.status IS '任务状态(0:暂停 1:运行中)'; -COMMENT ON COLUMN crontab.tb_crontab_task.description IS '任务描述'; -COMMENT ON COLUMN crontab.tb_crontab_task.concurrent IS '是否允许并发执行(0:否 1:是)'; -COMMENT ON COLUMN crontab.tb_crontab_task.misfire_policy IS '错过执行策略(1:立即执行 2:执行一次 3:放弃执行)'; -COMMENT ON COLUMN crontab.tb_crontab_task.creator IS '创建者'; -COMMENT ON COLUMN crontab.tb_crontab_task.updater IS '更新者'; -COMMENT ON COLUMN crontab.tb_crontab_task.create_time IS '创建时间'; -COMMENT ON COLUMN crontab.tb_crontab_task.update_time IS '更新时间'; -COMMENT ON COLUMN crontab.tb_crontab_task.delete_time IS '删除时间'; -COMMENT ON COLUMN crontab.tb_crontab_task.deleted IS '是否删除(0:否 1:是)'; - --- ==================================================== --- 定时任务执行日志表 --- ==================================================== -DROP TABLE IF EXISTS crontab.tb_crontab_log CASCADE; -CREATE TABLE crontab.tb_crontab_log ( - id VARCHAR(64) NOT NULL, - task_id VARCHAR(64) NOT NULL, - task_name VARCHAR(100) NOT NULL, - task_group VARCHAR(50) NOT NULL DEFAULT 'DEFAULT', - bean_name VARCHAR(100) NOT NULL, - method_name VARCHAR(100) NOT NULL, - method_params VARCHAR(500) DEFAULT NULL, - execute_status SMALLINT NOT NULL, -- 执行状态(0:失败 1:成功) - execute_message TEXT DEFAULT NULL, - exception_info TEXT DEFAULT NULL, - start_time TIMESTAMPTZ NOT NULL, - end_time TIMESTAMPTZ DEFAULT NULL, - execute_duration INT DEFAULT NULL, - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), - update_time TIMESTAMPTZ DEFAULT NULL, - delete_time TIMESTAMPTZ DEFAULT NULL, - deleted SMALLINT NOT NULL DEFAULT 0, -- 是否删除(0:否 1:是) - PRIMARY KEY (id) -); - -CREATE INDEX IF NOT EXISTS idx_task_id ON crontab.tb_crontab_log(task_id); -CREATE INDEX IF NOT EXISTS idx_log_task_name ON crontab.tb_crontab_log(task_name); -CREATE INDEX IF NOT EXISTS idx_execute_status ON crontab.tb_crontab_log(execute_status); -CREATE INDEX IF NOT EXISTS idx_start_time ON crontab.tb_crontab_log(start_time); -CREATE INDEX IF NOT EXISTS idx_log_deleted ON crontab.tb_crontab_log(deleted); - -COMMENT ON TABLE crontab.tb_crontab_log IS '定时任务执行日志表'; -COMMENT ON COLUMN crontab.tb_crontab_log.id IS '主键ID'; -COMMENT ON COLUMN crontab.tb_crontab_log.task_id IS '任务ID'; -COMMENT ON COLUMN crontab.tb_crontab_log.task_name IS '任务名称'; -COMMENT ON COLUMN crontab.tb_crontab_log.task_group IS '任务分组'; -COMMENT ON COLUMN crontab.tb_crontab_log.bean_name IS 'Bean名称'; -COMMENT ON COLUMN crontab.tb_crontab_log.method_name IS '方法名称'; -COMMENT ON COLUMN crontab.tb_crontab_log.method_params IS '方法参数'; -COMMENT ON COLUMN crontab.tb_crontab_log.execute_status IS '执行状态(0:失败 1:成功)'; -COMMENT ON COLUMN crontab.tb_crontab_log.execute_message IS '执行结果信息'; -COMMENT ON COLUMN crontab.tb_crontab_log.exception_info IS '异常信息'; -COMMENT ON COLUMN crontab.tb_crontab_log.start_time IS '开始时间'; -COMMENT ON COLUMN crontab.tb_crontab_log.end_time IS '结束时间'; -COMMENT ON COLUMN crontab.tb_crontab_log.execute_duration IS '执行时长(毫秒)'; -COMMENT ON COLUMN crontab.tb_crontab_log.create_time IS '创建时间'; -COMMENT ON COLUMN crontab.tb_crontab_log.update_time IS '更新时间'; -COMMENT ON COLUMN crontab.tb_crontab_log.delete_time IS '删除时间'; -COMMENT ON COLUMN crontab.tb_crontab_log.deleted IS '是否删除(0:否 1:是)'; - --- ==================================================== --- 定时任务元数据表(存储爬虫任务的元数据配置) --- ==================================================== -DROP TABLE IF EXISTS crontab.tb_crontab_task_meta CASCADE; -CREATE TABLE crontab.tb_crontab_task_meta ( - id VARCHAR(64) NOT NULL, - meta_id VARCHAR(64) NOT NULL, - name VARCHAR(100) NOT NULL, - description VARCHAR(500) DEFAULT NULL, - category VARCHAR(50) NOT NULL, - bean_name VARCHAR(100) NOT NULL, - method_name VARCHAR(100) NOT NULL, - script_path VARCHAR(255) DEFAULT NULL, - param_schema TEXT DEFAULT NULL, - auto_publish SMALLINT NOT NULL DEFAULT 0, -- 是否自动发布 - sort_order INT DEFAULT 0, - creator VARCHAR(64) DEFAULT NULL, - updater VARCHAR(64) DEFAULT NULL, - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), - update_time TIMESTAMPTZ DEFAULT NULL, - delete_time TIMESTAMPTZ DEFAULT NULL, - deleted SMALLINT NOT NULL DEFAULT 0, -- 是否删除(0:否 1:是) - PRIMARY KEY (id), - UNIQUE (meta_id) -); - -CREATE INDEX IF NOT EXISTS idx_category ON crontab.tb_crontab_task_meta(category); -CREATE INDEX IF NOT EXISTS idx_meta_deleted ON crontab.tb_crontab_task_meta(deleted); - -COMMENT ON TABLE crontab.tb_crontab_task_meta IS '定时任务元数据表'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.id IS '主键ID'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.meta_id IS '元数据ID'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.name IS '任务名称'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.description IS '任务描述'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.category IS '任务分类(如:人民日报新闻爬取)'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.bean_name IS 'Bean名称(执行器类名)'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.method_name IS '执行方法名'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.script_path IS 'Python脚本路径(相对于basePath)'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.param_schema IS '参数模板(JSON格式,定义参数名、类型、描述、默认值等)'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.auto_publish IS '是否自动发布'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.sort_order IS '排序号'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.creator IS '创建者'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.updater IS '更新者'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.create_time IS '创建时间'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.update_time IS '更新时间'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.delete_time IS '删除时间'; -COMMENT ON COLUMN crontab.tb_crontab_task_meta.deleted IS '是否删除(0:否 1:是)'; \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableFile.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableFile.sql deleted file mode 100644 index 06b2f7ac..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableFile.sql +++ /dev/null @@ -1,79 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS file; - -DROP TABLE IF EXISTS file.tb_sys_file CASCADE; -CREATE TABLE file.tb_sys_file ( - -- BaseDTO 继承字段 - optsn VARCHAR(50) NOT NULL, -- 操作流水号 - creator VARCHAR(50) DEFAULT NULL, -- 创建人 - updater VARCHAR(50) DEFAULT NULL, -- 更新人 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门路径 - remark TEXT DEFAULT NULL, -- 备注 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否已删除(false-未删除,true-已删除) - - -- TbSysFileDTO 特有字段 - file_id VARCHAR(50) NOT NULL, -- 文件ID (主键) - file_root_id VARCHAR(50) DEFAULT NULL, -- 文件根ID - version INTEGER DEFAULT 1, -- 文件版本 - name VARCHAR(255) NOT NULL, -- 文件名 - path VARCHAR(500) NOT NULL, -- 文件路径 - size BIGINT NOT NULL, -- 文件大小(字节) - type VARCHAR(50) DEFAULT NULL, -- 文件类型 - storage_type VARCHAR(50) DEFAULT NULL, -- 存储类型 - mime_type VARCHAR(255) DEFAULT NULL, -- MIME 类型 - url VARCHAR(500) DEFAULT NULL, -- 后端下载接口路径(保留用于扩展,建议使用 /api/file/download/{fileId}) - status VARCHAR(50) DEFAULT NULL, -- 文件状态 - module VARCHAR(100) DEFAULT NULL, -- 所属模块 - business_id VARCHAR(50) DEFAULT NULL, -- 业务ID - uploader VARCHAR(50) DEFAULT NULL, -- 上传者用户ID - object_name VARCHAR(500) DEFAULT NULL, -- MinIO对象名称 - bucket_name VARCHAR(100) DEFAULT NULL, -- MinIO存储桶名称 - md5_hash VARCHAR(32) DEFAULT NULL, -- 文件MD5值 - extension VARCHAR(20) DEFAULT NULL, -- 文件扩展名 - - PRIMARY KEY (file_id), - UNIQUE (optsn) -); - -COMMENT ON TABLE file.tb_sys_file IS '系统文件表'; - --- BaseDTO 继承字段注释 -COMMENT ON COLUMN file.tb_sys_file.optsn IS '操作流水号'; -COMMENT ON COLUMN file.tb_sys_file.creator IS '创建人'; -COMMENT ON COLUMN file.tb_sys_file.updater IS '更新人'; -COMMENT ON COLUMN file.tb_sys_file.dept_path IS '部门路径'; -COMMENT ON COLUMN file.tb_sys_file.remark IS '备注'; -COMMENT ON COLUMN file.tb_sys_file.create_time IS '创建时间'; -COMMENT ON COLUMN file.tb_sys_file.update_time IS '更新时间'; -COMMENT ON COLUMN file.tb_sys_file.delete_time IS '删除时间'; -COMMENT ON COLUMN file.tb_sys_file.deleted IS '是否已删除(false-未删除,true-已删除)'; - --- TbSysFileDTO 特有字段注释 -COMMENT ON COLUMN file.tb_sys_file.file_id IS '文件ID (主键)'; -COMMENT ON COLUMN file.tb_sys_file.file_root_id IS '文件根ID'; -COMMENT ON COLUMN file.tb_sys_file.version IS '文件版本'; -COMMENT ON COLUMN file.tb_sys_file.name IS '文件名'; -COMMENT ON COLUMN file.tb_sys_file.path IS '文件路径'; -COMMENT ON COLUMN file.tb_sys_file.size IS '文件大小(字节)'; -COMMENT ON COLUMN file.tb_sys_file.type IS '文件类型'; -COMMENT ON COLUMN file.tb_sys_file.storage_type IS '存储类型'; -COMMENT ON COLUMN file.tb_sys_file.mime_type IS 'MIME 类型'; -COMMENT ON COLUMN file.tb_sys_file.url IS '后端下载接口路径(保留用于扩展,建议使用 /api/file/download/{fileId})'; -COMMENT ON COLUMN file.tb_sys_file.status IS '文件状态'; -COMMENT ON COLUMN file.tb_sys_file.module IS '所属模块'; -COMMENT ON COLUMN file.tb_sys_file.business_id IS '业务ID'; -COMMENT ON COLUMN file.tb_sys_file.uploader IS '上传者用户ID'; -COMMENT ON COLUMN file.tb_sys_file.object_name IS 'MinIO对象名称'; -COMMENT ON COLUMN file.tb_sys_file.bucket_name IS 'MinIO存储桶名称'; -COMMENT ON COLUMN file.tb_sys_file.md5_hash IS '文件MD5值'; -COMMENT ON COLUMN file.tb_sys_file.extension IS '文件扩展名'; - --- 文件表索引 --- CREATE INDEX idx_file_module_business ON file.tb_sys_file(module, business_id) WHERE deleted = false; --- CREATE INDEX idx_file_uploader ON file.tb_sys_file(uploader) WHERE deleted = false; --- CREATE INDEX idx_file_bucket ON file.tb_sys_file(bucket_name) WHERE deleted = false; --- CREATE INDEX idx_file_status ON file.tb_sys_file(status) WHERE deleted = false; --- CREATE INDEX idx_file_create_time ON file.tb_sys_file(create_time) WHERE deleted = false; --- CREATE INDEX idx_file_md5 ON file.tb_sys_file(md5_hash) WHERE deleted = false; \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableLog.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableLog.sql deleted file mode 100644 index 34f64652..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableLog.sql +++ /dev/null @@ -1,42 +0,0 @@ -DROP TABLE IF EXISTS sys.tb_sys_log CASCADE; -CREATE TABLE sys.tb_sys_log ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - log_id VARCHAR(50) NOT NULL, -- 日志ID - type VARCHAR(50) NOT NULL, -- 日志类型 - level VARCHAR(50) NOT NULL, -- 日志级别 - module VARCHAR(50) NOT NULL, -- 日志模块 - ip_address VARCHAR(45), -- IP地址 - ip_source VARCHAR(100), -- IP来源 - browser VARCHAR(100), -- 浏览器 - os VARCHAR(100), -- 操作系统 - message VARCHAR(255) NOT NULL, -- 日志消息 - data JSONB DEFAULT NULL, -- 日志数据 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - creator_name VARCHAR(200) DEFAULT NULL, -- 创建者姓名 - service VARCHAR(50) NOT NULL, -- 服务类型 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 日志创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 日志更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 日志删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (log_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_log IS '系统日志表'; -COMMENT ON COLUMN sys.tb_sys_log.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_log.log_id IS '日志ID'; -COMMENT ON COLUMN sys.tb_sys_log.type IS '日志类型'; -COMMENT ON COLUMN sys.tb_sys_log.level IS '日志级别'; -COMMENT ON COLUMN sys.tb_sys_log.module IS '日志模块'; -COMMENT ON COLUMN sys.tb_sys_log.message IS '日志消息'; -COMMENT ON COLUMN sys.tb_sys_log.data IS '日志数据'; -COMMENT ON COLUMN sys.tb_sys_log.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_log.creator_name IS '创建者姓名'; -COMMENT ON COLUMN sys.tb_sys_log.service IS '服务类型'; -COMMENT ON COLUMN sys.tb_sys_log.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_log.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_log.create_time IS '日志创建时间'; -COMMENT ON COLUMN sys.tb_sys_log.update_time IS '日志更新时间'; -COMMENT ON COLUMN sys.tb_sys_log.delete_time IS '日志删除时间'; -COMMENT ON COLUMN sys.tb_sys_log.deleted IS '是否删除'; \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableMessage.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableMessage.sql deleted file mode 100644 index 43aad8ba..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableMessage.sql +++ /dev/null @@ -1,200 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS message; - -DROP TABLE IF EXISTS message.tb_message CASCADE; -CREATE TABLE message.tb_message ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - message_id VARCHAR(50) NOT NULL, -- 消息ID - title VARCHAR(255) NOT NULL, -- 消息标题 - content VARCHAR(255) NOT NULL, -- 消息内容 - type VARCHAR(50) NOT NULL, -- 消息类型 - status VARCHAR(50) NOT NULL, -- 消息状态 - service VARCHAR(50) NOT NULL, -- 服务类型 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径(隔离) - creator VARCHAR(50) NOT NULL DEFAULT 'system',-- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, - delete_time TIMESTAMPTZ DEFAULT NULL, - deleted BOOLEAN NOT NULL DEFAULT false, - PRIMARY KEY (message_id), - UNIQUE (optsn) -); - -COMMENT ON TABLE message.tb_message IS '消息表'; -COMMENT ON COLUMN message.tb_message.optsn IS '流水号'; -COMMENT ON COLUMN message.tb_message.message_id IS '消息ID'; -COMMENT ON COLUMN message.tb_message.title IS '消息标题'; -COMMENT ON COLUMN message.tb_message.content IS '消息内容'; -COMMENT ON COLUMN message.tb_message.type IS '消息类型'; -COMMENT ON COLUMN message.tb_message.status IS '消息状态'; -COMMENT ON COLUMN message.tb_message.service IS '服务类型'; -COMMENT ON COLUMN message.tb_message.dept_path IS '部门全路径'; -COMMENT ON COLUMN message.tb_message.creator IS '创建者'; -COMMENT ON COLUMN message.tb_message.updater IS '更新者'; -COMMENT ON COLUMN message.tb_message.create_time IS '创建时间'; -COMMENT ON COLUMN message.tb_message.update_time IS '更新时间'; -COMMENT ON COLUMN message.tb_message.delete_time IS '删除时间'; -COMMENT ON COLUMN message.tb_message.deleted IS '是否删除'; - - --- 消息发送范围定义表(定义消息要发送给哪些对象,通过什么渠道) -DROP TABLE IF EXISTS message.tb_message_range CASCADE; -CREATE TABLE message.tb_message_range ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - message_id VARCHAR(50) NOT NULL, -- 消息ID - target_type VARCHAR(20) NOT NULL, -- 目标类型:user/dept/role/all - target_id VARCHAR(50) DEFAULT NULL, -- 目标ID(用户、部门、角色ID等,all类型时为空) - channel VARCHAR(20) NOT NULL DEFAULT 'app', -- 发送渠道:app/sms/email/wechat_official_account/wechat_applet等 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径,支持like递归(如/1/2/3/) - creator VARCHAR(50) NOT NULL DEFAULT 'system',-- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (optsn), - UNIQUE (message_id, target_type, target_id, channel) -); - -COMMENT ON TABLE message.tb_message_range IS '消息发送范围定义表'; -COMMENT ON COLUMN message.tb_message_range.optsn IS '流水号'; -COMMENT ON COLUMN message.tb_message_range.message_id IS '消息ID'; -COMMENT ON COLUMN message.tb_message_range.target_type IS '目标类型:user-指定用户/dept-部门/role-角色/all-全员'; -COMMENT ON COLUMN message.tb_message_range.target_id IS '目标ID(用户、部门、角色ID等,all类型时为空)'; -COMMENT ON COLUMN message.tb_message_range.channel IS '发送渠道:app/sms/email/wechat_official_account/wechat_applet等'; -COMMENT ON COLUMN message.tb_message_range.dept_path IS '部门全路径'; -COMMENT ON COLUMN message.tb_message_range.creator IS '创建者'; -COMMENT ON COLUMN message.tb_message_range.updater IS '更新者'; -COMMENT ON COLUMN message.tb_message_range.create_time IS '创建时间'; -COMMENT ON COLUMN message.tb_message_range.update_time IS '更新时间'; -COMMENT ON COLUMN message.tb_message_range.delete_time IS '删除时间'; -COMMENT ON COLUMN message.tb_message_range.deleted IS '是否删除'; - - --- 用户消息接收记录表(记录每个用户实际收到的消息及处理状态) -DROP TABLE IF EXISTS message.tb_message_receiver CASCADE; -CREATE TABLE message.tb_message_receiver ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - message_id VARCHAR(50) NOT NULL, -- 消息ID - user_id VARCHAR(50) NOT NULL, -- 用户ID - channel VARCHAR(20) DEFAULT 'app', -- 接收渠道:app/sms/email/wechat等 - status VARCHAR(20) NOT NULL DEFAULT 'unread', -- 消息状态:unread-未读/read-已读/handled-已处理/deleted-已删除 - read_time TIMESTAMPTZ DEFAULT NULL, -- 阅读时间 - handle_time TIMESTAMPTZ DEFAULT NULL, -- 处理时间 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径(数据隔离) - creator VARCHAR(50) NOT NULL DEFAULT 'system',-- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间(接收时间) - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (optsn), - UNIQUE (message_id, user_id, channel) -); - --- 创建索引以提高查询效率 -CREATE INDEX idx_message_user_user_status ON message.tb_message_receiver(user_id, status, create_time DESC) WHERE deleted = false; -CREATE INDEX idx_message_user_message ON message.tb_message_receiver(message_id) WHERE deleted = false; - -COMMENT ON TABLE message.tb_message_receiver IS '用户消息接收记录表'; -COMMENT ON COLUMN message.tb_message_receiver.optsn IS '流水号'; -COMMENT ON COLUMN message.tb_message_receiver.message_id IS '消息ID'; -COMMENT ON COLUMN message.tb_message_receiver.user_id IS '用户ID'; -COMMENT ON COLUMN message.tb_message_receiver.channel IS '接收渠道:app/sms/email/wechat等'; -COMMENT ON COLUMN message.tb_message_receiver.status IS '消息状态:unread-未读/read-已读/handled-已处理/deleted-已删除'; -COMMENT ON COLUMN message.tb_message_receiver.read_time IS '阅读时间'; -COMMENT ON COLUMN message.tb_message_receiver.handle_time IS '处理时间'; -COMMENT ON COLUMN message.tb_message_receiver.dept_path IS '部门全路径'; -COMMENT ON COLUMN message.tb_message_receiver.creator IS '创建者'; -COMMENT ON COLUMN message.tb_message_receiver.updater IS '更新者'; -COMMENT ON COLUMN message.tb_message_receiver.create_time IS '创建时间(接收时间)'; -COMMENT ON COLUMN message.tb_message_receiver.update_time IS '更新时间'; -COMMENT ON COLUMN message.tb_message_receiver.delete_time IS '删除时间'; -COMMENT ON COLUMN message.tb_message_receiver.deleted IS '是否删除'; - - --- 消息渠道配置表(管理各种消息发送渠道的配置) -DROP TABLE IF EXISTS message.tb_message_channel CASCADE; -CREATE TABLE message.tb_message_channel ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - channel_id VARCHAR(50) NOT NULL, -- 渠道ID - channel_code VARCHAR(50) NOT NULL, -- 渠道编码:app/sms/email/wechat/dingtalk等 - channel_name VARCHAR(100) NOT NULL, -- 渠道名称 - channel_desc VARCHAR(255) DEFAULT NULL, -- 渠道描述 - config JSON DEFAULT NULL, -- 渠道配置(如API密钥、服务器地址等) - status VARCHAR(20) NOT NULL DEFAULT 'enabled', -- 渠道状态:enabled-启用/disabled-禁用/maintenance-维护中 - priority INTEGER DEFAULT 0, -- 优先级(数字越大优先级越高) - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径(数据隔离) - creator VARCHAR(50) NOT NULL DEFAULT 'system',-- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (channel_id), - UNIQUE (optsn), - UNIQUE (channel_code) -); - -COMMENT ON TABLE message.tb_message_channel IS '消息渠道配置表'; -COMMENT ON COLUMN message.tb_message_channel.optsn IS '流水号'; -COMMENT ON COLUMN message.tb_message_channel.channel_id IS '渠道ID'; -COMMENT ON COLUMN message.tb_message_channel.channel_code IS '渠道编码:app/sms/email/wechat/dingtalk等'; -COMMENT ON COLUMN message.tb_message_channel.channel_name IS '渠道名称'; -COMMENT ON COLUMN message.tb_message_channel.channel_desc IS '渠道描述'; -COMMENT ON COLUMN message.tb_message_channel.config IS '渠道配置(JSON格式)'; -COMMENT ON COLUMN message.tb_message_channel.status IS '渠道状态:enabled-启用/disabled-禁用/maintenance-维护中'; -COMMENT ON COLUMN message.tb_message_channel.priority IS '优先级(数字越大优先级越高)'; -COMMENT ON COLUMN message.tb_message_channel.dept_path IS '部门全路径'; -COMMENT ON COLUMN message.tb_message_channel.creator IS '创建者'; -COMMENT ON COLUMN message.tb_message_channel.updater IS '更新者'; -COMMENT ON COLUMN message.tb_message_channel.create_time IS '创建时间'; -COMMENT ON COLUMN message.tb_message_channel.update_time IS '更新时间'; -COMMENT ON COLUMN message.tb_message_channel.delete_time IS '删除时间'; -COMMENT ON COLUMN message.tb_message_channel.deleted IS '是否删除'; - --- ============================= --- 消息模板表 --- ============================= -DROP TABLE IF EXISTS message.tb_message_template CASCADE; -CREATE TABLE message.tb_message_template ( - optsn VARCHAR(50) NOT NULL, - template_id VARCHAR(50) NOT NULL, - template_code VARCHAR(100) NOT NULL, -- 模板编码 - template_name VARCHAR(255) NOT NULL, -- 模板名称 - template_type VARCHAR(30) NOT NULL, -- 模板类型:system-系统/business-业务 - title_template TEXT, -- 标题模板(支持变量) - content_template TEXT NOT NULL, -- 内容模板(支持变量) - variables JSONB, -- 模板变量定义 - service VARCHAR(50) NOT NULL, -- 服务类型 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (template_id), - UNIQUE (optsn), - UNIQUE (template_code) -); - -COMMENT ON TABLE message.tb_message_template IS '消息模板表'; -COMMENT ON COLUMN message.tb_message_template.optsn IS '流水号'; -COMMENT ON COLUMN message.tb_message_template.template_id IS '模板ID'; -COMMENT ON COLUMN message.tb_message_template.template_code IS '模板编码'; -COMMENT ON COLUMN message.tb_message_template.template_name IS '模板名称'; -COMMENT ON COLUMN message.tb_message_template.template_type IS '模板类型:system-系统/business-业务'; -COMMENT ON COLUMN message.tb_message_template.title_template IS '标题模板(支持变量)'; -COMMENT ON COLUMN message.tb_message_template.content_template IS '内容模板(支持变量)'; -COMMENT ON COLUMN message.tb_message_template.variables IS '模板变量定义'; -COMMENT ON COLUMN message.tb_message_template.service IS '服务类型'; -COMMENT ON COLUMN message.tb_message_template.dept_path IS '部门全路径'; -COMMENT ON COLUMN message.tb_message_template.creator IS '创建者'; -COMMENT ON COLUMN message.tb_message_template.updater IS '更新者'; -COMMENT ON COLUMN message.tb_message_template.create_time IS '创建时间'; -COMMENT ON COLUMN message.tb_message_template.update_time IS '更新时间'; -COMMENT ON COLUMN message.tb_message_template.delete_time IS '删除时间'; -COMMENT ON COLUMN message.tb_message_template.deleted IS '是否删除'; - -CREATE INDEX idx_template_type ON message.tb_message_template(template_type) WHERE deleted = false; diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTablePermission.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTablePermission.sql deleted file mode 100644 index dcf5082a..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTablePermission.sql +++ /dev/null @@ -1,473 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS sys; - --- 通用更新时间触发函数(用于模拟 MySQL 的 ON UPDATE CURRENT_TIMESTAMP) --- CREATE OR REPLACE FUNCTION sys.set_update_time() --- RETURNS trigger AS $$ --- BEGIN --- NEW.update_time := CURRENT_TIMESTAMP; --- RETURN NEW; --- END; --- $$ LANGUAGE plpgsql; - --- 部门表 -DROP TABLE IF EXISTS sys.tb_sys_dept CASCADE; -CREATE TABLE sys.tb_sys_dept ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - dept_id VARCHAR(50) NOT NULL, -- 部门ID - name VARCHAR(100) NOT NULL, -- 部门名称 - parent_id VARCHAR(50) DEFAULT NULL, -- 父部门ID - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - description VARCHAR(255) DEFAULT NULL, -- 部门描述 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (dept_id), - UNIQUE (optsn) -); --- 创建索引 -CREATE INDEX idx_sys_dept_parent ON sys.tb_sys_dept USING btree (parent_id); -COMMENT ON TABLE sys.tb_sys_dept IS '部门表'; -COMMENT ON COLUMN sys.tb_sys_dept.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_dept.dept_id IS '部门ID'; -COMMENT ON COLUMN sys.tb_sys_dept.name IS '部门名称'; -COMMENT ON COLUMN sys.tb_sys_dept.parent_id IS '父部门ID'; -COMMENT ON COLUMN sys.tb_sys_dept.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_dept.description IS '部门描述'; -COMMENT ON COLUMN sys.tb_sys_dept.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_dept.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_dept.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_dept.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_dept.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_dept.deleted IS '是否删除'; - --- 角色表 -DROP TABLE IF EXISTS sys.tb_sys_role CASCADE; -CREATE TABLE sys.tb_sys_role ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - role_id VARCHAR(50) NOT NULL, -- 角色ID - name VARCHAR(100) NOT NULL, - description VARCHAR(200) DEFAULT NULL, -- 角色名称 - scope VARCHAR(20) NOT NULL DEFAULT 'dept', -- 角色作用域:global/dept - owner_dept_id VARCHAR(50) DEFAULT NULL, -- 当scope=dept时,所属部门ID - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - dept_path VARCHAR(255) DEFAULT NULL, - status BOOLEAN NOT NULL DEFAULT false, -- 部门全路径 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (role_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_role IS '角色表'; -COMMENT ON COLUMN sys.tb_sys_role.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_role.role_id IS '角色ID'; -COMMENT ON COLUMN sys.tb_sys_role.name IS '角色名称'; -COMMENT ON COLUMN sys.tb_sys_role.description IS '角色名称'; -COMMENT ON COLUMN sys.tb_sys_role.scope IS '角色作用域:global=通用,dept=部门私有'; -COMMENT ON COLUMN sys.tb_sys_role.owner_dept_id IS '部门私有角色的所属部门ID(scope=dept 时必填)'; -COMMENT ON COLUMN sys.tb_sys_role.status IS '角色状态'; -COMMENT ON COLUMN sys.tb_sys_role.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_role.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_role.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_role.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_role.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_role.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_role.deleted IS '是否删除'; - --- 唯一性: --- 全局角色:name 在未删除且 scope=global 下唯一 --- 部门私有角色:同一部门下 name 唯一(scope=dept) -CREATE UNIQUE INDEX IF NOT EXISTS uq_sys_role_global_name - ON sys.tb_sys_role USING btree (name) - WHERE deleted = false AND scope = 'global'; -CREATE UNIQUE INDEX IF NOT EXISTS uq_sys_role_dept_name - ON sys.tb_sys_role USING btree (owner_dept_id, name) - WHERE deleted = false AND scope = 'dept'; -CREATE INDEX IF NOT EXISTS idx_sys_role_owner_dept ON sys.tb_sys_role USING btree (owner_dept_id) WHERE deleted = false; - --- 部门角色关联表 -DROP TABLE IF EXISTS sys.tb_sys_dept_role CASCADE; -CREATE TABLE sys.tb_sys_dept_role ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - dept_id VARCHAR(50) NOT NULL, -- 部门ID - role_id VARCHAR(50) NOT NULL, -- 角色ID - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (dept_id, role_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_dept_role IS '部门角色关联表'; -COMMENT ON COLUMN sys.tb_sys_dept_role.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_dept_role.dept_id IS '部门ID'; -COMMENT ON COLUMN sys.tb_sys_dept_role.role_id IS '角色ID'; -COMMENT ON COLUMN sys.tb_sys_dept_role.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_dept_role.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_dept_role.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_dept_role.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_dept_role.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_dept_role.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_dept_role.deleted IS '是否删除'; - --- 用户角色关联表 -DROP TABLE IF EXISTS sys.tb_sys_user_role CASCADE; -CREATE TABLE sys.tb_sys_user_role ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - user_id VARCHAR(50) NOT NULL, -- 用户ID - role_id VARCHAR(50) NOT NULL, -- 角色ID - dept_id VARCHAR(50) NOT NULL, -- 部门ID - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (user_id, role_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_user_role IS '用户角色关联表'; -COMMENT ON COLUMN sys.tb_sys_user_role.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_user_role.user_id IS '用户ID'; -COMMENT ON COLUMN sys.tb_sys_user_role.role_id IS '角色ID'; -COMMENT ON COLUMN sys.tb_sys_user_role.dept_id IS '部门ID'; -COMMENT ON COLUMN sys.tb_sys_user_role.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_user_role.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_user_role.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_user_role.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_user_role.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_user_role.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_user_role.deleted IS '是否删除'; - --- 视图表 -DROP TABLE IF EXISTS sys.tb_sys_view CASCADE; -CREATE TABLE sys.tb_sys_view ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - view_id VARCHAR(50) NOT NULL, -- 视图ID - name VARCHAR(100) NOT NULL, -- 视图名称 - parent_id VARCHAR(50) DEFAULT NULL, -- 父视图ID - url VARCHAR(255) DEFAULT NULL, -- 视图URL - component VARCHAR(255) DEFAULT NULL, -- 视图组件 - icon VARCHAR(100) DEFAULT NULL, -- 视图图标 - type INTEGER DEFAULT 0, -- 视图类型:0=导航栏 1=侧边栏 2=按钮,3空白页 - view_type VARCHAR(20) DEFAULT 'route', -- 页面类型:route=路由页面 iframe=嵌入页面 - iframe_url VARCHAR(500) DEFAULT NULL, -- iframe URL(仅当view_type=iframe时有效) - service VARCHAR(20) DEFAULT 'platform', -- 所属服务:platform=平台应用 bidding=招标应用 workcase=客服应用 - layout VARCHAR(100) DEFAULT NULL, -- 布局组件路径名称 - order_num INTEGER DEFAULT 0, -- 视图排序号 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - description VARCHAR(255) DEFAULT NULL, -- 视图描述 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (view_id), - UNIQUE (optsn) -); --- 创建索引 -CREATE INDEX idx_sys_view_parent ON sys.tb_sys_view USING btree (parent_id) WHERE deleted = false; -CREATE INDEX idx_sys_view_service ON sys.tb_sys_view USING btree (service) WHERE deleted = false; -CREATE INDEX idx_sys_view_type ON sys.tb_sys_view USING btree (view_type) WHERE deleted = false; -COMMENT ON TABLE sys.tb_sys_view IS '视图表(菜单表)'; -COMMENT ON COLUMN sys.tb_sys_view.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_view.view_id IS '视图ID'; -COMMENT ON COLUMN sys.tb_sys_view.name IS '视图名称'; -COMMENT ON COLUMN sys.tb_sys_view.parent_id IS '父视图ID'; -COMMENT ON COLUMN sys.tb_sys_view.url IS '视图URL'; -COMMENT ON COLUMN sys.tb_sys_view.component IS '视图组件'; -COMMENT ON COLUMN sys.tb_sys_view.icon IS '视图图标'; -COMMENT ON COLUMN sys.tb_sys_view.type IS '视图类型:0=目录 1=菜单页面 2=按钮'; -COMMENT ON COLUMN sys.tb_sys_view.view_type IS '页面类型:route=路由页面 iframe=嵌入页面'; -COMMENT ON COLUMN sys.tb_sys_view.iframe_url IS 'iframe URL(仅当view_type=iframe时有效)'; -COMMENT ON COLUMN sys.tb_sys_view.service IS '所属服务:platform=平台应用 bidding=招标应用 workcase=客服应用'; -COMMENT ON COLUMN sys.tb_sys_view.layout IS '布局组件路径名称'; -COMMENT ON COLUMN sys.tb_sys_view.order_num IS '视图排序号'; -COMMENT ON COLUMN sys.tb_sys_view.description IS '视图描述'; -COMMENT ON COLUMN sys.tb_sys_view.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_view.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_view.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_view.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_view.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_view.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_view.deleted IS '是否删除'; - - --- 模块表 -DROP TABLE IF EXISTS sys.tb_sys_module CASCADE; -CREATE TABLE sys.tb_sys_module ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - module_id VARCHAR(50) NOT NULL, -- 模块ID - name VARCHAR(100) NOT NULL, -- 模块名称 - description VARCHAR(255) DEFAULT NULL, -- 模块描述 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (module_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_module IS '模块表'; -COMMENT ON COLUMN sys.tb_sys_module.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_module.module_id IS '模块ID'; -COMMENT ON COLUMN sys.tb_sys_module.name IS '模块名称'; -COMMENT ON COLUMN sys.tb_sys_module.description IS '模块描述'; -COMMENT ON COLUMN sys.tb_sys_module.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_module.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_module.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_module.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_module.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_module.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_module.deleted IS '是否删除'; - --- 权限表 -DROP TABLE IF EXISTS sys.tb_sys_permission CASCADE; -CREATE TABLE sys.tb_sys_permission ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - permission_id VARCHAR(50) NOT NULL, -- 权限ID - name VARCHAR(100) NOT NULL, -- 权限名称 - code VARCHAR(100) NOT NULL, -- 权限代码 - description VARCHAR(255) DEFAULT NULL, -- 权限描述 - module_id VARCHAR(50) DEFAULT NULL, -- 所属模块ID - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - dept_path VARCHAR(255) DEFAULT NULL, - status BOOLEAN NOT NULL DEFAULT false, -- 部门全路径 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (permission_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_permission IS '权限表'; -COMMENT ON COLUMN sys.tb_sys_permission.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_permission.permission_id IS '权限ID'; -COMMENT ON COLUMN sys.tb_sys_permission.name IS '权限名称'; -COMMENT ON COLUMN sys.tb_sys_permission.code IS '权限代码'; -COMMENT ON COLUMN sys.tb_sys_permission.description IS '权限描述' ; -COMMENT ON COLUMN sys.tb_sys_permission.module_id IS '所属模块ID'; -COMMENT ON COLUMN sys.tb_sys_permission.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_permission.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_permission.status IS '角色状态'; -COMMENT ON COLUMN sys.tb_sys_permission.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_permission.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_permission.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_permission.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_permission.deleted IS '是否删除'; - --- 角色权限 -DROP TABLE IF EXISTS sys.tb_sys_role_permission CASCADE; -CREATE TABLE sys.tb_sys_role_permission ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - role_id VARCHAR(50) NOT NULL, -- 角色ID - permission_id VARCHAR(50) NOT NULL, -- 权限ID - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (role_id, permission_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_role_permission IS '角色权限表'; -COMMENT ON COLUMN sys.tb_sys_role_permission.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_role_permission.role_id IS '角色ID'; -COMMENT ON COLUMN sys.tb_sys_role_permission.permission_id IS '权限ID'; -COMMENT ON COLUMN sys.tb_sys_role_permission.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_role_permission.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_role_permission.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_role_permission.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_role_permission.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_role_permission.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_role_permission.deleted IS '是否删除'; - --- 视图权限 -DROP TABLE IF EXISTS sys.tb_sys_view_permission CASCADE; -CREATE TABLE sys.tb_sys_view_permission ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - view_id VARCHAR(50) NOT NULL, -- 视图ID - permission_id VARCHAR(50) NOT NULL, -- 权限ID - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (view_id, permission_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_view_permission IS '视图权限表'; -COMMENT ON COLUMN sys.tb_sys_view_permission.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_view_permission.view_id IS '视图ID'; -COMMENT ON COLUMN sys.tb_sys_view_permission.permission_id IS '权限ID'; -COMMENT ON COLUMN sys.tb_sys_view_permission.creator IS '创建者'; -COMMENT ON COLUMN sys.tb_sys_view_permission.dept_path IS '部门全路径'; -COMMENT ON COLUMN sys.tb_sys_view_permission.updater IS '更新者'; -COMMENT ON COLUMN sys.tb_sys_view_permission.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_view_permission.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_view_permission.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_view_permission.deleted IS '是否删除'; - --- 为所有表创建更新时间触发器 --- DROP TRIGGER IF EXISTS trg_tb_sys_dept_update_time ON sys.tb_sys_dept; --- CREATE TRIGGER trg_tb_sys_dept_update_time --- BEFORE UPDATE ON sys.tb_sys_dept --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- DROP TRIGGER IF EXISTS trg_tb_sys_role_update_time ON sys.tb_sys_role; --- CREATE TRIGGER trg_tb_sys_role_update_time --- BEFORE UPDATE ON sys.tb_sys_role --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- DROP TRIGGER IF EXISTS trg_tb_sys_dept_role_update_time ON sys.tb_sys_dept_role; --- CREATE TRIGGER trg_tb_sys_dept_role_update_time --- BEFORE UPDATE ON sys.tb_sys_dept_role --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- DROP TRIGGER IF EXISTS trg_tb_sys_user_role_update_time ON sys.tb_sys_user_role; --- CREATE TRIGGER trg_tb_sys_user_role_update_time --- BEFORE UPDATE ON sys.tb_sys_user_role --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- DROP TRIGGER IF EXISTS trg_tb_sys_view_update_time ON sys.tb_sys_view; --- CREATE TRIGGER trg_tb_sys_view_update_time --- BEFORE UPDATE ON sys.tb_sys_view --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- DROP TRIGGER IF EXISTS trg_tb_sys_module_update_time ON sys.tb_sys_module; --- CREATE TRIGGER trg_tb_sys_module_update_time --- BEFORE UPDATE ON sys.tb_sys_module --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- DROP TRIGGER IF EXISTS trg_tb_sys_permission_update_time ON sys.tb_sys_permission; --- CREATE TRIGGER trg_tb_sys_permission_update_time --- BEFORE UPDATE ON sys.tb_sys_permission --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- DROP TRIGGER IF EXISTS trg_tb_sys_role_permission_update_time ON sys.tb_sys_role_permission; --- CREATE TRIGGER trg_tb_sys_role_permission_update_time --- BEFORE UPDATE ON sys.tb_sys_role_permission --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- DROP TRIGGER IF EXISTS trg_tb_sys_view_permission_update_time ON sys.tb_sys_view_permission; --- CREATE TRIGGER trg_tb_sys_view_permission_update_time --- BEFORE UPDATE ON sys.tb_sys_view_permission --- FOR EACH ROW --- EXECUTE FUNCTION sys.set_update_time(); - --- ============================= --- 通用对象级权限(ACL) --- 支持对象类型:任意(如 article/file/course/...) --- 支持主体:user/dept/role --- 权限位:1=读(read),2=写(write),4=执行(exec),可相加 --- include_descendants:当主体为 dept/role 时,是否包含其子级(便于“所有子级可查看”场景) --- allow:true=允许;false=显式拒绝(拒绝优先生效) --- dept_path:用于数据范围隔离(与现有规则一致) --- ============================= - -DROP TABLE IF EXISTS sys.tb_sys_acl CASCADE; -CREATE TABLE sys.tb_sys_acl ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - acl_id VARCHAR(50) NOT NULL, -- ACL主键 - object_type VARCHAR(50) NOT NULL, -- 对象类型:article/file/course/... - object_id VARCHAR(50) NOT NULL, -- 对象ID - principal_type VARCHAR(20) NOT NULL, -- 主体类型:user/dept/role - principal_id VARCHAR(50) NOT NULL, -- 主体ID - principal_dept_id VARCHAR(50) DEFAULT NULL, -- 当主体为role且限定到某部门时的部门ID(支持“某部门的某角色”) - permission SMALLINT NOT NULL, -- 权限位:1读 2写 4执行 - allow BOOLEAN NOT NULL DEFAULT true, -- 允许或显式拒绝 - include_descendants BOOLEAN NOT NULL DEFAULT false, -- 是否包含子级(对dept/role生效) - dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径(数据隔离) - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - updater VARCHAR(50) DEFAULT NULL, -- 更新者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (acl_id), - UNIQUE (object_type, object_id, principal_type, principal_id, principal_dept_id, deleted), - UNIQUE (optsn) -); - -COMMENT ON TABLE sys.tb_sys_acl IS '通用对象级权限表(ACL)'; -COMMENT ON COLUMN sys.tb_sys_acl.object_type IS '对象类型:article/file/course/...'; -COMMENT ON COLUMN sys.tb_sys_acl.object_id IS '对象ID'; -COMMENT ON COLUMN sys.tb_sys_acl.principal_type IS '主体类型:user/dept/role'; -COMMENT ON COLUMN sys.tb_sys_acl.principal_id IS '主体ID'; -COMMENT ON COLUMN sys.tb_sys_acl.principal_dept_id IS '当主体为角色时,可选的限定部门ID(某部门的某角色)'; -COMMENT ON COLUMN sys.tb_sys_acl.permission IS '权限位:1读 2写 4执行,可相加'; -COMMENT ON COLUMN sys.tb_sys_acl.allow IS '是否允许(false=显式拒绝)'; -COMMENT ON COLUMN sys.tb_sys_acl.include_descendants IS '是否包含子级(dept/role时启用)'; -COMMENT ON COLUMN sys.tb_sys_acl.dept_path IS '部门全路径(用于数据范围隔离)'; - -CREATE INDEX idx_sys_acl_object ON sys.tb_sys_acl USING btree (object_type, object_id) WHERE deleted = false; -CREATE INDEX idx_sys_acl_principal ON sys.tb_sys_acl USING btree (principal_type, principal_id) WHERE deleted = false; -CREATE INDEX idx_sys_acl_dept_path ON sys.tb_sys_acl USING btree (dept_path) WHERE deleted = false; --- 针对“某部门的某角色”的检索优化 -CREATE INDEX idx_sys_acl_role_scoped ON sys.tb_sys_acl USING btree (principal_id, principal_dept_id) - WHERE deleted = false AND principal_type = 'role'; - --- ============================= --- ACL 策略表:定义对象类型的层级可见/可编辑规则 --- 例如: --- - 同级与父级管理员可修改(edit_hierarchy_rule = 'parent_or_same_admin') --- - 子级全部可查看(view_hierarchy_rule = 'children_all') --- - 课程:下级只有指定部门/角色可查看(view_hierarchy_rule = 'children_specified') --- 说明:业务侧需结合“管理员”的判定(通常由角色判定)在应用层实现;本表做规则声明 --- ============================= - -DROP TABLE IF EXISTS sys.tb_sys_acl_policy CASCADE; -CREATE TABLE sys.tb_sys_acl_policy ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - policy_id VARCHAR(50) NOT NULL, -- 策略ID - name VARCHAR(255) NOT NULL, -- 策略名称 - object_type VARCHAR(50) NOT NULL, -- 目标对象类型 - edit_hierarchy_rule VARCHAR(50) DEFAULT NULL, -- 编辑层级规则:parent_only/parent_or_same_admin/owner_only/none - view_hierarchy_rule VARCHAR(50) DEFAULT NULL, -- 查看层级规则:children_all/children_specified/none - default_permission SMALLINT DEFAULT 0, -- 默认权限位(无显式ACL时应用) - default_allow BOOLEAN DEFAULT true, -- 默认是否允许 - apply_to_children BOOLEAN DEFAULT true, -- 是否默认应用到子级 - creator VARCHAR(50) DEFAULT NULL, - updater VARCHAR(50) DEFAULT NULL, - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), - update_time TIMESTAMPTZ DEFAULT NULL, - delete_time TIMESTAMPTZ DEFAULT NULL, - deleted BOOLEAN NOT NULL DEFAULT false, - PRIMARY KEY (policy_id), - UNIQUE (object_type, deleted), - UNIQUE (optsn) -); - -COMMENT ON TABLE sys.tb_sys_acl_policy IS 'ACL对象类型策略表(层级可见/可编辑规则)'; -COMMENT ON COLUMN sys.tb_sys_acl_policy.object_type IS '对象类型:article/file/course/...'; -COMMENT ON COLUMN sys.tb_sys_acl_policy.edit_hierarchy_rule IS '编辑层级规则:parent_only/parent_or_same_admin/owner_only/none'; -COMMENT ON COLUMN sys.tb_sys_acl_policy.view_hierarchy_rule IS '查看层级规则:children_all/children_specified/none'; -COMMENT ON COLUMN sys.tb_sys_acl_policy.default_permission IS '默认权限位(无显式ACL时兜底)'; -COMMENT ON COLUMN sys.tb_sys_acl_policy.apply_to_children IS '默认是否应用到子级'; - -CREATE INDEX idx_sys_acl_policy_object ON sys.tb_sys_acl_policy USING btree (object_type) WHERE deleted = false; \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableUser.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableUser.sql deleted file mode 100644 index 22e0f225..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableUser.sql +++ /dev/null @@ -1,124 +0,0 @@ - --- 创建 sys schema(如果不存在) -CREATE SCHEMA IF NOT EXISTS sys; - --- 用户表 -DROP TABLE IF EXISTS sys.tb_sys_user CASCADE; -CREATE TABLE sys.tb_sys_user ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - user_id VARCHAR(50) NOT NULL, -- 用户ID - usercode VARCHAR(100) DEFAULT NULL, -- 用户code。sso同步数据获取 - password VARCHAR(128) NOT NULL, -- 密码(建议存储 bcrypt/argon2 哈希) - email VARCHAR(100), -- 电子邮件 - phone VARCHAR(500), -- 电话号码 - phone_hash VARCHAR(200), -- 电话hash - wechat_id VARCHAR(50), -- 微信ID - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间(使用带时区时间) - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除(使用 BOOLEAN) - status INTEGER NOT NULL DEFAULT 1, -- 状态 - remark VARCHAR(255) DEFAULT NULL, - PRIMARY KEY (user_id), - UNIQUE (optsn), - UNIQUE (email), - UNIQUE (phone), - UNIQUE (wechat_id), - UNIQUE (usercode) -); -CREATE INDEX idx_tb_sys_user_phone ON sys.tb_sys_user USING btree (phone); - --- 按 email 域名建立表达式索引(对域名小写处理以实现不区分大小写的域名查询) --- 使用 split_part(email, '@', 2) 提取 @ 之后的域名部分,再做 lower() 归一化 --- WHERE email IS NOT NULL 可以避免索引包含大量 NULL -CREATE INDEX idx_tb_sys_user_email_domain ON sys.tb_sys_user USING btree (lower(split_part(email, '@', 2))) - WHERE email IS NOT NULL; -CREATE INDEX idx_tb_sys_user_wechat_id ON sys.tb_sys_user USING btree (wechat_id); - --- 可选:保留列注释(如果你想把 MySQL 的 COMMENT 同步到 Postgres) -COMMENT ON TABLE sys.tb_sys_user IS '用户表'; -COMMENT ON COLUMN sys.tb_sys_user.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_user.user_id IS '用户ID'; -COMMENT ON COLUMN sys.tb_sys_user.password IS '密码(建议存储 bcrypt/argon2 哈希)'; -COMMENT ON COLUMN sys.tb_sys_user.email IS '电子邮件'; -COMMENT ON COLUMN sys.tb_sys_user.phone IS '电话号码'; -COMMENT ON COLUMN sys.tb_sys_user.wechat_id IS '微信ID'; -COMMENT ON COLUMN sys.tb_sys_user.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_user.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_user.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_user.deleted IS '是否删除'; -COMMENT ON COLUMN sys.tb_sys_user.status IS '状态'; - --- 用户信息表 -DROP TABLE IF EXISTS sys.tb_sys_user_info CASCADE; -CREATE TABLE sys.tb_sys_user_info ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - user_id VARCHAR(50) NOT NULL, -- 用户ID - avatar VARCHAR(255), -- 头像 - gender INTEGER DEFAULT 0, -- 性别 - username VARCHAR(100) NOT NULL, -- 用户名 - level INTEGER DEFAULT 1, -- 等级 - id_card VARCHAR(50), -- 身份证号 - address VARCHAR(255), -- 地址 - creator VARCHAR(50) DEFAULT NULL, -- 创建者 - remark VARCHAR(500) DEFAULT NULL, -- 备注 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(触发器维护) - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (user_id), - UNIQUE (optsn) -); -COMMENT ON TABLE sys.tb_sys_user_info IS '用户信息表'; -COMMENT ON COLUMN sys.tb_sys_user_info.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_user_info.user_id IS '用户ID'; -COMMENT ON COLUMN sys.tb_sys_user_info.avatar IS '头像'; -COMMENT ON COLUMN sys.tb_sys_user_info.gender IS '性别'; -COMMENT ON COLUMN sys.tb_sys_user_info.username IS '用户名'; -COMMENT ON COLUMN sys.tb_sys_user_info.level IS '等级'; -COMMENT ON COLUMN sys.tb_sys_user_info.id_card IS '身份证号'; -COMMENT ON COLUMN sys.tb_sys_user_info.address IS '地址'; -COMMENT ON COLUMN sys.tb_sys_user_info.remark IS '备注'; -COMMENT ON COLUMN sys.tb_sys_user_info.create_time IS '创建时间'; -COMMENT ON COLUMN sys.tb_sys_user_info.update_time IS '更新时间'; -COMMENT ON COLUMN sys.tb_sys_user_info.delete_time IS '删除时间'; -COMMENT ON COLUMN sys.tb_sys_user_info.deleted IS '是否删除'; - --- 登录日志表 -DROP TABLE IF EXISTS sys.tb_sys_login_log CASCADE; -CREATE TABLE sys.tb_sys_login_log ( - optsn VARCHAR(50) NOT NULL, -- 流水号(作为主键) - user_id VARCHAR(50) NOT NULL, -- 用户ID - username VARCHAR(50) NOT NULL, -- 用户名 - ip_address VARCHAR(45), -- IP地址 - ip_source VARCHAR(100), -- IP来源 - browser VARCHAR(100), -- 浏览器 - os VARCHAR(100), -- 操作系统 - password VARCHAR(128), -- 密码(建议存储 bcrypt/argon2 哈希) - login_time TIMESTAMPTZ DEFAULT now(), -- 登录时间 - status INTEGER DEFAULT 1, -- 登录状态(0失败 1成功) - error_count INTEGER DEFAULT 0, -- 错误次数 - message VARCHAR(255), -- 登录消息 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - PRIMARY KEY (optsn) -); --- B-tree 索引(显式指定 USING btree,Postgres 默认即为 btree) -CREATE INDEX idx_tb_sys_login_log_user_id ON sys.tb_sys_login_log USING btree (user_id); -CREATE INDEX idx_tb_sys_login_log_login_time ON sys.tb_sys_login_log USING btree (login_time); - --- 可选:保留列注释 -COMMENT ON TABLE sys.tb_sys_login_log IS '登录日志表'; -COMMENT ON COLUMN sys.tb_sys_login_log.optsn IS '流水号'; -COMMENT ON COLUMN sys.tb_sys_login_log.user_id IS '用户ID'; -COMMENT ON COLUMN sys.tb_sys_login_log.username IS '用户名'; -COMMENT ON COLUMN sys.tb_sys_login_log.ip_address IS 'IP地址'; -COMMENT ON COLUMN sys.tb_sys_login_log.ip_source IS 'IP来源'; -COMMENT ON COLUMN sys.tb_sys_login_log.browser IS '浏览器'; -COMMENT ON COLUMN sys.tb_sys_login_log.os IS '操作系统'; -COMMENT ON COLUMN sys.tb_sys_login_log.password IS '密码(建议存储 bcrypt/argon2 哈希)'; -COMMENT ON COLUMN sys.tb_sys_login_log.login_time IS '登录时间'; -COMMENT ON COLUMN sys.tb_sys_login_log.status IS '登录状态(0失败 1成功)'; -COMMENT ON COLUMN sys.tb_sys_login_log.error_count IS '错误次数'; -COMMENT ON COLUMN sys.tb_sys_login_log.message IS '登录消息'; -COMMENT ON COLUMN sys.tb_sys_login_log.create_time IS '创建时间'; diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql deleted file mode 100644 index 0fdb9ad1..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql +++ /dev/null @@ -1,331 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS workcase; - --- 系统外部人员(来客)管理 用于给系统外人员创建id -DROP TABLE IF EXISTS sys.tb_guest CASCADE; -CREATE TABLE sys.tb_guest( - optsn VARCHAR(50) NOT NULL, -- 流水号 - user_id VARCHAR(50) NOT NULL, -- 来客ID - name VARCHAR(50) NOT NULL, -- 姓名 - phone VARCHAR(50) DEFAULT NULL, -- 电话 - email VARCHAR(50) DEFAULT NULL, -- 邮箱 - wechat_id VARCHAR(50) DEFAULT NULL, -- 微信号 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 创建时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (user_id), - UNIQUE (wechat_id), - UNIQUE (phone), - UNIQUE (email) -); - - --- ========================================== --- IM聊天室 + Jitsi Meet 视频会议 表设计 --- ========================================== - --- 1. 聊天室表(核心表) --- 一个工单对应一个聊天室,来客创建,客服人员可加入 -DROP TABLE IF EXISTS workcase.tb_chat_room CASCADE; -CREATE TABLE workcase.tb_chat_room( - optsn VARCHAR(50) NOT NULL, -- 流水号 - room_id VARCHAR(50) NOT NULL, -- 聊天室ID - workcase_id VARCHAR(50) DEFAULT NULL, -- 关联工单ID - room_name VARCHAR(200) NOT NULL, -- 聊天室名称(如:工单#12345的客服支持) - room_type VARCHAR(20) NOT NULL DEFAULT 'workcase', -- 聊天室类型:workcase-工单客服 - status VARCHAR(20) NOT NULL DEFAULT 'active', -- 状态:active-活跃 closed-已关闭 archived-已归档 - guest_id VARCHAR(50) NOT NULL, -- 来客ID(创建者) - guest_name VARCHAR(100) NOT NULL, -- 来客姓名 - ai_session_id VARCHAR(50) DEFAULT NULL, -- AI对话会话ID(从ai.tb_chat同步) - message_count INTEGER NOT NULL DEFAULT 0, -- 消息总数 - device_code VARCHAR(50) NOT NULL, -- 设备代码 - last_message_time TIMESTAMPTZ DEFAULT NULL, -- 最后消息时间 - last_message TEXT DEFAULT NULL, -- 最后一条消息内容(用于列表展示) - comment_level INTEGER DEFAULT 0, -- 服务评分(1-5) - closed_by VARCHAR(50) DEFAULT NULL, -- 关闭人 - closed_time TIMESTAMPTZ DEFAULT NULL, -- 关闭时间 - creator VARCHAR(50) NOT NULL, -- 创建人(系统自动创建) - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (room_id), - UNIQUE (workcase_id), - UNIQUE (optsn) -); -CREATE INDEX idx_chat_room_guest ON workcase.tb_chat_room(guest_id, status); -CREATE INDEX idx_chat_room_time ON workcase.tb_chat_room(last_message_time DESC); -COMMENT ON TABLE workcase.tb_chat_room IS 'IM聊天室表,一个工单对应一个聊天室'; - --- 2. 聊天室成员表 --- 记录聊天室内的所有成员(来客+客服人员) -DROP TABLE IF EXISTS workcase.tb_chat_room_member CASCADE; -CREATE TABLE workcase.tb_chat_room_member( - optsn VARCHAR(50) NOT NULL, -- 流水号 - member_id VARCHAR(50) NOT NULL, -- 成员记录ID - room_id VARCHAR(50) NOT NULL, -- 聊天室ID - user_id VARCHAR(50) NOT NULL, -- 用户ID(来客ID或员工ID) - user_type VARCHAR(20) NOT NULL, -- 用户类型:guest-来客 staff-客服 ai-AI助手 - user_name VARCHAR(100) NOT NULL, -- 用户名称 - status VARCHAR(20) NOT NULL DEFAULT 'active', -- 状态:active-活跃 left-已离开 removed-被移除 - unread_count INTEGER NOT NULL DEFAULT 0, -- 该成员的未读消息数 - last_read_time TIMESTAMPTZ DEFAULT NULL, -- 最后阅读时间 - last_read_msg_id VARCHAR(50) DEFAULT NULL, -- 最后阅读的消息ID - join_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 加入时间 - leave_time TIMESTAMPTZ DEFAULT NULL, -- 离开时间 - creator VARCHAR(50) NOT NULL, -- 创建人 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - PRIMARY KEY (member_id), - UNIQUE (room_id, user_id) -); -CREATE INDEX idx_chat_member_room ON workcase.tb_chat_room_member(room_id, status); -CREATE INDEX idx_chat_member_user ON workcase.tb_chat_room_member(user_id, user_type, status); -COMMENT ON TABLE workcase.tb_chat_room_member IS '聊天室成员表,记录来客和客服人员'; - --- 3. 聊天室消息表 --- 存储所有聊天消息(AI对话+人工客服对话) -DROP TABLE IF EXISTS workcase.tb_chat_room_message CASCADE; -CREATE TABLE workcase.tb_chat_room_message( - optsn VARCHAR(50) NOT NULL, -- 流水号 - message_id VARCHAR(50) NOT NULL, -- 消息ID - room_id VARCHAR(50) NOT NULL, -- 聊天室ID - sender_id VARCHAR(50) NOT NULL, -- 发送者ID - sender_type VARCHAR(20) NOT NULL, -- 发送者类型:guest-来客 agent-客服 ai-AI助手 system-系统消息 - sender_name VARCHAR(100) NOT NULL, -- 发送者名称 - message_type VARCHAR(20) NOT NULL DEFAULT 'text', -- 消息类型:text-文本 image-图片 file-文件 voice-语音 video-视频 system-系统消息 meeting-会议通知 - content TEXT NOT NULL, -- 消息内容 - files VARCHAR(50)[] DEFAULT '{}', -- 附件文件ID数组(图片、文件、语音、视频等) - content_extra JSONB DEFAULT NULL, -- 扩展内容(会议链接、引用信息等) - reply_to_msg_id VARCHAR(50) DEFAULT NULL, -- 回复的消息ID(引用回复) - is_ai_message BOOLEAN NOT NULL DEFAULT false, -- 是否AI消息(标记从ai.tb_chat同步的消息) - ai_message_id VARCHAR(50) DEFAULT NULL, -- AI原始消息ID(用于追溯) - status VARCHAR(20) NOT NULL DEFAULT 'sent', -- 状态:sending-发送中 sent-已发送 delivered-已送达 read-已读 failed-失败 recalled-已撤回 - read_count INTEGER NOT NULL DEFAULT 0, -- 已读人数 - send_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 发送时间 - creator VARCHAR(50) NOT NULL, -- 创建人 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - PRIMARY KEY (message_id) -); -CREATE INDEX idx_chat_msg_room ON workcase.tb_chat_room_message(room_id, send_time DESC); -CREATE INDEX idx_chat_msg_sender ON workcase.tb_chat_room_message(sender_id, sender_type); -CREATE INDEX idx_chat_msg_ai ON workcase.tb_chat_room_message(ai_message_id) WHERE ai_message_id IS NOT NULL; -COMMENT ON TABLE workcase.tb_chat_room_message IS 'IM聊天消息表,包含AI对话和人工客服消息'; - -DROP TABLE IF EXISTS workcase.tb_chat_room_summary CASCADE; -CREATE TABLE workcase.tb_chat_room_summary ( - optsn VARCHAR(50) NOT NULL, -- 流水号 - summary_id VARCHAR(50) NOT NULL, -- 总结ID - room_id VARCHAR(50) NOT NULL, -- 聊天室ID - question TEXT DEFAULT NULL, -- 核心问题 - needs VARCHAR(500)[] DEFAULT '{}', -- 核心诉求数组 - answer TEXT DEFAULT NULL, -- 解决方案 - workcloud VARCHAR(500)[] DEFAULT '{}', -- 词云关键词数组 - message_count INTEGER DEFAULT 0, -- 参与总结的消息数量 - summary_time TIMESTAMPTZ DEFAULT NULL, -- 总结生成时间 - creator VARCHAR(50) NOT NULL, -- 创建人 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (summary_id), - UNIQUE (optsn) -); -CREATE INDEX idx_chat_room_summary_room ON workcase.tb_chat_room_summary(room_id, summary_time DESC); -CREATE INDEX idx_chat_room_summary_time ON workcase.tb_chat_room_summary(summary_time DESC); -COMMENT ON TABLE workcase.tb_chat_room_summary IS '聊天室总结表,保存AI生成的聊天总结分析'; - - --- 4. 视频会议表(Jitsi Meet) --- 记录聊天室内创建的视频会议 -DROP TABLE IF EXISTS workcase.tb_video_meeting CASCADE; -CREATE TABLE workcase.tb_video_meeting( - optsn VARCHAR(50) NOT NULL, -- 流水号 - meeting_id VARCHAR(50) NOT NULL, -- 会议ID(也是Jitsi房间名) - room_id VARCHAR(50) NOT NULL, -- 关联聊天室ID - workcase_id VARCHAR(50) NOT NULL, -- 关联工单ID - meeting_name VARCHAR(200) NOT NULL, -- 会议名称 - meeting_password VARCHAR(50) DEFAULT NULL, -- 会议密码(可选) - description VARCHAR(500) DEFAULT NULL, -- 会议模式 - jwt_token TEXT DEFAULT NULL, -- JWT Token(用于身份验证) - jitsi_room_name VARCHAR(200) NOT NULL, -- Jitsi房间名(格式:workcase_{workcase_id}_{timestamp}) - jitsi_server_url VARCHAR(500) NOT NULL DEFAULT 'https://meet.jit.si', -- Jitsi服务器地址 - status VARCHAR(20) NOT NULL DEFAULT 'scheduled', -- 状态:scheduled-已安排 ongoing-进行中 ended-已结束 cancelled-已取消 - creator_type VARCHAR(20) NOT NULL, -- 创建者类型:guest-来客 agent-客服 - creator_name VARCHAR(100) NOT NULL, -- 创建者名称 - participant_count INTEGER NOT NULL DEFAULT 0, -- 参与人数 - max_participants INTEGER DEFAULT 10, -- 最大参与人数 - start_time TIMESTAMPTZ NOT NULL, -- 定义会议开始时间 - end_time TIMESTAMPTZ NOT NULL, -- 定义会议结束时间 - advance INTEGER DEFAULT 5, -- 提前入会时间(分钟) - actual_start_time TIMESTAMPTZ DEFAULT NULL, -- 真正会议开始时间 - actual_end_time TIMESTAMPTZ DEFAULT NULL, -- 真正会议结束时间 - duration_seconds INTEGER DEFAULT 0, -- 会议时长(秒) - iframe_url TEXT DEFAULT NULL, -- iframe嵌入URL(生成后存储) - config JSONB DEFAULT NULL, -- Jitsi配置项(自定义配置) - creator VARCHAR(50) NOT NULL, -- 创建人 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (meeting_id), - UNIQUE (jitsi_room_name) -); -CREATE INDEX idx_meeting_room ON workcase.tb_video_meeting(room_id, status); -CREATE INDEX idx_meeting_workcase ON workcase.tb_video_meeting(workcase_id, status); -CREATE INDEX idx_meeting_time ON workcase.tb_video_meeting(create_time DESC); -COMMENT ON TABLE workcase.tb_video_meeting IS 'Jitsi Meet视频会议表'; - --- 5. 会议参与记录表(可选,用于审计和统计) -DROP TABLE IF EXISTS workcase.tb_meeting_participant CASCADE; -CREATE TABLE workcase.tb_meeting_participant( - optsn VARCHAR(50) NOT NULL, -- 流水号 - participant_id VARCHAR(50) NOT NULL, -- 参与记录ID - meeting_id VARCHAR(50) NOT NULL, -- 会议ID - user_id VARCHAR(50) NOT NULL, -- 用户ID - user_type VARCHAR(20) NOT NULL, -- 用户类型:guest-来客 agent-客服 - user_name VARCHAR(100) NOT NULL, -- 用户名称 - join_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 加入时间 - leave_time TIMESTAMPTZ DEFAULT NULL, -- 离开时间 - duration_seconds INTEGER DEFAULT 0, -- 参与时长(秒) - is_moderator BOOLEAN NOT NULL DEFAULT false, -- 是否主持人 - join_method VARCHAR(20) DEFAULT 'web', -- 加入方式:web-网页 mobile-移动端 desktop-桌面端 - device_info VARCHAR(200) DEFAULT NULL, -- 设备信息 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - PRIMARY KEY (participant_id) -); -CREATE INDEX idx_meeting_participant ON workcase.tb_meeting_participant(meeting_id, join_time); -CREATE INDEX idx_participant_user ON workcase.tb_meeting_participant(user_id, user_type); -COMMENT ON TABLE workcase.tb_meeting_participant IS '视频会议参与记录表'; - --- 7. 会议转录记录表(音频转文字) -DROP TABLE IF EXISTS workcase.tb_meeting_transcription CASCADE; -CREATE TABLE workcase.tb_meeting_transcription( - optsn VARCHAR(50) NOT NULL, -- 流水号 - transcription_id VARCHAR(50) NOT NULL, -- 转录记录ID - meeting_id VARCHAR(50) NOT NULL, -- 会议ID - speaker_id VARCHAR(50) NOT NULL, -- 说话人ID - speaker_name VARCHAR(100) NOT NULL, -- 说话人名称 - speaker_type VARCHAR(20) NOT NULL, -- 说话人类型:guest-来客 agent-客服 - content TEXT NOT NULL, -- 转录文本内容 - content_raw TEXT DEFAULT NULL, -- 原始转录结果(含标点前) - language VARCHAR(10) DEFAULT 'zh-CN', -- 语言:zh-CN en-US等 - confidence NUMERIC(3,2) DEFAULT NULL, -- 识别置信度(0-1) - speech_start_time TIMESTAMPTZ NOT NULL, -- 语音开始时间 - speech_end_time TIMESTAMPTZ NOT NULL, -- 语音结束时间 - duration_ms INTEGER NOT NULL, -- 语音时长(毫秒) - audio_url VARCHAR(500) DEFAULT NULL, -- 音频片段URL(可选) - segment_index INTEGER NOT NULL DEFAULT 0, -- 片段序号(按时间排序) - is_final BOOLEAN NOT NULL DEFAULT true, -- 是否最终结果(实时转录会有中间结果) - service_provider VARCHAR(50) DEFAULT 'xunfei', -- 服务提供商:xunfei aliyun tencent google - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - PRIMARY KEY (transcription_id) -); -CREATE INDEX idx_transcription_meeting ON workcase.tb_meeting_transcription(meeting_id, segment_index); -COMMENT ON TABLE workcase.tb_meeting_transcription IS '会议转录记录表,用于保存视频会议的语音转文字内容'; - --- 8. 员工配置表 --- 用于控制哪些人员可以在聊天室里接待来客 -DROP TABLE IF EXISTS workcase.tb_customer_service CASCADE; -CREATE TABLE workcase.tb_customer_service( - optsn VARCHAR(50) NOT NULL, -- 流水号 - user_id VARCHAR(50) NOT NULL, -- 员工ID(关联sys用户ID) - username VARCHAR(100) NOT NULL, -- 员工姓名 - user_code VARCHAR(50) DEFAULT NULL, -- 员工工号 - status VARCHAR(20) NOT NULL DEFAULT 'offline', -- 状态:online-在线 busy-忙碌 offline-离线 - skill_tags VARCHAR(50)[] DEFAULT '{}', -- 技能标签(如:电力、燃气、水务) - max_concurrent INTEGER NOT NULL DEFAULT 5, -- 最大并发接待数 - current_workload INTEGER NOT NULL DEFAULT 0, -- 当前工作量 - total_served INTEGER NOT NULL DEFAULT 0, -- 累计服务次数 - avg_response_time INTEGER DEFAULT NULL, -- 平均响应时间(秒) - satisfaction_score NUMERIC(3,2) DEFAULT NULL, -- 满意度评分(0-5) - creator VARCHAR(50) NOT NULL, -- 创建人 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (user_id) -); -CREATE INDEX idx_customer_service_status ON workcase.tb_customer_service(status, current_workload); -COMMENT ON TABLE workcase.tb_customer_service IS '员工配置表,用于控制哪些人员可以在聊天室接待来客'; - --- 工单表 -DROP TABLE IF EXISTS workcase.tb_workcase CASCADE; -CREATE TABLE workcase.tb_workcase( - optsn VARCHAR(50) NOT NULL, -- 流水号 - workcase_id VARCHAR(50) NOT NULL, -- 工单ID - room_id VARCHAR(50) NOT NULL, -- 聊天室ID - user_id VARCHAR(50) NOT NULL, -- 来客ID - username VARCHAR(200) NOT NULL, -- 来客姓名 - phone VARCHAR(20) NOT NULL, -- 来客电话 - type VARCHAR(50) NOT NULL, -- 故障类型 - device VARCHAR(50) DEFAULT NULL, -- 设备名称 - device_code VARCHAR(50) DEFAULT NULL, -- 设备代码 - device_name_plate VARCHAR(50) NOT NULL, -- 设备名称牌 - device_name_plate_img VARCHAR(50) DEFAULT NULL, -- 设备名称牌图片 - address VARCHAR(1000) DEFAULT NULL, -- 现场地址 - description VARCHAR(1000) DEFAULT NULL, -- 故障描述 - imgs VARCHAR(50)[] DEFAULT '{}', -- 工单图片id - emergency VARCHAR(50) NOT NULL DEFAULT 'normal', -- 紧急程度 normal-普通 emergency-紧急 - status VARCHAR(50) NOT NULL DEFAULT 'pending', -- 状态 pending-待处理 processing-处理中 done-已完成 - processor VARCHAR(50) DEFAULT NULL, -- 处理人 - creator VARCHAR(50) NOT NULL, -- 创建人 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 - deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 - PRIMARY KEY (workcase_id), - UNIQUE (room_id), - UNIQUE (optsn) -); - --- 工单处理过程表(包含工单流转) -DROP TABLE IF EXISTS workcase.tb_workcase_process CASCADE; -CREATE TABLE workcase.tb_workcase_process( - optsn VARCHAR(50) NOT NULL, -- 流水号 - workcase_id VARCHAR(50) NOT NULL, -- 工单ID - process_id VARCHAR(50) NOT NULL, -- 过程id - action VARCHAR(50) NOT NULL, -- 动作 info:记录,assign:指派,redeploy:转派,repeal:撤销,finish:完成 - message VARCHAR(200) DEFAULT NULL, -- 消息 - files VARCHAR(50)[] DEFAULT '{}', -- 携带文件 - processor VARCHAR(50) DEFAULT NULL, -- 处理人(指派、转派专属) - remark VARCHAR(500) DEFAULT NULL, -- 备注 - creator VARCHAR(50) NOT NULL, -- 过程发起人 - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - PRIMARY KEY (process_id) -); - --- 工单设备涉及的文件表 -DROP TABLE IF EXISTS workcase.tb_workcase_device CASCADE; -CREATE TABLE workcase.tb_workcase_device( - optsn VARCHAR(50) NOT NULL, -- 流水号 - workcase_id VARCHAR(50) NOT NULL, -- 工单ID - device VARCHAR(50) NOT NULL, -- 设备名称 - device_code VARCHAR(50) DEFAULT NULL, -- 设备代码 - file_id VARCHAR(50) NOT NULL, -- 文件id - file_name VARCHAR(50) NOT NULL, -- 文件名 - file_root_id VARCHAR(50) DEFAULT NULL, -- 文件根id - PRIMARY KEY(workcase_id, file_id) -); - --- 来客对话、工单过程中生成的词云表 -DROP TABLE IF EXISTS workcase.tb_word_cloud CASCADE; -CREATE TABLE workcase.tb_word_cloud( - optsn VARCHAR(50) NOT NULL, -- 流水号 - word_id VARCHAR(50) NOT NULL, -- 词条ID - word VARCHAR(100) NOT NULL, -- 词语 - frequency INTEGER NOT NULL DEFAULT 1, -- 词频 - source_type VARCHAR(20) NOT NULL, -- 来源类型 chat-聊天 workcase-工单 global-全局 - source_id VARCHAR(50) DEFAULT NULL, -- 来源ID(room_id/workcase_id,NULL表示全局统计) - category VARCHAR(50) DEFAULT NULL, -- 分类(如:fault-故障类型 device-设备 emotion-情绪词等) - stat_date DATE NOT NULL, -- 统计日期(按天聚合) - create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 - update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 - PRIMARY KEY (word_id), - UNIQUE (word, source_type, source_id, stat_date, category) -- 同一天同一来源同一分类的词唯一 -); -CREATE INDEX idx_word_cloud_source ON workcase.tb_word_cloud(source_type, source_id, stat_date); -CREATE INDEX idx_word_cloud_category ON workcase.tb_word_cloud(category, stat_date); -COMMENT ON TABLE workcase.tb_word_cloud IS '词云统计表,记录聊天和工单中的关键词'; \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/postgres/sql/initAll.sql b/urbanLifelineServ/.bin/database/postgres/sql/initAll.sql deleted file mode 100644 index 2e8b5549..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/initAll.sql +++ /dev/null @@ -1,52 +0,0 @@ --- ============================= --- 城市生命线AI数智化平台 - 数据库初始化脚本 --- 按顺序执行各模块建表SQL及数据初始化 --- ============================= - --- ============================= --- 第一阶段:创建数据库和表结构 --- ============================= -\i createDB.sql - --- 1. 系统基础模块 -\i createTablePermission.sql -\i createTableUser.sql - --- 2. 文件管理模块 -\i createTableFile.sql - --- 3. 消息通知模块 -\i createTableMessage.sql - --- 4. 日志模块 -\i createTableLog.sql - --- 5. 配置管理模块 -\i createTableConfig.sql - --- 6. AI模块 智能体+知识库 -\i createTableAI.sql - --- 7. 招投标业务模块 -\i createTableBidding.sql - --- 8. 智能客服业务模块 -\i createTableWorkcase.sql - --- ============================= --- 第二阶段:初始化基础数据 --- ============================= - --- 1. 初始化权限相关基础数据(部门、角色、权限、视图、模块) -\i initDataPermission.sql - --- 2. 初始化用户数据(管理员账户) -\i initDataUser.sql - --- 3. 初始化消息渠道配置 -\i initDataMessage.sql - --- 4. 初始化系统配置 -\i initDataConfig.sql - --- 注意:文件、日志、知识库、招投标、客服等业务表无需初始化数据 \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/postgres/sql/initDataConfig.sql b/urbanLifelineServ/.bin/database/postgres/sql/initDataConfig.sql deleted file mode 100644 index 739a7127..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/initDataConfig.sql +++ /dev/null @@ -1,112 +0,0 @@ --- 初始化系统常用配置(与 config.tb_sys_config 对应) --- 仅插入常用示例,可按需调整 value/remark - -INSERT INTO config.tb_sys_config ( - optsn, config_id, key, name, value, config_type, render_type, description, - re, options, "group", module_id, order_num, status, remark, - creator, dept_path, updater, create_time, update_time, delete_time, deleted -) VALUES - --- 站点与品牌 -('CFG-0001', 'cfg_site_name', 'site.name', '站点名称', 'urban-lifeline 平台', 'String', 'input', '站点名称', NULL, NULL, 'site', 'mod_system', 10, 0, '展示在标题/登录/页脚', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0002', 'cfg_site_logo', 'site.logo', '站点Logo', '/static/logo.png', 'String', 'input', '站点Logo地址', NULL, NULL, 'site', 'mod_system', 20, 0, '相对或绝对URL', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0003', 'cfg_site_icp', 'site.icp', 'ICP备案号', '', 'String', 'input', 'ICP备案号', NULL, NULL, 'site', 'mod_system', 30, 0, '页脚展示', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 国际化与时区 -('CFG-0101', 'cfg_i18n_locale', 'i18n.defaultLocale', '默认语言', 'zh-CN', 'String', 'select', '默认语言', NULL, '["zh-CN", "en-US"]'::json, 'i18n', 'mod_system', 10, 0, '如 zh-CN/en-US', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0102', 'cfg_timezone', 'system.timezone', '系统时区', 'Asia/Shanghai', 'String', 'input', '系统默认时区', NULL, NULL, 'i18n', 'mod_system', 20, 0, 'IANA时区名', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 安全与认证 -('CFG-0201', 'cfg_pwd_policy', 'security.passwordPolicy','密码策略', '{"minLen":8,"upper":1,"lower":1,"digit":1,"special":0}', 'String', 'textarea', '密码策略', NULL, NULL, 'security', 'mod_system', 10, 0, 'JSON结构', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0202', 'cfg_jwt_exp', 'security.jwt.expireSeconds','JWT过期时间', '86400', 'INTEGER', 'input', 'JWT过期秒数', NULL, NULL, 'security', 'mod_system', 20, 0, '默认24小时', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0203', 'cfg_session_timeout', 'security.session.timeoutMinutes','会话超时', '30', 'INTEGER', 'input', '会话超时(分钟)', NULL, NULL, 'security', 'mod_system', 30, 0, '空闲登出', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0204', 'cfg_signup_enabled', 'security.signup.enabled','开放注册', 'false', 'BOOLEAN', 'switch', '是否开放注册', NULL, NULL, 'security', 'mod_system', 40, 0, '生产建议关闭', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 存储与上传 -('CFG-0301', 'cfg_upload_max', 'upload.maxSizeMB', '最大上传大小', '50', 'INTEGER', 'input', '单文件最大上传(MB)', NULL, NULL, 'storage', 'mod_file', 10, 0, '前后端需一致校验', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0302', 'cfg_storage_backend', 'storage.backend', '存储后端', 'minio', 'String', 'select', '存储后端类型', NULL, '["local", "minio", "s3"]'::json, 'storage', 'mod_file', 20, 0, '本地/MinIO/S3等,当前默认MinIO', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0303', 'cfg_storage_base', 'storage.basePath', '存储路径', '/data/urban-lifeline', 'String', 'input', '本地存储基路径', NULL, NULL, 'storage', 'mod_file', 30, 0, '当 backend=local', 'system', NULL, NULL, now(), NULL, NULL, false), - --- MinIO 对象存储配置 -('CFG-0310', 'cfg_minio_endpoint', 'minio.endpoint', 'MinIO服务端点', 'http://localhost:9000', 'String', 'input', 'MinIO服务器地址', NULL, NULL, 'storage', 'mod_file', 40, 0, 'MinIO API服务地址,如 http://localhost:9000', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0311', 'cfg_minio_accesskey', 'minio.accessKey', 'MinIO访问密钥', 'minioadmin', 'String', 'input', 'MinIO AccessKey', NULL, NULL, 'storage', 'mod_file', 50, 0, 'MinIO认证的AccessKey', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0312', 'cfg_minio_secretkey', 'minio.secretKey', 'MinIO私钥', 'minioadmin123', 'String', 'password', 'MinIO SecretKey', NULL, NULL, 'storage', 'mod_file', 60, 0, 'MinIO认证的SecretKey', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0313', 'cfg_minio_bucket', 'minio.bucketName', 'MinIO存储桶', 'urban-lifeline', 'String', 'input', 'MinIO默认存储桶名称', NULL, NULL, 'storage', 'mod_file', 70, 0, '用于存储文件的默认bucket', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0314', 'cfg_minio_publicurl', 'minio.publicUrl', 'MinIO公网地址', 'http://localhost:9000', 'String', 'input', 'MinIO公网访问地址', NULL, NULL, 'storage', 'mod_file', 80, 0, '用于生成文件访问URL,可与endpoint不同', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0315', 'cfg_minio_ssl', 'minio.ssl.enabled', '启用SSL', 'false', 'BOOLEAN', 'switch', '是否启用SSL连接', NULL, NULL, 'storage', 'mod_file', 90, 0, 'HTTPS连接MinIO服务', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0316', 'cfg_minio_region', 'minio.region', 'MinIO区域', 'us-east-1', 'String', 'input', 'MinIO存储区域', NULL, NULL, 'storage', 'mod_file', 100, 0, 'AWS S3兼容的区域配置', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 文件管理配置 -('CFG-0320', 'cfg_file_allowed_exts','file.allowedExtensions', '允许的文件扩展名', 'jpg,jpeg,png,gif,pdf,doc,docx,xls,xlsx,ppt,pptx,txt,zip,rar', 'String', 'textarea', '允许上传的文件扩展名', NULL, NULL, 'storage', 'mod_file', 110, 0, '逗号分隔,如 jpg,png,pdf', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0321', 'cfg_file_forbidden_exts','file.forbiddenExtensions','禁止的文件扩展名', 'exe,bat,sh,php,jsp,asp', 'String', 'textarea', '禁止上传的文件扩展名', NULL, NULL, 'storage', 'mod_file', 120, 0, '逗号分隔,安全考虑', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0322', 'cfg_file_cleanup_days', 'file.tempCleanupDays', '临时文件清理天数', '7', 'INTEGER', 'input', '临时文件自动清理天数', NULL, NULL, 'storage', 'mod_file', 130, 0, '超过天数的临时文件将被清理', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0323', 'cfg_file_duplicate_check','file.duplicateCheck.enabled','启用文件去重', 'true', 'BOOLEAN', 'switch', '是否启用MD5去重检查', NULL, NULL, 'storage', 'mod_file', 140, 0, '基于MD5值检查重复文件', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0324', 'cfg_file_virus_scan', 'file.virusScan.enabled', '启用病毒扫描', 'false', 'BOOLEAN', 'switch', '是否启用文件病毒扫描', NULL, NULL, 'storage', 'mod_file', 150, 0, '需要集成防病毒引擎', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 通知(邮件/SMS) --- 邮件配置 -('CFG-0401', 'cfg_mail_host', 'email.host', 'SMTP服务器地址', 'smtp.qq.com', 'String', 'input', 'SMTP服务器地址', NULL, NULL, 'notify', 'mod_message', 10, 1, '邮件发送服务器地址', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0402', 'cfg_mail_port', 'email.port', 'SMTP端口', '587', 'INTEGER', 'input', 'SMTP服务器端口', NULL, NULL, 'notify', 'mod_message', 20, 1, '常用:25/465/587', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0403', 'cfg_mail_username', 'email.username', '发件人邮箱', '3223905473@qq.com', 'String', 'input', '发件人邮箱地址', NULL, NULL, 'notify', 'mod_message', 30, 1, '用于发送邮件的邮箱账号', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0404', 'cfg_mail_password', 'email.password', '邮箱授权码', 'xmdmxvtjumxocicc', 'String', 'password', '邮箱授权码/密码', NULL, NULL, 'notify', 'mod_message', 40, 1, '邮箱的授权码或密码', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0405', 'cfg_mail_fromname', 'email.fromName', '发件人名称', 'urban-lifeline平台', 'String', 'input', '发件人显示名称', NULL, NULL, 'notify', 'mod_message', 50, 1, '邮件中显示的发件人名称', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0406', 'cfg_mail_ssl', 'email.ssl.enable', '启用SSL', 'true', 'BOOLEAN', 'switch', '是否启用SSL', NULL, NULL, 'notify', 'mod_message', 60, 1, 'SSL加密连接', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0407', 'cfg_mail_timeout', 'email.timeout', '连接超时时间', '30000', 'INTEGER', 'input', '连接超时时间(毫秒)', NULL, NULL, 'notify', 'mod_message', 70, 1, 'SMTP连接超时时间(5000-60000)', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 短信配置 -('CFG-0411', 'cfg_sms_provider', 'sms.provider', '短信服务商', 'aliyun', 'String', 'select', '短信服务提供商', NULL, '["aliyun", "tencent"]'::json, 'notify', 'mod_message', 80, 1, '短信服务提供商类型', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0412', 'cfg_sms_keyid', 'sms.accessKeyId', 'AccessKey ID', 'LTAI5t68do3qVXx5Rufugt3X', 'String', 'input', '短信服务AccessKey ID', NULL, NULL, 'notify', 'mod_message', 90, 1, '云服务商的AccessKey ID', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0413', 'cfg_sms_secret', 'sms.accessKeySecret', 'AccessKey Secret', '2vD9ToIff49Vph4JQXsn0Cy8nXQfzA', 'String', 'password', '短信服务AccessKey Secret', NULL, NULL, 'notify', 'mod_message', 100, 1, '云服务商的AccessKey Secret', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0414', 'cfg_sms_sign', 'sms.signName', '短信签名', 'urban-lifeline', 'String', 'input', '短信签名', NULL, NULL, 'notify', 'mod_message', 110, 1, '发送短信使用的签名', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0415', 'cfg_sms_tpl_login', 'sms.templateCode.login', '登录验证码模板', 'SMS_491985030', 'String', 'input', '登录验证码模板编码', NULL, NULL, 'notify', 'mod_message', 120, 1, '登录验证码短信模板', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0416', 'cfg_sms_tpl_register', 'sms.templateCode.register','注册验证码模板', 'SMS_491985030', 'String', 'input', '注册验证码模板编码', NULL, NULL, 'notify', 'mod_message', 130, 1, '注册验证码短信模板', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0417', 'cfg_sms_timeout', 'sms.timeout', '请求超时时间', '30000', 'INTEGER', 'input', '请求超时时间(毫秒)', NULL, NULL, 'notify', 'mod_message', 140, 1, 'API请求超时时间(5000-60000)', 'system', NULL, NULL, now(), NULL, NULL, false), - --- Dify AI 配置 --- Dify 基础配置 -('CFG-0450', 'cfg_dify_api_base', 'dify.apiBaseUrl', 'Dify API地址', 'http://localhost:8000/v1', 'String', 'input', 'Dify API基础地址', NULL, NULL, 'dify', 'mod_agent', 10, 1, 'Dify服务的API基础地址,如 http://localhost/dify/api', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0452', 'cfg_dify_knowledge_key','dify.knowledgeApiKey', '知识库API密钥', 'dataset-LepcmgOE95n2S7yweNhQzNoB', 'String', 'password', '知识库API密钥', NULL, NULL, 'dify', 'mod_agent', 30, 1, '用于访问Dify知识库的API密钥', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0453', 'cfg_dify_timeout', 'dify.timeout', '请求超时时间', '60', 'INTEGER', 'input', '请求超时时间(秒)', NULL, NULL, 'dify', 'mod_agent', 40, 1, 'API请求的超时时间(10-600秒)', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0454', 'cfg_dify_conn_timeout','dify.connectTimeout', '连接超时时间', '10', 'INTEGER', 'input', '连接超时时间(秒)', NULL, NULL, 'dify', 'mod_agent', 50, 1, 'API连接的超时时间(5-60秒)', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0455', 'cfg_dify_read_timeout','dify.readTimeout', '读取超时时间', '60', 'INTEGER', 'input', '读取超时时间(秒)', NULL, NULL, 'dify', 'mod_agent', 60, 1, 'API读取响应的超时时间(10-600秒)', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0456', 'cfg_dify_stream_timeout','dify.streamTimeout', '流式响应超时时间', '300', 'INTEGER', 'input', '流式响应超时时间(秒)', NULL, NULL, 'dify', 'mod_agent', 70, 1, '流式API响应的超时时间(30-1800秒)', 'system', NULL, NULL, now(), NULL, NULL, false), - --- Dify 上传配置 -('CFG-0460', 'cfg_dify_upload_types','dify.upload.allowedTypes','允许的文件类型', 'pdf,txt,docx,doc,md,html,htm,xlsx,xls,csv', 'String', 'textarea', '上传文件允许的类型', NULL, NULL, 'dify', 'mod_agent', 80, 1, '支持上传的文件类型列表,逗号分隔', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0461', 'cfg_dify_upload_max', 'dify.upload.maxSize', '最大文件大小', '50', 'INTEGER', 'input', '最大文件大小(MB)', NULL, NULL, 'dify', 'mod_agent', 90, 1, '单个文件上传的最大大小限制(1-500MB)', 'system', NULL, NULL, now(), NULL, NULL, false), - --- Dify 知识库配置 -('CFG-0470', 'cfg_dify_index_tech', 'dify.knowledge.indexing.tchnique','默认索引方式', 'high_quality', 'String', 'select', '默认索引方式', NULL, '["high_quality", "economy"]'::json, 'dify', 'mod_agent', 100, 1, '知识库文档的默认索引方式:high_quality(高质量)或 economy(经济)', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0471', 'cfg_dify_embed_model', 'dify.knowledge.embedding.model','默认Embedding模型', 'Qwen/Qwen3-Embedding-8B', 'String', 'input', '默认Embedding模型', NULL, NULL, 'dify', 'mod_agent', 110, 1, '知识库使用的默认Embedding模型名称', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0472', 'cfg_dify_embed_provider', 'dify.knowledge.embedding.model.provider','Embedding模型供应商', 'langgenius/siliconflow/siliconflow', 'String', 'input', 'Embedding模型供应商', NULL, NULL, 'dify', 'mod_agent', 120, 1, 'Embedding模型的供应商标识', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0473', 'cfg_dify_rerank_enable', 'dify.knowledge.reranking.enable','启用Rerank', 'true', 'BOOLEAN', 'switch', '是否启用Rerank重排序', NULL, NULL, 'dify', 'mod_agent', 130, 1, '启用后会对检索结果进行重排序提升相关性', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0474', 'cfg_dify_rerank_model', 'dify.knowledge.rerank.model','Rerank模型', 'Qwen/Qwen3-Reranker-8B', 'String', 'input', 'Rerank重排序模型', NULL, NULL, 'dify', 'mod_agent', 140, 1, '知识库使用的Rerank模型名称', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0475', 'cfg_dify_rerank_provider', 'dify.knowledge.rerank.model.provider','Rerank模型供应商', 'langgenius/siliconflow/siliconflow', 'String', 'input', 'Rerank模型供应商', NULL, NULL, 'dify', 'mod_agent', 150, 1, 'Rerank模型的供应商标识', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0476', 'cfg_dify_retrieval_topk', 'dify.knowledge.retrieval.top.k','检索TopK', '5', 'INTEGER', 'input', '检索返回的最大文档数', NULL, NULL, 'dify', 'mod_agent', 160, 1, '知识库检索时返回的最相关文档数量(1-20)', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0477', 'cfg_dify_retrieval_threshold', 'dify.knowledge.retrieval.score.threshold','相似度阈值', '0.5', 'DOUBLE', 'input', '检索相似度阈值', NULL, NULL, 'dify', 'mod_agent', 170, 1, '低于此阈值的文档将被过滤(0.0-1.0)', 'system', NULL, NULL, now(), NULL, NULL, false), --- Dify workcase相关智能体配置 -('CFG-0478', 'cfg_dify_workcase_chat', 'dify.workcase.agent.chat','泰豪小电AgentApiKey', 'app-CDKy0wYkPnl6dA6G7eu113Vw', 'String', 'input', '泰豪小电AgentApiKey', NULL, NULL, 'dify', 'mod_agent', 160, 1, '泰豪小电AgentApiKey', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0479', 'cfg_dify_workcase_summary', 'dify.workcase.workflow.summary','工单总结AgentApikey', 'app-YMlj2B0m21KpYZPv3YdObi7r', 'String', 'input', '工单总结AgentApikey', NULL, NULL, 'dify', 'mod_agent', 170, 1, '工单总结AgentApikey', 'system', NULL, NULL, now(), NULL, NULL, false), - - --- 日志与审计 -('CFG-0501', 'cfg_log_level', 'log.level', '日志级别', 'INFO', 'String', 'select', '系统日志级别', NULL, '["DEBUG", "INFO", "WARN", "ERROR"]'::json, 'log', 'mod_system', 10, 0, 'DEBUG/INFO/WARN/ERROR', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0502', 'cfg_audit_retention', 'audit.retentionDays', '审计日志保留', '90', 'INTEGER', 'input', '审计日志保留天数', NULL, NULL, 'log', 'mod_system', 20, 0, '合规按需调整', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 平台特性 -('CFG-0601', 'cfg_maintenance', 'platform.maintenance', '维护模式', 'false', 'BOOLEAN', 'switch', '维护模式开关', NULL, NULL, 'platform', 'mod_system', 10, 0, 'true时仅管理员可用', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0602', 'cfg_feature_acl_policy','feature.acl.policy', 'ACL策略', 'enabled', 'String', 'select', 'ACL策略开关', NULL, '["enabled", "disabled"]'::json, 'platform', 'mod_system', 20, 0, 'enabled/disabled', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 微信客服配置 -('CFG-0701', 'cfg_wechat_kefu_corpid', 'wechat.kefu.corpId', '企业ID', '', 'String', 'input', '企业微信的企业ID', NULL, NULL, 'wechat', 'mod_workcase', 10, 1, '企业微信管理后台获取', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0702', 'cfg_wechat_kefu_secret', 'wechat.kefu.secret', '客服应用Secret', '', 'String', 'password', '微信客服应用的Secret', NULL, NULL, 'wechat', 'mod_workcase', 20, 1, '微信客服应用的密钥', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0703', 'cfg_wechat_kefu_token', 'wechat.kefu.token', '回调Token', '', 'String', 'input', '消息回调的Token', NULL, NULL, 'wechat', 'mod_workcase', 30, 1, '用于验证消息回调的Token', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0704', 'cfg_wechat_kefu_aeskey', 'wechat.kefu.encodingAesKey','回调加密密钥', '', 'String', 'password', '消息回调的EncodingAESKey', NULL, NULL, 'wechat', 'mod_workcase', 40, 1, '用于解密消息回调的AES密钥', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0705', 'cfg_wechat_kefu_openkfid', 'wechat.kefu.openKfid', '客服账号ID', '', 'String', 'input', '微信客服账号的open_kfid', NULL, NULL, 'wechat', 'mod_workcase', 50, 1, '用于发送消息的客服账号ID', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0706', 'cfg_wechat_kefu_welcome', 'wechat.kefu.welcomeTemplate','欢迎语模板', '您好,您的工单已创建。\n工单编号:{workcaseId}\n问题类型:{type}\n设备:{device}\n我们将尽快为您处理。', 'String', 'textarea', '客服欢迎语消息模板', NULL, NULL, 'wechat', 'mod_workcase', 60, 1, '支持变量:{workcaseId},{type},{device},{username}', 'system', NULL, NULL, now(), NULL, NULL, false), - --- 微信小程序配置 -('CFG-0710', 'cfg_wechat_mp_appid', 'wechat.miniprogram.appid', '小程序AppID', 'wx15e67484db6d431f', 'String', 'input', '微信小程序的AppID', NULL, NULL, 'wechat', 'mod_workcase', 70, 1, '在微信公众平台获取', 'system', NULL, NULL, now(), NULL, NULL, false), -('CFG-0711', 'cfg_wechat_mp_appsecret', 'wechat.miniprogram.appsecret', '小程序AppSecret', '127dcc9c90dd1b66a700b52094922253', 'String', 'password', '微信小程序的AppSecret', NULL, NULL, 'wechat', 'mod_workcase', 80, 1, '在微信公众平台获取,用于获取openid和解密手机号', 'system', NULL, NULL, now(), NULL, NULL, false); - - diff --git a/urbanLifelineServ/.bin/database/postgres/sql/initDataMessage.sql b/urbanLifelineServ/.bin/database/postgres/sql/initDataMessage.sql deleted file mode 100644 index cd86f138..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/initDataMessage.sql +++ /dev/null @@ -1,118 +0,0 @@ --- 初始化消息渠道配置(与 message schema 对应) --- 配置常用消息发送渠道 - --- ============================= --- 1. 初始化消息渠道 --- ============================= -INSERT INTO message.tb_message_channel ( - optsn, channel_id, channel_code, channel_name, channel_desc, - config, status, priority, creator, create_time, deleted -) VALUES --- 应用内消息(默认渠道,优先级最高) -('CH-0001', 'channel_app', 'app', '应用内消息', '系统内部消息通知', - '{"enabled": true, "realtime": true}'::json, - 'enabled', 100, 'system', now(), false), - --- 短信通知 -('CH-0002', 'channel_sms', 'sms', '短信通知', '短信发送服务', - '{ - "enabled": false, - "provider": "", - "apiKey": "", - "apiSecret": "", - "signName": "", - "templateCode": "" - }'::json, - 'disabled', 80, 'system', now(), false), - --- 邮件通知 -('CH-0003', 'channel_email', 'email', '邮件通知', '电子邮件发送服务', - '{ - "enabled": false, - "smtpHost": "", - "smtpPort": 465, - "username": "", - "password": "", - "fromAddress": "", - "useSsl": true - }'::json, - 'disabled', 70, 'system', now(), false), - --- 微信公众号 -('CH-0004', 'channel_wechat_mp', 'wechat_official_account', '微信公众号', '微信公众号模板消息', - '{ - "enabled": false, - "appId": "", - "appSecret": "", - "templateId": "" - }'::json, - 'disabled', 60, 'system', now(), false), - --- 微信小程序 -('CH-0005', 'channel_wechat_mini', 'wechat_applet', '微信小程序', '微信小程序订阅消息', - '{ - "enabled": false, - "appId": "", - "appSecret": "", - "templateId": "" - }'::json, - 'disabled', 50, 'system', now(), false), - --- 钉钉通知 -('CH-0006', 'channel_dingtalk', 'dingtalk', '钉钉通知', '钉钉工作通知', - '{ - "enabled": false, - "agentId": "", - "appKey": "", - "appSecret": "", - "robotToken": "" - }'::json, - 'disabled', 40, 'system', now(), false); - --- ============================= --- 2. 初始化消息模板(系统通用模板) --- ============================= -INSERT INTO message.tb_message_template ( - optsn, template_id, template_code, template_name, template_type, - title_template, content_template, variables, service, - creator, create_time, deleted -) VALUES --- 用户注册欢迎消息 -('TPL-0001', 'tpl_user_welcome', 'USER_WELCOME', '用户注册欢迎', 'system', - '欢迎加入 {{platformName}}', - '您好,{{username}}!\n\n欢迎加入 {{platformName}} 平台。您的账号已成功创建。\n\n账号信息:\n- 用户名:{{usercode}}\n- 邮箱:{{email}}\n- 注册时间:{{registerTime}}\n\n祝您使用愉快!', - '["platformName", "username", "usercode", "email", "registerTime"]'::jsonb, - 'system', - 'system', now(), false), - --- 密码重置通知 -('TPL-0002', 'tpl_password_reset', 'PASSWORD_RESET', '密码重置通知', 'system', - '密码重置验证码', - '您好,{{username}}!\n\n您正在重置密码,验证码为:{{code}}\n\n验证码有效期为 {{expireMinutes}} 分钟,请尽快完成操作。\n\n如非本人操作,请忽略此消息。', - '["username", "code", "expireMinutes"]'::jsonb, - 'system', - 'system', now(), false), - --- 系统维护通知 -('TPL-0003', 'tpl_system_maintenance', 'SYSTEM_MAINTENANCE', '系统维护通知', 'system', - '系统维护通知', - '尊敬的用户:\n\n系统将于 {{startTime}} 至 {{endTime}} 进行维护升级。\n\n维护内容:{{content}}\n\n维护期间系统将暂停服务,请您提前做好相关安排。\n\n给您带来不便,敬请谅解!', - '["startTime", "endTime", "content"]'::jsonb, - 'system', - 'system', now(), false), - --- 工单创建通知 -('TPL-0101', 'tpl_ticket_created', 'TICKET_CREATED', '工单创建通知', 'business', - '新工单通知', - '您好,{{username}}!\n\n您有一条新的工单需要处理:\n\n工单编号:{{ticketNo}}\n工单标题:{{title}}\n优先级:{{priority}}\n创建时间:{{createTime}}\n\n请及时登录系统查看处理。', - '["username", "ticketNo", "title", "priority", "createTime"]'::jsonb, - 'customer_service', - 'system', now(), false), - --- 招标公告发布通知 -('TPL-0201', 'tpl_bidding_published', 'BIDDING_PUBLISHED', '招标公告发布', 'business', - '招标公告发布通知', - '您好!\n\n新的招标项目已发布:\n\n项目名称:{{projectName}}\n项目编号:{{projectNo}}\n发布时间:{{publishTime}}\n截止时间:{{deadlineTime}}\n\n详情请登录系统查看。', - '["projectName", "projectNo", "publishTime", "deadlineTime"]'::jsonb, - 'bidding', - 'system', now(), false); diff --git a/urbanLifelineServ/.bin/database/postgres/sql/initDataPermission.sql b/urbanLifelineServ/.bin/database/postgres/sql/initDataPermission.sql deleted file mode 100644 index ed27224e..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/initDataPermission.sql +++ /dev/null @@ -1,471 +0,0 @@ --- 初始化权限相关基础数据(与 sys schema 对应) --- 包含:部门、角色、模块、权限、视图及其关联关系 - --- ============================= --- 1. 初始化根部门 --- ============================= -INSERT INTO sys.tb_sys_dept ( - optsn, dept_id, name, parent_id, dept_path, description, - creator, create_time, deleted -) VALUES -('DEPT-0001', 'dept_root', '根部门', NULL, '/dept_root/', '系统根部门', - 'system', now(), false); - --- ============================= --- 2. 初始化全局角色 --- ============================= -INSERT INTO sys.tb_sys_role ( - optsn, role_id, name, description, scope, owner_dept_id, - status, creator, dept_path, create_time, deleted -) VALUES --- 超级管理员(全局) -('ROLE-0001', 'role_super_admin', '超级管理员', '拥有系统所有权限的最高管理员', - 'global', NULL, true, 'system', NULL, now(), false), - --- 系统管理员(全局) -('ROLE-0002', 'role_system_admin', '系统管理员', '负责系统配置和用户管理', - 'global', NULL, true, 'system', NULL, now(), false), - --- 普通用户(全局) -('ROLE-0003', 'role_user', '普通用户', '系统普通用户角色', - 'global', NULL, true, 'system', NULL, now(), false), - --- 访客(全局)- 注册用户默认角色,具备客服聊天和工单的所有接口权限 -('ROLE-0004', 'role_guest', '访客', '访客角色,具备客服聊天和工单的所有接口权限', - 'global', NULL, true, 'system', NULL, now(), false); - --- ============================= --- 3. 初始化系统模块 --- ============================= -INSERT INTO sys.tb_sys_module ( - optsn, module_id, name, description, creator, dept_path, create_time, deleted -) VALUES -('MODULE-0001', 'module_system', '系统管理', '用户、角色、权限、部门管理', 'system', NULL, now(), false), -('MODULE-0002', 'module_file', '文件管理', '文件上传、下载、关联管理', 'system', NULL, now(), false), -('MODULE-0003', 'module_message', '消息通知', '消息发送、接收、模板管理', 'system', NULL, now(), false), -('MODULE-0004', 'module_config', '配置管理', '系统配置参数管理', 'system', NULL, now(), false), -('MODULE-0008', 'module_agent', '智能体', '智能体管理', 'system', NULL, now(), false), -('MODULE-0005', 'module_knowledge', '知识库', '知识文档管理', 'system', NULL, now(), false), -('MODULE-0006', 'module_bidding', '招投标', '招投标业务管理', 'system', NULL, now(), false), -('MODULE-0007', 'module_workcase', '智能客服', '客服工单管理', 'system', NULL, now(), false), -('MODULE-0009', 'module_meeting', '视频会议', 'Jitsi Meet视频会议管理', 'system', NULL, now(), false); - --- ============================= --- 4. 初始化系统权限 --- ============================= -INSERT INTO sys.tb_sys_permission ( - optsn, permission_id, name, code, description, module_id, status, creator, dept_path, create_time, deleted -) VALUES --- 系统管理模块权限 -('PERM-0001', 'perm_user_view', '用户查看', 'system:user:view', '查看用户列表和详情', 'module_system', true, 'system', NULL, now(), false), -('PERM-0002', 'perm_user_create', '用户创建', 'system:user:create', '创建新用户', 'module_system', true, 'system', NULL, now(), false), -('PERM-0003', 'perm_user_edit', '用户编辑', 'system:user:edit', '编辑用户信息', 'module_system', true, 'system', NULL, now(), false), -('PERM-0004', 'perm_user_delete', '用户删除', 'system:user:delete', '删除用户', 'module_system', true, 'system', NULL, now(), false), -('PERM-0011', 'perm_role_view', '角色查看', 'system:role:view', '查看角色列表和详情', 'module_system', true, 'system', NULL, now(), false), -('PERM-0012', 'perm_role_create', '角色创建', 'system:role:create', '创建新角色', 'module_system', true, 'system', NULL, now(), false), -('PERM-0013', 'perm_role_edit', '角色编辑', 'system:role:edit', '编辑角色信息', 'module_system', true, 'system', NULL, now(), false), -('PERM-0014', 'perm_role_delete', '角色删除', 'system:role:delete', '删除角色', 'module_system', true, 'system', NULL, now(), false), -('PERM-0021', 'perm_dept_view', '部门查看', 'system:dept:view', '查看部门列表和详情', 'module_system', true, 'system', NULL, now(), false), -('PERM-0022', 'perm_dept_create', '部门创建', 'system:dept:create', '创建新部门', 'module_system', true, 'system', NULL, now(), false), -('PERM-0023', 'perm_dept_edit', '部门编辑', 'system:dept:edit', '编辑部门信息', 'module_system', true, 'system', NULL, now(), false), -('PERM-0024', 'perm_dept_delete', '部门删除', 'system:dept:delete', '删除部门', 'module_system', true, 'system', NULL, now(), false), -('PERM-0031', 'perm_permission_view', '权限查看', 'system:permission:view', '查看权限列表', 'module_system', true, 'system', NULL, now(), false), -('PERM-0032', 'perm_permission_manage', '权限管理', 'system:permission:manage', '管理权限配置', 'module_system', true, 'system', NULL, now(), false), - --- 系统管理模块导出权限 -('PERM-0041', 'perm_user_export', '用户导出', 'system:user:export', '导出用户数据', 'module_system', true, 'system', NULL, now(), false), -('PERM-0042', 'perm_role_export', '角色导出', 'system:role:export', '导出角色数据', 'module_system', true, 'system', NULL, now(), false), -('PERM-0043', 'perm_dept_export', '部门导出', 'system:dept:export', '导出部门数据', 'module_system', true, 'system', NULL, now(), false), - --- 文件管理模块权限 -('PERM-0101', 'perm_file_view', '文件查看', 'file:file:view', '查看文件列表', 'module_file', true, 'system', NULL, now(), false), -('PERM-0102', 'perm_file_upload', '文件上传', 'file:file:upload', '上传文件', 'module_file', true, 'system', NULL, now(), false), -('PERM-0103', 'perm_file_download', '文件下载', 'file:file:download', '下载文件', 'module_file', true, 'system', NULL, now(), false), -('PERM-0104', 'perm_file_delete', '文件删除', 'file:file:delete', '删除文件', 'module_file', true, 'system', NULL, now(), false), -('PERM-0105', 'perm_file_export', '文件导出', 'file:file:export', '导出文件列表数据', 'module_file', true, 'system', NULL, now(), false), --- 智能体权限 -('PERM-0120', 'perm_ai_create', '智能体创建', 'ai:agent:create', '创建智能体', 'module_agent', true, 'system', NULL, now(), false), -('PERM-0121', 'perm_ai_update', '智能体更新', 'ai:agent:update', '更新智能体', 'module_agent', true, 'system', NULL, now(), false), -('PERM-0122', 'perm_ai_delete', '智能体删除', 'ai:agent:delete', '删除智能体', 'module_agent', true, 'system', NULL, now(), false), -('PERM-0123', 'perm_ai_view', '智能体查询', 'ai:agent:view', '查询智能体', 'module_agent', true, 'system', NULL, now(), false), --- 智能体对话权限 没有,因为所有人都可以 --- Dify代理功能权限(知识库分段管理) -('PERM-0130', 'perm_dify_segment_view', '分段查看', 'ai:dify:segment:view', '查看文档分段列表', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0131', 'perm_dify_segment_create', '分段创建', 'ai:dify:segment:create', '创建文档分段', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0132', 'perm_dify_segment_update', '分段更新', 'ai:dify:segment:update', '更新文档分段', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0133', 'perm_dify_segment_delete', '分段删除', 'ai:dify:segment:delete', '删除文档分段', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0134', 'perm_dify_document_status', '文档状态管理', 'ai:dify:document:status', '更新文档状态(启用/禁用/归档)', 'module_knowledge', true, 'system', NULL, now(), false), --- 知识库管理权限 -('PERM-0140', 'perm_knowledge_create', '知识库创建', 'ai:knowledge:create', '创建知识库', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0141', 'perm_knowledge_update', '知识库更新', 'ai:knowledge:update', '更新知识库', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0142', 'perm_knowledge_delete', '知识库删除', 'ai:knowledge:delete', '删除知识库', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0143', 'perm_knowledge_view', '知识库查看', 'ai:knowledge:view', '查看知识库列表和详情', 'module_knowledge', true, 'system', NULL, now(), false), --- 知识库文件管理权限 -('PERM-0150', 'perm_knowledge_file_upload', '知识库文件上传', 'ai:knowledge:file:upload', '上传文件到知识库', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0151', 'perm_knowledge_file_update', '知识库文件更新', 'ai:knowledge:file:update', '更新知识库文件信息', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0152', 'perm_knowledge_file_delete', '知识库文件删除', 'ai:knowledge:file:delete', '删除知识库文件', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0153', 'perm_knowledge_file_view', '知识库文件查看', 'ai:knowledge:file:view', '查看知识库文件历史', 'module_knowledge', true, 'system', NULL, now(), false), - --- 消息通知模块权限 -('PERM-0201', 'perm_message_view', '消息查看', 'message:message:view', '查看消息列表', 'module_message', true, 'system', NULL, now(), false), -('PERM-0202', 'perm_message_send', '消息发送', 'message:message:send', '发送消息通知', 'module_message', true, 'system', NULL, now(), false), -('PERM-0203', 'perm_message_manage', '消息管理', 'message:message:manage', '管理消息模板和配置', 'module_message', true, 'system', NULL, now(), false), -('PERM-0204', 'perm_message_export', '消息导出', 'message:message:export', '导出消息数据', 'module_message', true, 'system', NULL, now(), false), --- 配置管理模块权限 -('PERM-0301', 'perm_config_view', '配置查看', 'config:config:view', '查看系统配置', 'module_config', true, 'system', NULL, now(), false), -('PERM-0302', 'perm_config_edit', '配置编辑', 'config:config:edit', '修改系统配置', 'module_config', true, 'system', NULL, now(), false), -('PERM-0303', 'perm_config_export', '配置导出', 'config:config:export', '导出系统配置数据', 'module_config', true, 'system', NULL, now(), false), --- 日志模块权限 -('PERM-0401', 'perm_log_view', '日志查看', 'log:log:view', '查看系统日志', 'module_system', true, 'system', NULL, now(), false), -('PERM-0402', 'perm_log_export', '日志导出', 'log:log:export', '导出系统日志数据', 'module_system', true, 'system', NULL, now(), false), --- 平台基础菜单访问权限(所有登录用户都有) -('PERM-0501', 'perm_platform_home', '工作台访问', 'platform:home:view', '访问平台工作台', 'module_system', true, 'system', NULL, now(), false), -('PERM-0502', 'perm_platform_chat', 'AI助手访问', 'platform:chat:view', '访问AI助手', 'module_system', true, 'system', NULL, now(), false), -('PERM-0503', 'perm_platform_bidding', '招标助手访问', 'platform:bidding:view', '访问招标助手(iframe)', 'module_bidding', true, 'system', NULL, now(), false), -('PERM-0504', 'perm_platform_workcase', '泰豪小电访问', 'platform:workcase:view', '访问泰豪小电客服(iframe)', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0505', 'perm_platform_workflow', '智能体编排访问', 'platform:workflow:view', '访问智能体编排(iframe)', 'module_system', true, 'system', NULL, now(), false), --- Platform 管理后台功能权限 -('PERM-0601', 'perm_platform_admin', '平台管理后台', 'platform:admin:view', '访问平台管理后台', 'module_system', true, 'system', NULL, now(), false), -('PERM-0602', 'perm_platform_admin_overview', '平台数据概览', 'platform:admin:overview', '访问平台数据概览', 'module_system', true, 'system', NULL, now(), false), -('PERM-0603', 'perm_platform_admin_user', '平台用户管理', 'platform:admin:user', '访问平台用户管理', 'module_system', true, 'system', NULL, now(), false), -('PERM-0604', 'perm_platform_admin_knowledge', '平台知识库', 'platform:admin:knowledge', '访问平台知识库', 'module_knowledge', true, 'system', NULL, now(), false), -('PERM-0605', 'perm_platform_admin_config', '平台系统配置', 'platform:admin:config', '访问平台系统配置', 'module_config', true, 'system', NULL, now(), false), --- Bidding 管理后台功能权限 -('PERM-0611', 'perm_bidding_admin', '招标管理后台', 'bidding:admin:view', '访问招标管理后台', 'module_bidding', true, 'system', NULL, now(), false), --- Workcase 管理后台功能权限 -('PERM-0621', 'perm_workcase_admin', '客服管理后台', 'workcase:admin:view', '访问客服管理后台', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0622', 'perm_workcase_overview', '数据概览', 'workcase:overview:view', '访问泰豪小电数据概览', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0623', 'perm_workcase_knowledge', '知识库管理', 'workcase:knowledge:view', '访问知识库管理', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0624', 'perm_workcase_tickets', '工单管理', 'workcase:tickets:view', '访问工单管理', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0625', 'perm_workcase_conversation', '对话数据', 'workcase:conversation:view', '访问对话数据管理', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0626', 'perm_workcase_agent', '智能体管理', 'workcase:agent:view', '访问智能体管理', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0627', 'perm_workcase_log', '日志管理', 'workcase:log:view', '访问日志管理', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0628', 'perm_workcase_chatroom', '聊天室控制台', 'workcase:chatroom:view', '访问聊天室控制台', 'module_workcase', true, 'system', NULL, now(), false), - --- Workcase 接口权限(访客用户可用) --- AI对话接口权限 -('PERM-0701', 'perm_workcase_chat_create', 'AI对话创建', 'workcase:chat:create', '创建对话', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0702', 'perm_workcase_chat_update', 'AI对话更新', 'workcase:chat:update', '更新对话', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0703', 'perm_workcase_chat_list', 'AI对话查询', 'workcase:chat:list', '查询对话列表', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0704', 'perm_workcase_chat_message', 'AI对话消息', 'workcase:chat:message', '获取对话消息列表', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0705', 'perm_workcase_chat_stream', 'AI流式对话', 'workcase:chat:stream', '流式对话接口', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0706', 'perm_workcase_chat_analyze', 'AI对话分析', 'workcase:chat:analyze', '分析对话生成工单信息', 'module_workcase', true, 'system', NULL, now(), false), --- 聊天室接口权限 -('PERM-0711', 'perm_workcase_room_create', '聊天室创建', 'workcase:room:create', '创建聊天室', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0712', 'perm_workcase_room_update', '聊天室更新', 'workcase:room:update', '更新聊天室', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0713', 'perm_workcase_room_close', '聊天室关闭', 'workcase:room:close', '关闭聊天室', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0714', 'perm_workcase_room_view', '聊天室查看', 'workcase:room:view', '查看聊天室', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0715', 'perm_workcase_room_member', '聊天室成员', 'workcase:room:member', '管理聊天室成员', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0716', 'perm_workcase_room_message', '聊天室消息', 'workcase:room:message', '发送和查看聊天室消息', 'module_workcase', true, 'system', NULL, now(), false), --- 工单接口权限 -('PERM-0721', 'perm_workcase_ticket_create', '工单创建', 'workcase:ticket:create', '创建工单', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0722', 'perm_workcase_ticket_update', '工单更新', 'workcase:ticket:update', '更新工单', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0723', 'perm_workcase_ticket_view', '工单查看', 'workcase:ticket:view', '查看工单详情和列表', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0724', 'perm_workcase_ticket_process', '工单处理', 'workcase:ticket:process', '工单处理过程管理', 'module_workcase', true, 'system', NULL, now(), false), -('PERM-0725', 'perm_workcase_ticket_device', '工单设备', 'workcase:ticket:device', '工单设备管理', 'module_workcase', true, 'system', NULL, now(), false), - --- 视频会议模块权限(Jitsi Meet) -('PERM-0730', 'perm_meeting_create', '创建会议', 'meeting:create:own', '创建视频会议', 'module_meeting', true, 'system', NULL, now(), false), -('PERM-0731', 'perm_meeting_join', '加入会议', 'meeting:join:any', '加入视频会议', 'module_meeting', true, 'system', NULL, now(), false), -('PERM-0732', 'perm_meeting_url', '获取会议链接', 'meeting:url:any', '获取会议加入链接', 'module_meeting', true, 'system', NULL, now(), false), -('PERM-0733', 'perm_meeting_token', '获取会议令牌', 'meeting:token:any', '获取会议参与令牌', 'module_meeting', true, 'system', NULL, now(), false); - --- ============================= --- 5. 初始化视图(菜单) --- ============================= -INSERT INTO sys.tb_sys_view ( - optsn, view_id, name, parent_id, url, component, icon, type, - view_type, iframe_url, service, layout, order_num, description, - creator, create_time, deleted -) VALUES --- ========================= --- 平台应用菜单 (platform) --- ========================= --- 一级菜单 (图标使用 lucide-vue-next) -('VIEW-P002', 'view_platform_chat', '泰豪AI助手', NULL, '/aichat', 'public/Chat/AIChatView.vue', 'MessageCircle', 1, - 'route', NULL, 'platform', 'SidebarLayout', 10, '泰豪AI助手-直接智能体对话', 'system', now(), false), -('VIEW-P001', 'view_platform_home', '全部应用', NULL, '/agents', 'public/Agents/AgentPlatformView.vue', 'LayoutGrid', 1, - 'route', NULL, 'platform', 'SidebarLayout', 20, '全部智能体', 'system', now(), false), --- iframe 嵌入菜单 --- url: platform中的路由路径(用于sidebar定位和路由跳转) --- iframe_url: iframe的src地址(实际内容的URL) -('VIEW-P005', 'view_platform_workflow', '智能体编排', NULL, '/app/workflow', NULL, 'Workflow', 1, - 'iframe', 'http://localhost:3000', 'platform', 'SidebarLayout', 30, 'Dify智能体编排(iframe)', 'system', now(), false), -('VIEW-P003', 'view_platform_bidding', '招标助手', NULL, '/app/bidding', NULL, 'FileText', 1, - 'iframe', '/bidding/', 'platform', 'SidebarLayout', 40, '招标应用(iframe)', 'system', now(), false), -('VIEW-P004', 'view_platform_workcase', '泰豪小电', NULL, '/app/workcase', NULL, 'Headphones', 1, - 'iframe', '/workcase/', 'platform', 'SidebarLayout', 50, '客服应用(iframe)', 'system', now(), false), - - --- 平台管理后台内部视图(SubSidebarLayout布局,在platform服务内) -('VIEW-P201', 'view_platform_admin_overview', '数据概览', NULL, '/admin/overview', 'admin/overview/OverviewView.vue', 'BarChart3', 1, - 'route', NULL, 'platform', 'SubSidebarLayout', 210, '平台数据概览', 'system', now(), false), -('VIEW-P202', 'view_platform_admin_user', '用户管理', NULL, '/admin/userManagement', 'admin/userManagement/UserManagementView.vue', 'Users', 1, - 'route', NULL, 'platform', 'SubSidebarLayout', 220, '平台用户管理', 'system', now(), false), -('VIEW-P203', 'view_platform_admin_knowledge', '知识库', NULL, '/admin/knowledge', 'admin/knowledge/KnowledgeView.vue', 'FileText', 1, - 'route', NULL, 'platform', 'SubSidebarLayout', 230, '平台知识库管理', 'system', now(), false), -('VIEW-P204', 'view_platform_admin_config', '系统配置', NULL, '/admin/config', 'admin/config/ConfigView.vue', 'Settings', 1, - 'route', NULL, 'platform', 'SubSidebarLayout', 240, '平台系统配置', 'system', now(), false), - --- -- 系统管理目录 --- ('VIEW-P100', 'view_system', '系统管理', NULL, '/system', NULL, 'Settings', 0, --- 'route', NULL, 'platform', 'SidebarLayout', 100, '系统管理目录', 'system', now(), false), --- --- -- 系统管理子菜单 --- ('VIEW-P101', 'view_user', '用户管理', 'view_system', '/system/user', 'system/UserList', 'Users', 1, --- 'route', NULL, 'platform', 'SidebarLayout', 10, '用户管理页面', 'system', now(), false), --- --- ('VIEW-P102', 'view_role', '角色管理', 'view_system', '/system/role', 'system/RoleList', 'Shield', 1, --- 'route', NULL, 'platform', 'SidebarLayout', 20, '角色管理页面', 'system', now(), false), --- --- ('VIEW-P103', 'view_dept', '部门管理', 'view_system', '/system/dept', 'system/DeptList', 'Building', 1, --- 'route', NULL, 'platform', 'SidebarLayout', 30, '部门管理页面', 'system', now(), false), --- --- ('VIEW-P104', 'view_permission', '权限管理', 'view_system', '/system/permission', 'system/PermissionList', 'Lock', 1, --- 'route', NULL, 'platform', 'SidebarLayout', 40, '权限管理页面', 'system', now(), false), --- --- ('VIEW-P105', 'view_config', '配置管理', 'view_system', '/system/config', 'system/ConfigList', 'Settings', 1, --- 'route', NULL, 'platform', 'SidebarLayout', 50, '配置管理页面', 'system', now(), false), --- --- ('VIEW-P106', 'view_file', '文件管理', 'view_system', '/system/file', 'system/FileList', 'FileText', 1, --- 'route', NULL, 'platform', 'SidebarLayout', 60, '文件管理页面', 'system', now(), false), --- --- ('VIEW-P107', 'view_message', '消息管理', 'view_system', '/system/message', 'system/MessageList', 'Mail', 1, --- 'route', NULL, 'platform', 'SidebarLayout', 70, '消息管理页面', 'system', now(), false), --- --- -- ========================= --- -- 招标应用菜单 (bidding) --- -- ========================= --- ('VIEW-B001', 'view_bidding_home', '首页', NULL, '/home', 'Home', 'House', 1, --- 'route', NULL, 'bidding', 'DefaultLayout', 10, '招标应用首页', 'system', now(), false), --- --- ('VIEW-B002', 'view_bidding_list', '招标列表', NULL, '/bidding/list', 'bidding/List', 'List', 1, --- 'route', NULL, 'bidding', 'DefaultLayout', 20, '招标项目列表', 'system', now(), false), --- --- ('VIEW-B003', 'view_bidding_detail', '招标详情', NULL, '/bidding/detail', 'bidding/Detail', 'Document', 1, --- 'route', NULL, 'bidding', 'DefaultLayout', 30, '招标项目详情', 'system', now(), false), --- --- ('VIEW-B004', 'view_bidding_offer', '投标管理', NULL, '/bidding/offer', 'bidding/Offer', 'Edit', 1, --- 'route', NULL, 'bidding', 'DefaultLayout', 40, '投标管理页面', 'system', now(), false), - --- ========================= --- 客服应用菜单 (workcase) - 图标使用 lucide-vue-next --- ========================= --- 用户端视图 -('VIEW-W001', 'view_workcase_home', '智能客服', NULL, '/aichat', 'public/AIChat/AIChatView.vue', 'Home', 1, - 'route', NULL, 'workcase', 'SubSidebarLayout', 10, '智能客服首页', 'system', now(), false), - -('VIEW-W002', 'view_workcase_chatroom', '聊天室控制台', NULL, '/chatroom', 'public/ChatRoom/ChatRoomView.vue', 'MessageSquare', 1, - 'route', NULL, 'workcase', 'SubSidebarLayout', 20, '实时聊天室控制台', 'system', now(), false), - --- 管理端视图(使用 SubSidebarLayout 布局) -('VIEW-W101', 'view_workcase_admin_overview', '数据概览', NULL, '/admin/overview', 'admin/overview/OverviewView.vue', 'BarChart3', 1, - 'route', NULL, 'workcase', 'SubSidebarLayout', 110, '泰豪小电数据概览', 'system', now(), false), - -('VIEW-W102', 'view_workcase_admin_knowledge', '知识库管理', NULL, '/admin/knowledge', 'admin/knowledge/KnowLedgeView.vue', 'FileText', 1, - 'route', NULL, 'workcase', 'SubSidebarLayout', 120, '知识库文档管理', 'system', now(), false), - -('VIEW-W103', 'view_workcase_admin_tickets', '工单管理', NULL, '/admin/workcase', 'admin/workcase/WorkcaseView.vue', 'Ticket', 1, - 'route', NULL, 'workcase', 'SubSidebarLayout', 130, '客服工单管理', 'system', now(), false), - -('VIEW-W104', 'view_workcase_admin_conversation', '对话数据', NULL, '/admin/customerChat', 'admin/customerChat/CustomerChatView.vue', 'MessageCircle', 1, - 'route', NULL, 'workcase', 'SubSidebarLayout', 140, '客户对话数据管理', 'system', now(), false), - -('VIEW-W105', 'view_workcase_admin_agent', '智能体管理', NULL, '/admin/agent', 'admin/agent/AgentView.vue', 'Bot', 1, - 'route', NULL, 'workcase', 'SubSidebarLayout', 150, '智能体配置管理', 'system', now(), false), - --- 日志管理(带子级的目录) -('VIEW-W106', 'view_workcase_admin_log', '日志管理', NULL, '/admin/log', NULL, 'ScrollText', 1, - 'route', NULL, 'workcase', 'SubSidebarLayout', 160, '日志管理目录', 'system', now(), false), - -('VIEW-W107', 'view_workcase_admin_log_knowledge', '知识库日志', 'view_workcase_admin_log', '/admin/log/knowledge', 'admin/log/knowledgeLog/KnowledgeLogView.vue', 'FileText', 1, - 'route', NULL, 'workcase', NULL, 161, '知识库操作日志', 'system', now(), false), - -('VIEW-W108', 'view_workcase_admin_log_workcase', '工单日志', 'view_workcase_admin_log', '/admin/log/workcase', 'admin/log/workcaseLog/WorkcaseLogView.vue', 'Ticket', 1, - 'route', NULL, 'workcase', NULL, 162, '工单操作日志', 'system', now(), false), - -('VIEW-W109', 'view_workcase_admin_log_system', '系统日志', 'view_workcase_admin_log', '/admin/log/system', 'admin/log/systemLog/SystemLogView.vue', 'Settings', 1, - 'route', NULL, 'workcase', NULL, 163, '系统运行日志', 'system', now(), false); --- ============================= --- 6. 角色权限关联(超级管理员拥有所有权限) --- ============================= -INSERT INTO sys.tb_sys_role_permission ( - optsn, role_id, permission_id, creator, dept_path, create_time, deleted -) -SELECT - 'RP-' || LPAD(ROW_NUMBER() OVER (ORDER BY permission_id)::TEXT, 4, '0'), - 'role_super_admin', - permission_id, - 'system', - NULL, - now(), - false -FROM sys.tb_sys_permission -WHERE deleted = false; - --- 系统管理员权限(除了用户删除外的系统管理权限 + 所有平台基础菜单) -INSERT INTO sys.tb_sys_role_permission ( - optsn, role_id, permission_id, creator, dept_path, create_time, deleted -) -SELECT - 'RP-SA-' || LPAD(ROW_NUMBER() OVER (ORDER BY permission_id)::TEXT, 4, '0'), - 'role_system_admin', - permission_id, - 'system', - NULL, - now(), - false -FROM sys.tb_sys_permission -WHERE deleted = false - AND code NOT IN ('system:user:delete', 'system:role:delete', 'system:dept:delete') - AND ( - module_id IN ('module_system', 'module_file', 'module_message', 'module_config', 'module_bidding', 'module_workcase') - OR code LIKE 'platform:%:view' -- 包含所有平台基础菜单权限 - ); - --- 普通用户权限(基础查看和文件操作 + 平台基础菜单访问) -INSERT INTO sys.tb_sys_role_permission ( - optsn, role_id, permission_id, creator, dept_path, create_time, deleted -) VALUES --- 平台基础菜单访问权限 -('RP-U-0001', 'role_user', 'perm_platform_home', 'system', NULL, now(), false), -('RP-U-0002', 'role_user', 'perm_platform_chat', 'system', NULL, now(), false), -('RP-U-0003', 'role_user', 'perm_platform_bidding', 'system', NULL, now(), false), -('RP-U-0004', 'role_user', 'perm_platform_workcase', 'system', NULL, now(), false), -('RP-U-0005', 'role_user', 'perm_platform_workflow', 'system', NULL, now(), false), --- 系统功能权限 -('RP-U-0011', 'role_user', 'perm_user_view', 'system', NULL, now(), false), -('RP-U-0012', 'role_user', 'perm_file_view', 'system', NULL, now(), false), -('RP-U-0013', 'role_user', 'perm_file_upload', 'system', NULL, now(), false), -('RP-U-0014', 'role_user', 'perm_file_download', 'system', NULL, now(), false), -('RP-U-0015', 'role_user', 'perm_message_view', 'system', NULL, now(), false), -('RP-U-0016', 'role_user', 'perm_config_view', 'system', NULL, now(), false), ---- 视频会议权限 -('RP-U-0050', 'role_user', 'perm_meeting_create', 'system', NULL, now(), false), -('RP-U-0051', 'role_user', 'perm_meeting_join', 'system', NULL, now(), false), -('RP-U-0052', 'role_user', 'perm_meeting_url', 'system', NULL, now(), false), -('RP-U-0053', 'role_user', 'perm_meeting_token', 'system', NULL, now(), false); - --- 访客权限(基础菜单 + workcase聊天和工单全部接口权限) -INSERT INTO sys.tb_sys_role_permission ( - optsn, role_id, permission_id, creator, dept_path, create_time, deleted -) VALUES --- 平台基础菜单访问权限 -('RP-G-0001', 'role_guest', 'perm_platform_home', 'system', NULL, now(), false), -('RP-G-0002', 'role_guest', 'perm_platform_chat', 'system', NULL, now(), false), -('RP-G-0003', 'role_guest', 'perm_platform_workcase', 'system', NULL, now(), false), --- 系统功能权限(仅查看) -('RP-G-0011', 'role_guest', 'perm_user_view', 'system', NULL, now(), false), -('RP-G-0012', 'role_guest', 'perm_file_view', 'system', NULL, now(), false), -('RP-G-0013', 'role_guest', 'perm_message_view', 'system', NULL, now(), false), --- Workcase AI对话接口权限 -('RP-G-0021', 'role_guest', 'perm_workcase_chat_create', 'system', NULL, now(), false), -('RP-G-0022', 'role_guest', 'perm_workcase_chat_update', 'system', NULL, now(), false), -('RP-G-0023', 'role_guest', 'perm_workcase_chat_list', 'system', NULL, now(), false), -('RP-G-0024', 'role_guest', 'perm_workcase_chat_message', 'system', NULL, now(), false), -('RP-G-0025', 'role_guest', 'perm_workcase_chat_stream', 'system', NULL, now(), false), -('RP-G-0026', 'role_guest', 'perm_workcase_chat_analyze', 'system', NULL, now(), false), --- Workcase 聊天室接口权限 -('RP-G-0031', 'role_guest', 'perm_workcase_room_create', 'system', NULL, now(), false), -('RP-G-0032', 'role_guest', 'perm_workcase_room_update', 'system', NULL, now(), false), -('RP-G-0033', 'role_guest', 'perm_workcase_room_close', 'system', NULL, now(), false), -('RP-G-0034', 'role_guest', 'perm_workcase_room_view', 'system', NULL, now(), false), -('RP-G-0035', 'role_guest', 'perm_workcase_room_member', 'system', NULL, now(), false), -('RP-G-0036', 'role_guest', 'perm_workcase_room_message', 'system', NULL, now(), false), -('RP-G-0037', 'role_guest', 'perm_workcase_chatroom', 'system', NULL, now(), false), --- Workcase 工单接口权限 -('RP-G-0041', 'role_guest', 'perm_workcase_ticket_create', 'system', NULL, now(), false), -('RP-G-0042', 'role_guest', 'perm_workcase_ticket_update', 'system', NULL, now(), false), -('RP-G-0043', 'role_guest', 'perm_workcase_ticket_view', 'system', NULL, now(), false), -('RP-G-0044', 'role_guest', 'perm_workcase_ticket_process', 'system', NULL, now(), false), -('RP-G-0045', 'role_guest', 'perm_workcase_ticket_device', 'system', NULL, now(), false), ---- 视频会议权限 -('RP-G-0050', 'role_guest', 'perm_meeting_create', 'system', NULL, now(), false), -('RP-G-0051', 'role_guest', 'perm_meeting_join', 'system', NULL, now(), false), -('RP-G-0052', 'role_guest', 'perm_meeting_url', 'system', NULL, now(), false), -('RP-G-0053', 'role_guest', 'perm_meeting_token', 'system', NULL, now(), false); - --- ============================= --- 7. 视图权限关联 --- ============================= --- 将视图与对应模块的权限关联(使用真正的 view_id,不是 optsn) -INSERT INTO sys.tb_sys_view_permission ( - optsn, view_id, permission_id, creator, dept_path, create_time, deleted -) VALUES --- 平台基础菜单权限关联(所有登录用户都可访问) -('VP-P001', 'view_platform_home', 'perm_platform_home', 'system', NULL, now(), false), -('VP-P002', 'view_platform_chat', 'perm_platform_chat', 'system', NULL, now(), false), -('VP-P003', 'view_platform_bidding', 'perm_platform_bidding', 'system', NULL, now(), false), -('VP-P004', 'view_platform_workcase', 'perm_platform_workcase', 'system', NULL, now(), false), -('VP-P005', 'view_platform_workflow', 'perm_platform_workflow', 'system', NULL, now(), false), - --- 管理后台入口权限关联(iframe入口) -('VP-P101', 'view_platform_admin_entry', 'perm_platform_admin', 'system', NULL, now(), false), -('VP-P102', 'view_bidding_admin_entry', 'perm_bidding_admin', 'system', NULL, now(), false), -('VP-P103', 'view_workcase_admin_entry', 'perm_workcase_admin', 'system', NULL, now(), false), - --- 平台管理后台内部视图权限关联(SubSidebarLayout) -('VP-P201', 'view_platform_admin_overview', 'perm_platform_admin_overview', 'system', NULL, now(), false), -('VP-P202', 'view_platform_admin_user', 'perm_platform_admin_user', 'system', NULL, now(), false), -('VP-P203', 'view_platform_admin_knowledge', 'perm_platform_admin_knowledge', 'system', NULL, now(), false), -('VP-P204', 'view_platform_admin_config', 'perm_platform_admin_config', 'system', NULL, now(), false), - --- Workcase服务用户端视图关联 -('VP-W001', 'view_workcase_home', 'perm_platform_workcase', 'system', NULL, now(), false), -('VP-W002', 'view_workcase_chatroom', 'perm_workcase_chatroom', 'system', NULL, now(), false), - --- Workcase服务管理端视图关联 -('VP-W101', 'view_workcase_admin_overview', 'perm_workcase_overview', 'system', NULL, now(), false), -('VP-W102', 'view_workcase_admin_knowledge', 'perm_workcase_knowledge', 'system', NULL, now(), false), -('VP-W103', 'view_workcase_admin_tickets', 'perm_workcase_tickets', 'system', NULL, now(), false), -('VP-W104', 'view_workcase_admin_conversation', 'perm_workcase_conversation', 'system', NULL, now(), false), -('VP-W105', 'view_workcase_admin_agent', 'perm_workcase_agent', 'system', NULL, now(), false), - --- 日志管理视图关联(包括父级和子级) -('VP-W106', 'view_workcase_admin_log', 'perm_workcase_log', 'system', NULL, now(), false), -('VP-W107', 'view_workcase_admin_log_knowledge', 'perm_workcase_log', 'system', NULL, now(), false), -('VP-W108', 'view_workcase_admin_log_workcase', 'perm_workcase_log', 'system', NULL, now(), false), -('VP-W109', 'view_workcase_admin_log_system', 'perm_workcase_log', 'system', NULL, now(), false); - --- -- 用户管理视图关联用户权限(已注释,因为view_user被注释掉了) --- -- ('VP-0001', 'view_user', 'perm_user_view', 'system', NULL, now(), false), --- -- ('VP-0002', 'view_user', 'perm_user_create', 'system', NULL, now(), false), --- -- ('VP-0003', 'view_user', 'perm_user_edit', 'system', NULL, now(), false), --- -- ('VP-0004', 'view_user', 'perm_user_delete', 'system', NULL, now(), false), --- -- ('VP-0005', 'view_user', 'perm_user_export', 'system', NULL, now(), false), --- -- --- -- -- 角色管理视图关联角色权限 --- -- ('VP-0011', 'view_role', 'perm_role_view', 'system', NULL, now(), false), --- -- ('VP-0012', 'view_role', 'perm_role_create', 'system', NULL, now(), false), --- -- ('VP-0013', 'view_role', 'perm_role_edit', 'system', NULL, now(), false), --- -- ('VP-0014', 'view_role', 'perm_role_delete', 'system', NULL, now(), false), --- -- ('VP-0015', 'view_role', 'perm_role_export', 'system', NULL, now(), false), --- -- --- -- -- 部门管理视图关联部门权限 --- -- ('VP-0021', 'view_dept', 'perm_dept_view', 'system', NULL, now(), false), --- -- ('VP-0022', 'view_dept', 'perm_dept_create', 'system', NULL, now(), false), --- -- ('VP-0023', 'view_dept', 'perm_dept_edit', 'system', NULL, now(), false), --- -- ('VP-0024', 'view_dept', 'perm_dept_delete', 'system', NULL, now(), false), --- -- ('VP-0025', 'view_dept', 'perm_dept_export', 'system', NULL, now(), false), --- -- --- -- -- 权限管理视图关联权限管理权限 --- -- ('VP-0031', 'view_permission', 'perm_permission_view', 'system', NULL, now(), false), --- -- ('VP-0032', 'view_permission', 'perm_permission_manage', 'system', NULL, now(), false), --- -- --- -- -- 配置管理视图关联配置权限 --- -- ('VP-0041', 'view_config', 'perm_config_view', 'system', NULL, now(), false), --- -- ('VP-0042', 'view_config', 'perm_config_edit', 'system', NULL, now(), false), --- -- ('VP-0043', 'view_config', 'perm_config_export', 'system', NULL, now(), false), --- -- --- -- -- 文件管理视图关联文件权限 --- -- ('VP-0051', 'view_file', 'perm_file_view', 'system', NULL, now(), false), --- -- ('VP-0052', 'view_file', 'perm_file_upload', 'system', NULL, now(), false), --- -- ('VP-0053', 'view_file', 'perm_file_download', 'system', NULL, now(), false), --- -- ('VP-0054', 'view_file', 'perm_file_delete', 'system', NULL, now(), false), --- -- ('VP-0055', 'view_file', 'perm_file_export', 'system', NULL, now(), false), --- -- --- -- -- 消息管理视图关联消息权限 --- -- ('VP-0061', 'view_message', 'perm_message_view', 'system', NULL, now(), false), --- -- ('VP-0062', 'view_message', 'perm_message_send', 'system', NULL, now(), false), --- -- ('VP-0063', 'view_message', 'perm_message_manage', 'system', NULL, now(), false), --- -- ('VP-0064', 'view_message', 'perm_message_export', 'system', NULL, now(), false); diff --git a/urbanLifelineServ/.bin/database/postgres/sql/initDataUser.sql b/urbanLifelineServ/.bin/database/postgres/sql/initDataUser.sql deleted file mode 100644 index 507b2ec7..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/initDataUser.sql +++ /dev/null @@ -1,64 +0,0 @@ --- 初始化用户数据(与 sys schema 对应) --- 创建系统管理员账户和示例用户 - --- ============================= --- 1. 创建超级管理员用户 --- ============================= --- 注意:密码需要使用 bcrypt 加密,这里使用的是 'admin123' 的 bcrypt hash --- 实际部署时应该修改为安全的密码 -INSERT INTO sys.tb_sys_user ( - optsn, user_id, usercode, password, email, phone, phone_hash, - create_time, status, deleted -) VALUES -('USER-0001', 'user_admin', 'admin', - '$2a$10$XAe0TE2p0ym94bKJ8LJ52el3M4oYyiExVH/kNCh.pWLLGDZWNM9Yu', -- admin123 - 'admin@urbanlifeline.com', 'DAWTIvnCQI/KmtwkBYI5WP2NpnSKTq4kStJpOJKahOeJLNhAQ0s1', '7503bbfc6171077b737cdc4f76e781893a9a474c9ead05b6b946ac936e5a0288', - now(), 0, false); - --- 超级管理员用户信息 -INSERT INTO sys.tb_sys_user_info ( - optsn, user_id, username, avatar, gender, level, remark, - create_time, deleted -) VALUES -('UINFO-0001', 'user_admin', '系统管理员', - '/static/avatar/admin.png', 1, 10, '系统超级管理员账户', - now(), false); - --- ============================= --- 2. 关联超级管理员角色 --- ============================= -INSERT INTO sys.tb_sys_user_role ( - optsn, user_id, role_id, dept_id, dept_path, - creator, create_time, deleted -) VALUES -('UR-0001', 'user_admin', 'role_super_admin', 'dept_root', '/dept_root/', - 'system', now(), false); - --- ============================= --- 3. 创建示例普通用户(可选) --- ============================= -INSERT INTO sys.tb_sys_user ( - optsn, user_id, usercode, password, email, phone, phone_hash, - create_time, status, deleted -) VALUES -('USER-0002', 'user_demo', 'demo', - '$2a$10$XAe0TE2p0ym94bKJ8LJ52el3M4oYyiExVH/kNCh.pWLLGDZWNM9Yu', -- admin123 - 'demo@urbanlifeline.com', 'Y9tsAZOppzsxmKvI7iqqRBMDHzvWym2DE5FX1KgEGVBC5Ii1UG68', '4e98ffd0e02a7f746291bff77c6c497225e8884758d503bde2efad64e45ad44b', - now(), 0, false); - --- 示例用户信息 -INSERT INTO sys.tb_sys_user_info ( - optsn, user_id, username, avatar, gender, level, remark, - create_time, deleted -) VALUES -('UINFO-0002', 'user_demo', '演示用户', - '/static/avatar/demo.png', 0, 1, '系统演示账户', - now(), false); - --- 关联普通用户角色 -INSERT INTO sys.tb_sys_user_role ( - optsn, user_id, role_id, dept_id, dept_path, - creator, create_time, deleted -) VALUES -('UR-0002', 'user_demo', 'role_user', 'dept_root', '/dept_root/', - 'system', now(), false); diff --git a/urbanLifelineServ/.bin/database/postgres/sql/initDataWorkcase.sql b/urbanLifelineServ/.bin/database/postgres/sql/initDataWorkcase.sql deleted file mode 100644 index cf786a91..00000000 --- a/urbanLifelineServ/.bin/database/postgres/sql/initDataWorkcase.sql +++ /dev/null @@ -1,6 +0,0 @@ --- 初始化聊天室人员 --- user_admin -INSERT INTO workcase.tb_chat_room_member( - optsn, member_id, room_id, user_id, user_type, user_name, status, unread_count, last_read_time, last_read_msg_id, join_time, leave_time, creator, create_time, update_time -) VALUES -('MEM-0001', 'member_admin', 'room_0001', 'user_admin', 'staff', '系统管理员', 'active', 0, null, null, now(), null, 'system', now(), null); \ No newline at end of file diff --git a/urbanLifelineServ/.bin/database/redis/redis.yaml b/urbanLifelineServ/.bin/database/redis/redis.yaml deleted file mode 100644 index 6c0f57c7..00000000 --- a/urbanLifelineServ/.bin/database/redis/redis.yaml +++ /dev/null @@ -1,137 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: redis-config - namespace: urban-lifeline -data: - redis.conf: | - bind 0.0.0.0 - protected-mode no - port 6379 - tcp-backlog 511 - timeout 0 - tcp-keepalive 300 - daemonize no - supervised no - pidfile /var/run/redis_6379.pid - loglevel notice - logfile "" - databases 16 - always-show-logo yes - save 900 1 - save 300 10 - save 60 10000 - stop-writes-on-bgsave-error yes - rdbcompression yes - rdbchecksum yes - dbfilename dump.rdb - dir /data - maxmemory 512mb - maxmemory-policy allkeys-lru - appendonly yes - appendfilename "appendonly.aof" - appendfsync everysec - no-appendfsync-on-rewrite no - auto-aof-rewrite-percentage 100 - auto-aof-rewrite-min-size 64mb ---- -apiVersion: v1 -kind: Service -metadata: - name: redis - namespace: urban-lifeline - labels: - app: redis -spec: - selector: - app: redis - ports: - - name: redis - port: 6379 - targetPort: 6379 - type: ClusterIP ---- -apiVersion: v1 -kind: Service -metadata: - name: redis-nodeport - namespace: urban-lifeline - labels: - app: redis -spec: - selector: - app: redis - type: NodePort - ports: - - name: redis - port: 6379 - targetPort: 6379 - nodePort: 30379 ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: redis - namespace: urban-lifeline - labels: - app: redis -spec: - serviceName: redis - replicas: 1 - selector: - matchLabels: - app: redis - template: - metadata: - labels: - app: redis - spec: - containers: - - name: redis - image: redis:7-alpine - imagePullPolicy: IfNotPresent - command: - - redis-server - - /usr/local/etc/redis/redis.conf - ports: - - containerPort: 6379 - name: redis - env: - - name: TZ - value: "Asia/Shanghai" - volumeMounts: - - name: redis-data - mountPath: /data - - name: redis-config - mountPath: /usr/local/etc/redis - livenessProbe: - exec: - command: - - redis-cli - - ping - initialDelaySeconds: 30 - periodSeconds: 30 - timeoutSeconds: 5 - readinessProbe: - exec: - command: - - redis-cli - - ping - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - memory: "128Mi" - cpu: "100m" - limits: - memory: "512Mi" - cpu: "500m" - volumes: - - name: redis-data - hostPath: - path: /data/k8s/redis/data - type: DirectoryOrCreate - - name: redis-config - configMap: - name: redis-config diff --git a/urbanLifelineServ/.bin/docker/urbanlifeline/docker-compose.yml b/urbanLifelineServ/.bin/docker/urbanlifeline/docker-compose.yml deleted file mode 100644 index add6154d..00000000 --- a/urbanLifelineServ/.bin/docker/urbanlifeline/docker-compose.yml +++ /dev/null @@ -1,251 +0,0 @@ -version: '3.8' - -networks: - urban-lifeline: - driver: bridge - name: urban-lifeline - -services: - nacos: - # 保持原有配置不变 - image: nacos/nacos-server:v3.1.0 - container_name: urban-lifeline-nacos - restart: unless-stopped - networks: - - urban-lifeline - ports: - - "8081:8080" - - "8848:8848" - - "9848:9848" - - "9849:9849" - environment: - MODE: standalone - SPRING_DATASOURCE_PLATFORM: mysql - MYSQL_SERVICE_HOST: host.docker.internal - MYSQL_SERVICE_PORT: 3306 - MYSQL_SERVICE_DB_NAME: nacos_config - MYSQL_SERVICE_USER: root - MYSQL_SERVICE_PASSWORD: "123456" - MYSQL_SERVICE_DB_PARAM: allowPublicKeyRetrieval=true&useSSL=false - JVM_XMS: 512m - JVM_XMX: 512m - JVM_XMN: 256m - NACOS_AUTH_ENABLE: "false" - NACOS_AUTH_TOKEN: ZlRkR2ZxR3BvZ1F0a3JxY2V6RUx2cUh1Rkx6V1ZQbE9kUVd1R1VOcWFFS2t3dG5hS0E9PQ== - NACOS_AUTH_IDENTITY_KEY: ZlRkR2ZxR3BvZ1F0a3JxY2V6RUx2cUh1Rkx6V1ZQbE9kUVd1R1VOcWFFS2t3dG5hS0E9PQ== - NACOS_AUTH_IDENTITY_VALUE: ZlRkR2ZxR3BvZ1F0a3JxY2V6RUx2cUh1Rkx6V1ZQbE9kUVd1R1VOcWFFS2t3dG5hS0E9PQ== - volumes: - - ../../../.data/docker/nacos/data:/home/nacos/data - - ../../../.data/docker/nacos/logs:/home/nacos/logs - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 60s - extra_hosts: - - "host.docker.internal:host-gateway" - - minio: - # 保持原有配置不变 - image: minio/minio:latest - container_name: urban-lifeline-minio - restart: unless-stopped - networks: - - urban-lifeline - ports: - - "9000:9000" - - "9001:9001" - environment: - MINIO_ROOT_USER: minioadmin - MINIO_ROOT_PASSWORD: minioadmin123 - MINIO_CONSOLE_ADDRESS: ":9001" - MINIO_ADDRESS: ":9000" - TZ: Asia/Shanghai - volumes: - - ../../../.data/docker/minio/data:/data - - ../../../.data/docker/minio/config:/root/.minio - command: server /data --console-address ":9001" - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] - interval: 30s - timeout: 20s - retries: 3 - start_period: 30s - - # ====================== Jitsi 核心修改开始 ====================== - jitsi-web: - # ✅ 保持原有配置不变,无需修改 - image: jitsi/web:stable-9584 - container_name: urban-lifeline-jitsi-web - restart: unless-stopped - networks: - - urban-lifeline - ports: - - "8280:80" - - "8443:443" - environment: - TZ: Asia/Shanghai - PUBLIC_URL: https://org.xyzh.yslg.jitsi - ENABLE_HTTPS: 0 - ENABLE_HTTP_REDIRECT: 0 - DISABLE_HTTPS: 1 - XMPP_DOMAIN: meet.jitsi - XMPP_AUTH_DOMAIN: auth.meet.jitsi - XMPP_BOSH_URL_BASE: http://jitsi-prosody:5280 - XMPP_MUC_DOMAIN: muc.meet.jitsi - XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi - XMPP_GUEST_DOMAIN: guest.meet.jitsi - JICOFO_COMPONENT_SECRET: jicofo-secret - JICOFO_AUTH_USER: focus - JVB_AUTH_USER: jvb - JVB_AUTH_PASSWORD: jvb-password - ENABLE_AUTH: 1 - ENABLE_GUESTS: 0 - AUTH_TYPE: jwt - JWT_APP_ID: urbanLifeline - JWT_APP_SECRET: urbanLifeline-jitsi-secret-key-2025-production-safe-hs256 - JWT_ACCEPTED_ISSUERS: urbanLifeline - JWT_ACCEPTED_AUDIENCES: jitsi - JWT_ASAP_KEYSERVER: https://org.xyzh.yslg.jitsi/ - JWT_ALLOW_EMPTY: 0 - JWT_AUTH_TYPE: token - JWT_TOKEN_AUTH_MODULE: token_verification - ENABLE_RECORDING: 0 - ENABLE_TRANSCRIPTIONS: 0 - ENABLE_SUBDOMAINS: 0 - ENABLE_XMPP_WEBSOCKET: 1 - ENABLE_SCTP: 1 - ENABLE_LETSENCRYPT: 0 - LETSENCRYPT_DOMAIN: org.xyzh.yslg.jitsi - volumes: - - ../../../.data/docker/jitsi/web:/config - - ../../../.data/docker/jitsi/web/crontabs:/var/spool/cron/crontabs - - ../../../.data/docker/jitsi/transcripts:/usr/share/jitsi-meet/transcripts - depends_on: - - jitsi-prosody - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:80/"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 60s - - jitsi-prosody: - image: jitsi/prosody:stable-9584 - container_name: urban-lifeline-jitsi-prosody - restart: unless-stopped - networks: - - urban-lifeline - expose: - - "5222" - - "5347" - - "5280" - environment: - TZ: Asia/Shanghai - XMPP_DOMAIN: meet.jitsi - XMPP_AUTH_DOMAIN: auth.meet.jitsi - XMPP_MUC_DOMAIN: muc.meet.jitsi - XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi - XMPP_GUEST_DOMAIN: guest.meet.jitsi - JICOFO_COMPONENT_SECRET: jicofo-secret - JICOFO_AUTH_USER: focus - JICOFO_AUTH_PASSWORD: focus-password - JVB_AUTH_USER: jvb - JVB_AUTH_PASSWORD: jvb-password - ENABLE_AUTH: 1 - ENABLE_GUESTS: 0 - AUTH_TYPE: jwt - JWT_APP_ID: urbanLifeline - JWT_APP_SECRET: urbanLifeline-jitsi-secret-key-2025-production-safe-hs256 - JWT_ACCEPTED_ISSUERS: urbanLifeline - JWT_ACCEPTED_AUDIENCES: jitsi - JWT_ALLOW_EMPTY: 0 - JWT_AUTH_TYPE: token - JWT_TOKEN_AUTH_MODULE: token_verification - LOG_LEVEL: info - PUBLIC_URL: https://org.xyzh.yslg.jitsi - # 🔥 新增1 - Prosody层禁用JWT自动授予主持人权限(JWT模式核心!) - JWT_DISABLE_AUTO_MODERATOR: true - volumes: - - ../../../.data/docker/jitsi/prosody/config:/config - - ../../../.data/docker/jitsi/prosody/prosody-plugins-custom:/prosody-plugins-custom - healthcheck: - test: ["CMD", "prosodyctl", "status"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 90s - - jitsi-jicofo: - image: jitsi/jicofo:stable-9584 - container_name: urban-lifeline-jitsi-jicofo - restart: unless-stopped - networks: - - urban-lifeline - environment: - TZ: Asia/Shanghai - XMPP_DOMAIN: meet.jitsi - XMPP_AUTH_DOMAIN: auth.meet.jitsi - XMPP_MUC_DOMAIN: muc.meet.jitsi - XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi - XMPP_SERVER: jitsi-prosody - JICOFO_COMPONENT_SECRET: jicofo-secret - JICOFO_AUTH_USER: focus - JICOFO_AUTH_PASSWORD: focus-password - AUTH_TYPE: jwt - JVB_BREWERY_MUC: jvbbrewery - JICOFO_ENABLE_HEALTH_CHECKS: true - # 保留原有配置 - JICOFO_ENABLE_AUTO_OWNER: false - JICOFO_ENABLE_AUTO_LOGIN: false - # 🔥 新增2 - 兜底:强制清空初始主持人,杜绝所有自动分配可能 - JICOFO_CONFERENCE_INITIAL_OWNER: "" - volumes: - - ../../../.data/docker/jitsi/jicofo:/config - depends_on: - - jitsi-prosody - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8888/about/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 90s - - jitsi-jvb: - # ✅ 保持原有配置不变,无需修改 - image: jitsi/jvb:stable-9584 - container_name: urban-lifeline-jitsi-jvb - restart: unless-stopped - networks: - - urban-lifeline - ports: - - "10000:10000/udp" - - "4443:4443/tcp" - environment: - TZ: Asia/Shanghai - XMPP_DOMAIN: meet.jitsi - XMPP_AUTH_DOMAIN: auth.meet.jitsi - XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi - XMPP_SERVER: jitsi-prosody - JVB_AUTH_USER: jvb - JVB_AUTH_PASSWORD: jvb-password - JVB_BREWERY_MUC: jvbbrewery - JVB_PORT: 10000 - JVB_STUN_SERVERS: stun.l.google.com:19302,stun1.l.google.com:19302 - DOCKER_HOST_ADDRESS: 192.168.0.253 - JVB_ADVERTISE_IPS: 192.168.0.253 - JVB_ENABLE_APIS: rest,colibri - JVB_TCP_HARVESTER_DISABLED: "false" - JVB_TCP_PORT: 4443 - JVB_TCP_MAPPED_PORT: 4443 - volumes: - - ../../../.data/docker/jitsi/jvb:/config - depends_on: - - jitsi-prosody - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8080/about/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 90s \ No newline at end of file diff --git a/urbanLifelineServ/.bin/docker/urbanlifeline/readme.md b/urbanLifelineServ/.bin/docker/urbanlifeline/readme.md deleted file mode 100644 index dfb38d94..00000000 --- a/urbanLifelineServ/.bin/docker/urbanlifeline/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -# 注意点 -1. mysql 开发 bind-address 必须是 0.0.0.0 否则无法连接 -2. root % 密码必须是 123456 \ No newline at end of file diff --git a/urbanLifelineServ/.bin/docker/urbanlifeline/start.sh b/urbanLifelineServ/.bin/docker/urbanlifeline/start.sh deleted file mode 100644 index d2b085d4..00000000 --- a/urbanLifelineServ/.bin/docker/urbanlifeline/start.sh +++ /dev/null @@ -1,210 +0,0 @@ -#!/bin/bash - -# urban-lifeline Docker Compose 启动脚本 - -set -e - -# If the user invoked this script with `sh start.sh` (which may be dash), -# some Bash-specific features (like ${BASH_SOURCE[0]} and [[ .. ]]) will -# fail with "Bad substitution". If we're not running under Bash, try to -# re-exec the script using `bash` if available. -if [ -z "$BASH_VERSION" ]; then - if command -v bash >/dev/null 2>&1; then - echo "脚本需要 Bash,正在重新以 Bash 执行..." - exec bash "$0" "$@" - else - echo "错误: 需要 Bash 运行此脚本,但系统未安装 Bash。" - exit 1 - fi -fi -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" -DATA_DIR="$PROJECT_ROOT/.data/docker" - -echo "==========================================" -echo "urban-lifeline Docker 开发环境启动" -echo "==========================================" -echo "项目目录: $PROJECT_ROOT" -echo "数据目录: $DATA_DIR" -echo "" - -# 1. 检查 Docker -echo "1. 检查 Docker..." -if ! command -v docker &> /dev/null; then - echo "❌ 错误: 未找到 Docker" - echo "请先安装 Docker: https://docs.docker.com/get-docker/" - exit 1 -fi - -if ! docker info &> /dev/null; then - echo "❌ 错误: Docker 未运行" - echo "请启动 Docker 服务" - exit 1 -fi -echo "✓ Docker 检查完成" -echo "" - -# 2. 检查 Docker Compose -echo "2. 检查 Docker Compose..." -if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then - echo "❌ 错误: 未找到 Docker Compose" - echo "请先安装 Docker Compose: https://docs.docker.com/compose/install/" - exit 1 -fi -echo "✓ Docker Compose 检查完成" -echo "" - -# 3. 检查主机 MySQL -echo "3. 检查主机 MySQL..." -if command -v mysql &> /dev/null; then - echo "请输入 MySQL 连接信息 (按 Enter 使用默认值):" - read -p " 主机 [127.0.0.1]: " MYSQL_HOST - MYSQL_HOST=${MYSQL_HOST:-127.0.0.1} - - read -p " 端口 [3306]: " MYSQL_PORT - MYSQL_PORT=${MYSQL_PORT:-3306} - - read -p " 用户名 [root]: " MYSQL_USER - MYSQL_USER=${MYSQL_USER:-root} - - read -s -p " 密码 [123456]: " MYSQL_PASSWORD - echo - MYSQL_PASSWORD=${MYSQL_PASSWORD:-123456} - - read -p " 数据库名 [nacos_config]: " MYSQL_DB - MYSQL_DB=${MYSQL_DB:-nacos_config} - - echo "" - echo "测试 MySQL 连接..." - if mysql -h"$MYSQL_HOST" -P"$MYSQL_PORT" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "USE $MYSQL_DB;" 2>/dev/null; then - echo "✓ MySQL 连接成功" - else - echo "⚠️ 警告: MySQL 连接失败" - echo "" - echo "请确保:" - echo " 1. MySQL 服务正在运行" - echo " 2. 数据库 '$MYSQL_DB' 已创建" - echo " 3. 用户 '$MYSQL_USER' 有权限访问该数据库" - echo "" - read -p "是否继续启动? (y/N): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - exit 1 - fi - fi -else - echo "⚠️ 警告: 未找到 mysql 客户端,无法验证数据库连接" - echo "将使用默认配置: root:123456@localhost:3306/nacos_config" - MYSQL_USER=root - MYSQL_PASSWORD=123456 - MYSQL_DB=nacos_config -fi -echo "" - -# 4. 创建数据目录 -echo "4. 创建数据目录..." -mkdir -p "$DATA_DIR"/nacos/{data,logs} -echo "✓ 数据目录创建完成" -echo "" - -# 5. 更新 docker-compose.yml 配置 -if [ -n "$MYSQL_USER" ] && [ "$MYSQL_USER" != "root" ]; then - echo "5. 更新 Docker Compose 配置..." - - # 创建临时 .env 文件 - cat > "$SCRIPT_DIR/.env" < /dev/null; then - docker-compose pull -else - docker compose pull -fi -echo "✓ 镜像拉取完成" -echo "" - -# 7. 启动服务 -echo "7. 启动服务..." -if command -v docker-compose &> /dev/null; then - docker-compose up -d -else - docker compose up -d -fi -echo "✓ 服务启动完成" -echo "" - -# 8. 等待 Nacos 启动 -echo "8. 等待 Nacos 启动..." -echo " 这可能需要 30-60 秒..." - -MAX_WAIT=60 -WAITED=0 -while [ $WAITED -lt $MAX_WAIT ]; do - if curl -s http://localhost:8848/nacos/ > /dev/null 2>&1; then - echo "✓ Nacos 启动成功" - break - fi - sleep 2 - WAITED=$((WAITED + 2)) - echo -n "." -done -echo "" - -if [ $WAITED -ge $MAX_WAIT ]; then - echo "⚠️ 警告: Nacos 启动超时" - echo "" - echo "查看日志:" - if command -v docker-compose &> /dev/null; then - docker-compose logs nacos - else - docker compose logs nacos - fi - echo "" - echo "请检查 MySQL 连接配置是否正确" - exit 1 -fi - -# 9. 显示服务信息 -echo "" -echo "==========================================" -echo "✅ urban-lifeline 开发环境启动完成!" -echo "==========================================" -echo "" -echo "服务访问地址:" -echo " - Nacos 控制台: http://localhost:8848/nacos/" -echo " - Nacos 默认账号: nacos / nacos" -echo "" -echo "数据库连接信息:" -echo " - 数据库: ${MYSQL_DB:-nacos_config}" -echo " - 用户: ${MYSQL_USER:-root}" -echo "" -echo "数据持久化目录:" -echo " - $DATA_DIR/nacos/data" -echo " - $DATA_DIR/nacos/logs" -echo "" -echo "常用命令:" -echo " 查看运行状态:" -echo " docker ps" -echo "" -echo " 查看 Nacos 日志:" -echo " docker logs -f urban-lifeline-nacos" -echo "" -echo " 停止服务:" -echo " cd $SCRIPT_DIR && docker-compose down" -echo "" -echo " 重启服务:" -echo " cd $SCRIPT_DIR && docker-compose restart" -echo "" -echo " 完全清理(删除容器和网络):" -echo " cd $SCRIPT_DIR && docker-compose down -v" -echo "" diff --git a/urbanLifelineServ/.bin/docker/urbanlifeline/stop.sh b/urbanLifelineServ/.bin/docker/urbanlifeline/stop.sh deleted file mode 100644 index 0c974078..00000000 --- a/urbanLifelineServ/.bin/docker/urbanlifeline/stop.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# urban-lifeline Docker Compose 停止脚本 - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -echo "==========================================" -echo "停止 urban-lifeline 开发环境" -echo "==========================================" -echo "" - -cd "$SCRIPT_DIR" - -if command -v docker-compose &> /dev/null; then - docker-compose down -else - docker compose down -fi - -echo "" -echo "✅ 服务已停止" -echo "" -echo "数据已保留在: ../../.data/docker/nacos/" -echo "" -echo "如需重新启动,请运行: ./start.sh" -echo "如需完全清理,请运行: docker-compose down -v" -echo "" diff --git a/urbanLifelineServ/.bin/sql/nacos/nacos-mysql-schema.sql b/urbanLifelineServ/.bin/sql/nacos/nacos-mysql-schema.sql deleted file mode 100644 index 36098b16..00000000 --- a/urbanLifelineServ/.bin/sql/nacos/nacos-mysql-schema.sql +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 1999-2018 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -DROP DATABASE IF EXISTS `nacos_config`; -CREATE DATABASE IF NOT EXISTS `nacos_config` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -USE `nacos_config`; - -/******************************************/ -/* 表名称 = config_info */ -/******************************************/ -CREATE TABLE `config_info` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', - `data_id` VARCHAR(255) NOT NULL COMMENT 'data_id', - `group_id` VARCHAR(128) DEFAULT NULL COMMENT 'group_id', - `content` longtext NOT NULL COMMENT 'content', - `md5` VARCHAR(32) DEFAULT NULL COMMENT 'md5', - `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', - `src_user` text COMMENT 'source user', - `src_ip` VARCHAR(50) DEFAULT NULL COMMENT 'source ip', - `app_name` VARCHAR(128) DEFAULT NULL COMMENT 'app_name', - `tenant_id` VARCHAR(128) DEFAULT '' COMMENT '租户字段', - `c_desc` VARCHAR(256) DEFAULT NULL COMMENT 'configuration description', - `c_use` VARCHAR(64) DEFAULT NULL COMMENT 'configuration usage', - `effect` VARCHAR(64) DEFAULT NULL COMMENT '配置生效的描述', - `type` VARCHAR(64) DEFAULT NULL COMMENT '配置的类型', - `c_schema` text COMMENT '配置的模式', - `encrypted_data_key` VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '密钥', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info'; - -/******************************************/ -/* 表名称 = config_info since 2.5.0 */ -/******************************************/ -CREATE TABLE `config_info_gray` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `data_id` VARCHAR(255) NOT NULL COMMENT 'data_id', - `group_id` VARCHAR(128) NOT NULL COMMENT 'group_id', - `content` longtext NOT NULL COMMENT 'content', - `md5` VARCHAR(32) DEFAULT NULL COMMENT 'md5', - `src_user` text COMMENT 'src_user', - `src_ip` VARCHAR(100) DEFAULT NULL COMMENT 'src_ip', - `gmt_create` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'gmt_create', - `gmt_modified` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'gmt_modified', - `app_name` VARCHAR(128) DEFAULT NULL COMMENT 'app_name', - `tenant_id` VARCHAR(128) DEFAULT '' COMMENT 'tenant_id', - `gray_name` VARCHAR(128) NOT NULL COMMENT 'gray_name', - `gray_rule` text NOT NULL COMMENT 'gray_rule', - `encrypted_data_key` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'encrypted_data_key', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_configinfogray_datagrouptenantgray` (`data_id`,`group_id`,`tenant_id`,`gray_name`), - KEY `idx_dataid_gmt_modified` (`data_id`,`gmt_modified`), - KEY `idx_gmt_modified` (`gmt_modified`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='config_info_gray'; - -/******************************************/ -/* 表名称 = config_tags_relation */ -/******************************************/ -CREATE TABLE `config_tags_relation` ( - `id` bigint(20) NOT NULL COMMENT 'id', - `tag_name` VARCHAR(128) NOT NULL COMMENT 'tag_name', - `tag_type` VARCHAR(64) DEFAULT NULL COMMENT 'tag_type', - `data_id` VARCHAR(255) NOT NULL COMMENT 'data_id', - `group_id` VARCHAR(128) NOT NULL COMMENT 'group_id', - `tenant_id` VARCHAR(128) DEFAULT '' COMMENT 'tenant_id', - `nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增长标识', - PRIMARY KEY (`nid`), - UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`), - KEY `idx_tenant_id` (`tenant_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation'; - -/******************************************/ -/* 表名称 = group_capacity */ -/******************************************/ -CREATE TABLE `group_capacity` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `group_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群', - `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值', - `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量', - `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值', - `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值', - `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值', - `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量', - `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_group_id` (`group_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表'; - -/******************************************/ -/* 表名称 = his_config_info */ -/******************************************/ -CREATE TABLE `his_config_info` ( - `id` bigint(20) unsigned NOT NULL COMMENT 'id', - `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增标识', - `data_id` VARCHAR(255) NOT NULL COMMENT 'data_id', - `group_id` VARCHAR(128) NOT NULL COMMENT 'group_id', - `app_name` VARCHAR(128) DEFAULT NULL COMMENT 'app_name', - `content` longtext NOT NULL COMMENT 'content', - `md5` VARCHAR(32) DEFAULT NULL COMMENT 'md5', - `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', - `src_user` text COMMENT 'source user', - `src_ip` VARCHAR(50) DEFAULT NULL COMMENT 'source ip', - `op_type` char(10) DEFAULT NULL COMMENT 'operation type', - `tenant_id` VARCHAR(128) DEFAULT '' COMMENT '租户字段', - `encrypted_data_key` VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '密钥', - `publish_type` VARCHAR(50) DEFAULT 'formal' COMMENT 'publish type gray or formal', - `gray_name` VARCHAR(50) DEFAULT NULL COMMENT 'gray name', - `ext_info` longtext DEFAULT NULL COMMENT 'ext info', - PRIMARY KEY (`nid`), - KEY `idx_gmt_create` (`gmt_create`), - KEY `idx_gmt_modified` (`gmt_modified`), - KEY `idx_did` (`data_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造'; - - -/******************************************/ -/* 表名称 = tenant_capacity */ -/******************************************/ -CREATE TABLE `tenant_capacity` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `tenant_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID', - `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值', - `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量', - `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值', - `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数', - `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值', - `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量', - `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_tenant_id` (`tenant_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表'; - - -CREATE TABLE `tenant_info` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', - `kp` VARCHAR(128) NOT NULL COMMENT 'kp', - `tenant_id` VARCHAR(128) default '' COMMENT 'tenant_id', - `tenant_name` VARCHAR(128) default '' COMMENT 'tenant_name', - `tenant_desc` VARCHAR(256) DEFAULT NULL COMMENT 'tenant_desc', - `create_source` VARCHAR(32) DEFAULT NULL COMMENT 'create_source', - `gmt_create` bigint(20) NOT NULL COMMENT '创建时间', - `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`), - KEY `idx_tenant_id` (`tenant_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info'; - -CREATE TABLE `users` ( - `username` VARCHAR(50) NOT NULL PRIMARY KEY COMMENT 'username', - `password` VARCHAR(500) NOT NULL COMMENT 'password', - `enabled` BOOLEAN NOT NULL COMMENT 'enabled' -); - -CREATE TABLE `roles` ( - `username` VARCHAR(50) NOT NULL COMMENT 'username', - `role` VARCHAR(50) NOT NULL COMMENT 'role', - UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE -); - -CREATE TABLE `permissions` ( - `role` VARCHAR(50) NOT NULL COMMENT 'role', - `resource` VARCHAR(128) NOT NULL COMMENT 'resource', - `action` VARCHAR(8) NOT NULL COMMENT 'action', - UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE -); - diff --git a/urbanLifelineServ/.gitignore b/urbanLifelineServ/.gitignore deleted file mode 100644 index 1bfb4993..00000000 --- a/urbanLifelineServ/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ -# Compiled class file -*.class - -# Log file -*.log -*/logs -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -.data -.idea -*/target -*/*/target -# example/* \ No newline at end of file diff --git a/urbanLifelineServ/.pids/auth.pid b/urbanLifelineServ/.pids/auth.pid deleted file mode 100644 index 1f3d8a7a..00000000 --- a/urbanLifelineServ/.pids/auth.pid +++ /dev/null @@ -1 +0,0 @@ -1028 diff --git a/urbanLifelineServ/.pids/gateway.pid b/urbanLifelineServ/.pids/gateway.pid deleted file mode 100644 index baccd039..00000000 --- a/urbanLifelineServ/.pids/gateway.pid +++ /dev/null @@ -1 +0,0 @@ -1003 diff --git a/urbanLifelineServ/.pids/system.pid b/urbanLifelineServ/.pids/system.pid deleted file mode 100644 index b96bfec6..00000000 --- a/urbanLifelineServ/.pids/system.pid +++ /dev/null @@ -1 +0,0 @@ -1053 diff --git a/urbanLifelineServ/.vscode/README-snippets.md b/urbanLifelineServ/.vscode/README-snippets.md deleted file mode 100644 index bc7ba332..00000000 --- a/urbanLifelineServ/.vscode/README-snippets.md +++ /dev/null @@ -1,88 +0,0 @@ -# MyBatis XML 代码片段使用说明 - -## 安装位置 - -代码片段文件已放置在 `.vscode/mybatis-xml.code-snippets`,VS Code 和 Cursor 会自动识别。 - -## 使用方法 - -### 1. 完整 Mapper XML 模板 - -在 XML 文件中输入 `mybatis-mapper`,然后按 `Tab` 键,会自动生成完整的 MyBatis Mapper XML 模板。 - -**占位符说明:** -- `${1}` - Mapper 命名空间(完整包路径) -- `${2}` - 模块名称(如:user, role, dept) -- `${3}` - 实体类名称(如:TbSysUser) -- `${4}` - DTO 完整类路径 -- `${5}` - 主键数据库字段名(如:user_id) -- `${6}` - 主键 Java 属性名(如:userId) -- `${7}` - 业务字段数据库字段名 -- `${8}` - 业务字段 Java 属性名 -- `${9}` - 实体中文名称(如:用户) -- `${10}` - 数据库表名(如:tb_sys_user) - -### 2. 单个 SQL 片段 - -#### ResultMap -输入 `mybatis-resultmap` 生成结果映射 - -#### Insert -输入 `mybatis-insert` 生成插入语句 - -#### Update -输入 `mybatis-update` 生成更新语句 - -#### Delete -输入 `mybatis-delete` 生成删除语句(逻辑删除) - -#### Select ById -输入 `mybatis-select-id` 生成根据ID查询 - -#### Select ByFilter -输入 `mybatis-select-filter` 生成条件查询 - -#### Select Page -输入 `mybatis-select-page` 生成分页查询 - -#### Select Count -输入 `mybatis-select-count` 生成计数查询 - -#### Base Column List -输入 `mybatis-columns` 生成基础列定义 - -## 示例 - -### 创建完整的 Mapper XML - -1. 新建文件:`TbSysRoleMapper.xml` -2. 输入 `mybatis-mapper` 并按 `Tab` -3. 依次填写占位符: - - 命名空间:`org.xyzh.system.mapper.role.TbSysRoleMapper` - - 模块名:`role` - - 实体名:`TbSysRole` - - DTO路径:`org.xyzh.common.dto.sys.TbSysRoleDTO` - - 主键字段:`role_id` - - 主键属性:`roleId` - - 业务字段:`role_name` - - 业务属性:`roleName` - - 实体中文名:`角色` - - 表名:`tb_sys_role` - -### 快速添加单个 SQL - -在已有的 Mapper XML 中,输入对应的前缀(如 `mybatis-insert`),按 `Tab` 即可快速插入对应的 SQL 片段。 - -## 注意事项 - -1. 所有模板都包含了 BaseDTO 的通用字段 -2. 删除操作使用逻辑删除(设置 deleted = true) -3. 查询时自动过滤已删除的记录(deleted = false) -4. 分页使用 LIMIT 和 OFFSET(PostgreSQL/MySQL 兼容) -5. 时间字段使用 TIMESTAMP 类型 -6. 字符串字段使用 VARCHAR 类型 - -## 自定义 - -如需修改模板,编辑 `.vscode/mybatis-xml.code-snippets` 文件即可。 - diff --git a/urbanLifelineServ/.vscode/launch.json b/urbanLifelineServ/.vscode/launch.json deleted file mode 100644 index 0fc9038e..00000000 --- a/urbanLifelineServ/.vscode/launch.json +++ /dev/null @@ -1,215 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "AesEncryptUtil", - "request": "launch", - "mainClass": "org.xyzh.common.utils.crypto.AesEncryptUtil", - "projectName": "common-utils" - }, - { - "type": "java", - "name": "Gateway (8180)", - "request": "launch", - "mainClass": "org.xyzh.gateway.GatewayApplication", - "projectName": "gateway", - "cwd": "${workspaceFolder}/gateway", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8180" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "Auth (8181)", - "request": "launch", - "mainClass": "org.xyzh.auth.AuthApp", - "projectName": "auth", - "cwd": "${workspaceFolder}/auth", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8181" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "System (8182)", - "request": "launch", - "mainClass": "org.xyzh.system.SystemApp", - "projectName": "system", - "cwd": "${workspaceFolder}/system", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8182" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "Log (8183)", - "request": "launch", - "mainClass": "org.xyzh.log.LogApp", - "projectName": "log", - "cwd": "${workspaceFolder}/log", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8183" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "File (8184)", - "request": "launch", - "mainClass": "org.xyzh.file.FileApp", - "projectName": "file", - "cwd": "${workspaceFolder}/file", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8184" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "Message (8185)", - "request": "launch", - "mainClass": "org.xyzh.message.MessageApp", - "projectName": "message", - "cwd": "${workspaceFolder}/message", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8185" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "Bidding (8186)", - "request": "launch", - "mainClass": "org.xyzh.bidding.BiddingApp", - "projectName": "bidding", - "cwd": "${workspaceFolder}/bidding", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8186" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "Platform (8187)", - "request": "launch", - "mainClass": "org.xyzh.platform.PlatformApp", - "projectName": "platform", - "cwd": "${workspaceFolder}/platform", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8187" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "Workcase (8188)", - "request": "launch", - "mainClass": "org.xyzh.workcase.WorkcaseApp", - "projectName": "workcase", - "cwd": "${workspaceFolder}/workcase", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8188" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "Crontab (8189)", - "request": "launch", - "mainClass": "org.xyzh.crontab.CrontabApp", - "projectName": "crontab", - "cwd": "${workspaceFolder}/crontab", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8189" - ], - "console": "integratedTerminal" - }, - { - "type": "java", - "name": "AI (8190)", - "request": "launch", - "mainClass": "org.xyzh.ai.AiApp", - "projectName": "ai", - "cwd": "${workspaceFolder}/ai", - "args": [ - "--spring.profiles.active=dev" - ], - "vmArgs": [ - "-Dserver.port=8190" - ], - "console": "integratedTerminal" - } - ], - "compounds": [ - { - "name": "Core Services (Gateway + Auth + System)", - "configurations": [ - "Gateway (8180)", - "Auth (8181)", - "System (8182)" - ], - "stopAll": true, - "presentation": { - "hidden": false, - "group": "服务组合", - "order": 1 - } - }, - { - "name": "All Services", - "configurations": [ - "Gateway (8180)", - "Auth (8181)", - "System (8182)", - // "Log (8183)", - "File (8184)", - // "Message (8185)", - // "Bidding (8186)", - // "Platform (8187)", - "Workcase (8188)", - // "Crontab (8189)", - "AI (8190)" - ], - "stopAll": true, - "presentation": { - "hidden": false, - "group": "服务组合", - "order": 2 - } - } - ] -} \ No newline at end of file diff --git a/urbanLifelineServ/.vscode/mybatis-xml.code-snippets b/urbanLifelineServ/.vscode/mybatis-xml.code-snippets deleted file mode 100644 index 206f38e6..00000000 --- a/urbanLifelineServ/.vscode/mybatis-xml.code-snippets +++ /dev/null @@ -1,313 +0,0 @@ -{ - "MyBatis Mapper XML Template": { - "prefix": "mybatis-mapper", - "body": [ - "", - "", - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "", - " ", - " ", - " ${5:entity_id}, ${7:field_name},", - " optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted", - " ", - "", - " ", - " ", - " INSERT INTO ${10:tb_entity_name} (", - " ${5:entity_id}, ${7:field_name},", - " optsn, creator, updater, dept_path, remark, create_time, update_time, deleted", - " ) VALUES (", - " #{${6:entityId}}, #{${8:fieldName}},", - " #{optsn}, #{creator}, #{updater}, #{deptPath}, #{remark}, #{createTime}, #{updateTime}, #{deleted}", - " )", - " ", - "", - " ", - " ", - " UPDATE ${10:tb_entity_name}", - " ", - " ", - " ${7:field_name} = #{${8:fieldName}},", - " ", - " ", - " updater = #{updater},", - " ", - " ", - " dept_path = #{deptPath},", - " ", - " ", - " remark = #{remark},", - " ", - " ", - " update_time = #{updateTime},", - " ", - " ", - " WHERE ${5:entity_id} = #{${6:entityId}}", - " ", - " AND deleted = #{deleted}", - " ", - " ", - "", - " ", - " ", - " UPDATE ${10:tb_entity_name}", - " SET deleted = true,", - " delete_time = NOW()", - " WHERE ${5:entity_id} = #{${6:entityId}}", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - "" - ], - "description": "MyBatis Mapper XML 完整模板" - }, - "MyBatis ResultMap": { - "prefix": "mybatis-resultmap", - "body": [ - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " " - ], - "description": "MyBatis ResultMap 映射" - }, - "MyBatis Insert": { - "prefix": "mybatis-insert", - "body": [ - " ", - " ", - " INSERT INTO ${4:tb_entity_name} (", - " ${5:entity_id}, ${6:field_name},", - " optsn, creator, updater, dept_path, remark, create_time, update_time, deleted", - " ) VALUES (", - " #{${7:entityId}}, #{${8:fieldName}},", - " #{optsn}, #{creator}, #{updater}, #{deptPath}, #{remark}, #{createTime}, #{updateTime}, #{deleted}", - " )", - " " - ], - "description": "MyBatis Insert 语句" - }, - "MyBatis Update": { - "prefix": "mybatis-update", - "body": [ - " ", - " ", - " UPDATE ${4:tb_entity_name}", - " ", - " ", - " ${6:field_name} = #{${5:fieldName}},", - " ", - " ", - " updater = #{updater},", - " ", - " ", - " dept_path = #{deptPath},", - " ", - " ", - " remark = #{remark},", - " ", - " ", - " update_time = #{updateTime},", - " ", - " ", - " WHERE ${7:entity_id} = #{${8:entityId}}", - " ", - " AND deleted = #{deleted}", - " ", - " " - ], - "description": "MyBatis Update 语句" - }, - "MyBatis Delete": { - "prefix": "mybatis-delete", - "body": [ - " ", - " ", - " UPDATE ${4:tb_entity_name}", - " SET deleted = true,", - " delete_time = NOW()", - " WHERE ${5:entity_id} = #{${6:entityId}}", - " " - ], - "description": "MyBatis Delete 语句(逻辑删除)" - }, - "MyBatis Select ById": { - "prefix": "mybatis-select-id", - "body": [ - " ", - " " - ], - "description": "MyBatis Select ById 查询" - }, - "MyBatis Select ByFilter": { - "prefix": "mybatis-select-filter", - "body": [ - " ", - " " - ], - "description": "MyBatis Select ByFilter 查询" - }, - "MyBatis Select Page": { - "prefix": "mybatis-select-page", - "body": [ - " ", - " " - ], - "description": "MyBatis Select Page 分页查询" - }, - "MyBatis Select Count": { - "prefix": "mybatis-select-count", - "body": [ - " ", - " " - ], - "description": "MyBatis Select Count 计数查询" - }, - "MyBatis Base Column List": { - "prefix": "mybatis-columns", - "body": [ - " ", - " ", - " ${1:entity_id}, ${2:field_name},", - " optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted", - " " - ], - "description": "MyBatis 基础列定义" - } -} - diff --git a/urbanLifelineServ/.vscode/settings.json b/urbanLifelineServ/.vscode/settings.json deleted file mode 100644 index d28f3d54..00000000 --- a/urbanLifelineServ/.vscode/settings.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "java.compile.nullAnalysis.mode": "automatic", - "java.configuration.updateBuildConfiguration": "automatic", - "maven.view": "hierarchical", - "tabSize": 4, - "java.debug.settings.onBuildFailureProceed": true, - "java.configuration.maven.userSettings": "", - "java.import.maven.enabled": true, - "java.project.referencedLibraries": [ - "**/*.jar" - ], - "maven.terminal.useJavaHome": true, - "java.configuration.runtimes": [], - "Codegeex.RepoIndex": true, - "terminal.integrated.defaultProfile.windows": "Command Prompt", - "terminal.integrated.profiles.windows": { - "PowerShell": { - "source": "PowerShell", - "args": ["-NoExit", "-Command", "chcp 65001"] - }, - "Command Prompt": { - "path": "cmd.exe", - "args": ["/k", "chcp 65001"] - }, - "Git Bash": { - "path": "F:\\Environment\\Git\\bin\\bash.exe", - "args": ["-i"], - "env": { - "LANG": "zh_CN.UTF-8", - "LC_ALL": "zh_CN.UTF-8" - } - } - }, -} \ No newline at end of file diff --git a/urbanLifelineServ/.windsurf/rules/urbanlife.md b/urbanLifelineServ/.windsurf/rules/urbanlife.md deleted file mode 100644 index 83137f98..00000000 --- a/urbanLifelineServ/.windsurf/rules/urbanlife.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -trigger: manual ---- - -1. 有BaseDTO基类,DTO\VO在api模块下面 -2. 用Dubbo注册和,引用服务 -3. 当个端Insert语句,对应sql表的必填项才生成(有默认值也是if生成),其他应该if条件生成 diff --git a/urbanLifelineServ/Makefile b/urbanLifelineServ/Makefile deleted file mode 100644 index fcfa494f..00000000 --- a/urbanLifelineServ/Makefile +++ /dev/null @@ -1,247 +0,0 @@ -# ================================================ -# Urban Lifeline 微服务管理 Makefile -# ================================================ - -# 项目根目录 -PROJECT_ROOT := $(shell pwd) - -# Maven 命令 -MAVEN := mvn -MAVEN_OPTS := -Dmaven.test.skip=true - -# 服务列表 -SERVICES := gateway auth system log file message bidding platform workcase crontab agent - -# 服务端口映射 -PORT_gateway := 8080 -PORT_auth := 8081 -PORT_system := 8082 -PORT_log := 8083 -PORT_file := 8084 -PORT_message := 8085 -PORT_bidding := 8086 -PORT_platform := 8087 -PORT_workcase := 8088 -PORT_crontab := 8089 -PORT_agent := 8090 - -# 服务主类映射 -MAINCLASS_gateway := org.xyzh.gateway.GatewayApplication -MAINCLASS_auth := org.xyzh.auth.AuthApp -MAINCLASS_system := org.xyzh.system.SystemApp -MAINCLASS_log := org.xyzh.log.LogApp -MAINCLASS_file := org.xyzh.file.FileApp -MAINCLASS_message := org.xyzh.message.MessageApp -MAINCLASS_bidding := org.xyzh.bidding.BiddingApp -MAINCLASS_platform := org.xyzh.platform.PlatformApp -MAINCLASS_workcase := org.xyzh.workcase.WorkcaseApp -MAINCLASS_crontab := org.xyzh.crontab.CrontabApp -MAINCLASS_agent := org.xyzh.agent.AgentApp - -# PID 文件目录 -PID_DIR := $(PROJECT_ROOT)/.pids -LOG_DIR := $(PROJECT_ROOT)/.logs - -# 颜色定义 -COLOR_RESET := \033[0m -COLOR_GREEN := \033[0;32m -COLOR_YELLOW := \033[0;33m -COLOR_BLUE := \033[0;34m -COLOR_RED := \033[0;31m - -# ================================================ -# 帮助信息 -# ================================================ -.PHONY: help -help: - @echo "$(COLOR_BLUE)=============================================$(COLOR_RESET)" - @echo "$(COLOR_BLUE) Urban Lifeline 微服务管理工具$(COLOR_RESET)" - @echo "$(COLOR_BLUE)=============================================$(COLOR_RESET)" - @echo "" - @echo "$(COLOR_GREEN)构建命令:$(COLOR_RESET)" - @echo " make build - 构建所有服务" - @echo " make build- - 构建指定服务 (如: make build-system)" - @echo " make clean - 清理所有服务" - @echo "" - @echo "$(COLOR_GREEN)启动命令:$(COLOR_RESET)" - @echo " make start - 启动所有服务" - @echo " make start- - 启动指定服务 (如: make start-system)" - @echo " make start-core - 启动核心服务 (gateway, auth, system)" - @echo "" - @echo "$(COLOR_GREEN)停止命令:$(COLOR_RESET)" - @echo " make stop - 停止所有服务" - @echo " make stop- - 停止指定服务 (如: make stop-system)" - @echo "" - @echo "$(COLOR_GREEN)重启命令:$(COLOR_RESET)" - @echo " make restart - 重启所有服务" - @echo " make restart- - 重启指定服务 (如: make restart-system)" - @echo "" - @echo "$(COLOR_GREEN)状态查看:$(COLOR_RESET)" - @echo " make status - 查看所有服务状态" - @echo " make status- - 查看指定服务状态" - @echo " make logs- - 查看指定服务日志" - @echo "" - @echo "$(COLOR_GREEN)可用服务:$(COLOR_RESET)" - @echo " $(SERVICES)" - @echo "" - -# ================================================ -# 初始化目录 -# ================================================ -.PHONY: init-dirs -init-dirs: - @mkdir -p $(PID_DIR) - @mkdir -p $(LOG_DIR) - -# ================================================ -# 构建相关 -# ================================================ -.PHONY: build -build: init-dirs - @echo "$(COLOR_YELLOW)开始构建所有服务...$(COLOR_RESET)" - @$(MAVEN) clean install $(MAVEN_OPTS) - @echo "$(COLOR_GREEN)✓ 所有服务构建完成$(COLOR_RESET)" - -.PHONY: $(addprefix build-,$(SERVICES)) -$(addprefix build-,$(SERVICES)): build-%: - @echo "$(COLOR_YELLOW)开始构建 $* 服务...$(COLOR_RESET)" - @cd $(PROJECT_ROOT)/$* && $(MAVEN) clean install $(MAVEN_OPTS) - @echo "$(COLOR_GREEN)✓ $* 服务构建完成$(COLOR_RESET)" - -.PHONY: clean -clean: - @echo "$(COLOR_YELLOW)开始清理所有服务...$(COLOR_RESET)" - @$(MAVEN) clean - @rm -rf $(PID_DIR) - @rm -rf $(LOG_DIR) - @echo "$(COLOR_GREEN)✓ 清理完成$(COLOR_RESET)" - -# ================================================ -# 启动服务 -# ================================================ -.PHONY: start -start: init-dirs $(addprefix start-,$(SERVICES)) - @echo "$(COLOR_GREEN)✓ 所有服务启动完成$(COLOR_RESET)" - -.PHONY: start-core -start-core: init-dirs start-gateway start-auth start-system - @echo "$(COLOR_GREEN)✓ 核心服务启动完成$(COLOR_RESET)" - -.PHONY: $(addprefix start-,$(SERVICES)) -$(addprefix start-,$(SERVICES)): start-%: - @if [ -f "$(PID_DIR)/$*.pid" ] && kill -0 $$(cat $(PID_DIR)/$*.pid) 2>/dev/null; then \ - echo "$(COLOR_YELLOW)⚠ $* 服务已在运行中 (PID: $$(cat $(PID_DIR)/$*.pid))$(COLOR_RESET)"; \ - else \ - echo "$(COLOR_BLUE)启动 $* 服务...$(COLOR_RESET)"; \ - nohup $(MAVEN) -pl $* spring-boot:run > $(LOG_DIR)/$*.log 2>&1 & \ - echo $$! > $(PID_DIR)/$*.pid; \ - sleep 2; \ - if kill -0 $$(cat $(PID_DIR)/$*.pid) 2>/dev/null; then \ - echo "$(COLOR_GREEN)✓ $* 服务启动成功 (PID: $$(cat $(PID_DIR)/$*.pid), Port: $(PORT_$*))$(COLOR_RESET)"; \ - else \ - echo "$(COLOR_RED)✗ $* 服务启动失败$(COLOR_RESET)"; \ - rm -f $(PID_DIR)/$*.pid; \ - fi; \ - fi - -# ================================================ -# 停止服务 -# ================================================ -.PHONY: stop -stop: $(addprefix stop-,$(SERVICES)) - @echo "$(COLOR_GREEN)✓ 所有服务停止完成$(COLOR_RESET)" - -.PHONY: $(addprefix stop-,$(SERVICES)) -$(addprefix stop-,$(SERVICES)): stop-%: - @if [ -f "$(PID_DIR)/$*.pid" ]; then \ - PID=$$(cat $(PID_DIR)/$*.pid); \ - if kill -0 $$PID 2>/dev/null; then \ - echo "$(COLOR_YELLOW)停止 $* 服务 (PID: $$PID)...$(COLOR_RESET)"; \ - kill $$PID; \ - sleep 2; \ - if kill -0 $$PID 2>/dev/null; then \ - echo "$(COLOR_RED)强制停止 $* 服务...$(COLOR_RESET)"; \ - kill -9 $$PID; \ - fi; \ - rm -f $(PID_DIR)/$*.pid; \ - echo "$(COLOR_GREEN)✓ $* 服务已停止$(COLOR_RESET)"; \ - else \ - echo "$(COLOR_YELLOW)⚠ $* 服务未运行$(COLOR_RESET)"; \ - rm -f $(PID_DIR)/$*.pid; \ - fi; \ - else \ - echo "$(COLOR_YELLOW)⚠ $* 服务未运行$(COLOR_RESET)"; \ - fi - -# ================================================ -# 重启服务 -# ================================================ -.PHONY: restart -restart: stop start - @echo "$(COLOR_GREEN)✓ 所有服务重启完成$(COLOR_RESET)" - -.PHONY: $(addprefix restart-,$(SERVICES)) -$(addprefix restart-,$(SERVICES)): restart-%: stop-% start-% - @echo "$(COLOR_GREEN)✓ $* 服务重启完成$(COLOR_RESET)" - -# ================================================ -# 查看状态 -# ================================================ -.PHONY: status -status: - @echo "$(COLOR_BLUE)=============================================$(COLOR_RESET)" - @echo "$(COLOR_BLUE) 服务运行状态$(COLOR_RESET)" - @echo "$(COLOR_BLUE)=============================================$(COLOR_RESET)" - @for service in $(SERVICES); do \ - printf "%-15s" "$$service:"; \ - if [ -f "$(PID_DIR)/$$service.pid" ]; then \ - PID=$$(cat $(PID_DIR)/$$service.pid); \ - if kill -0 $$PID 2>/dev/null; then \ - echo "$(COLOR_GREEN)✓ Running (PID: $$PID)$(COLOR_RESET)"; \ - else \ - echo "$(COLOR_RED)✗ Stopped$(COLOR_RESET)"; \ - rm -f $(PID_DIR)/$$service.pid; \ - fi; \ - else \ - echo "$(COLOR_YELLOW)○ Not Started$(COLOR_RESET)"; \ - fi; \ - done - @echo "" - -.PHONY: $(addprefix status-,$(SERVICES)) -$(addprefix status-,$(SERVICES)): status-%: - @if [ -f "$(PID_DIR)/$*.pid" ]; then \ - PID=$$(cat $(PID_DIR)/$*.pid); \ - if kill -0 $$PID 2>/dev/null; then \ - echo "$(COLOR_GREEN)✓ $* 服务运行中 (PID: $$PID, Port: $(PORT_$*))$(COLOR_RESET)"; \ - else \ - echo "$(COLOR_RED)✗ $* 服务已停止$(COLOR_RESET)"; \ - fi; \ - else \ - echo "$(COLOR_YELLOW)○ $* 服务未启动$(COLOR_RESET)"; \ - fi - -# ================================================ -# 查看日志 -# ================================================ -.PHONY: $(addprefix logs-,$(SERVICES)) -$(addprefix logs-,$(SERVICES)): logs-%: - @if [ -f "$(LOG_DIR)/$*.log" ]; then \ - tail -f $(LOG_DIR)/$*.log; \ - else \ - echo "$(COLOR_YELLOW)⚠ $* 服务日志文件不存在$(COLOR_RESET)"; \ - fi - -# ================================================ -# 快捷命令 -# ================================================ -.PHONY: dev -dev: start-core - @echo "$(COLOR_GREEN)✓ 开发环境启动完成 (gateway, auth, system)$(COLOR_RESET)" - -.PHONY: prod -prod: start - @echo "$(COLOR_GREEN)✓ 生产环境启动完成$(COLOR_RESET)" - -# 默认目标 -.DEFAULT_GOAL := help diff --git a/urbanLifelineServ/ai/AI模块功能说明.md b/urbanLifelineServ/ai/AI模块功能说明.md deleted file mode 100644 index 48f91a9e..00000000 --- a/urbanLifelineServ/ai/AI模块功能说明.md +++ /dev/null @@ -1,51 +0,0 @@ -# 智能体创建 - -说明: 本服务只对智能体进行对话的转发,不能对dify智能体进行修改 -1. 智能体创建,用户上传tb_agent需要的字段进行智能体创建 - -# 智能体更新 -1. 更新数据库和redis缓存 -2. 注意加锁,避免并发时,其他线程用了错误数据 - -# 智能体删除 -软删除本服务的智能体数据 - -# 智能体对话 -1. 校验智能体是否可以用 -2. 用户会先对1个智能体创建一个会话 -3. 用户先发起对话预处理请求,传入会话携带的对象数据到redis中,产生一个临时的消息id -4. 真正发起对话数据请求时,会传入3个必须参数,1智能体id,2会话id,3本次消息id -5. 优先从redis缓存中获取agentid对应的agent配置,没有找数据库。这里要进行双检加锁,避免智能体修改、重复加载等问题 -6. 从redis中获取消息id真正的数据,包含各种数据对象和fileid等等内容 -7. 和dify构建sse流式对话,并回应前端的sse流式对话。 不要乱生成无用的data事件,直接返回dify的事件和数据 -8. 前端会自动处理dify的事件 - -# 对话评价 -1. 用户对对话进行评价,评价会存储到tb_chat_message的comment字段中 -2. 调用dify代理服务,更新dify智能体本消息的评价 - -# 知识库创建 -1. 用户上传tb_knowledge需要的字段进行知识库创建 - -# 知识库文件上传 -1. 用户上传文件到本服务,存储到文件表和minio中,并生成version版本 -2. 上传文件到dify知识库,dify返回上传成功后插入tb_knowledge_file表,并更新version版本,否则提示用户 - -# 知识库更新文件 -1. 用户上传文件到本服务,并生成version版本,存储到文件表和minio中 -2. 上传文件到dify知识库,dify返回上传成功后插入tb_knowledge_file表,并更新version版本,否则提示用户 -3. 删除dify旧的version的文件document,来控制版本 -4. 本服务中,旧的文件对象不会删除,本条新的file对象会有file_root_id指向原始第一个file对象的file_id,用来进行版本展示,但dify知识库实际只有1个最新的文件 - -# 知识库删除文件 -1. 软删除本服务服务中tb_knowledge_file的该文件所有版本 -2. 真删除dify本文件 - - -# 知识库创建、更新、删除文件分段 -1. 直接调用dify代理服务实现,不存储到本服务,也不生成新的version版本 - -# 知识库删除 -1. 软删除本服务服务中tb_knowledge的该知识库 -2. 真删除dify知识库 - diff --git a/urbanLifelineServ/ai/pom.xml b/urbanLifelineServ/ai/pom.xml deleted file mode 100644 index 56b025e4..00000000 --- a/urbanLifelineServ/ai/pom.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - ai - 1.0.0 - - - 21 - 21 - - - - org.xyzh.apis - api-ai - ${urban-lifeline.version} - - - org.xyzh.apis - api-system - ${urban-lifeline.version} - - - org.xyzh.apis - api-file - ${urban-lifeline.version} - - - org.xyzh.common - common-redis - - - org.xyzh.common - common-auth - - - org.xyzh.common - common-utils - - - org.xyzh.common - common-jdbc - - - org.xyzh.common - common-exception - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - - - - org.apache.dubbo - dubbo-spring-boot-starter - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - - - ch.qos.logback - logback-classic - - - - - com.baomidou - mybatis-plus-boot-starter - - - com.squareup.okhttp3 - okhttp - - - com.squareup.okhttp3 - okhttp-sse - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - - - - - ai - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/AiApp.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/AiApp.java deleted file mode 100644 index 91f4ff78..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/AiApp.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.xyzh.ai; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@ComponentScan(basePackages = { - "org.xyzh.ai", // 当前ai模块 - "org.xyzh.common" // 公共模块 -}) -public class AiApp { - private static final Logger logger = LoggerFactory.getLogger(AiApp.class); - - public static void main(String[] args) { - logger.info("======================== AI服务启动中 ========================="); - SpringApplication.run(AiApp.class, args); - logger.info("======================== AI服务启动完成 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java deleted file mode 100644 index 2bb53866..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java +++ /dev/null @@ -1,1121 +0,0 @@ -package org.xyzh.ai.client; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; - -import jakarta.annotation.PostConstruct; -import okhttp3.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.xyzh.ai.client.dto.*; -import org.xyzh.ai.client.callback.StreamCallback; -import org.xyzh.ai.config.DifyConfig; -import org.xyzh.ai.exception.DifyException; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * @description Dify API客户端 - 封装所有Dify平台HTTP调用 - * @filename DifyApiClient.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-12-15 - */ -@Component -public class DifyApiClient { - - private static final Logger logger = LoggerFactory.getLogger(DifyApiClient.class); - - @Autowired - private DifyConfig difyConfig; - - private OkHttpClient httpClient; - private OkHttpClient streamHttpClient; - - @PostConstruct - public void init() { - // 普通请求客户端 - this.httpClient = new OkHttpClient.Builder() - .connectTimeout(difyConfig.getConnectTimeout(), TimeUnit.SECONDS) - .readTimeout(difyConfig.getReadTimeout(), TimeUnit.SECONDS) - .writeTimeout(difyConfig.getTimeout(), TimeUnit.SECONDS) - .retryOnConnectionFailure(true) - .build(); - - // 流式请求客户端(更长的读取超时) - this.streamHttpClient = new OkHttpClient.Builder() - .connectTimeout(difyConfig.getConnectTimeout(), TimeUnit.SECONDS) - .readTimeout(difyConfig.getStreamTimeout(), TimeUnit.SECONDS) - .writeTimeout(difyConfig.getTimeout(), TimeUnit.SECONDS) - .retryOnConnectionFailure(false) // 流式不重试 - .build(); - - logger.info("DifyApiClient初始化完成,API地址: {}", difyConfig.getApiBaseUrl()); - } - - // ===================== 知识库管理 API ===================== - - /** - * 创建知识库(Dataset) - */ - public DatasetCreateResponse createDataset(DatasetCreateRequest request) { - String url = difyConfig.getFullApiUrl("/datasets"); - - try { - String jsonBody = JSON.toJSONString(request); - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .header("Content-Type", "application/json") - .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("创建知识库失败: {} - {}", response.code(), responseBody); - throw new DifyException("创建知识库失败: " + responseBody); - } - - return JSON.parseObject(responseBody, DatasetCreateResponse.class); - } - } catch (IOException e) { - logger.error("创建知识库异常", e); - throw new DifyException("创建知识库异常: " + e.getMessage(), e); - } - } - - /** - * 查询知识库列表 - */ - public DatasetListResponse listDatasets(int page, int limit) { - String url = difyConfig.getFullApiUrl("/datasets?page=" + page + "&limit=" + limit); - - try { - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("查询知识库列表失败: {} - {}", response.code(), responseBody); - throw new DifyException("查询知识库列表失败: " + responseBody); - } - - return JSON.parseObject(responseBody, DatasetListResponse.class); - } - } catch (IOException e) { - logger.error("查询知识库列表异常", e); - throw new DifyException("查询知识库列表异常: " + e.getMessage(), e); - } - } - - /** - * 查询知识库详情 - */ - public DatasetDetailResponse getDatasetDetail(String datasetId) { - String url = difyConfig.getFullApiUrl("/datasets/" + datasetId); - - try { - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("查询知识库详情失败: {} - {}", response.code(), responseBody); - throw new DifyException("查询知识库详情失败: " + responseBody); - } - - return JSON.parseObject(responseBody, DatasetDetailResponse.class); - } - } catch (IOException e) { - logger.error("查询知识库详情异常", e); - throw new DifyException("查询知识库详情异常: " + e.getMessage(), e); - } - } - - - /** - * 更新知识库 - */ - public void updateDataset(String datasetId, DatasetUpdateRequest request) { - String url = difyConfig.getFullApiUrl("/datasets/" + datasetId); - - try { - String jsonBody = JSON.toJSONString(request); - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .header("Content-Type", "application/json") - .patch(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - if (!response.isSuccessful()) { - String responseBody = response.body() != null ? response.body().string() : ""; - logger.error("更新知识库失败: {} - {}", response.code(), responseBody); - throw new DifyException("更新知识库失败: " + responseBody); - } - logger.info("知识库更新成功: {}", datasetId); - } - } catch (IOException e) { - logger.error("更新知识库异常", e); - throw new DifyException("更新知识库异常: " + e.getMessage(), e); - } - } - /** - * 删除知识库 - */ - public void deleteDataset(String datasetId) { - String url = difyConfig.getFullApiUrl("/datasets/" + datasetId); - - try { - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .delete() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - if (!response.isSuccessful()) { - String responseBody = response.body() != null ? response.body().string() : ""; - logger.error("删除知识库失败: {} - {}", response.code(), responseBody); - throw new DifyException("删除知识库失败: " + responseBody); - } - logger.info("知识库删除成功: {}", datasetId); - } - } catch (IOException e) { - logger.error("删除知识库异常", e); - throw new DifyException("删除知识库异常: " + e.getMessage(), e); - } - } - - // ===================== 对话文件上传 API ===================== - - /** - * 上传文件用于对话(图文多模态) - * @param file 文件 - * @param originalFilename 原始文件名 - * @param user 用户标识 - * @param apiKey API密钥 - * @return 文件信息(包含id、name、size等) - */ - public DifyFileInfo uploadFileForChat(File file, String originalFilename, String user, String apiKey) { - String url = difyConfig.getFullApiUrl("/files/upload"); - - try { - MultipartBody.Builder bodyBuilder = new MultipartBody.Builder() - .setType(MultipartBody.FORM) - .addFormDataPart("file", originalFilename, - RequestBody.create(file, MediaType.parse("application/octet-stream"))) - .addFormDataPart("user", user); - - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .post(bodyBuilder.build()) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("上传对话文件失败: {} - {}", response.code(), responseBody); - throw new DifyException("上传对话文件失败: " + responseBody); - } - - return JSON.parseObject(responseBody, DifyFileInfo.class); - } - } catch (IOException e) { - logger.error("上传对话文件异常", e); - throw new DifyException("上传对话文件异常: " + e.getMessage(), e); - } - } - - // ===================== 文档管理 API ===================== - - /** - * 上传文档到知识库(通过文件) - * 根据 Dify API 文档: POST /datasets/{dataset_id}/document/create-by-file - */ - public DocumentUploadResponse uploadDocumentByFile( - String datasetId, - File file, - String originalFilename, - DocumentUploadRequest uploadRequest) { - - String url = difyConfig.getFullApiUrl("/datasets/" + datasetId + "/document/create-by-file"); - - try { - // 构建 data JSON 字符串(包含所有元数据) - Map dataMap = new HashMap<>(); - - // name 字段:如果提供则使用,否则使用文件名 - if (uploadRequest.getName() != null && !uploadRequest.getName().trim().isEmpty()) { - dataMap.put("name", uploadRequest.getName()); - } else { - dataMap.put("name", originalFilename); - } - - // indexing_technique 字段:只有在明确提供且非空时才添加 - if (uploadRequest.getIndexingTechnique() != null && !uploadRequest.getIndexingTechnique().trim().isEmpty()) { - dataMap.put("indexing_technique", uploadRequest.getIndexingTechnique()); - } - - // process_rule 是必填字段,如果没有提供则使用默认配置 - if (uploadRequest.getProcessRule() != null) { - dataMap.put("process_rule", uploadRequest.getProcessRule()); - } else { - // 默认分段规则 - Map defaultProcessRule = new HashMap<>(); - defaultProcessRule.put("mode", "automatic"); - dataMap.put("process_rule", defaultProcessRule); - } - - String dataJson = JSON.toJSONString(dataMap); - logger.info("上传文档到知识库: datasetId={}, file={}, data={}", datasetId, originalFilename, dataJson); - - // 构建 multipart/form-data 请求体 - MultipartBody.Builder bodyBuilder = new MultipartBody.Builder() - .setType(MultipartBody.FORM) - .addFormDataPart("file", originalFilename, - RequestBody.create(file, MediaType.parse("application/octet-stream"))) - .addFormDataPart("data", dataJson); - - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .post(bodyBuilder.build()) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("上传文档失败: {} - {}", response.code(), responseBody); - throw new DifyException("上传文档失败: " + responseBody); - } - - logger.info("文档上传成功: datasetId={}, file={}", datasetId, originalFilename); - return JSON.parseObject(responseBody, DocumentUploadResponse.class); - } - } catch (IOException e) { - logger.error("上传文档异常", e); - throw new DifyException("上传文档异常: " + e.getMessage(), e); - } - } - - /** - * 查询文档处理状态 - */ - public DocumentStatusResponse getDocumentStatus(String datasetId, String batchId) { - String url = difyConfig.getFullApiUrl("/datasets/" + datasetId + "/documents/" + batchId + "/indexing-status"); - - try { - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("查询文档状态失败: {} - {}", response.code(), responseBody); - throw new DifyException("查询文档状态失败: " + responseBody); - } - - return JSON.parseObject(responseBody, DocumentStatusResponse.class); - } - } catch (IOException e) { - logger.error("查询文档状态异常", e); - throw new DifyException("查询文档状态异常: " + e.getMessage(), e); - } - } - - /** - * 查询知识库文档列表 - */ - public DocumentListResponse listDocuments(String datasetId, int page, int limit) { - String url = difyConfig.getFullApiUrl("/datasets/" + datasetId + "/documents?page=" + page + "&limit=" + limit); - - try { - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("查询文档列表失败: {} - {}", response.code(), responseBody); - throw new DifyException("查询文档列表失败: " + responseBody); - } - - return JSON.parseObject(responseBody, DocumentListResponse.class); - } - } catch (IOException e) { - logger.error("查询文档列表异常", e); - throw new DifyException("查询文档列表异常: " + e.getMessage(), e); - } - } - - /** - * 删除文档 - */ - public void deleteDocument(String datasetId, String documentId) { - String url = difyConfig.getFullApiUrl("/datasets/" + datasetId + "/documents/" + documentId); - - try { - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .delete() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - if (!response.isSuccessful()) { - String responseBody = response.body() != null ? response.body().string() : ""; - logger.error("删除文档失败: {} - {}", response.code(), responseBody); - throw new DifyException("删除文档失败: " + responseBody); - } - logger.info("文档删除成功: {}", documentId); - } - } catch (IOException e) { - logger.error("删除文档异常", e); - throw new DifyException("删除文档异常: " + e.getMessage(), e); - } - } - - // ===================== 知识库检索 API ===================== - - /** - * 从知识库检索相关内容 - */ - public RetrievalResponse retrieveFromDataset(String datasetId, RetrievalRequest request) { - String url = difyConfig.getFullApiUrl("/datasets/" + datasetId + "/retrieve"); - - try { - String jsonBody = JSON.toJSONString(request); - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .header("Content-Type", "application/json") - .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("知识库检索失败: {} - {}", response.code(), responseBody); - throw new DifyException("知识库检索失败: " + responseBody); - } - - return JSON.parseObject(responseBody, RetrievalResponse.class); - } - } catch (IOException e) { - logger.error("知识库检索异常", e); - throw new DifyException("知识库检索异常: " + e.getMessage(), e); - } - } - - // ===================== 对话 API ===================== - - /** - * 流式对话(SSE) - */ - public void streamChat(ChatRequest request, String apiKey, StreamCallback callback) { - String url = difyConfig.getFullApiUrl("/chat-messages"); - - try { - // 设置为流式模式 - request.setResponseMode("streaming"); - - String jsonBody = JSON.toJSONString(request); - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .header("Content-Type", "application/json") - .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - streamHttpClient.newCall(httpRequest).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) throws IOException { - if (!response.isSuccessful()) { - String errorBody = response.body() != null ? response.body().string() : ""; - callback.onError(new DifyException("流式对话失败: " + errorBody)); - return; - } - - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(response.body().byteStream()))) { - - String line; - while ((line = reader.readLine()) != null) { - if (line.startsWith("data: ")) { - String data = line.substring(6).trim(); - - if ("[DONE]".equals(data)) { - callback.onComplete(); - break; - } - - if (!data.isEmpty()) { - // 解析SSE数据 - JSONObject jsonNode = JSON.parseObject(data); - String event = jsonNode.containsKey("event") ? jsonNode.getString("event") : ""; - - // 转发事件给回调(用于前端SSE转发) - callback.onEvent(event, data); - - switch (event) { - case "message": - case "agent_message": - // 消息内容 - if (jsonNode.containsKey("answer")) { - callback.onMessage(jsonNode.getString("answer")); - } - break; - case "message_end": - // 消息结束,提取元数据 - callback.onMessageEnd(data); - break; - case "error": - // 错误事件 - String errorMsg = jsonNode.containsKey("message") ? - jsonNode.getString("message") : "未知错误"; - callback.onError(new DifyException(errorMsg)); - return; - // 其他事件(workflow_started、node_started、node_finished等) - // 已通过onEvent转发,这里不需要额外处理 - } - } - } - } - // 流正常读取完毕,如果没有收到 [DONE] 标记,也当作完成 - logger.info("SSE流读取完毕"); - callback.onComplete(); - } catch (java.io.EOFException e) { - // EOFException 通常表示流正常结束(Dify可能没有发送[DONE]标记) - logger.info("SSE流已结束(EOF)"); - callback.onComplete(); - } catch (Exception e) { - logger.error("流式响应处理异常", e); - callback.onError(e); - } - } - - @Override - public void onFailure(Call call, IOException e) { - logger.error("流式对话请求失败", e); - callback.onError(e); - } - }); - - } catch (Exception e) { - logger.error("流式对话异常", e); - callback.onError(e); - } - } - - /** - * 阻塞式对话(非流式) - */ - public ChatResponse blockingChat(ChatRequest request, String apiKey) { - String url = difyConfig.getFullApiUrl("/chat-messages"); - - try { - // 设置为阻塞模式 - request.setResponseMode("blocking"); - - String jsonBody = JSON.toJSONString(request); - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .header("Content-Type", "application/json") - .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("阻塞式对话失败: {} - {}", response.code(), responseBody); - throw new DifyException("阻塞式对话失败: " + responseBody); - } - - return JSON.parseObject(responseBody, ChatResponse.class); - } - } catch (IOException e) { - logger.error("阻塞式对话异常", e); - throw new DifyException("阻塞式对话异常: " + e.getMessage(), e); - } - } - - // ===================== 工作流 API ===================== - - /** - * 执行工作流(阻塞模式) - */ - public WorkflowRunResponse runWorkflowBlocking(WorkflowRunRequest request, String apiKey) { - String url = difyConfig.getFullApiUrl("/workflows/run"); - - try { - // 设置为阻塞模式 - request.setResponseMode("blocking"); - - String jsonBody = JSON.toJSONString(request); - logger.info("调用Dify工作流接口: url={}, request={}", url, jsonBody); - - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .header("Content-Type", "application/json") - .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("工作流执行失败: {} - {}", response.code(), responseBody); - throw new DifyException("工作流执行失败: " + responseBody); - } - - logger.info("工作流执行成功: {}", responseBody); - return JSON.parseObject(responseBody, WorkflowRunResponse.class); - } - } catch (IOException e) { - logger.error("工作流执行异常", e); - throw new DifyException("工作流执行异常: " + e.getMessage(), e); - } - } - - /** - * 停止对话生成 - */ - public void stopChatMessage(String taskId, String userId, String apiKey) { - String url = difyConfig.getFullApiUrl("/chat-messages/" + taskId + "/stop"); - - try { - String jsonBody = JSON.toJSONString(new StopRequest(userId)); - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .header("Content-Type", "application/json") - .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - if (!response.isSuccessful()) { - String responseBody = response.body() != null ? response.body().string() : ""; - logger.error("停止对话失败: {} - {}", response.code(), responseBody); - throw new DifyException("停止对话失败: " + responseBody); - } - logger.info("对话停止成功: {}", taskId); - } - } catch (IOException e) { - logger.error("停止对话异常", e); - throw new DifyException("停止对话异常: " + e.getMessage(), e); - } - } - - /** - * 提交消息反馈 - * @param messageId Dify消息ID - * @param rating 评分(like/dislike/null) - * @param userId 用户ID - * @param apiKey API密钥 - */ - public void submitMessageFeedback(String messageId, String rating, String userId, String feedback, String apiKey) { - String url = difyConfig.getFullApiUrl("/messages/" + messageId + "/feedbacks"); - - try { - FeedbackRequest feedbackRequest = new FeedbackRequest(rating, userId, feedback); - String jsonBody = JSON.toJSONString(feedbackRequest); - - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .header("Content-Type", "application/json") - .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("提交消息反馈失败: {} - {}", response.code(), responseBody); - throw new DifyException("提交消息反馈失败: " + responseBody); - } - if (responseBody!="success") { - logger.error("提交消息反馈失败: {} - {}", response.code(), responseBody); - throw new DifyException("提交消息反馈失败: " + responseBody); - } - logger.info("消息反馈提交成功: {} - {}", messageId, rating); - } - } catch (IOException e) { - logger.error("提交消息反馈异常", e); - throw new DifyException("提交消息反馈异常: " + e.getMessage(), e); - } - } - - // ===================== 对话历史 API ===================== - - /** - * 获取对话历史消息 - */ - public MessageHistoryResponse getMessageHistory( - String conversationId, - String userId, - String firstId, - Integer limit, - String apiKey) { - - StringBuilder urlBuilder = new StringBuilder(difyConfig.getFullApiUrl("/messages")); - urlBuilder.append("?user=").append(userId); - - if (conversationId != null && !conversationId.isEmpty()) { - urlBuilder.append("&conversation_id=").append(conversationId); - } - if (firstId != null && !firstId.isEmpty()) { - urlBuilder.append("&first_id=").append(firstId); - } - if (limit != null) { - urlBuilder.append("&limit=").append(limit); - } - - try { - Request httpRequest = new Request.Builder() - .url(urlBuilder.toString()) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("获取对话历史失败: {} - {}", response.code(), responseBody); - throw new DifyException("获取对话历史失败: " + responseBody); - } - - return JSON.parseObject(responseBody, MessageHistoryResponse.class); - } - } catch (IOException e) { - logger.error("获取对话历史异常", e); - throw new DifyException("获取对话历史异常: " + e.getMessage(), e); - } - } - - /** - * 获取对话列表 - */ - public ConversationListResponse getConversations( - String userId, - String lastId, - Integer limit, - String apiKey) { - - StringBuilder urlBuilder = new StringBuilder(difyConfig.getFullApiUrl("/conversations")); - urlBuilder.append("?user=").append(userId); - - if (lastId != null && !lastId.isEmpty()) { - urlBuilder.append("&last_id=").append(lastId); - } - if (limit != null) { - urlBuilder.append("&limit=").append(limit); - } - - try { - Request httpRequest = new Request.Builder() - .url(urlBuilder.toString()) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("获取对话列表失败: {} - {}", response.code(), responseBody); - throw new DifyException("获取对话列表失败: " + responseBody); - } - - return JSON.parseObject(responseBody, ConversationListResponse.class); - } - } catch (IOException e) { - logger.error("获取对话列表异常", e); - throw new DifyException("获取对话列表异常: " + e.getMessage(), e); - } - } - - /** - * 获取对话变量 - * @param conversationId 会话ID - * @param userId 用户标识 - * @param lastId 当前页最后面一条记录的ID,默认null - * @param limit 一次请求返回多少条记录,默认20条,最大100条,最小1条 - * @param apiKey API密钥 - * @return 对话变量响应 - */ - public ConversationVariablesResponse getConversationVariables( - String conversationId, - String userId, - String lastId, - Integer limit, - String apiKey) { - - StringBuilder urlBuilder = new StringBuilder( - difyConfig.getFullApiUrl("/conversations/" + conversationId + "/variables")); - urlBuilder.append("?user=").append(userId); - - if (lastId != null && !lastId.isEmpty()) { - urlBuilder.append("&last_id=").append(lastId); - } - if (limit != null) { - urlBuilder.append("&limit=").append(limit); - } - - try { - Request httpRequest = new Request.Builder() - .url(urlBuilder.toString()) - .header("Authorization", "Bearer " + getApiKey(apiKey)) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("获取对话变量失败: {} - {}", response.code(), responseBody); - throw new DifyException("获取对话变量失败: " + responseBody); - } - - return JSON.parseObject(responseBody, ConversationVariablesResponse.class); - } - } catch (IOException e) { - logger.error("获取对话变量异常", e); - throw new DifyException("获取对话变量异常: " + e.getMessage(), e); - } - } - - // ===================== 通用 HTTP 方法(用于代理转发)===================== - - /** - * 通用 GET 请求 - * @param path API路径 - * @param apiKey API密钥(为null时使用知识库API Key) - * @return JSON响应字符串 - */ - public String get(String path, String apiKey) { - String url = difyConfig.getFullApiUrl(path); - - try { - // 如果apiKey为null,使用知识库API Key(因为通用方法主要用于知识库相关操作) - String actualApiKey = apiKey != null ? apiKey : getKnowledgeApiKey(); - - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + actualApiKey) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("GET请求失败: {} - {} - {}", url, response.code(), responseBody); - throw new DifyException("GET请求失败[" + response.code() + "]: " + responseBody); - } - - return responseBody; - } - } catch (IOException e) { - logger.error("GET请求异常: {}", url, e); - throw new DifyException("GET请求异常: " + e.getMessage(), e); - } - } - - /** - * 通用 POST 请求 - * @param path API路径 - * @param requestBody 请求体(JSON字符串或Map) - * @param apiKey API密钥(为null时使用知识库API Key) - * @return JSON响应字符串 - */ - public String post(String path, Object requestBody, String apiKey) { - String url = difyConfig.getFullApiUrl(path); - - try { - // 如果apiKey为null,使用知识库API Key - String actualApiKey = apiKey != null ? apiKey : getKnowledgeApiKey(); - - String jsonBody = requestBody instanceof String ? - (String) requestBody : JSON.toJSONString(requestBody); - - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + actualApiKey) - .header("Content-Type", "application/json") - .post(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("POST请求失败: {} - {} - {}", url, response.code(), responseBody); - throw new DifyException("POST请求失败[" + response.code() + "]: " + responseBody); - } - - return responseBody; - } - } catch (IOException e) { - logger.error("POST请求异常: {}", url, e); - throw new DifyException("POST请求异常: " + e.getMessage(), e); - } - } - - /** - * 通用 PATCH 请求 - * @param path API路径 - * @param requestBody 请求体(JSON字符串或Map) - * @param apiKey API密钥(为null时使用知识库API Key) - * @return JSON响应字符串 - */ - public String patch(String path, Object requestBody, String apiKey) { - String url = difyConfig.getFullApiUrl(path); - - try { - // 如果apiKey为null,使用知识库API Key - String actualApiKey = apiKey != null ? apiKey : getKnowledgeApiKey(); - - String jsonBody = requestBody instanceof String ? - (String) requestBody : JSON.toJSONString(requestBody); - - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + actualApiKey) - .header("Content-Type", "application/json") - .patch(RequestBody.create(jsonBody, MediaType.parse("application/json"))) - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("PATCH请求失败: {} - {} - {}", url, response.code(), responseBody); - throw new DifyException("PATCH请求失败[" + response.code() + "]: " + responseBody); - } - - return responseBody; - } - } catch (IOException e) { - logger.error("PATCH请求异常: {}", url, e); - throw new DifyException("PATCH请求异常: " + e.getMessage(), e); - } - } - - /** - * 通用 DELETE 请求 - * @param path API路径 - * @param apiKey API密钥(为null时使用知识库API Key) - * @return JSON响应字符串 - */ - public String delete(String path, String apiKey) { - String url = difyConfig.getFullApiUrl(path); - - try { - // 如果apiKey为null,使用知识库API Key - String actualApiKey = apiKey != null ? apiKey : getKnowledgeApiKey(); - - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + actualApiKey) - .delete() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("DELETE请求失败: {} - {} - {}", url, response.code(), responseBody); - throw new DifyException("DELETE请求失败[" + response.code() + "]: " + responseBody); - } - - return responseBody; - } - } catch (IOException e) { - logger.error("DELETE请求异常: {}", url, e); - throw new DifyException("DELETE请求异常: " + e.getMessage(), e); - } - } - - // ===================== 工具方法 ===================== - - /** - * 获取API密钥(优先使用传入的密钥,否则使用配置的默认密钥) - * 用于智能体相关的API - */ - private String getApiKey(String apiKey) { - if (apiKey != null && !apiKey.trim().isEmpty()) { - return apiKey; - } - throw new DifyException("未配置Dify API密钥"); - } - - /** - * 获取知识库API密钥(统一使用配置中的knowledgeApiKey) - * 用于知识库相关的API - */ - private String getKnowledgeApiKey() { - if (difyConfig.getKnowledgeApiKey() != null && !difyConfig.getKnowledgeApiKey().trim().isEmpty()) { - return difyConfig.getKnowledgeApiKey(); - } - throw new DifyException("未配置Dify知识库API密钥"); - } - - /** - * 停止请求的内部类 - */ - private static class StopRequest { - private String user; - - public StopRequest(String user) { - this.user = user; - } - - public String getUser() { - return user; - } - - public void setUser(String user) { - this.user = user; - } - } - - /** - * 反馈请求的内部类 - */ - private static class FeedbackRequest { - private String rating; - private String user; - - private String feedback; - - public FeedbackRequest(String rating, String user, String feedback) { - this.rating = rating; - this.user = user; - this.feedback = feedback; - } - - public String getRating() { - return rating; - } - - public void setRating(String rating) { - this.rating = rating; - } - - public String getUser() { - return user; - } - - public void setUser(String user) { - this.user = user; - } - - public String getFeedback() { - return feedback; - } - - public void setFeedback(String feedback) { - this.feedback = feedback; - } - } - - // ===================== 模型管理 API ===================== - - /** - * 获取可用的嵌入模型列表 - */ - public EmbeddingModelResponse getAvailableEmbeddingModels() { - String url = difyConfig.getFullApiUrl("/workspaces/current/models/model-types/text-embedding"); - - try { - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("获取嵌入模型列表失败: {} - {}", response.code(), responseBody); - throw new DifyException("获取嵌入模型列表失败: " + responseBody); - } - - return JSON.parseObject(responseBody, EmbeddingModelResponse.class); - } - } catch (IOException e) { - logger.error("获取嵌入模型列表异常", e); - throw new DifyException("获取嵌入模型列表异常: " + e.getMessage(), e); - } - } - - /** - * 获取可用的Rerank模型列表 - */ - public RerankModelResponse getAvailableRerankModels() { - String url = difyConfig.getFullApiUrl("/workspaces/current/models/model-types/rerank"); - - try { - Request httpRequest = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + getKnowledgeApiKey()) - .get() - .build(); - - try (Response response = httpClient.newCall(httpRequest).execute()) { - String responseBody = response.body() != null ? response.body().string() : ""; - - if (!response.isSuccessful()) { - logger.error("获取Rerank模型列表失败: {} - {}", response.code(), responseBody); - throw new DifyException("获取Rerank模型列表失败: " + responseBody); - } - - return JSON.parseObject(responseBody, RerankModelResponse.class); - } - } catch (IOException e) { - logger.error("获取Rerank模型列表异常", e); - throw new DifyException("获取Rerank模型列表异常: " + e.getMessage(), e); - } - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/callback/StreamCallback.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/callback/StreamCallback.java deleted file mode 100644 index f2c47744..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/callback/StreamCallback.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.xyzh.ai.client.callback; - -/** - * @description 流式响应回调接口 - * @filename StreamCallback.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -public interface StreamCallback { - - /** - * 接收到消息片段 - * @param message 消息内容 - */ - void onMessage(String message); - - /** - * 消息结束(包含元数据) - * @param metadata JSON格式的元数据 - */ - void onMessageEnd(String metadata); - - /** - * 接收到Dify原始事件(用于转发完整事件数据) - * @param eventType 事件类型(如workflow_started、node_started等) - * @param eventData 完整的事件JSON数据 - */ - default void onEvent(String eventType, String eventData) { - // 默认实现:不处理 - } - - /** - * 流式响应完成 - */ - void onComplete(); - - /** - * 发生错误 - * @param error 错误对象 - */ - void onError(Throwable error); -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ChatRequest.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ChatRequest.java deleted file mode 100644 index 260415fe..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ChatRequest.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; -import java.util.List; -import java.util.Map; -import org.xyzh.api.ai.dto.DifyFileInfo; - -/** - * @description 对话请求 - * @filename ChatRequest.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-12-15 - */ -@Data -public class ChatRequest { - - /** - * 输入变量(Dify API 必需字段) - */ - @JSONField(serializeFeatures = com.alibaba.fastjson2.JSONWriter.Feature.WriteMapNullValue) - private Map inputs = new java.util.HashMap<>(); - - /** - * 用户问题 - */ - private String query; - - /** - * 响应模式:streaming(流式)、blocking(阻塞) - */ - @JSONField(name = "response_mode") - private String responseMode = "streaming"; - - /** - * 对话ID(继续对话时传入) - */ - @JSONField(name = "conversation_id") - private String conversationId; - - /** - * 用户标识 - */ - private String user; - - /** - * 上传的文件列表 - */ - private List files; - - /** - * 自动生成标题 - */ - @JSONField(name = "auto_generate_name") - private Boolean autoGenerateName = true; - - /** - * 指定的数据集ID列表(知识库检索) - */ - @JSONField(name = "dataset_ids") - private List datasetIds; - - /** - * 温度参数(0.0-1.0) - */ - private Double temperature; - - /** - * 最大token数 - */ - @JSONField(name = "max_tokens") - private Integer maxTokens; - -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ChatResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ChatResponse.java deleted file mode 100644 index 8b166668..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ChatResponse.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; -import java.util.List; -import java.util.Map; - -/** - * @description 对话响应(阻塞模式) - * @filename ChatResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class ChatResponse { - - /** - * 消息ID - */ - @JSONField(name = "message_id") - private String messageId; - - /** - * 对话ID - */ - @JSONField(name = "conversation_id") - private String conversationId; - - /** - * 模式 - */ - private String mode; - - /** - * 回答内容 - */ - private String answer; - - /** - * 元数据 - */ - private Map metadata; - - /** - * 创建时间 - */ - @JSONField(name = "created_at") - private Long createdAt; - - /** - * Token使用情况 - */ - private Usage usage; - - /** - * 检索信息 - */ - @JSONField(name = "retrieval_info") - private List retrievalInfo; - - @Data - public static class Usage { - @JSONField(name = "prompt_tokens") - private Integer promptTokens; - - @JSONField(name = "prompt_unit_price") - private String promptUnitPrice; - - @JSONField(name = "prompt_price_unit") - private String promptPriceUnit; - - @JSONField(name = "prompt_price") - private String promptPrice; - - @JSONField(name = "completion_tokens") - private Integer completionTokens; - - @JSONField(name = "completion_unit_price") - private String completionUnitPrice; - - @JSONField(name = "completion_price_unit") - private String completionPriceUnit; - - @JSONField(name = "completion_price") - private String completionPrice; - - @JSONField(name = "total_tokens") - private Integer totalTokens; - - @JSONField(name = "total_price") - private String totalPrice; - - private String currency; - - private Double latency; - } - - @Data - public static class RetrievalInfo { - @JSONField(name = "dataset_id") - private String datasetId; - - @JSONField(name = "dataset_name") - private String datasetName; - - @JSONField(name = "document_id") - private String documentId; - - @JSONField(name = "document_name") - private String documentName; - - @JSONField(name = "segment_id") - private String segmentId; - - private Double score; - - private String content; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ConversationListResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ConversationListResponse.java deleted file mode 100644 index f177cfd7..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ConversationListResponse.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.xyzh.ai.client.dto; - -import lombok.Data; -import java.util.List; - -import com.alibaba.fastjson2.annotation.JSONField; - -/** - * @description 对话列表响应 - * @filename ConversationListResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class ConversationListResponse { - - private Integer limit; - - @JSONField(name = "has_more") - private Boolean hasMore; - - private List data; - - @Data - public static class ConversationInfo { - private String id; - - private String name; - - private List inputs; - - private String status; - - private String introduction; - - @JSONField(name = "created_at") - private Long createdAt; - - @JSONField(name = "updated_at") - private Long updatedAt; - } - - @Data - public static class InputInfo { - private String key; - private String value; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ConversationVariablesResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ConversationVariablesResponse.java deleted file mode 100644 index 292a8018..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/ConversationVariablesResponse.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -import java.util.List; - -/** - * @description 对话变量响应 - * @filename ConversationVariablesResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-12-29 - */ -@Data -public class ConversationVariablesResponse { - - private Integer limit; - - @JSONField(name = "has_more") - private Boolean hasMore; - - private List data; - - /** - * 对话中的变量项 - */ - @Data - public static class ConversationVariableItem { - - /** - * 变量ID - */ - private String id; - - /** - * 变量名称 - */ - private String name; - - /** - * 变量类型 (string, number, boolean 等) - */ - @JSONField(name = "value_type") - private String valueType; - - /** - * 变量值 - */ - private String value; - - /** - * 变量描述 - */ - private String description; - - /** - * 创建时间戳 - */ - @JSONField(name = "created_at") - private Long createdAt; - - /** - * 最后更新时间戳 - */ - @JSONField(name = "updated_at") - private Long updatedAt; - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetCreateRequest.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetCreateRequest.java deleted file mode 100644 index c408cbf3..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetCreateRequest.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description 创建知识库请求 - * @filename DatasetCreateRequest.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class DatasetCreateRequest { - - /** - * 知识库名称 - */ - private String name; - - /** - * 知识库描述 - */ - private String description; - - /** - * 索引方式:high_quality(高质量)、economy(经济) - */ - @JSONField(name = "indexing_technique") - private String indexingTechnique = "high_quality"; - - /** - * Embedding模型 - */ - @JSONField(name = "embedding_model") - private String embeddingModel; - - /** - * Embedding模型提供商 - */ - @JSONField(name = "embedding_model_provider") - private String embeddingModelProvider; - - /** - * 检索模型配置(包含 Rerank、Top K、Score 阈值等) - */ - @JSONField(name = "retrieval_model") - private RetrievalModel retrievalModel; - - /** - * 权限:only_me(仅自己)、all_team_members(团队所有成员) - */ - private String permission = "only_me"; -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetCreateResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetCreateResponse.java deleted file mode 100644 index 8f3b3f40..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetCreateResponse.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description 创建知识库响应 - * @filename DatasetCreateResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class DatasetCreateResponse { - - /** - * 知识库ID - */ - private String id; - - /** - * 知识库名称 - */ - private String name; - - /** - * 描述 - */ - private String description; - - /** - * 索引方式 - */ - @JSONField(name = "indexing_technique") - private String indexingTechnique; - - /** - * Embedding模型 - */ - @JSONField(name = "embedding_model") - private String embeddingModel; - - /** - * 创建时间 - */ - @JSONField(name = "created_at") - private Long createdAt; - - /** - * 创建人 - */ - @JSONField(name = "created_by") - private String createdBy; -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetDetailResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetDetailResponse.java deleted file mode 100644 index 33c2f947..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetDetailResponse.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description 知识库详情响应 - * @filename DatasetDetailResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class DatasetDetailResponse { - - private String id; - - private String name; - - private String description; - - @JSONField(name = "indexing_technique") - private String indexingTechnique; - - @JSONField(name = "embedding_model") - private String embeddingModel; - - @JSONField(name = "embedding_model_provider") - private String embeddingModelProvider; - - @JSONField(name = "embedding_available") - private Boolean embeddingAvailable; - - @JSONField(name = "retrieval_model_dict") - private RetrievalModelDict retrievalModelDict; - - @JSONField(name = "document_count") - private Integer documentCount; - - @JSONField(name = "word_count") - private Integer wordCount; - - @JSONField(name = "app_count") - private Integer appCount; - - @JSONField(name = "created_by") - private String createdBy; - - @JSONField(name = "created_at") - private Long createdAt; - - @JSONField(name = "updated_at") - private Long updatedAt; - - @Data - public static class RetrievalModelDict { - @JSONField(name = "search_method") - private String searchMethod; - - @JSONField(name = "reranking_enable") - private Boolean rerankingEnable; - - @JSONField(name = "reranking_model") - private RerankingModel rerankingModel; - - @JSONField(name = "top_k") - private Integer topK; - - @JSONField(name = "score_threshold_enabled") - private Boolean scoreThresholdEnabled; - } - - @Data - public static class RerankingModel { - @JSONField(name = "reranking_provider_name") - private String rerankingProviderName; - - @JSONField(name = "reranking_model_name") - private String rerankingModelName; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetListResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetListResponse.java deleted file mode 100644 index 6ef4f821..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetListResponse.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; -import java.util.List; - -/** - * @description 知识库列表响应 - * @filename DatasetListResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class DatasetListResponse { - - /** - * 知识库列表 - */ - private List data; - - /** - * 是否有更多 - */ - @JSONField(name = "has_more") - private Boolean hasMore; - - /** - * 分页限制 - */ - private Integer limit; - - /** - * 总数 - */ - private Integer total; - - /** - * 当前页 - */ - private Integer page; - - @Data - public static class DatasetInfo { - private String id; - private String name; - private String description; - private String permission; - @JSONField(name = "document_count") - private Integer documentCount; - @JSONField(name = "word_count") - private Integer wordCount; - @JSONField(name = "created_by") - private String createdBy; - @JSONField(name = "created_at") - private Long createdAt; - @JSONField(name = "updated_at") - private Long updatedAt; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetUpdateRequest.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetUpdateRequest.java deleted file mode 100644 index cd639539..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DatasetUpdateRequest.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description Dify知识库更新请求 - * @filename DatasetUpdateRequest.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class DatasetUpdateRequest { - - /** - * 知识库名称 - */ - private String name; - - /** - * 知识库描述 - */ - private String description; - - /** - * 索引方式(high_quality/economy) - */ - @JSONField(name = "indexing_technique") - private String indexingTechnique; - - /** - * Embedding模型 - */ - @JSONField(name = "embedding_model") - private String embeddingModel; - - /** - * Embedding模型提供商 - */ - @JSONField(name = "embedding_model_provider") - private String embeddingModelProvider; - - /** - * 检索模型配置(包含 Rerank、Top K、Score 阈值等) - */ - @JSONField(name = "retrieval_model") - private RetrievalModel retrievalModel; -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DifyFileInfo.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DifyFileInfo.java deleted file mode 100644 index 956232c2..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DifyFileInfo.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; - -import lombok.Data; - -/** - * Dify文件上传响应DTO - * 对应 Dify API /files/upload 的响应结构 - */ -@Data -public class DifyFileInfo { - - /** - * 文件ID(Dify返回) - */ - private String id; - - /** - * 文件名 - */ - private String name; - - /** - * 文件大小(字节) - */ - private Integer size; - - /** - * 文件扩展名 - */ - private String extension; - - /** - * 文件MIME类型 - */ - @JSONField(name="mime_type") - private String mimeType; - - /** - * 上传人ID - */ - @JSONField(name="created_by") - private String createdBy; - - /** - * 上传时间(时间戳) - */ - @JSONField(name="created_at") - private Long createdAt; - - /** - * 预览URL - */ - @JSONField(name="preview_url") - private String previewUrl; - - /** - * 源文件URL - */ - @JSONField(name="source_url") - private String sourceUrl; - - /** - * 文件类型:image、document、audio、video、file - */ - private String type; - - /** - * 传输方式:remote_url、local_file - */ - @JSONField(name="transfer_method") - private String transferMethod; - - /** - * 文件URL或ID - */ - private String url; - - /** - * 本地文件上传ID - */ - @JSONField(name="upload_file_id") - private String uploadFileId; - - /** - * 系统文件ID - */ - @JSONField(name="sys_file_id") - private String sysFileId; - - /** - * 文件路径(从系统文件表获取) - */ - @JSONField(name="file_path") - private String filePath; -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentListResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentListResponse.java deleted file mode 100644 index cb4c9c5a..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentListResponse.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -import java.util.List; - -/** - * @description Dify文档列表响应 - * @filename DocumentListResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-07 - */ -@Data -public class DocumentListResponse { - - private List data; - - @JSONField(name = "has_more") - private Boolean hasMore; - - private Integer limit; - - private Integer total; - - private Integer page; - - /** - * 文档信息 - */ - @Data - public static class Document { - private String id; - - private Integer position; - - @JSONField(name = "data_source_type") - private String dataSourceType; - - @JSONField(name = "data_source_info") - private DataSourceInfo dataSourceInfo; - - @JSONField(name = "dataset_process_rule_id") - private String datasetProcessRuleId; - - private String name; - - @JSONField(name = "created_from") - private String createdFrom; - - @JSONField(name = "created_by") - private String createdBy; - - @JSONField(name = "created_at") - private Long createdAt; - - private Integer tokens; - - @JSONField(name = "indexing_status") - private String indexingStatus; - - private String error; - - private Boolean enabled; - - @JSONField(name = "disabled_at") - private Long disabledAt; - - @JSONField(name = "disabled_by") - private String disabledBy; - - private Boolean archived; - - @JSONField(name = "display_status") - private String displayStatus; - - @JSONField(name = "word_count") - private Integer wordCount; - - @JSONField(name = "hit_count") - private Integer hitCount; - - @JSONField(name = "doc_form") - private String docForm; - } - - /** - * 数据源信息 - */ - @Data - public static class DataSourceInfo { - @JSONField(name = "upload_file_id") - private String uploadFileId; - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentStatusResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentStatusResponse.java deleted file mode 100644 index fa8ac9c2..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentStatusResponse.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; -import java.util.List; - -/** - * @description 文档处理状态响应 - * @filename DocumentStatusResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class DocumentStatusResponse { - - /** - * 文档列表 - */ - private List data; - - @Data - public static class DocumentStatus { - /** - * 文档ID - */ - private String id; - - /** - * 索引状态:waiting、parsing、cleaning、splitting、indexing、completed、error - */ - @JSONField(name = "indexing_status") - private String indexingStatus; - - /** - * 处理开始时间 - */ - @JSONField(name = "processing_started_at") - private Long processingStartedAt; - - /** - * 解析完成时间 - */ - @JSONField(name = "parsing_completed_at") - private Long parsingCompletedAt; - - /** - * 清洗完成时间 - */ - @JSONField(name = "cleaning_completed_at") - private Long cleaningCompletedAt; - - /** - * 分割完成时间 - */ - @JSONField(name = "splitting_completed_at") - private Long splittingCompletedAt; - - /** - * 完成时间 - */ - @JSONField(name = "completed_at") - private Long completedAt; - - /** - * 暂停时间 - */ - @JSONField(name = "paused_at") - private Long pausedAt; - - /** - * 错误信息 - */ - private String error; - - /** - * 停止时间 - */ - @JSONField(name = "stopped_at") - private Long stoppedAt; - - /** - * 分段数量 - */ - @JSONField(name = "completed_segments") - private Integer completedSegments; - - /** - * 总分段数 - */ - @JSONField(name = "total_segments") - private Integer totalSegments; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentUploadRequest.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentUploadRequest.java deleted file mode 100644 index aca27ee9..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentUploadRequest.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description 文档上传请求 - * @filename DocumentUploadRequest.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class DocumentUploadRequest { - - /** - * 文档名称 - */ - private String name; - - /** - * 索引方式 - */ - @JSONField(name = "indexing_technique") - private String indexingTechnique; - - /** - * 处理规则 - */ - @JSONField(name = "process_rule") - private ProcessRule processRule; - - @Data - public static class ProcessRule { - /** - * 分段模式:automatic(自动)、custom(自定义) - */ - private String mode = "automatic"; - - /** - * 预处理规则 - */ - private Rules rules; - - @Data - public static class Rules { - /** - * 自动分段配置 - */ - @JSONField(name = "pre_processing_rules") - private PreProcessingRules preProcessingRules; - - /** - * 分段配置 - */ - private Segmentation segmentation; - } - - @Data - public static class PreProcessingRules { - /** - * 移除额外空格 - */ - @JSONField(name = "remove_extra_spaces") - private Boolean removeExtraSpaces = true; - - /** - * 移除URL和邮箱 - */ - @JSONField(name = "remove_urls_emails") - private Boolean removeUrlsEmails = false; - } - - @Data - public static class Segmentation { - /** - * 分隔符 - */ - private String separator = "\\n"; - - /** - * 最大分段长度 - */ - @JSONField(name = "max_tokens") - private Integer maxTokens = 1000; - - /** - * 分段重叠长度 - */ - @JSONField(name = "chunk_overlap") - private Integer chunkOverlap = 50; - } - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentUploadResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentUploadResponse.java deleted file mode 100644 index b46e4bc4..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/DocumentUploadResponse.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description 文档上传响应(根据 Dify API 返回结构) - * @filename DocumentUploadResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class DocumentUploadResponse { - - /** - * 文档详细信息 - */ - private Document document; - - /** - * 批次ID(用于查询处理状态) - */ - private String batch; - - /** - * 文档详细信息 - */ - @Data - public static class Document { - /** - * 文档ID - */ - private String id; - - /** - * 文档名称 - */ - private String name; - - /** - * 位置(序号) - */ - private Integer position; - - /** - * 数据源类型 - */ - @JSONField(name = "data_source_type") - private String dataSourceType; - - /** - * 数据源信息 - */ - @JSONField(name = "data_source_info") - private Object dataSourceInfo; - - /** - * 数据集处理规则ID - */ - @JSONField(name = "dataset_process_rule_id") - private String datasetProcessRuleId; - - /** - * 创建来源 - */ - @JSONField(name = "created_from") - private String createdFrom; - - /** - * 创建人 - */ - @JSONField(name = "created_by") - private String createdBy; - - /** - * 创建时间(时间戳) - */ - @JSONField(name = "created_at") - private Long createdAt; - - /** - * Token数量 - */ - private Integer tokens; - - /** - * 索引状态 - */ - @JSONField(name = "indexing_status") - private String indexingStatus; - - /** - * 错误信息 - */ - private String error; - - /** - * 是否启用 - */ - private Boolean enabled; - - /** - * 禁用时间 - */ - @JSONField(name = "disabled_at") - private Long disabledAt; - - /** - * 禁用人 - */ - @JSONField(name = "disabled_by") - private String disabledBy; - - /** - * 是否归档 - */ - private Boolean archived; - - /** - * 显示状态 - */ - @JSONField(name = "display_status") - private String displayStatus; - - /** - * 字数 - */ - @JSONField(name = "word_count") - private Integer wordCount; - - /** - * 命中次数 - */ - @JSONField(name = "hit_count") - private Integer hitCount; - - /** - * 文档形式 - */ - @JSONField(name = "doc_form") - private String docForm; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/EmbeddingModelResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/EmbeddingModelResponse.java deleted file mode 100644 index 0b1ebdaa..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/EmbeddingModelResponse.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -import java.util.List; -import java.util.Map; - -/** - * @description Dify嵌入模型响应 - * @filename EmbeddingModelResponse.java - * @author AI Assistant - * @since 2025-11-06 - */ -@Data -public class EmbeddingModelResponse { - - /** - * 模型提供商列表 - */ - @JSONField(name = "data") - private List data; - - /** - * 模型提供商 - */ - @Data - public static class ModelProvider { - /** - * 提供商标识 - */ - @JSONField(name = "provider") - private String provider; - - /** - * 提供商标签 - */ - @JSONField(name = "label") - private Map label; - - /** - * 小图标 - */ - @JSONField(name = "icon_small") - private Map iconSmall; - - /** - * 大图标 - */ - @JSONField(name = "icon_large") - private Map iconLarge; - - /** - * 状态 - */ - @JSONField(name = "status") - private String status; - - /** - * 模型列表 - */ - @JSONField(name = "models") - private List models; - } - - /** - * 模型详情 - */ - @Data - public static class Model { - /** - * 模型名称 - */ - @JSONField(name = "model") - private String model; - - /** - * 模型标签 - */ - @JSONField(name = "label") - private Map label; - - /** - * 模型类型 - */ - @JSONField(name = "model_type") - private String modelType; - - /** - * 特性列表 - */ - @JSONField(name = "features") - private List features; - - /** - * 获取来源 - */ - @JSONField(name = "fetch_from") - private String fetchFrom; - - /** - * 模型属性 - */ - @JSONField(name = "model_properties") - private ModelProperties modelProperties; - - /** - * 是否已弃用 - */ - @JSONField(name = "deprecated") - private Boolean deprecated; - - /** - * 状态 - */ - @JSONField(name = "status") - private String status; - - /** - * 是否启用负载均衡 - */ - @JSONField(name = "load_balancing_enabled") - private Boolean loadBalancingEnabled; - } - - /** - * 模型属性 - */ - @Data - public static class ModelProperties { - /** - * 上下文大小 - */ - @JSONField(name = "context_size") - private Integer contextSize; - - /** - * 最大分块数 - */ - @JSONField(name = "max_chunks") - private Integer maxChunks; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/MessageHistoryResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/MessageHistoryResponse.java deleted file mode 100644 index 50e5c981..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/MessageHistoryResponse.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; -import java.util.List; - -/** - * @description 消息历史响应 - * @filename MessageHistoryResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class MessageHistoryResponse { - - private Integer limit; - - @JSONField(name = "has_more") - private Boolean hasMore; - - private List data; - - @Data - public static class MessageInfo { - private String id; - - @JSONField(name = "conversation_id") - private String conversationId; - - private List inputs; - - private String query; - - private String answer; - - @JSONField(name = "message_files") - private List messageFiles; - - private Feedback feedback; - - @JSONField(name = "retriever_resources") - private List retrieverResources; - - @JSONField(name = "created_at") - private Long createdAt; - - @JSONField(name = "agent_thoughts") - private List agentThoughts; - } - - @Data - public static class MessageContent { - private String key; - private String value; - } - - @Data - public static class MessageFile { - private String id; - private String type; - private String url; - @JSONField(name = "belongs_to") - private String belongsTo; - } - - @Data - public static class Feedback { - private String rating; - } - - @Data - public static class RetrieverResource { - @JSONField(name = "dataset_id") - private String datasetId; - - @JSONField(name = "dataset_name") - private String datasetName; - - @JSONField(name = "document_id") - private String documentId; - - @JSONField(name = "document_name") - private String documentName; - - @JSONField(name = "segment_id") - private String segmentId; - - private Double score; - - private String content; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RerankModelResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RerankModelResponse.java deleted file mode 100644 index d1124bc6..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RerankModelResponse.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -import java.util.List; -import java.util.Map; - -/** - * @description Dify Rerank模型响应 - * @filename RerankModelResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-06 - */ -@Data -public class RerankModelResponse { - private List data; - - @Data - public static class ModelProvider { - private String provider; - private Map label; // e.g., {"en_US": "Cohere", "zh_Hans": "Cohere"} - @JSONField(name = "icon_small") - private String iconSmall; - @JSONField(name = "icon_large") - private String iconLarge; - private String status; // e.g., "active" - private List models; - } - - @Data - public static class Model { - private String model; // e.g., "rerank-multilingual-v3.0" - private Map label; - @JSONField(name = "model_type") - private String modelType; // e.g., "rerank" - private List features; - @JSONField(name = "fetch_from") - private String fetchFrom; - @JSONField(name = "model_properties") - private ModelProperties modelProperties; - private Boolean deprecated; - private String status; // e.g., "active" - private String provider; // 模型提供商(可能在 model 数据中) - } - - @Data - public static class ModelProperties { - @JSONField(name = "context_size") - private Integer contextSize; - @JSONField(name = "max_chunks") - private Integer maxChunks; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalModel.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalModel.java deleted file mode 100644 index cad94eeb..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalModel.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description Dify检索模型配置(Retrieval Model) - * @filename RetrievalModel.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-06 - */ -@Data -public class RetrievalModel { - - /** - * 搜索方法:vector_search(向量搜索)、full_text_search(全文搜索)、hybrid_search(混合搜索) - */ - @JSONField(name = "search_method") - private String searchMethod; - - /** - * Rerank是否启用 - */ - @JSONField(name = "reranking_enable") - private Boolean rerankingEnable; - - /** - * Rerank模式(字符串,值为 "reranking_model") - */ - @JSONField(name = "reranking_mode") - private String rerankingMode; - - /** - * Rerank模型配置(当 reranking_enable=true 时必须设置) - */ - @JSONField(name = "reranking_model") - private RerankingModel rerankingModel; - - /** - * Top K(返回前K个结果) - */ - @JSONField(name = "top_k") - private Integer topK; - - /** - * 分数阈值(0.00-1.00) - */ - @JSONField(name = "score_threshold") - private Double scoreThreshold; - - /** - * 是否启用分数阈值 - */ - @JSONField(name = "score_threshold_enabled") - private Boolean scoreThresholdEnabled; - - /** - * Rerank模型配置(嵌套对象) - */ - @Data - public static class RerankingModel { - /** - * Rerank模型提供商 - */ - @JSONField(name = "reranking_provider_name") - private String rerankingProviderName; - - /** - * Rerank模型名称 - */ - @JSONField(name = "reranking_model_name") - private String rerankingModelName; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalRequest.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalRequest.java deleted file mode 100644 index 2eee2af4..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalRequest.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description 知识库检索请求 - * @filename RetrievalRequest.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class RetrievalRequest { - - /** - * 查询文本 - */ - private String query; - - /** - * 返回的最相关结果数量 - */ - @JSONField(name = "top_k") - private Integer topK = 3; - - /** - * 相似度阈值(0-1) - */ - @JSONField(name = "score_threshold") - private Double scoreThreshold = 0.7; -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalResponse.java deleted file mode 100644 index e2724cf3..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/RetrievalResponse.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; -import java.util.List; -import java.util.Map; - -/** - * @description 知识库检索响应 - * @filename RetrievalResponse.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Data -public class RetrievalResponse { - - /** - * 查询ID - */ - @JSONField(name = "query_id") - private String queryId; - - /** - * 检索结果列表 - */ - private List records; - - @Data - public static class RetrievalRecord { - /** - * 分段内容 - */ - private String content; - - /** - * 相似度分数 - */ - private Double score; - - /** - * 标题 - */ - private String title; - - /** - * 元数据 - */ - private Map metadata; - - /** - * 文档ID - */ - @JSONField(name = "document_id") - private String documentId; - - /** - * 文档名称 - */ - @JSONField(name = "document_name") - private String documentName; - - /** - * 分段ID - */ - @JSONField(name = "segment_id") - private String segmentId; - - /** - * 分段位置 - */ - @JSONField(name = "segment_position") - private Integer segmentPosition; - - /** - * 索引节点ID - */ - @JSONField(name = "index_node_id") - private String indexNodeId; - - /** - * 索引节点哈希 - */ - @JSONField(name = "index_node_hash") - private String indexNodeHash; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/WorkflowRunRequest.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/WorkflowRunRequest.java deleted file mode 100644 index a2661d3f..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/WorkflowRunRequest.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; -import java.util.Map; - -/** - * @description 工作流执行请求 - * @filename WorkflowRunRequest.java - * @author system - * @copyright xyzh - * @since 2026-01-01 - */ -@Data -public class WorkflowRunRequest { - - /** - * 输入变量(Dify 工作流 API 必需字段) - */ - @JSONField(serializeFeatures = com.alibaba.fastjson2.JSONWriter.Feature.WriteMapNullValue) - private Map inputs = new java.util.HashMap<>(); - - /** - * 响应模式:streaming(流式)、blocking(阻塞) - */ - @JSONField(name = "response_mode") - private String responseMode = "blocking"; - - /** - * 用户标识 - */ - private String user; - -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/WorkflowRunResponse.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/WorkflowRunResponse.java deleted file mode 100644 index b87a6fee..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/dto/WorkflowRunResponse.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.xyzh.ai.client.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; -import java.util.Map; - -/** - * @description 工作流执行响应(阻塞模式) - * @filename WorkflowRunResponse.java - * @author system - * @copyright xyzh - * @since 2026-01-01 - */ -@Data -public class WorkflowRunResponse { - - /** - * 工作流执行ID - */ - @JSONField(name = "workflow_run_id") - private String workflowRunId; - - /** - * 任务ID - */ - @JSONField(name = "task_id") - private String taskId; - - /** - * 工作流执行数据 - */ - private WorkflowData data; - - @Data - public static class WorkflowData { - /** - * 执行ID - */ - private String id; - - /** - * 工作流ID - */ - @JSONField(name = "workflow_id") - private String workflowId; - - /** - * 执行状态:running、succeeded、failed、stopped - */ - private String status; - - /** - * 工作流输出结果 - */ - private Map outputs; - - /** - * 错误信息 - */ - private String error; - - /** - * 执行耗时(秒) - */ - @JSONField(name = "elapsed_time") - private Double elapsedTime; - - /** - * 总Token数 - */ - @JSONField(name = "total_tokens") - private Integer totalTokens; - - /** - * 创建时间 - */ - @JSONField(name = "created_at") - private Long createdAt; - - /** - * 完成时间 - */ - @JSONField(name = "finished_at") - private Long finishedAt; - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/config/DifyConfig.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/config/DifyConfig.java deleted file mode 100644 index 41f980f4..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/config/DifyConfig.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.xyzh.ai.config; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.springframework.context.annotation.Configuration; -import org.xyzh.api.system.service.SysConfigService; - -import jakarta.annotation.PostConstruct; - -/** - * @description Dify配置类 - * @filename DifyConfig.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -@Slf4j -@Data -@Configuration -public class DifyConfig { - - @DubboReference(version = "1.0.0", group = "system", timeout = 30000, retries = 0) - private SysConfigService sysConfigService; - - /** - * Dify API基础地址 - */ - private String apiBaseUrl = "http://192.168.130.131/v1"; - - private String knowledgeApiKey="dataset-nupqKP4LONpzdXmGthIrbjeJ"; - - /** - * 请求超时时间(秒) - */ - private Integer timeout = 60; - - /** - * 连接超时时间(秒) - */ - private Integer connectTimeout = 10; - - /** - * 读取超时时间(秒) - */ - private Integer readTimeout = 60; - - /** - * 流式响应超时时间(秒) - */ - private Integer streamTimeout = 300; - - /** - * 上传文件配置 - */ - private Upload upload = new Upload(); - - /** - * 知识库配置 - */ - private Dataset dataset = new Dataset(); - - /** - * 初始化配置,从数据库加载 - */ - @PostConstruct - public void init() { - try { - log.info("开始从数据库加载Dify配置..."); - - // 基础配置 - loadStringConfig("dify.apiBaseUrl", val -> this.apiBaseUrl = val); - loadStringConfig("dify.knowledgeApiKey", val -> this.knowledgeApiKey = val); - loadIntegerConfig("dify.timeout", val -> this.timeout = val); - loadIntegerConfig("dify.connectTimeout", val -> this.connectTimeout = val); - loadIntegerConfig("dify.readTimeout", val -> this.readTimeout = val); - loadIntegerConfig("dify.streamTimeout", val -> this.streamTimeout = val); - - // Upload配置 - loadStringConfig("dify.upload.allowedTypes", val -> { - if (val != null && !val.trim().isEmpty()) { - this.upload.allowedTypes = val.split(","); - } - }); - loadIntegerConfig("dify.upload.maxSize", val -> this.upload.maxSize = val); - - // Dataset配置 - loadStringConfig("dify.dataset.defaultIndexingTechnique", val -> this.dataset.defaultIndexingTechnique = val); - loadStringConfig("dify.dataset.defaultEmbeddingModel", val -> this.dataset.defaultEmbeddingModel = val); - - log.info("Dify配置加载完成 - API地址: {}", apiBaseUrl); - } catch (Exception e) { - log.error("加载Dify配置失败,将使用默认值", e); - } - } - - /** - * 加载字符串配置 - */ - private void loadStringConfig(String key, java.util.function.Consumer setter) { - try { - String value = sysConfigService.getStringConfig(key); - if (value != null && !value.trim().isEmpty()) { - setter.accept(value); - log.debug("加载配置: {} = {}", key, value); - } - } catch (Exception e) { - log.warn("加载配置失败: {}, 错误: {}", key, e.getMessage()); - } - } - - /** - * 加载整数配置 - */ - private void loadIntegerConfig(String key, java.util.function.Consumer setter) { - try { - Integer value = sysConfigService.getIntConfig(key); - if (value != null) { - setter.accept(value); - log.debug("加载配置: {} = {}", key, value); - } - } catch (Exception e) { - log.warn("加载配置失败: {}, 错误: {}", key, e.getMessage()); - } - } - - @Data - public static class Upload { - /** - * 支持的文件类型 - */ - private String[] allowedTypes = {"pdf", "txt", "docx", "doc", "md", "html", "htm"}; - - /** - * 最大文件大小(MB) - */ - private Integer maxSize = 50; - } - - @Data - public static class Dataset { - /** - * 默认索引方式(high_quality/economy) - */ - private String defaultIndexingTechnique = "high_quality"; - - /** - * 默认Embedding模型 - */ - private String defaultEmbeddingModel = "text-embedding-ada-002"; - } - - /** - * 验证配置是否有效 - */ - public boolean isValid() { - return apiBaseUrl != null && !apiBaseUrl.trim().isEmpty(); - } - - /** - * 刷新配置(从数据库重新加载) - * 由Redis事件监听器调用 - */ - public void refresh() { - log.info("收到配置刷新请求,重新加载Dify配置..."); - init(); - } - - /** - * 获取完整的API URL - */ - public String getFullApiUrl(String endpoint) { - String baseUrl = apiBaseUrl.endsWith("/") ? apiBaseUrl.substring(0, apiBaseUrl.length() - 1) : apiBaseUrl; - String path = endpoint.startsWith("/") ? endpoint : "/" + endpoint; - return baseUrl + path; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/config/RedisSubscriberConfig.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/config/RedisSubscriberConfig.java deleted file mode 100644 index 2e12b7c8..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/config/RedisSubscriberConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.xyzh.ai.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.listener.PatternTopic; -import org.springframework.data.redis.listener.RedisMessageListenerContainer; -import org.xyzh.ai.listener.DifyConfigListener; - -/** - * AI模块Redis订阅配置 - * - * @author cascade - * @since 2026-01-01 - */ -@Configuration -public class RedisSubscriberConfig { - - @Autowired - private DifyConfigListener difyConfigListener; - - @Bean - public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) { - RedisMessageListenerContainer container = new RedisMessageListenerContainer(); - container.setConnectionFactory(connectionFactory); - - // 订阅Dify配置变更频道 - container.addMessageListener(difyConfigListener, - new PatternTopic(difyConfigListener.getChannelPattern())); - - return container; - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/AgentController.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/AgentController.java deleted file mode 100644 index 2eac5640..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/AgentController.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.xyzh.ai.controller; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import org.xyzh.api.ai.service.AgentService; -import org.xyzh.api.ai.dto.TbAgent; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.validation.ValidationResult; -import org.xyzh.common.utils.validation.ValidationParam; -import org.xyzh.common.utils.validation.ValidationUtils; - -import jakarta.validation.constraints.NotNull; - -import java.util.Arrays; - -/** - * @description 智能体控制器 - * @filename AgentController.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Slf4j -@Validated -@RestController -@RequestMapping("/ai/agent") -public class AgentController { - - @Autowired - private AgentService agentService; - - /** - * @description 创建智能体 - * @param agent - * @author yslg - * @since 2025-12-17 - */ - @PostMapping - @PreAuthorize("hasAuthority('ai:agent:create')") - public ResultDomain createAgent(@RequestBody TbAgent agent) { - log.info("创建智能体: name={}", agent.getName()); - // 参数校验 - ValidationResult result = ValidationUtils.validate(agent, Arrays.asList( - ValidationUtils.requiredString("name", "智能体名称", 1, 100), - ValidationUtils.requiredString("apiKey", "API密钥", 1, 100), - ValidationUtils.requiredString("link", "智能体url",10,500) - )); - if (!result.isValid()) { - return ResultDomain.failure(result.getAllErrors()); - } - return agentService.addAgent(agent); - } - - /** - * @description 更新智能体 - * @param agent - * @author yslg - * @since 2025-12-17 - */ - @PutMapping - @PreAuthorize("hasAuthority('ai:agent:update')") - public ResultDomain updateAgent(@RequestBody TbAgent agent) { - log.info("更新智能体: agentId={}", agent.getAgentId()); - // 参数校验 - ValidationResult result = ValidationUtils.validate(agent, Arrays.asList( - ValidationUtils.requiredString("agentId", "智能体ID"), - ValidationUtils.requiredString("name", "智能体名称", 1, 100), - ValidationUtils.requiredString("apiKey", "API密钥", 1, 100), - ValidationUtils.requiredString("link", "智能体url",10,500) - )); - if (!result.isValid()) { - return ResultDomain.failure(result.getAllErrors()); - } - return agentService.updateAgent(agent); - } - - /** - * @description 删除智能体 - * @param agentId - * @author yslg - * @since 2025-12-17 - */ - @DeleteMapping("/{agentId}") - @PreAuthorize("hasAuthority('ai:agent:delete')") - public ResultDomain deleteAgent(@PathVariable("agentId") @NotNull String agentId) { - log.info("删除智能体: agentId={}", agentId); - TbAgent agent = new TbAgent(); - agent.setAgentId(agentId); - return agentService.deleteAgent(agent); - } - - /** - * @description 获取智能体详情 - * @param agentId - * @author yslg - * @since 2025-12-17 - */ - @GetMapping("/{agentId}") - @PreAuthorize("hasAuthority('ai:agent:view')") - public ResultDomain getAgent(@PathVariable("agentId") @NotNull String agentId) { - log.info("获取智能体: agentId={}", agentId); - ResultDomain agentResult = agentService.selectAgentById(agentId); - if (agentResult.getSuccess() && agentResult.getData() != null) { - return ResultDomain.success("查询成功", agentResult.getData()); - } - return ResultDomain.failure("智能体不存在"+agentResult.getMessage()); - } - - /** - * @description 分页查询智能体 - * @param pageRequest - * @author yslg - * @since 2025-12-17 - */ - @PostMapping("/page") - @PreAuthorize("hasAuthority('ai:agent:view')") - public ResultDomain getAgentPage(@RequestBody PageRequest pageRequest) { - log.info("分页查询智能体"); - // 参数校验(支持嵌套属性路径) - ValidationResult result = ValidationUtils.validate(pageRequest, Arrays.asList( - ValidationParam.builder().fieldName("pageParam").fieldLabel("分页参数").required().build(), - ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null), - ValidationUtils.requiredNumber("pageParam.pageSize", "每页条数", 1, 100) - )); - if (!result.isValid()) { - return ResultDomain.failure(result.getAllErrors()); - } - return agentService.getAgentPage(pageRequest); - } - - /** - * @description 获取智能体列表 - * @param tbAgent - * @author yslg - * @since 2025-12-17 - */ - @GetMapping("/list") - @PreAuthorize("hasAuthority('ai:agent:view')") - public ResultDomain getAgentList(TbAgent tbAgent) { - log.info("获取智能体列表"); - return agentService.getAgentList(tbAgent); - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/ChatController.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/ChatController.java deleted file mode 100644 index a7d0c012..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/ChatController.java +++ /dev/null @@ -1,378 +0,0 @@ -package org.xyzh.ai.controller; - -import jakarta.validation.constraints.NotNull; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; -import org.xyzh.ai.client.dto.ConversationVariablesResponse; -import org.xyzh.api.ai.dto.ChatPrepareData; -import org.xyzh.api.ai.dto.TbChat; -import org.xyzh.api.ai.dto.TbChatMessage; -import org.xyzh.api.ai.service.AIFileUploadService; -import org.xyzh.api.ai.service.AgentChatService; -import org.xyzh.common.auth.utils.LoginUtil; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.NonUtils; -import org.xyzh.common.utils.validation.ValidationParam; -import org.xyzh.common.utils.validation.ValidationResult; -import org.xyzh.common.utils.validation.ValidationUtils; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; - -/** - * @description 智能体对话控制器 所有接口开放 - * @filename ChatController.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Slf4j -@RestController -@Validated -@RequestMapping("/ai/chat") -public class ChatController { - - @Autowired - private AgentChatService chatService; - - @Autowired - private AIFileUploadService fileUploadService; - - @Autowired - private org.xyzh.ai.client.DifyApiClient difyApiClient; - - // ====================== 会话管理 ====================== - - /** - * @description 创建会话 - * @param - * @author yslg - * @since 2025-12-17 - */ - @PostMapping("/conversation") - public ResultDomain createChat(@RequestBody TbChat chat, @RequestHeader("Authorization") String token) { - ValidationResult result = ValidationUtils.validate(chat, Arrays.asList( - ValidationUtils.requiredString("agentId", "智能体id", 1, 100), - ValidationUtils.requiredString("title", "对话标题", 1, 100), - ValidationUtils.requiredString("userId", "用户id", 1, 100) - )); - if (!result.isValid()) { - return ResultDomain.failure(result.getAllErrors()); - } - // 默认来客,如果token不为空且token对应的用户存在,说明是员工 - chat.setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - chat.setUserType(true); - } - } - - log.info("创建会话: agentId={}, title={}, userId={}, userType={}", chat.getAgentId(), chat.getTitle(), chat.getUserId(), chat.getUserType()); - return chatService.createChat(chat); - } - - /** - * @description 更新对话 - * @param - * @author yslg - * @since 2025-12-17 - */ - @PutMapping("/conversation") - public ResultDomain updateChat(@RequestBody TbChat chat, @RequestHeader("Authorization") String token) { - ValidationResult result = ValidationUtils.validate(chat, Arrays.asList( - ValidationUtils.requiredString("agentId", "智能体id", 1, 100), - ValidationUtils.requiredString("title", "对话标题", 1, 100), - ValidationUtils.requiredString("userId", "用户id", 1, 100), - ValidationParam.builder().fieldName("userType").fieldLabel("用户类型").required().fieldType(Boolean.class).build() - )); - if (!result.isValid()) { - return ResultDomain.failure(result.getAllErrors()); - } - chat.setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - chat.setUserType(true); - } - } - log.info("更新会话: chatId={}", chat.getChatId()); - return chatService.updateChat(chat); - } - - /** - * @description 删除对话 - * @param - * @author yslg - * @since 2025-12-17 - */ - @DeleteMapping("/conversation") - public ResultDomain deleteChat(@RequestBody TbChat chat, @RequestHeader("Authorization") String token) { - chat.setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - chat.setUserType(true); - } - } - log.info("删除会话: chatId={}", chat.getChatId()); - return chatService.deleteChat(chat); - } - - /** - * @description 获取对话列表 - * @param - * @author yslg - * @since 2025-12-17 - */ - @PostMapping("/conversation/list") - public ResultDomain getChatList(@RequestBody TbChat filter, @RequestHeader("Authorization") String token) { - log.info("获取会话列表: agentId={}", filter.getAgentId()); - - filter.setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - filter.setUserType(true); - } - } - return chatService.getChatList(filter); - } - - /** - * @description 分页获取对话列表 - * @param pageRequest 分页请求参数 - * @author yslg - * @since 2025-12-17 - */ - @PostMapping("/conversation/page") - public ResultDomain getChatPage(@RequestBody PageRequest pageRequest, @RequestHeader("Authorization") String token) { - log.info("分页获取会话列表: agentId={}", pageRequest.getFilter().getAgentId()); - - pageRequest.getFilter().setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - pageRequest.getFilter().setUserType(true); - } - } - return chatService.getChatPage(pageRequest); - } - - /** - * @description 获取对话变量 - * @param params 请求参数(包含agentId, conversationId, userId, lastId, limit) - * @author yslg - * @since 2025-12-29 - */ - @PostMapping("/conversation/variables") - public ResultDomain getConversationVariables( - @RequestBody Map params, - @RequestHeader("Authorization") String token) { - - // 参数验证 - ValidationResult result = ValidationUtils.validateMap(params, Arrays.asList( - ValidationUtils.requiredString("agentId", "智能体ID", 1, 100), - ValidationUtils.requiredString("conversationId", "会话ID", 1, 100), - ValidationUtils.requiredString("userId", "用户ID", 1, 100) - )); - if (!result.isValid()) { - return ResultDomain.failure(result.getAllErrors()); - } - - String agentId = (String) params.get("agentId"); - String conversationId = (String) params.get("conversationId"); - String userId = (String) params.get("userId"); - String lastId = params.containsKey("lastId") ? (String) params.get("lastId") : null; - Integer limit = params.containsKey("limit") ? - Integer.parseInt(params.get("limit").toString()) : 20; - - log.info("获取对话变量: agentId={}, conversationId={}, userId={}", agentId, conversationId, userId); - - try { - // 获取智能体信息以获取 API Key - // 这里需要根据 agentId 获取对应的 API Key - // 暂时先使用一个占位符,实际使用时需要从数据库或配置中获取 - // 或者通过 chatService 获取智能体配置 - - // 调用 Dify API 获取会话变量 - ConversationVariablesResponse response = - difyApiClient.getConversationVariables(conversationId, userId, lastId, limit, agentId); - - return ResultDomain.success("获取对话变量成功",response); - } catch (Exception e) { - log.error("获取对话变量失败", e); - return ResultDomain.failure("获取对话变量失败: " + e.getMessage()); - } - } - - // ====================== 消息管理 ====================== - - /** - * @description 获取对话消息列表 - * @param - * @author yslg - * @since 2025-12-17 - */ - @PostMapping("/messages") - public ResultDomain getMessageList(@RequestBody TbChat filter, @RequestHeader("Authorization") String token) { - ValidationResult result = ValidationUtils.validate(filter, Arrays.asList( - ValidationUtils.requiredString("agentId", "智能体id",10,50), - ValidationUtils.requiredString("chatId", "对话Id", 10, 50), - ValidationUtils.requiredString("userId", "用户Id") - )); - - filter.setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - filter.setUserType(true); - } - } - log.info("获取消息列表: chatId={}", filter.getChatId()); - return chatService.getChatMessageList(filter); - } - - // ====================== 流式对话 ====================== - - /** - * @description 准备流式对话会话数据 - * @param chatPrepareData - * @author yslg - * @since 2025-12-17 - */ - @PostMapping("/stream/prepare") - public ResultDomain prepareStreamChat(@RequestBody ChatPrepareData chatPrepareData, @RequestHeader("Authorization") String token) { - ValidationResult result = ValidationUtils.validate(chatPrepareData, Arrays.asList( - ValidationUtils.requiredString("agentId", "智能体Id", 1, 50), - ValidationUtils.requiredString("chatId", "会话Id", 1, 50), - ValidationUtils.requiredString("query", "用户问题"), - ValidationUtils.requiredString("userId", "用户Id", 1, 100) - )); - if(!result.isValid()){ - return ResultDomain.failure(result.getAllErrors()); - } - // 设置用户类型 - chatPrepareData.setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - chatPrepareData.setUserType(true); - } - } - log.info("准备流式对话: agentId={}, chatId={}, query={}", chatPrepareData.getAgentId(), chatPrepareData.getChatId(), chatPrepareData.getQuery()); - return chatService.prepareChatMessageSession(chatPrepareData); - } - - /** - * @description 进行流式对话 - * @param - * @author yslg - * @since 2025-12-17 - */ - @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public SseEmitter streamChat(@RequestParam("sessionId") String sessionId) { - if(NonUtils.isEmpty(sessionId)){ - SseEmitter emitter = new SseEmitter(300000L); - try { - emitter.send(SseEmitter.event().name("error").data("{\"message\":\"会话不存在\"}")); - } catch (IOException e) { - log.error("发送错误事件失败", e); - }finally { - emitter.complete(); - } - return emitter; - } - log.info("建立SSE连接: sessionId={}", sessionId); - return chatService.streamChatMessageWithSse(sessionId); - } - - /** - * @description 停止会话 - * @param - * @author yslg - * @since 2025-12-17 - */ - @PostMapping("/stop") - public ResultDomain stopChat(@RequestBody Map params, @RequestHeader("Authorization") String token) { - ValidationResult result = ValidationUtils.validateMap(params, Arrays.asList( - ValidationUtils.requiredString("taskId", "任务ID"), - ValidationUtils.requiredString("agentId", "智能体ID"), - ValidationUtils.requiredString("userId", "用户ID") - )); - if (!result.isValid()) { - return ResultDomain.failure(result.getAllErrors()); - } - TbChat filter = new TbChat(); - filter.setAgentId(params.get("agentId")); - filter.setUserId(params.get("userId")); - filter.setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - filter.setUserType(true); - } - } - log.info("停止对话: taskId={}", params.get("taskId")); - return chatService.stopChatMessageByTaskId(filter, params.get("taskId")); - } - - /** - * @description 评价消息 - * @param - * @author yslg - * @since 2025-12-17 - */ - @PostMapping("/comment") - public ResultDomain commentMessage(@RequestBody Map params, @RequestHeader("Authorization") String token) { - ValidationResult result = ValidationUtils.validateMap(params, Arrays.asList( - ValidationUtils.requiredString("agentId", "智能体ID"), - ValidationUtils.requiredString("chatId", "对话ID"), - ValidationUtils.requiredString("messageId", "消息ID"), - ValidationUtils.requiredString("comment", "评价"), - ValidationUtils.requiredString("userId", "用户ID") - )); - if (!result.isValid()) { - return ResultDomain.failure(result.getAllErrors()); - } - TbChat filter = new TbChat(); - filter.setAgentId(params.get("agentId")); - filter.setChatId(params.get("chatId")); - filter.setUserId(params.get("userId")); - filter.setUserType(false); - if(NonUtils.isNotEmpty(token)){ - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (NonUtils.isNotEmpty(loginDomain) && !"guest".equals(loginDomain.getUser().getStatus())) { - filter.setUserType(true); - } - } - log.info("评价消息: messageId={}, comment={}", params.get("messageId"), params.get("comment")); - return chatService.commentChatMessage(filter, params.get("messageId"), params.get("comment")); - } - - // ====================== 文件上传 ====================== - - /** - * @description 上传文件用于对话(图文多模态) - * @param file 文件 - * @param agentId 智能体ID - * @author yslg - * @since 2025-12-17 - */ - @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResultDomain> uploadFileForChat( - @RequestPart("file") @NotNull MultipartFile file, - @RequestPart("agentId") @NotNull String agentId) { - log.info("上传对话文件: agentId={}, fileName={}", agentId, file.getOriginalFilename()); - return fileUploadService.uploadFileForChat(file, agentId); - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/KnowledgeController.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/KnowledgeController.java deleted file mode 100644 index 509a4a36..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/KnowledgeController.java +++ /dev/null @@ -1,379 +0,0 @@ -package org.xyzh.ai.controller; - -import com.alibaba.fastjson2.JSONObject; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; -import org.xyzh.api.ai.service.DifyProxyService; -import org.xyzh.api.ai.service.KnowledgeFileLogService; -import org.xyzh.api.ai.service.KnowledgeService; -import org.xyzh.api.ai.dto.TbKnowledge; -import org.xyzh.api.ai.dto.TbKnowledgeFile; -import org.xyzh.api.ai.dto.TbKnowledgeFileLog; -import org.xyzh.api.ai.vo.KnowledgeFileVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.validation.ValidationResult; -import org.xyzh.common.utils.validation.ValidationUtils; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -/** - * @description 知识库控制器 - * @filename KnowledgeController.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@RestController -@Validated -@RequestMapping("/ai/knowledge") -public class KnowledgeController { - private static final Logger logger = LoggerFactory.getLogger(KnowledgeController.class); - - @Autowired - private KnowledgeService knowledgeService; - - @Autowired - private KnowledgeFileLogService knowledgeFileLogService; - - @Autowired - private DifyProxyService difyProxyService; - - // ====================== 知识库管理 ====================== - - /** - * @description 创建知识库基础信息,包含dify知识库各种参数的配置 - * @param knowledge - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:create')") - @PostMapping - public ResultDomain createKnowledge(@RequestBody TbKnowledge knowledge) { - ValidationResult result = ValidationUtils.validate(knowledge, Arrays.asList( - ValidationUtils.requiredString("title", "知识库标题", 1, 50), - ValidationUtils.inSet("difyIndexingTechnique", "Dify索引方式(high_quality/economy)" , true, new HashSet<>(Arrays.asList("high_quality", "economy"))), - ValidationUtils.inSet("category", "所属分类 workcase 内部知识库、外部知识库", true, new HashSet<>(Arrays.asList("default", "内部知识库", "外部知识库"))) - )); - if(!result.isValid()){ - return ResultDomain.failure(result.getAllErrors()); - } - logger.info("创建知识库: title={}", knowledge.getTitle()); - return knowledgeService.createKnowledge(knowledge); - } - - /** - * @description 更新知识库,包含dify知识库各种参数的配置 - * @param knowledge - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:update')") - @PutMapping - public ResultDomain updateKnowledge(@RequestBody @Valid TbKnowledge knowledge) { - ValidationResult result = ValidationUtils.validate(knowledge, Arrays.asList( - ValidationUtils.requiredString("title", "知识库标题", 1, 50), - ValidationUtils.inSet("difyIndexingTechnique", "Dify索引方式(high_quality/economy)" , true, new HashSet<>(Arrays.asList("high_quality", "economy"))), - ValidationUtils.inSet("category", "所属分类 workcase 内部知识库、外部知识库", true, new HashSet<>(Arrays.asList("default", "内部知识库", "外部知识库"))) - - )); - if(!result.isValid()){ - return ResultDomain.failure(result.getAllErrors()); - } - logger.info("更新知识库: knowledgeId={}", knowledge.getKnowledgeId()); - return knowledgeService.updateKnowledge(knowledge); - } - - /** - * @description 删除知识库,同时删除dify知识库 - * @param knowledgeId - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:delete')") - @DeleteMapping("/{knowledgeId}") - public ResultDomain deleteKnowledge(@PathVariable("knowledgeId") @NotBlank String knowledgeId) { - logger.info("删除知识库: knowledgeId={}", knowledgeId); - return knowledgeService.deleteKnowledge(knowledgeId); - } - - /** - * @description 获取知识库详情,包含dify知识库各种参数的配置 - * @param knowledgeId - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:view')") - @GetMapping("/{knowledgeId}") - public ResultDomain getKnowledge(@PathVariable("knowledgeId") @NotBlank String knowledgeId) { - logger.info("获取知识库: knowledgeId={}", knowledgeId); - return knowledgeService.getKnowledgeById(knowledgeId); - } - - /** - * @description 查询知识库列表 - * @param filter - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:view')") - @PostMapping("/list") - public ResultDomain listKnowledges(@RequestBody(required = false) TbKnowledge filter) { - logger.info("查询知识库列表"); - return knowledgeService.listKnowledges(filter); - } - - /** - * @description 分页查询知识库 - * @param pageRequest - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:view')") - @PostMapping("/page") - public ResultDomain pageKnowledges(@RequestBody @Valid PageRequest pageRequest) { - logger.info("分页查询知识库"); - return knowledgeService.pageKnowledges(pageRequest.getFilter(), pageRequest.getPageParam()); - } - - /** - * @description 获取知识库统计信息 - * @param knowledgeId - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:view')") - @GetMapping("/{knowledgeId}/stats") - public ResultDomain getKnowledgeStats(@PathVariable("knowledgeId") @NotBlank String knowledgeId) { - logger.info("获取知识库统计: knowledgeId={}", knowledgeId); - return knowledgeService.getKnowledgeStats(knowledgeId); - } - - // ====================== 文件管理 ====================== - - /** - * @description 获取知识库文档列表(含文件详细信息) - * @param pageRequest 分页请求 - * @author yslg - * @since 2025-12-20 - */ - @PreAuthorize("hasAuthority('ai:knowledge:file:view')") - @PostMapping("/{knowledgeId}/documents") - public ResultDomain getDocumentList(@RequestBody PageRequest pageRequest) { - logger.info("获取文档列表: knowledgeId={}", pageRequest.getFilter().getKnowledgeId()); - return knowledgeService.getDocumentList(pageRequest); - } - - /** - * @description 上传文件到知识库(同步到Dify) - * @param file 上传文件 - * @param knowledgeId 知识库id - * @param indexingTechnique 索引方式 - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:file:upload')") - @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResultDomain uploadToKnowledge( - @RequestParam("file") @NotNull MultipartFile file, - @RequestParam("knowledgeId") @NotBlank String knowledgeId, - @RequestParam(value = "indexingTechnique", required = false) String indexingTechnique) { - logger.info("上传知识库文件: knowledgeId={}, fileName={}", knowledgeId, file.getOriginalFilename()); - return knowledgeService.uploadKnowledgeFile(knowledgeId, file, indexingTechnique); - } - - /** - * @description 批量上传文件到知识库 - * @param files 文件数组 - * @param knowledgeId 知识库id - * @param indexingTechnique 索引方式 - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:file:upload')") - @PostMapping(value = "/file/batch-upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResultDomain batchUploadToKnowledge( - @RequestParam("files") @NotEmpty List files, - @RequestParam("knowledgeId") @NotBlank String knowledgeId, - @RequestParam(value = "indexingTechnique", required = false) String indexingTechnique) { - logger.info("批量上传知识库文件: knowledgeId={}, fileCount={}", knowledgeId, files.size()); - return knowledgeService.batchUploadKnowledgeFile(knowledgeId, files, indexingTechnique); - } - - /** - * 上传新文件来更新知识库文件,注意fileRootId一致,生成新id - * @param file 上传文件 - * @param knowledgeId 知识库id - * @param fileRootId 文件Rootid,多version下一致 - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:file:update')") - @PutMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResultDomain updateFile( - @RequestParam("file") @NotNull MultipartFile file, - @RequestParam("knowledgeId") @NotBlank String knowledgeId, - @RequestParam("fileRootId") @NotBlank String fileRootId) { - logger.info("更新知识库文件: knowledgeId={}, fileName={}", knowledgeId, file.getOriginalFilename()); - return knowledgeService.updateKnowledgeFileVersion(knowledgeId, file, fileRootId); - } - - /** - * 删除知识库文件(同时删除Dify文档),所有filtRootId的文件一起软删除 - * @param fileId 文件id - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:file:delete')") - @DeleteMapping("/file/{fileRootId}") - public ResultDomain deleteFile(@PathVariable("fileRootId") @NotBlank String fileRootId) { - logger.info("删除知识库文件: fileId={}", fileRootId); - return knowledgeService.deleteKnowledgeFileById(fileRootId); - } - - /** - * 获取文件历史版本,获取fileRootId下所有version - * @param fileRootId 文件根ID - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:file:view')") - @GetMapping("/file/{fileRootId}/history") - public ResultDomain getFileHistory(@PathVariable("fileRootId") @NotBlank String fileRootId) { - logger.info("获取文件历史: fileRootId={}", fileRootId); - return knowledgeService.getKnowledgeFileHistory(fileRootId); - } - - // ====================== 文档分段管理 ====================== - - /** - * @description 获取文档分段列表 - * @param datasetId Dify数据集ID - * @param documentId Dify文档ID - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:dify:segment:view')") - @GetMapping("/datasets/{datasetId}/documents/{documentId}/segments") - public ResultDomain getDocumentSegments( - @PathVariable("datasetId") @NotBlank String datasetId, - @PathVariable("documentId") @NotBlank String documentId) { - logger.info("获取文档分段: datasetId={}, documentId={}", datasetId, documentId); - return difyProxyService.getDocumentSegments(datasetId, documentId); - } - - /** - * @description 创建文档分段 - * @param datasetId Dify数据集ID - * @param documentId Dify文档ID - * @param requestBody 分段内容 - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:dify:segment:create')") - @PostMapping("/datasets/{datasetId}/documents/{documentId}/segments") - public ResultDomain createSegment( - @PathVariable("datasetId") @NotBlank String datasetId, - @PathVariable("documentId") @NotBlank String documentId, - @RequestBody Map requestBody) { - logger.info("创建文档分段: datasetId={}, documentId={}", datasetId, documentId); - return difyProxyService.createSegment(datasetId, documentId, requestBody); - } - - /** - * @description 更新文档分段 - * @param datasetId Dify数据集ID - * @param documentId Dify文档ID - * @param segmentId Dify分段ID - * @param requestBody 分段内容 - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:dify:segment:update')") - @PatchMapping("/datasets/{datasetId}/documents/{documentId}/segments/{segmentId}") - public ResultDomain updateSegment( - @PathVariable("datasetId") @NotBlank String datasetId, - @PathVariable("documentId") @NotBlank String documentId, - @PathVariable("segmentId") @NotBlank String segmentId, - @RequestBody Map requestBody) { - logger.info("更新文档分段: datasetId={}, documentId={}, segmentId={}", datasetId, documentId, segmentId); - return difyProxyService.updateSegment(datasetId, documentId, segmentId, requestBody); - } - - /** - * @description 删除文档分段 - * @param datasetId Dify数据集ID - * @param documentId Dify文档ID - * @param segmentId Dify分段ID - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:dify:segment:delete')") - @DeleteMapping("/datasets/{datasetId}/documents/{documentId}/segments/{segmentId}") - public ResultDomain deleteSegment( - @PathVariable("datasetId") @NotBlank String datasetId, - @PathVariable("documentId") @NotBlank String documentId, - @PathVariable("segmentId") @NotBlank String segmentId) { - logger.info("删除文档分段: datasetId={}, documentId={}, segmentId={}", datasetId, documentId, segmentId); - return difyProxyService.deleteSegment(datasetId, documentId, segmentId); - } - - // ====================== 文档状态管理 ====================== - - /** - * @description 更新文档状态(启用/禁用/归档) - * @param datasetId Dify数据集ID - * @param action 操作类型: enable/disable/archive/un_archive - * @param requestBody 请求体 - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:dify:document:status')") - @PatchMapping("/datasets/{datasetId}/documents/{action}/status") - public ResultDomain updateDocumentStatus( - @PathVariable("datasetId") @NotBlank String datasetId, - @PathVariable("action") @NotBlank String action, - @RequestBody Map requestBody) { - logger.info("更新文档状态: datasetId={}, action={}", datasetId, action); - return difyProxyService.updateDocumentStatus(datasetId, action, requestBody); - } - - // ================================ 知识库文件操作日志 ======================= - /** - * @description 查询知识库操作日志列表 - * @param fileLog - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:file:view')") - @PostMapping("/datasets/log/list") - public ResultDomain getKnowledgeFileLogList(@RequestBody TbKnowledgeFileLog fileLog){ - return knowledgeFileLogService.getKnowledgeFileLogList(fileLog); - } - - /** - * @description 查询知识库操作日志分页 - * @param pageRequest - * @author yslg - * @since 2025-12-18 - */ - @PreAuthorize("hasAuthority('ai:knowledge:file:view')") - @PostMapping("/datasets/log/page") - public ResultDomain getKnowledgeFileLogPage(@RequestBody PageRequest pageRequest){ - return knowledgeFileLogService.getKnowledgeFileLogPage(pageRequest); - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/exception/DifyException.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/exception/DifyException.java deleted file mode 100644 index 45b39e7e..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/exception/DifyException.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.xyzh.ai.exception; - -/** - * @description Dify API调用异常 - * @filename DifyException.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-11-04 - */ -public class DifyException extends RuntimeException { - - private static final long serialVersionUID = 1L; - - private Integer code; - - public DifyException(String message) { - super(message); - } - - public DifyException(Integer code, String message) { - super(message); - this.code = code; - } - - public DifyException(String message, Throwable cause) { - super(message, cause); - } - - public DifyException(Integer code, String message, Throwable cause) { - super(message, cause); - this.code = code; - } - - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } -} - diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/handler/PromptCardsTypeHandler.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/handler/PromptCardsTypeHandler.java deleted file mode 100644 index 0eb09ce4..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/handler/PromptCardsTypeHandler.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.xyzh.ai.handler; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.TypeReference; -import org.apache.ibatis.type.BaseTypeHandler; -import org.apache.ibatis.type.JdbcType; -import org.apache.ibatis.type.MappedTypes; -import org.xyzh.api.ai.dto.PromptCard; - -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - -/** - * @description 提示卡片列表类型处理器(JSONB <-> List) - * @filename PromptCardsTypeHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@MappedTypes({List.class}) -public class PromptCardsTypeHandler extends BaseTypeHandler> { - - @Override - public void setNonNullParameter(PreparedStatement ps, int i, List parameter, JdbcType jdbcType) throws SQLException { - if (parameter == null || parameter.isEmpty()) { - ps.setString(i, "[]"); - } else { - ps.setString(i, JSON.toJSONString(parameter)); - } - } - - @Override - public List getNullableResult(ResultSet rs, String columnName) throws SQLException { - String jsonString = rs.getString(columnName); - return parseToList(jsonString); - } - - @Override - public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - String jsonString = rs.getString(columnIndex); - return parseToList(jsonString); - } - - @Override - public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - String jsonString = cs.getString(columnIndex); - return parseToList(jsonString); - } - - private List parseToList(String jsonString) { - if (jsonString == null || jsonString.trim().isEmpty()) { - return new ArrayList<>(); - } - try { - return JSON.parseObject(jsonString, new TypeReference>() {}); - } catch (Exception e) { - return new ArrayList<>(); - } - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/listener/DifyConfigListener.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/listener/DifyConfigListener.java deleted file mode 100644 index 585bb0cd..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/listener/DifyConfigListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.xyzh.ai.listener; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.xyzh.api.system.constance.SysConfigRedisPrefix; -import org.xyzh.ai.config.DifyConfig; -import org.xyzh.common.redis.listener.AbstractSysConfigListener; - -/** - * Dify配置变更监听器 - * 监听sys:config:dify频道,接收到事件后延时2秒刷新配置 - * - * @author cascade - * @since 2026-01-01 - */ -@Component -public class DifyConfigListener extends AbstractSysConfigListener { - - @Autowired - private DifyConfig difyConfig; - - @Override - protected void doRefresh(String channel, String body) { - difyConfig.refresh(); - } - - @Override - public String getChannelPattern() { - return SysConfigRedisPrefix.SYS_CONFIG_DIFY; - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbAgentMapper.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbAgentMapper.java deleted file mode 100644 index 982b6973..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbAgentMapper.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.xyzh.ai.mapper; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.ai.dto.TbAgent; -import org.xyzh.common.core.page.PageParam; - -import java.util.List; - -/** - * @description 智能体数据访问层 - * @filename AgentMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Mapper -public interface TbAgentMapper { - - /** - * 插入智能体 - */ - int insertAgent(TbAgent agent); - - /** - * 更新智能体(只更新非null字段) - */ - int updateAgent(TbAgent agent); - - /** - * 逻辑删除智能体 - */ - int deleteAgent(TbAgent agent); - - /** - * 根据ID查询智能体 - */ - TbAgent selectAgentById(@Param("agentId") String agentId); - - /** - * 根据ApiKey查询智能体 - */ - TbAgent selectAgentByApiKey(@Param("apiKey") String apiKey); - - /** - * 查询智能体列表 - */ - List selectAgentList(@Param("filter") TbAgent filter); - - /** - * 分页查询智能体 - */ - List selectAgentPage( - @Param("filter") TbAgent filter, - @Param("pageParam") PageParam pageParam - ); - - /** - * 统计智能体数量 - */ - long countAgents(@Param("filter") TbAgent filter); - - /** - * 根据名称检查是否存在 - */ - int countByName( - @Param("name") String name, - @Param("excludeId") String excludeId - ); -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbChatMapper.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbChatMapper.java deleted file mode 100644 index ce62d4e2..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbChatMapper.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.xyzh.ai.mapper; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.ai.dto.TbChat; -import org.xyzh.common.core.page.PageParam; - -import java.util.List; - -/** - * @description 对话数据访问层 - * @filename ChatMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Mapper -public interface TbChatMapper { - - /** - * 插入对话 - */ - int insertChat(TbChat chat); - - /** - * 更新对话 - */ - int updateChat(TbChat chat); - - /** - * 逻辑删除对话 - */ - int deleteChat(TbChat chat); - - /** - * 根据ID查询对话 - */ - TbChat selectChatById(@Param("chatId") String chatId); - - /** - * 根据智能体ID和用户ID查询对话列表 - */ - List selectChatList( - @Param("agentId") String agentId, - @Param("userId") String userId - ); - - /** - * 分页查询对话 - */ - List selectChatPage( - @Param("filter") TbChat filter, - @Param("pageParam") PageParam pageParam - ); - - /** - * 统计对话数量 - */ - long countChats(@Param("filter") TbChat filter); -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbChatMessageMapper.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbChatMessageMapper.java deleted file mode 100644 index 63e77ecf..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbChatMessageMapper.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.xyzh.ai.mapper; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.ai.dto.TbChatMessage; -import org.xyzh.common.core.page.PageParam; - -import java.util.List; - -/** - * @description 对话消息数据访问层 - * @filename ChatMessageMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Mapper -public interface TbChatMessageMapper { - - /** - * 插入消息 - */ - int insertChatMessage(TbChatMessage message); - - /** - * 更新消息 - */ - int updateChatMessage(TbChatMessage message); - - /** - * 逻辑删除消息 - */ - int deleteChatMessage(TbChatMessage message); - - /** - * 根据ID查询消息 - */ - TbChatMessage selectMessageById(@Param("messageId") String messageId); - - /** - * 根据对话ID查询消息列表 - */ - List selectMessagesByChatId(@Param("chatId") String chatId); - - /** - * 分页查询消息 - */ - List selectMessagePage( - @Param("chatId") String chatId, - @Param("pageParam") PageParam pageParam - ); - - /** - * 统计消息数量 - */ - long countMessages(@Param("chatId") String chatId); - - /** - * 批量删除消息(根据对话ID) - */ - int deleteMessagesByChatId(@Param("chatId") String chatId); -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeFileLogMapper.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeFileLogMapper.java deleted file mode 100644 index e290c570..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeFileLogMapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.xyzh.ai.mapper; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.ai.dto.TbKnowledgeFile; -import org.xyzh.api.ai.dto.TbKnowledgeFileLog; -import org.xyzh.api.ai.vo.KnowledgeFileVO; -import org.xyzh.common.core.page.PageParam; - -import java.util.List; - -/** - * @description 知识库文件数据访问层 - * @filename KnowledgeFileMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Mapper -public interface TbKnowledgeFileLogMapper { - - int addKnowledgeFileLog(TbKnowledgeFileLog tbKnowledgeFileLog); - - List getKnowledgeFileLogList(@Param("filter") TbKnowledgeFileLog filter); - - List getKnowledgeFileLogPage(@Param("pageParam") PageParam pageParam,@Param("filter") TbKnowledgeFileLog filter); - - - int countKnowledgeFileLog(@Param("filter") TbKnowledgeFileLog filter); - -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeFileMapper.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeFileMapper.java deleted file mode 100644 index ddcdc5e9..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeFileMapper.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.xyzh.ai.mapper; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.ai.dto.TbKnowledgeFile; -import org.xyzh.api.ai.vo.KnowledgeFileVO; -import org.xyzh.common.core.page.PageParam; - -import java.util.List; - -/** - * @description 知识库文件数据访问层 - * @filename KnowledgeFileMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Mapper -public interface TbKnowledgeFileMapper { - - /** - * 插入知识库文件 - */ - int insertKnowledgeFile(TbKnowledgeFile file); - - /** - * 更新知识库文件 - */ - int updateKnowledgeFile(TbKnowledgeFile file); - - /** - * 逻辑删除知识库文件 - */ - int deleteKnowledgeFile(TbKnowledgeFile file); - - /** - * 根据知识库ID和文件ID查询 - */ - TbKnowledgeFile selectKnowledgeFile( - @Param("knowledgeId") String knowledgeId, - @Param("fileId") String fileId - ); - - /** - * 根据知识库ID查询文件列表(关联文件详细信息) - */ - List selectFilesByKnowledgeId(@Param("knowledgeId") String knowledgeId); - - /** - * 根据文件根ID查询所有版本 - */ - List selectFileVersions(@Param("fileRootId") String fileRootId); - - /** - * 分页查询知识库文件(关联文件详细信息) - */ - List selectFilePage( - @Param("knowledgeId") String knowledgeId, - @Param("pageParam") PageParam pageParam - ); - - /** - * 统计知识库文件数量 - */ - long countFiles(@Param("knowledgeId") String knowledgeId); - - /** - * 批量删除知识库文件(根据文件根ID) - */ - int deleteFilesByRootId(@Param("fileRootId") String fileRootId); - - /** - * 获取文件最新版本号 - */ - Integer selectLatestVersion( - @Param("knowledgeId") String knowledgeId, - @Param("fileRootId") String fileRootId - ); - - /** - * 根据文件根ID查询最大版本的文件 - */ - TbKnowledgeFile selectLatestVersionFile(@Param("fileRootId") String fileRootId); - - /** - * 根据文件根ID查询所有版本(包含文件详细信息) - */ - List selectFileVersionsWithDetail(@Param("fileRootId") String fileRootId); -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeMapper.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeMapper.java deleted file mode 100644 index 561b8412..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeMapper.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.xyzh.ai.mapper; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.ai.dto.TbKnowledge; -import org.xyzh.common.core.page.PageParam; - -import java.util.List; - -/** - * @description 知识库数据访问层 - * @filename KnowledgeMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Mapper -public interface TbKnowledgeMapper { - - /** - * 插入知识库 - */ - int insertKnowledge(TbKnowledge knowledge); - - /** - * 更新知识库 - */ - int updateKnowledge(TbKnowledge knowledge); - - /** - * 逻辑删除知识库 - */ - int deleteKnowledge(TbKnowledge knowledge); - - int updateKnowledgeFileCount(@Param("knowledgeId") String knowledgeId, @Param("num") Integer num); - - /** - * 根据ID查询知识库 - */ - TbKnowledge selectKnowledgeById(@Param("knowledgeId") String knowledgeId); - - /** - * 根据DifyDatasetId查询知识库 - */ - TbKnowledge selectKnowledgeByDifyId(@Param("difyDatasetId") String difyDatasetId); - - /** - * 查询知识库列表 - */ - List selectKnowledgeList(@Param("filter") TbKnowledge filter); - - /** - * 分页查询知识库 - */ - List selectKnowledgePage( - @Param("filter") TbKnowledge filter, - @Param("pageParam") PageParam pageParam - ); - - /** - * 统计知识库数量 - */ - long countKnowledges(@Param("filter") TbKnowledge filter); -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AIFileUploadServiceImpl.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AIFileUploadServiceImpl.java deleted file mode 100644 index a1c7d21a..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AIFileUploadServiceImpl.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.xyzh.ai.service.impl; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.StringUtils; -import org.springframework.web.multipart.MultipartFile; -import org.xyzh.ai.client.DifyApiClient; -import org.xyzh.ai.client.dto.DifyFileInfo; -import org.xyzh.ai.client.dto.DocumentUploadRequest; -import org.xyzh.ai.client.dto.DocumentUploadResponse; -import org.xyzh.api.ai.dto.TbAgent; -import org.xyzh.api.ai.service.AIFileUploadService; -import org.xyzh.api.ai.service.AgentService; -import org.xyzh.api.file.dto.TbSysFileDTO; -import org.xyzh.api.file.service.FileService; -import org.xyzh.common.auth.utils.LoginUtil; -import org.xyzh.common.core.domain.ResultDomain; - -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @description AI文件上传服务实现(同时上传到MinIO和Dify) - * @filename AIFileUploadServiceImpl.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@DubboService(version = "1.0.0", group = "ai", timeout = 30000, retries = 0) -public class AIFileUploadServiceImpl implements AIFileUploadService { - private static final Logger logger = LoggerFactory.getLogger(AIFileUploadServiceImpl.class); - - @Autowired - private DifyApiClient difyApiClient; - - @Autowired - private AgentService agentService; - - @DubboReference(version = "1.0.0", group = "file", timeout = 30000, retries = 0) - private FileService fileService; - - // ============================ 对话文件管理 ============================ - - @Override - public ResultDomain> uploadFileForChat(MultipartFile file, String agentId) { - // 1. 参数校验 - if (file == null || file.isEmpty()) { - return ResultDomain.failure("文件不能为空"); - } - if (!StringUtils.hasText(agentId)) { - return ResultDomain.failure("智能体ID不能为空"); - } - - // 2. 获取智能体API Key - ResultDomain agentResult = agentService.selectAgentById(agentId); - if (!agentResult.getSuccess() || agentResult.getData() == null) { - return ResultDomain.failure("智能体不存在"); - } - TbAgent agent = agentResult.getData(); - - // 3. 获取当前用户 - String userId = LoginUtil.getCurrentUserId(); - if (!StringUtils.hasText(userId)) { - userId = "anonymous"; - } - - File tempFile = null; - String sysFileId = null; - String sysFileUrl = null; - - try { - // 4. 上传到MinIO(通过FileService,使用字节数组方式) - byte[] fileBytes = file.getBytes(); - String fileName = file.getOriginalFilename(); - String contentType = file.getContentType(); - ResultDomain fileResult = fileService.uploadFileBytes(fileBytes, fileName, contentType, "ai-chat", agentId); - if (fileResult.getSuccess() && fileResult.getData() != null) { - TbSysFileDTO sysFile = fileResult.getData(); - sysFileId = sysFile.getFileId(); - sysFileUrl = sysFile.getUrl(); - logger.info("上传文件到MinIO成功: fileId={}, url={}", sysFileId, sysFileUrl); - } else { - logger.warn("上传文件到MinIO失败: {}", fileResult.getMessage()); - // MinIO上传失败不阻断流程,继续上传到Dify - } - - // 5. 将MultipartFile转换为临时File用于Dify上传 - tempFile = File.createTempFile("upload_", "_" + file.getOriginalFilename()); - file.transferTo(tempFile); - - // 6. 上传到Dify - DifyFileInfo difyFile = difyApiClient.uploadFileForChat(tempFile, file.getOriginalFilename(), userId, agent.getApiKey()); - if (difyFile != null && StringUtils.hasText(difyFile.getId())) { - logger.info("上传对话文件到Dify成功: agentId={}, difyFileId={}", agentId, difyFile.getId()); - - Map result = new HashMap<>(); - // Dify返回的信息 - result.put("id", difyFile.getId()); - result.put("name", difyFile.getName()); - result.put("size", difyFile.getSize()); - result.put("type", difyFile.getType()); - result.put("extension", difyFile.getExtension()); - result.put("mime_type", difyFile.getMimeType()); - result.put("upload_file_id", difyFile.getUploadFileId()); - // 系统文件信息(用于前端展示和数据库存储) - result.put("sys_file_id", sysFileId); - result.put("preview_url", sysFileUrl); - result.put("source_url", sysFileUrl); - - return ResultDomain.success("上传成功", result); - } - return ResultDomain.failure("上传文件到Dify失败"); - } catch (Exception e) { - logger.error("上传对话文件异常: {}", e.getMessage(), e); - return ResultDomain.failure("上传文件异常: " + e.getMessage()); - } finally { - if (tempFile != null && tempFile.exists()) { - tempFile.delete(); - } - } - } - - // ============================ 知识库Dify文档管理 ============================ - - /** - * @description 上传文件到Dify知识库(只负责Dify上传,不处理minio和数据库) - * @param difyDatasetId Dify知识库ID - * @param file 文件 - * @param fileName 文件名 - * @param indexingTechnique 索引方式 - * @return ResultDomain Dify文档ID - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain uploadFileToDify(String difyDatasetId, File file, String fileName, String indexingTechnique) { - if (!StringUtils.hasText(difyDatasetId)) { - return ResultDomain.failure("Dify知识库ID不能为空"); - } - if (file == null || !file.exists()) { - return ResultDomain.failure("文件不能为空"); - } - - try { - DocumentUploadRequest uploadRequest = new DocumentUploadRequest(); - uploadRequest.setName(fileName); - if (StringUtils.hasText(indexingTechnique)) { - uploadRequest.setIndexingTechnique(indexingTechnique); - } - - DocumentUploadResponse uploadResponse = difyApiClient.uploadDocumentByFile( - difyDatasetId, - file, - fileName, - uploadRequest - ); - - if (uploadResponse != null && uploadResponse.getDocument() != null) { - String difyDocumentId = uploadResponse.getDocument().getId(); - logger.info("上传文件到Dify成功: difyDatasetId={}, difyDocumentId={}", difyDatasetId, difyDocumentId); - return ResultDomain.success("上传成功", difyDocumentId); - } - return ResultDomain.failure("上传文件到Dify失败"); - } catch (Exception e) { - logger.error("上传文件到Dify异常: {}", e.getMessage(), e); - return ResultDomain.failure("上传文件到Dify异常: " + e.getMessage()); - } - } - - /** - * @description 从Dify知识库删除文档 - * @param difyDatasetId Dify知识库ID - * @param difyDocumentId Dify文档ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain deleteFileFromDify(String difyDatasetId, String difyDocumentId) { - if (!StringUtils.hasText(difyDatasetId)) { - return ResultDomain.failure("Dify知识库ID不能为空"); - } - if (!StringUtils.hasText(difyDocumentId)) { - return ResultDomain.failure("Dify文档ID不能为空"); - } - - try { - difyApiClient.deleteDocument(difyDatasetId, difyDocumentId); - logger.info("从Dify删除文档成功: difyDatasetId={}, difyDocumentId={}", difyDatasetId, difyDocumentId); - return ResultDomain.success("删除成功", true); - } catch (Exception e) { - logger.error("从Dify删除文档异常: {}", e.getMessage(), e); - return ResultDomain.failure("从Dify删除文档异常: " + e.getMessage()); - } - } - - /** - * @description 批量从Dify知识库删除文档 - * @param difyDatasetId Dify知识库ID - * @param difyDocumentIds Dify文档ID列表 - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain batchDeleteFilesFromDify(String difyDatasetId, List difyDocumentIds) { - if (!StringUtils.hasText(difyDatasetId)) { - return ResultDomain.failure("Dify知识库ID不能为空"); - } - if (difyDocumentIds == null || difyDocumentIds.isEmpty()) { - return ResultDomain.failure("Dify文档ID列表不能为空"); - } - - int successCount = 0; - int failCount = 0; - for (String difyDocumentId : difyDocumentIds) { - if (StringUtils.hasText(difyDocumentId)) { - try { - difyApiClient.deleteDocument(difyDatasetId, difyDocumentId); - successCount++; - } catch (Exception e) { - logger.warn("批量删除Dify文档失败: difyDocumentId={}, error={}", difyDocumentId, e.getMessage()); - failCount++; - } - } - } - - logger.info("批量从Dify删除文档完成: 成功={}, 失败={}", successCount, failCount); - if (failCount == 0) { - return ResultDomain.success("批量删除成功", true); - } else if (successCount == 0) { - return ResultDomain.failure("批量删除全部失败"); - } else { - return ResultDomain.success("部分删除成功", true); - } - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentChatServiceImpl.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentChatServiceImpl.java deleted file mode 100644 index f6e77cf2..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentChatServiceImpl.java +++ /dev/null @@ -1,773 +0,0 @@ -package org.xyzh.ai.service.impl; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; - -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; -import org.xyzh.ai.client.DifyApiClient; -import org.xyzh.ai.client.callback.StreamCallback; -import org.xyzh.ai.client.dto.ChatRequest; -import org.xyzh.ai.client.dto.ChatResponse; -import org.xyzh.ai.client.dto.WorkflowRunRequest; -import org.xyzh.ai.client.dto.WorkflowRunResponse; -import org.xyzh.ai.config.DifyConfig; -import org.xyzh.ai.mapper.TbChatMapper; -import org.xyzh.ai.mapper.TbChatMessageMapper; -import org.xyzh.api.ai.dto.ChatPrepareData; -import org.xyzh.api.ai.dto.DifyFileInfo; -import org.xyzh.api.ai.dto.TbAgent; -import org.xyzh.api.ai.dto.TbChat; -import org.xyzh.api.ai.dto.TbChatMessage; -import org.xyzh.api.ai.dto.TbKnowledge; -import org.xyzh.api.ai.service.AgentChatService; -import org.xyzh.api.ai.service.AgentService; -import org.xyzh.api.ai.service.KnowledgeService; -import org.xyzh.api.system.service.GuestService; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.redis.service.RedisService; -import org.xyzh.common.utils.NonUtils; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.auth.utils.LoginUtil; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * @description 智能体对话服务实现 - * @filename AgentChatServiceImpl.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@DubboService( - version = "1.0.0", - group = "ai", - timeout = 3000, - retries = 0 -) -public class AgentChatServiceImpl implements AgentChatService { - private static final Logger logger = LoggerFactory.getLogger(AgentChatServiceImpl.class); - - private static final String CHAT_SESSION_PREFIX = "ai:chat:session:"; - private static final String WORKFLOW_SESSION_PREFIX = "ai:workflow:session:"; - private static final long SESSION_TTL = 5 * 60; - - @Autowired - private TbChatMapper chatMapper; - - @Autowired - private TbChatMessageMapper chatMessageMapper; - - @Autowired - private AgentService agentService; - - @Autowired - private DifyApiClient difyApiClient; - - @Autowired - private RedisService redisService; - - @Autowired - private KnowledgeService knowledgeService; - - @Autowired - private DifyConfig difyConfig; - - /** - * @description 判断智能体是否是outer - * @param agentId 智能体ID - * @return true-是outer,false-不是outer - */ - private Boolean isOuterAgent(String agentId){ - // 智能体必须是outer - ResultDomain agentResult = agentService.selectAgentById(agentId); - if(!agentResult.getSuccess()|| agentResult.getData() == null || !agentResult.getData().getIsOuter()){ - return false; - } - return true; - } - - // ====================== 智能体会话管理 ====================== - - @Override - @Transactional(rollbackFor = Exception.class) - public ResultDomain createChat(TbChat chat) { - // 如果是来客(userType=false),校验智能体是否是 isOuter - if(!chat.getUserType()){ - if(!isOuterAgent(chat.getAgentId())){ - return ResultDomain.failure("智能体不可用"); - } - } - // 设置chat(来客传入的 userId 已经是真正的系统 userId) - chat.setOptsn(IdUtil.getOptsn()); - chat.setChatId(IdUtil.generateID()); - chatMapper.insertChat(chat); - return ResultDomain.success("创建成功", chat); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public ResultDomain updateChat(TbChat chat) { - // 1. 校验会话 - TbChat chat2 = chatMapper.selectChatById(chat.getChatId()); - if (chat2 == null) { - return ResultDomain.failure("会话不存在"); - } - // 判断agent是否是outer - if(!isOuterAgent(chat.getAgentId())){ - return ResultDomain.failure("智能体不可用"); - } - - // 2. 获取用户ID并校验权限 - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - String userId = loginDomain.getUser().getUserId(); - if (userId == null) { - return ResultDomain.failure("用户信息获取失败"); - } - if (!chat2.getUserId().equals(userId)) { - return ResultDomain.failure("无权修改此会话"); - } - - // 3. 更新会话 - TbChat update = new TbChat(); - update.setChatId(chat.getChatId()); - update.setTitle(chat.getTitle()); - - int rows = chatMapper.updateChat(update); - if (rows > 0) { - return ResultDomain.success("更新会话成功", update); - } - - return ResultDomain.failure("更新会话失败"); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public ResultDomain deleteChat(TbChat filter) { - // 1. 校验会话 - TbChat chat = chatMapper.selectChatById(filter.getChatId()); - if (chat == null) { - return ResultDomain.failure("会话不存在"); - } - // 判断agent是否是outer - if(!isOuterAgent(chat.getAgentId())){ - return ResultDomain.failure("智能体不可用"); - } - // 2. 获取用户ID并校验权限 - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - String userId = loginDomain.getUser().getUserId(); - if (userId == null) { - return ResultDomain.failure("用户信息获取失败"); - } - if (!chat.getUserId().equals(userId)) { - return ResultDomain.failure("无权删除此会话"); - } - - // 3. 删除会话消息 - chatMessageMapper.deleteMessagesByChatId(filter.getChatId()); - - // 4. 删除会话 - TbChat delete = new TbChat(); - delete.setChatId(filter.getChatId()); - int rows = chatMapper.deleteChat(delete); - if (rows > 0) { - logger.info("删除会话成功: chatId={}", filter.getChatId()); - return ResultDomain.success("删除会话成功", chat); - } - - return ResultDomain.failure("删除会话失败"); - } - - @Override - public ResultDomain getChatList(TbChat filter) { - - // 获取用户ID - String userId = LoginUtil.getCurrentUserId(); - if (userId == null) { - return ResultDomain.failure("用户信息获取失败"); - } - - List chatList = chatMapper.selectChatList(filter.getAgentId(), userId); - return ResultDomain.success("查询成功", chatList); - } - - @Override - public ResultDomain getChatPage(PageRequest pageRequest) { - TbChat filter = pageRequest.getFilter(); - // 判断agent是否是outer(来客才需要校验) - if (!filter.getUserType() && !isOuterAgent(filter.getAgentId())) { - return ResultDomain.failure("智能体不可用"); - } - // 获取用户ID - String userId = LoginUtil.getCurrentUserId(); - if (userId == null) { - return ResultDomain.failure("用户信息获取失败"); - } - filter.setUserId(userId); - - // 分页查询 - PageParam pageParam = pageRequest.getPageParam(); - List chatList = chatMapper.selectChatPage(filter, pageParam); - long total = chatMapper.countChats(filter); - pageParam.setTotal((int) total); - - PageDomain pageDomain = new PageDomain<>(pageParam, chatList); - return ResultDomain.success("查询成功", pageDomain); - } - - // ====================== 智能体聊天管理 ====================== - - @Override - public ResultDomain getChatMessageList(TbChat filter) { - // 1. 校验会话 - TbChat chat = chatMapper.selectChatById(filter.getChatId()); - if (chat == null) { - return ResultDomain.failure("会话不存在"); - } - // 判断agent是否是outer - if(!isOuterAgent(chat.getAgentId())){ - return ResultDomain.failure("智能体不可用"); - } - // 2. 获取用户ID并校验权限 - String userId = LoginUtil.getCurrentUserId(); - if (userId == null) { - return ResultDomain.failure("用户信息获取失败"); - } - if (!chat.getUserId().equals(userId)) { - return ResultDomain.failure("无权查看此会话"); - } - - List messages = chatMessageMapper.selectMessagesByChatId(filter.getChatId()); - return ResultDomain.success("查询成功", messages); - } - - @Override - public ResultDomain prepareChatMessageSession(ChatPrepareData prepareData) { - String agentId = prepareData.getAgentId(); - String chatId = prepareData.getChatId(); - String query = prepareData.getQuery(); - - // 1. 校验智能体 - ResultDomain agentResult = agentService.selectAgentById(agentId); - if (!agentResult.getSuccess() || agentResult.getData() == null || !agentResult.getData().getIsOuter()) { - return ResultDomain.failure("智能体不存在或不可用"); - } - TbAgent agent = agentResult.getData(); - - // 2. 获取用户ID(根据userType处理来客/员工) - TbChat chatFilter = new TbChat(); - chatFilter.setAgentId(agentId); - chatFilter.setUserId(prepareData.getUserId()); - chatFilter.setUserType(prepareData.getUserType()); - - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - String userId = loginDomain.getUser().getUserId(); - if (userId == null) { - return ResultDomain.failure("用户信息获取失败"); - } - - // 3. 校验会话 - if (StringUtils.hasText(chatId)) { - TbChat chat = chatMapper.selectChatById(chatId); - if (chat == null) { - return ResultDomain.failure("会话不存在"); - } - if (!chat.getUserId().equals(userId)) { - return ResultDomain.failure("无权操作此会话"); - } - } - - // 4. 生成临时消息ID(sessionId) - String sessionId = IdUtil.getSnowflakeId(); - - // 5. 准备 inputs 参数 - Map inputsMap = prepareData.getInputsMap(); - if (inputsMap == null) { - inputsMap = new HashMap<>(); - } - - // 处理动态知识库 - Boolean isGuest = "guest".equals(loginDomain.getUser().getStatus()); - if (agent.getIsOuter() && NonUtils.isNotEmpty(prepareData.getService())) { - TbKnowledge filter = new TbKnowledge(); - filter.setService(prepareData.getService()); - filter.setCategory(isGuest ? "external" : "internal"); - ResultDomain knowledgeRD = knowledgeService.listKnowledges(filter); - List datasets = new ArrayList<>(); - if (knowledgeRD.getSuccess()) { - datasets = knowledgeRD.getDataList().stream() - .map(TbKnowledge::getDifyDatasetId) - .toList(); - } - inputsMap.put("datasets", JSON.toJSONString(datasets)); - inputsMap.put("dataset_apikey", difyConfig.getKnowledgeApiKey()); - } - - // 6. 存储会话数据到Redis - Map sessionData = new HashMap<>(); - sessionData.put("agentId", agentId); - sessionData.put("chatId", chatId); - sessionData.put("query", query); - sessionData.put("userId", userId); - sessionData.put("filesData", prepareData.getFiles()); - sessionData.put("apiKey", agent.getApiKey()); - sessionData.put("outer", agent.getIsOuter()); - sessionData.put("service", prepareData.getService()); - sessionData.put("isGuest", isGuest); - sessionData.put("inputsMap", inputsMap); // 存储处理好的 inputs - sessionData.put("appType", prepareData.getAppType()); // 存储应用类型 - - // 根据应用类型选择不同的Redis key前缀 - String appType = prepareData.getAppType(); - String prefix = "workflow".equals(appType) ? WORKFLOW_SESSION_PREFIX : CHAT_SESSION_PREFIX; - String cacheKey = prefix + sessionId; - redisService.set(cacheKey, sessionData, SESSION_TTL, TimeUnit.SECONDS); - - logger.info("准备{}会话: sessionId={}, agentId={}", appType, sessionId, agentId); - return ResultDomain.success("准备成功", sessionId); - } - - @Override - public SseEmitter streamChatMessageWithSse(String sessionId) { - SseEmitter emitter = new SseEmitter(300000L); - - // 1. 从Redis获取会话数据 - String cacheKey = CHAT_SESSION_PREFIX + sessionId; - @SuppressWarnings("unchecked") - Map sessionData = redisService.get(cacheKey, Map.class); - - if (sessionData == null) { - try { - emitter.send(SseEmitter.event().name("error").data("{\"message\":\"会话已过期\"}")); - emitter.complete(); - } catch (IOException e) { - logger.error("发送错误事件失败", e); - } - return emitter; - } - - // 2. 解析会话数据 - String agentId = (String) sessionData.get("agentId"); - String chatId = (String) sessionData.get("chatId"); - String query = (String) sessionData.get("query"); - String userId = (String) sessionData.get("userId"); - String apiKey = (String) sessionData.get("apiKey"); - - @SuppressWarnings("unchecked") - Map inputsMap = (Map) sessionData.get("inputsMap"); - - @SuppressWarnings("unchecked") - List filesData = (List) sessionData.get("filesData"); - - // 3. 删除已使用的会话数据 - redisService.delete(cacheKey); - - // 4. 保存用户消息 - String userMessageId = IdUtil.getSnowflakeId(); - TbChatMessage userMessage = new TbChatMessage(); - userMessage.setOptsn(IdUtil.getOptsn()); - userMessage.setMessageId(userMessageId); - userMessage.setChatId(chatId); - userMessage.setRole("user"); - userMessage.setContent(query); - - // 提取系统文件ID列表保存到消息中 - if (filesData != null && !filesData.isEmpty()) { - List sysFileIds = filesData.stream() - .map(DifyFileInfo::getSysFileId) - .filter(StringUtils::hasText) - .collect(java.util.stream.Collectors.toList()); - if (!sysFileIds.isEmpty()) { - userMessage.setFiles(sysFileIds); - } - } - - chatMessageMapper.insertChatMessage(userMessage); - - // 5. 构建Dify请求 - ChatRequest chatRequest = new ChatRequest(); - chatRequest.setQuery(query); - chatRequest.setUser(userId); - chatRequest.setResponseMode("streaming"); - - // 使用从Redis获取的inputsMap,如果为空则创建新的 - if (inputsMap == null) { - inputsMap = new HashMap<>(); - } - chatRequest.setInputs(inputsMap); // Dify API 要求 inputs 必传 - - if (filesData != null && !filesData.isEmpty()) { - chatRequest.setFiles(filesData); - } - - // 6. 准备AI消息记录 - String aiMessageId = IdUtil.getSnowflakeId(); - StringBuilder aiContent = new StringBuilder(); - - // 7. 发起流式请求 - difyApiClient.streamChat(chatRequest, apiKey, new StreamCallback() { - @Override - public void onEvent(String event, String data) { - try { - // 使用SseEmitter标准格式发送:event: xxx\ndata: xxx - emitter.send(SseEmitter.event().name(event).data(data)); - } catch (IOException e) { - logger.error("发送SSE事件失败: event={}", event, e); - } - } - - @Override - public void onMessage(String content) { - aiContent.append(content); - } - - @Override - public void onMessageEnd(String data) { - // 从message_end事件中提取difyMessageId - String difyMessageId = null; - try { - JSONObject json = JSONObject.parseObject(data); - if (json != null && json.containsKey("message_id")) { - difyMessageId = json.getString("message_id"); - } - } catch (Exception e) { - logger.warn("解析difyMessageId失败: {}", e.getMessage()); - } - - // 保存AI回复消息 - TbChatMessage aiMessage = new TbChatMessage(); - aiMessage.setOptsn(IdUtil.getOptsn()); - aiMessage.setMessageId(aiMessageId); - aiMessage.setDifyMessageId(difyMessageId); - aiMessage.setChatId(chatId); - aiMessage.setRole("ai"); - aiMessage.setContent(aiContent.toString()); - chatMessageMapper.insertChatMessage(aiMessage); - - logger.info("对话完成: chatId={}, aiMessageId={}, difyMessageId={}", chatId, aiMessageId, difyMessageId); - } - - @Override - public void onComplete() { - try { - emitter.complete(); - } catch (Exception e) { - logger.error("完成SSE失败", e); - } - } - - @Override - public void onError(Throwable throwable) { - logger.error("流式对话异常", throwable); - try { - JSONObject errorData = new JSONObject(); - errorData.put("message", throwable.getMessage()); - emitter.send(SseEmitter.event().name("error").data(errorData.toJSONString())); - emitter.complete(); - } catch (IOException e) { - logger.error("发送错误事件失败", e); - } - } - }); - - return emitter; - } - - @Override - public ResultDomain blockingChatMessageWithSession(String sessionId) { - try { - // 1. 从Redis获取会话数据 - String cacheKey = CHAT_SESSION_PREFIX + sessionId; - @SuppressWarnings("unchecked") - Map sessionData = redisService.get(cacheKey, Map.class); - - if (sessionData == null) { - return ResultDomain.failure("会话已过期"); - } - - // 2. 解析会话数据 - String agentId = (String) sessionData.get("agentId"); - String chatId = (String) sessionData.get("chatId"); - String query = (String) sessionData.get("query"); - String userId = (String) sessionData.get("userId"); - String apiKey = (String) sessionData.get("apiKey"); - - @SuppressWarnings("unchecked") - Map inputsMap = (Map) sessionData.get("inputsMap"); - - @SuppressWarnings("unchecked") - List filesData = (List) sessionData.get("filesData"); - - // 3. 删除已使用的会话数据 - redisService.delete(cacheKey); - - // 4. 保存用户消息(如果有 chatId 的话) - if (StringUtils.hasText(chatId)) { - String userMessageId = IdUtil.getSnowflakeId(); - TbChatMessage userMessage = new TbChatMessage(); - userMessage.setOptsn(IdUtil.getOptsn()); - userMessage.setMessageId(userMessageId); - userMessage.setChatId(chatId); - userMessage.setRole("user"); - userMessage.setContent(query); - - // 提取系统文件ID列表保存到消息中 - if (filesData != null && !filesData.isEmpty()) { - List sysFileIds = filesData.stream() - .map(DifyFileInfo::getSysFileId) - .filter(StringUtils::hasText) - .collect(java.util.stream.Collectors.toList()); - if (!sysFileIds.isEmpty()) { - userMessage.setFiles(sysFileIds); - } - } - - chatMessageMapper.insertChatMessage(userMessage); - } - - // 5. 构建Dify请求 - ChatRequest chatRequest = new ChatRequest(); - chatRequest.setQuery(query); - chatRequest.setUser(userId); - chatRequest.setResponseMode("blocking"); - - // 使用从Redis获取的inputsMap,如果为空则创建新的 - if (inputsMap == null) { - inputsMap = new HashMap<>(); - } - chatRequest.setInputs(inputsMap); // Dify API 要求 inputs 必传 - - if (filesData != null && !filesData.isEmpty()) { - chatRequest.setFiles(filesData); - } - - // 6. 调用Dify阻塞式接口 - logger.info("调用Dify阻塞式接口: agentId={}, userId={}", agentId, userId); - ChatResponse chatResponse = difyApiClient.blockingChat(chatRequest, apiKey); - - if (chatResponse == null || chatResponse.getAnswer() == null) { - return ResultDomain.failure("工作流返回结果为空"); - } - - String answer = chatResponse.getAnswer(); - - // 7. 保存AI回复消息(如果有 chatId 的话) - if (StringUtils.hasText(chatId)) { - String aiMessageId = IdUtil.getSnowflakeId(); - TbChatMessage aiMessage = new TbChatMessage(); - aiMessage.setOptsn(IdUtil.getOptsn()); - aiMessage.setMessageId(aiMessageId); - aiMessage.setDifyMessageId(chatResponse.getMessageId()); - aiMessage.setChatId(chatId); - aiMessage.setRole("ai"); - aiMessage.setContent(answer); - chatMessageMapper.insertChatMessage(aiMessage); - - logger.info("阻塞式对话完成: chatId={}, aiMessageId={}", chatId, aiMessageId); - } else { - logger.info("阻塞式对话完成(无chatId): userId={}", userId); - } - - return ResultDomain.success("对话成功", answer); - - } catch (Exception e) { - logger.error("阻塞式对话异常: sessionId={}", sessionId, e); - return ResultDomain.failure("对话失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain stopChatMessageByTaskId(TbChat filter, String taskId) { - // 1. 获取智能体 - ResultDomain agentResult = agentService.selectAgentById(filter.getAgentId()); - if (!agentResult.getSuccess() || agentResult.getData() == null || !agentResult.getData().getIsOuter()) { - return ResultDomain.failure("智能体不存在"); - } - TbAgent agent = agentResult.getData(); - - // 2. 获取用户ID - String userId = LoginUtil.getCurrentUserId(); - if (userId == null) { - return ResultDomain.failure("用户信息获取失败"); - } - - try { - // 3. 调用Dify停止接口 - difyApiClient.stopChatMessage(taskId, userId, agent.getApiKey()); - logger.info("停止对话成功: taskId={}", taskId); - return ResultDomain.success("停止成功", true); - } catch (Exception e) { - logger.error("停止对话失败: taskId={}", taskId, e); - return ResultDomain.failure("停止对话失败: " + e.getMessage()); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public ResultDomain commentChatMessage(TbChat filter, String messageId, String comment) { - // 1. 校验消息 - TbChatMessage message = chatMessageMapper.selectMessageById(messageId); - if (message == null) { - return ResultDomain.failure("消息不存在"); - } - - // 2. 获取用户ID - String userId = LoginUtil.getCurrentUserId(); - if (userId == null) { - return ResultDomain.failure("用户信息获取失败"); - } - - // 3. 更新评价 - TbChatMessage update = new TbChatMessage(); - update.setMessageId(messageId); - update.setComment(comment); - - int rows = chatMessageMapper.updateChatMessage(update); - if (rows > 0) { - // 4. 同步到Dify(转换评价格式,使用difyMessageId) - if (StringUtils.hasText(message.getDifyMessageId())) { - ResultDomain agentResult = agentService.selectAgentById(filter.getAgentId()); - if (agentResult.getSuccess() && agentResult.getData() != null) { - TbAgent agent = agentResult.getData(); - String rating = "like".equals(comment) ? "like" : ("dislike".equals(comment) ? "dislike" : null); - try { - difyApiClient.submitMessageFeedback(message.getDifyMessageId(), rating, userId, comment, agent.getApiKey()); - } catch (Exception e) { - logger.warn("同步评价到Dify失败: difyMessageId={}", message.getDifyMessageId(), e); - } - } - } - - logger.info("评价消息成功: messageId={}, comment={}", messageId, comment); - return ResultDomain.success("评价成功", true); - } - - return ResultDomain.failure("评价失败"); - } - - @Override - public ResultDomain runWorkflowWithSession(String sessionId) { - try { - // 1. 从Redis获取会话数据(使用workflow前缀) - String cacheKey = WORKFLOW_SESSION_PREFIX + sessionId; - Map sessionData = redisService.get(cacheKey, Map.class); - - if (sessionData == null) { - return ResultDomain.failure("会话已过期"); - } - - // 2. 解析会话数据 - String agentId = (String) sessionData.get("agentId"); - String userId = (String) sessionData.get("userId"); - String apiKey = (String) sessionData.get("apiKey"); - Map inputsMap = (Map) sessionData.get("inputsMap"); - - // 3. 删除已使用的会话数据 - redisService.delete(cacheKey); - - // 4. 构建工作流请求 - WorkflowRunRequest workflowRequest = new WorkflowRunRequest(); - workflowRequest.setInputs(inputsMap != null ? inputsMap : new HashMap<>()); - workflowRequest.setResponseMode("blocking"); - workflowRequest.setUser(userId); - - logger.info("执行工作流: agentId={}, userId={}, sessionId={}", agentId, userId, sessionId); - - // 5. 调用Dify工作流接口 - WorkflowRunResponse workflowResponse = difyApiClient.runWorkflowBlocking(workflowRequest, apiKey); - - if (workflowResponse == null || workflowResponse.getData() == null) { - return ResultDomain.failure("工作流执行失败:返回结果为空"); - } - - // 6. 检查工作流执行状态 - String status = workflowResponse.getData().getStatus(); - if (!"succeeded".equals(status)) { - String error = workflowResponse.getData().getError(); - logger.error("工作流执行失败: status={}, error={}", status, error); - return ResultDomain.failure("工作流执行失败: " + (error != null ? error : status)); - } - - // 7. 提取outputs - Map outputs = workflowResponse.getData().getOutputs(); - if (outputs == null) { - return ResultDomain.failure("工作流执行失败:outputs为空"); - } - - // 8. 将outputs转为JSON字符串返回 - String outputsJson = JSON.toJSONString(outputs); - logger.info("工作流执行成功: agentId={}, workflowRunId={}", agentId, workflowResponse.getWorkflowRunId()); - - return ResultDomain.success("工作流执行成功", outputsJson); - - } catch (Exception e) { - logger.error("工作流执行异常: sessionId={}", sessionId, e); - return ResultDomain.failure("工作流执行异常: " + e.getMessage()); - } - } - - @Override - public ResultDomain runWorkflowBlocking(String agentId, Map inputs, String userId) { - try { - // 1. 获取智能体信息 - ResultDomain agentResult = agentService.selectAgentById(agentId); - if (!agentResult.getSuccess() || agentResult.getData() == null) { - return ResultDomain.failure("智能体不存在"); - } - TbAgent agent = agentResult.getData(); - - // 2. 构建工作流请求 - WorkflowRunRequest workflowRequest = new WorkflowRunRequest(); - workflowRequest.setInputs(inputs); - workflowRequest.setResponseMode("blocking"); - workflowRequest.setUser(userId); - - logger.info("执行工作流: agentId={}, userId={}, inputs={}", agentId, userId, JSON.toJSONString(inputs)); - - // 3. 调用Dify工作流接口 - WorkflowRunResponse workflowResponse = difyApiClient.runWorkflowBlocking(workflowRequest, agent.getApiKey()); - - if (workflowResponse == null || workflowResponse.getData() == null) { - return ResultDomain.failure("工作流执行失败:返回结果为空"); - } - - // 4. 检查工作流执行状态 - String status = workflowResponse.getData().getStatus(); - if (!"succeeded".equals(status)) { - String error = workflowResponse.getData().getError(); - logger.error("工作流执行失败: status={}, error={}", status, error); - return ResultDomain.failure("工作流执行失败: " + (error != null ? error : status)); - } - - // 5. 提取outputs - Map outputs = workflowResponse.getData().getOutputs(); - if (outputs == null) { - return ResultDomain.failure("工作流执行失败:outputs为空"); - } - - // 6. 将outputs转为JSON字符串返回 - String outputsJson = JSON.toJSONString(outputs); - logger.info("工作流执行成功: agentId={}, workflowRunId={}", agentId, workflowResponse.getWorkflowRunId()); - - return ResultDomain.success("工作流执行成功", outputsJson); - - } catch (Exception e) { - logger.error("工作流执行异常: agentId={}, userId={}", agentId, userId, e); - return ResultDomain.failure("工作流执行异常: " + e.getMessage()); - } - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentServiceImpl.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentServiceImpl.java deleted file mode 100644 index 8684ab2c..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentServiceImpl.java +++ /dev/null @@ -1,253 +0,0 @@ -package org.xyzh.ai.service.impl; - -import lombok.extern.slf4j.Slf4j; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; -import org.xyzh.ai.mapper.TbAgentMapper; -import org.xyzh.api.ai.dto.TbAgent; -import org.xyzh.api.ai.service.AgentService; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.redis.service.RedisService; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.auth.utils.LoginUtil; - -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; - -/** - * @description 智能体服务实现 - * @filename AgentServiceImpl.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@DubboService(version = "1.0.0", group = "ai", timeout = 3000, retries = 0) -public class AgentServiceImpl implements AgentService { - private static final Logger logger = LoggerFactory.getLogger(AgentServiceImpl.class); - - private static final String AGENT_CACHE_PREFIX = "ai:agent:"; - private static final long AGENT_CACHE_TTL = 24 * 60 * 60; - - private final ReentrantLock agentLock = new ReentrantLock(); - - @Autowired - private TbAgentMapper agentMapper; - - @Autowired - private RedisService redisService; - - @Override - @Transactional(rollbackFor = Exception.class) - public ResultDomain addAgent(TbAgent tbAgent) { - // 1. 参数校验 - if (!StringUtils.hasText(tbAgent.getName())) { - return ResultDomain.failure("智能体名称不能为空"); - } - if (!StringUtils.hasText(tbAgent.getApiKey())) { - return ResultDomain.failure("智能体API Key不能为空"); - } - if (!StringUtils.hasText(tbAgent.getIntroduce())) { - return ResultDomain.failure("引导词不能为空"); - } - if (!StringUtils.hasText(tbAgent.getCategory())) { - return ResultDomain.failure("分类不能为空"); - } - - // 2. 检查名称是否重复 - int count = agentMapper.countByName(tbAgent.getName(), null); - if (count > 0) { - return ResultDomain.failure("智能体名称已存在"); - } - - // 3. 检查ApiKey是否重复 - TbAgent existAgent = agentMapper.selectAgentByApiKey(tbAgent.getApiKey()); - if (existAgent != null) { - return ResultDomain.failure("该API Key已被使用"); - } - - // 4. 生成ID和流水号 - tbAgent.setOptsn(IdUtil.getOptsn()); - tbAgent.setAgentId(IdUtil.getSnowflakeId()); - - // 5. 设置创建者 - String userId = LoginUtil.getCurrentUserId(); - if (StringUtils.hasText(userId)) { - tbAgent.setCreator(userId); - } - - // 6. 插入数据库 - int rows = agentMapper.insertAgent(tbAgent); - if (rows > 0) { - logger.info("创建智能体成功: agentId={}, name={}", tbAgent.getAgentId(), tbAgent.getName()); - return ResultDomain.success("创建智能体成功", tbAgent); - } - - return ResultDomain.failure("创建智能体失败"); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public ResultDomain updateAgent(TbAgent tbAgent) { - // 1. 参数校验 - if (!StringUtils.hasText(tbAgent.getAgentId())) { - return ResultDomain.failure("智能体ID不能为空"); - } - - // 2. 检查是否存在 - TbAgent existAgent = agentMapper.selectAgentById(tbAgent.getAgentId()); - if (existAgent == null) { - return ResultDomain.failure("智能体不存在"); - } - - // 3. 检查名称是否重复(排除自身) - if (StringUtils.hasText(tbAgent.getName())) { - int count = agentMapper.countByName(tbAgent.getName(), tbAgent.getAgentId()); - if (count > 0) { - return ResultDomain.failure("智能体名称已存在"); - } - } - - // 4. 加锁更新(避免并发问题) - agentLock.lock(); - try { - // 5. 设置更新者 - String userId = LoginUtil.getCurrentUserId(); - if (StringUtils.hasText(userId)) { - tbAgent.setUpdater(userId); - } - - // 6. 更新数据库 - int rows = agentMapper.updateAgent(tbAgent); - if (rows > 0) { - // 7. 返回最新数据 - TbAgent updated = agentMapper.selectAgentById(tbAgent.getAgentId()); - // 8. 更新缓存 - String cacheKey = AGENT_CACHE_PREFIX + tbAgent.getAgentId(); - logger.info("更新智能体成功: agentId={}", tbAgent.getAgentId()); - redisService.set(cacheKey, updated); - return ResultDomain.success("更新智能体成功", updated); - } - } finally { - agentLock.unlock(); - } - - return ResultDomain.failure("更新智能体失败"); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public ResultDomain deleteAgent(TbAgent tbAgent) { - // 1. 参数校验 - if (!StringUtils.hasText(tbAgent.getAgentId())) { - return ResultDomain.failure("智能体ID不能为空"); - } - - // 2. 检查是否存在 - TbAgent existAgent = agentMapper.selectAgentById(tbAgent.getAgentId()); - if (existAgent == null) { - return ResultDomain.failure("智能体不存在"); - } - - // 3. 设置更新者 - String userId = LoginUtil.getCurrentUserId(); - if (StringUtils.hasText(userId)) { - tbAgent.setUpdater(userId); - } - - // 4. 逻辑删除 - int rows = agentMapper.deleteAgent(tbAgent); - if (rows > 0) { - // 5. 删除缓存 - String cacheKey = AGENT_CACHE_PREFIX + tbAgent.getAgentId(); - redisService.delete(cacheKey); - - logger.info("删除智能体成功: agentId={}", tbAgent.getAgentId()); - return ResultDomain.success("删除智能体成功", existAgent); - } - - return ResultDomain.failure("删除智能体失败"); - } - - /** - * 根据ID获取智能体(优先从缓存获取,双检加锁) - */ - public ResultDomain selectAgentById(String agentId) { - if (!StringUtils.hasText(agentId)) { - return ResultDomain.failure("智能体ID不能为空"); - } - - String cacheKey = AGENT_CACHE_PREFIX + agentId; - - // 1. 先从缓存获取 - TbAgent agent = redisService.get(cacheKey, TbAgent.class); - if (agent != null) { - return ResultDomain.success("查询成功", agent); - } - - // 2. 双检加锁 - agentLock.lock(); - try { - // 再次检查缓存 - agent = redisService.get(cacheKey, TbAgent.class); - if (agent != null) { - return ResultDomain.success("查询成功", agent); - } - - // 3. 从数据库获取 - agent = agentMapper.selectAgentById(agentId); - if (agent != null) { - // 4. 写入缓存 - redisService.set(cacheKey, agent); - return ResultDomain.success("查询成功", agent); - } - - return ResultDomain.failure("智能体不存在"); - } finally { - agentLock.unlock(); - } - } - - /** - * 根据ApiKey获取智能体 - */ - public TbAgent getAgentByApiKey(String apiKey) { - if (!StringUtils.hasText(apiKey)) { - return null; - } - return agentMapper.selectAgentByApiKey(apiKey); - } - - @Override - public ResultDomain getAgentPage(PageRequest pageRequest) { - TbAgent filter = pageRequest.getFilter(); - PageParam pageParam = pageRequest.getPageParam(); - - // 查询总数 - long total = agentMapper.countAgents(filter); - pageParam.setTotal((int) total); - - // 查询分页数据 - List list = agentMapper.selectAgentPage(filter, pageParam); - - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - - @Override - public ResultDomain getAgentList(TbAgent filter) { - // 查询列表 - List list = agentMapper.selectAgentList(filter); - - ResultDomain result = ResultDomain.success("查询成功"); - result.setDataList(list); - return result; - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/DifyProxyServiceImpl.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/DifyProxyServiceImpl.java deleted file mode 100644 index c5f1bd50..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/DifyProxyServiceImpl.java +++ /dev/null @@ -1,165 +0,0 @@ -package org.xyzh.ai.service.impl; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; -import lombok.extern.slf4j.Slf4j; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; -import org.xyzh.ai.client.DifyApiClient; -import org.xyzh.api.ai.service.DifyProxyService; -import org.xyzh.common.core.domain.ResultDomain; - -import java.util.Map; - -/** - * @description Dify代理服务实现(直接转发请求到Dify API) - * @filename DifyProxyServiceImpl.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@DubboService(version="1.0.0", group="ai", timeout=3000, retries=0) -public class DifyProxyServiceImpl implements DifyProxyService { - private static final Logger logger = LoggerFactory.getLogger(DifyProxyServiceImpl.class); - - @Autowired - private DifyApiClient difyApiClient; - - @Override - public ResultDomain getDocumentSegments(String datasetId, String documentId) { - // 1. 参数校验 - if (!StringUtils.hasText(datasetId)) { - return ResultDomain.failure("数据集ID不能为空"); - } - if (!StringUtils.hasText(documentId)) { - return ResultDomain.failure("文档ID不能为空"); - } - - try { - // 2. 调用Dify API获取分段 - String url = String.format("/datasets/%s/documents/%s/segments", datasetId, documentId); - String response = difyApiClient.get(url, null); - - if (StringUtils.hasText(response)) { - JSONObject result = JSON.parseObject(response); - logger.info("获取文档分段成功: datasetId={}, documentId={}", datasetId, documentId); - return ResultDomain.success("查询成功", result); - } - - return ResultDomain.failure("获取文档分段失败"); - } catch (Exception e) { - logger.error("获取文档分段异常: datasetId={}, documentId={}, error={}", datasetId, documentId, e.getMessage(), e); - return ResultDomain.failure("获取文档分段异常: " + e.getMessage()); - } - } - - @Override - public ResultDomain updateSegment(String datasetId, String documentId, String segmentId, Map requestBody) { - // 1. 参数校验 - if (!StringUtils.hasText(datasetId)) { - return ResultDomain.failure("数据集ID不能为空"); - } - if (!StringUtils.hasText(documentId)) { - return ResultDomain.failure("文档ID不能为空"); - } - if (!StringUtils.hasText(segmentId)) { - return ResultDomain.failure("分段ID不能为空"); - } - - try { - // 2. 调用Dify API更新分段 - String url = String.format("/datasets/%s/documents/%s/segments/%s", datasetId, documentId, segmentId); - String response = difyApiClient.patch(url, requestBody, null); - - logger.info("更新分段成功: datasetId={}, documentId={}, segmentId={}", datasetId, documentId, segmentId); - return ResultDomain.success("更新成功", response); - } catch (Exception e) { - logger.error("更新分段异常: datasetId={}, documentId={}, segmentId={}, error={}", - datasetId, documentId, segmentId, e.getMessage(), e); - return ResultDomain.failure("更新分段异常: " + e.getMessage()); - } - } - - @Override - public ResultDomain createSegment(String datasetId, String documentId, Map requestBody) { - // 1. 参数校验 - if (!StringUtils.hasText(datasetId)) { - return ResultDomain.failure("数据集ID不能为空"); - } - if (!StringUtils.hasText(documentId)) { - return ResultDomain.failure("文档ID不能为空"); - } - - try { - // 2. 调用Dify API创建分段 - String url = String.format("/datasets/%s/documents/%s/segments", datasetId, documentId); - String response = difyApiClient.post(url, requestBody, null); - - logger.info("创建分段成功: datasetId={}, documentId={}", datasetId, documentId); - return ResultDomain.success("创建成功", response); - } catch (Exception e) { - logger.error("创建分段异常: datasetId={}, documentId={}, error={}", datasetId, documentId, e.getMessage(), e); - return ResultDomain.failure("创建分段异常: " + e.getMessage()); - } - } - - @Override - public ResultDomain deleteSegment(String datasetId, String documentId, String segmentId) { - // 1. 参数校验 - if (!StringUtils.hasText(datasetId)) { - return ResultDomain.failure("数据集ID不能为空"); - } - if (!StringUtils.hasText(documentId)) { - return ResultDomain.failure("文档ID不能为空"); - } - if (!StringUtils.hasText(segmentId)) { - return ResultDomain.failure("分段ID不能为空"); - } - - try { - // 2. 调用Dify API删除分段 - String url = String.format("/datasets/%s/documents/%s/segments/%s", datasetId, documentId, segmentId); - String response = difyApiClient.delete(url, null); - - logger.info("删除分段成功: datasetId={}, documentId={}, segmentId={}", datasetId, documentId, segmentId); - return ResultDomain.success("删除成功", response); - } catch (Exception e) { - logger.error("删除分段异常: datasetId={}, documentId={}, segmentId={}, error={}", - datasetId, documentId, segmentId, e.getMessage(), e); - return ResultDomain.failure("删除分段异常: " + e.getMessage()); - } - } - - @Override - public ResultDomain updateDocumentStatus(String datasetId, String action, Map requestBody) { - // 1. 参数校验 - if (!StringUtils.hasText(datasetId)) { - return ResultDomain.failure("数据集ID不能为空"); - } - if (!StringUtils.hasText(action)) { - return ResultDomain.failure("操作类型不能为空"); - } - - // 校验action合法性 - if (!action.equals("enable") && !action.equals("disable") && - !action.equals("archive") && !action.equals("un_archive")) { - return ResultDomain.failure("操作类型不合法,支持:enable/disable/archive/un_archive"); - } - - try { - // 2. 调用Dify API更新文档状态 - String url = String.format("/datasets/%s/documents/%s/status", datasetId, action); - String response = difyApiClient.patch(url, requestBody, null); - - logger.info("更新文档状态成功: datasetId={}, action={}", datasetId, action); - return ResultDomain.success("更新成功", response); - } catch (Exception e) { - logger.error("更新文档状态异常: datasetId={}, action={}, error={}", datasetId, action, e.getMessage(), e); - return ResultDomain.failure("更新文档状态异常: " + e.getMessage()); - } - } -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeFileLogServiceImpl.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeFileLogServiceImpl.java deleted file mode 100644 index 66dbb6c1..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeFileLogServiceImpl.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.xyzh.ai.service.impl; - -import java.util.Arrays; -import java.util.List; - -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.ai.mapper.TbKnowledgeFileLogMapper; -import org.xyzh.api.ai.dto.TbKnowledgeFileLog; -import org.xyzh.api.ai.service.KnowledgeFileLogService; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.NonUtils; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.validation.ValidationResult; -import org.xyzh.common.utils.validation.ValidationUtils; - -@DubboService(version="1.0.0", group="ai", timeout=3000, retries=0) -public class KnowledgeFileLogServiceImpl implements KnowledgeFileLogService{ - - private static final Logger logger = LoggerFactory.getLogger(KnowledgeServiceImpl.class); - - @Autowired - private TbKnowledgeFileLogMapper knowledgeFileLogMapper; - - /** - * @description 新增知识库文件操作日志 - * @param knowledgeFileLog - * @return 日志 - * @author yslg - * @since 2025-12-31 - */ - @Override - public ResultDomain addKnowledgeFileLog(TbKnowledgeFileLog knowledgeFileLog){ - knowledgeFileLog.setOptsn(IdUtil.getOptsn()); - knowledgeFileLog.setLogId(IdUtil.generateID()); - ValidationResult rt = ValidationUtils.validate(knowledgeFileLog, Arrays.asList( - ValidationUtils.requiredString("fileId", "文件id") - )); - if(!rt.isValid()){ - return ResultDomain.failure("日志参数校验失败"); - } - int result = knowledgeFileLogMapper.addKnowledgeFileLog(knowledgeFileLog); - if(result >0){ - return ResultDomain.success("添加知识库文件日志成功", knowledgeFileLog); - }else { - return ResultDomain.failure("添加知识库文件日志失败"); - } - } - - /** - * @description 查询知识库日志操作列表 - * @param filter - * @return 日志列表 - * @author yslg - * @since 2025-12-31 - */ - @Override - public ResultDomain getKnowledgeFileLogList(TbKnowledgeFileLog filter){ - List logs = knowledgeFileLogMapper.getKnowledgeFileLogList(filter); - return ResultDomain.success("查询知识库日志成功",logs); - } - - /** - * @description 查询知识库日志操作分页 - * @param pageRequest - * @return 日志分页数据 - * @author yslg - * @since 2025-12-31 - */ - @Override - public ResultDomain getKnowledgeFileLogPage(PageRequest pageRequest){ - List logs = knowledgeFileLogMapper.getKnowledgeFileLogPage(pageRequest.getPageParam(), pageRequest.getFilter()); - int total = knowledgeFileLogMapper.countKnowledgeFileLog(pageRequest.getFilter()); - PageDomain pageDomain = new PageDomain<>(); - pageDomain.setDataList(logs); - PageParam pageParam = pageRequest.getPageParam(); - pageParam.setTotal(total); - pageDomain.setPageParam(pageParam); - return ResultDomain.success("查询知识库日志成功", pageDomain); - } - - -} diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeServiceImpl.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeServiceImpl.java deleted file mode 100644 index 68a3029e..00000000 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeServiceImpl.java +++ /dev/null @@ -1,801 +0,0 @@ -package org.xyzh.ai.service.impl; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.StringUtils; -import org.springframework.web.multipart.MultipartFile; -import org.xyzh.ai.client.DifyApiClient; -import org.xyzh.ai.client.dto.DatasetCreateRequest; -import org.xyzh.ai.client.dto.DatasetCreateResponse; -import org.xyzh.ai.client.dto.DatasetDetailResponse; -import org.xyzh.ai.client.dto.DocumentListResponse; -import org.xyzh.ai.mapper.TbKnowledgeFileMapper; -import org.xyzh.ai.mapper.TbKnowledgeMapper; -import org.xyzh.api.ai.dto.TbKnowledge; -import org.xyzh.api.ai.dto.TbKnowledgeFile; -import org.xyzh.api.ai.dto.TbKnowledgeFileLog; -import org.xyzh.api.ai.constance.KnowledgeFileLogAction; -import org.xyzh.api.ai.service.AIFileUploadService; -import org.xyzh.api.ai.service.KnowledgeFileLogService; -import org.xyzh.api.ai.service.KnowledgeService; -import org.xyzh.api.ai.vo.KnowledgeFileVO; -import org.xyzh.api.file.dto.TbSysFileDTO; -import org.xyzh.api.file.service.FileService; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.auth.utils.LoginUtil; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @description 知识库服务实现 - * @filename KnowledgeServiceImpl.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@DubboService(version="1.0.0", group="ai", timeout=3000, retries=0) -public class KnowledgeServiceImpl implements KnowledgeService { - private static final Logger logger = LoggerFactory.getLogger(KnowledgeServiceImpl.class); - - @Autowired - private TbKnowledgeMapper knowledgeMapper; - - @Autowired - private TbKnowledgeFileMapper knowledgeFileMapper; - - @Autowired - private DifyApiClient difyApiClient; - - @DubboReference(version = "1.0.0", group = "file", timeout = 30000, retries = 0) - private FileService fileService; - - @Autowired - private KnowledgeFileLogService knowledgeFileLogService; - - @Autowired - private AIFileUploadService aiFileUploadService; - - // ================================= 知识库管理 ================================= - - /** - * @description 创建知识库基础信息,包含dify知识库各种参数的配置 - * 注意:涉及外部API调用,不使用@Transactional,采用手动补偿机制 - * @param knowledge 知识库信息 - * @return ResultDomain 创建结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain createKnowledge(TbKnowledge knowledge) { - // 1. 参数校验 - if (!StringUtils.hasText(knowledge.getTitle())) { - return ResultDomain.failure("知识库标题不能为空"); - } - - // 2. 获取当前用户 - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (loginDomain == null || !StringUtils.hasText(loginDomain.getUser().getUserId())) { - return ResultDomain.failure("用户未登录"); - } - String userId = loginDomain.getUser().getUserId(); - - // 3. 生成ID - knowledge.setDeptPath(loginDomain.getUserDepts().get(0).getDeptPath()); - knowledge.setOptsn(IdUtil.getOptsn()); - knowledge.setKnowledgeId(IdUtil.getSnowflakeId()); - knowledge.setCreator(userId); - - // 4. 创建Dify知识库 - String difyDatasetId = null; - try { - DatasetCreateRequest createRequest = new DatasetCreateRequest(); - createRequest.setName(knowledge.getTitle()); - createRequest.setDescription(knowledge.getDescription()); - if (StringUtils.hasText(knowledge.getDifyIndexingTechnique())) { - createRequest.setIndexingTechnique(knowledge.getDifyIndexingTechnique()); - } - - DatasetCreateResponse difyResponse = difyApiClient.createDataset(createRequest); - if (difyResponse != null && StringUtils.hasText(difyResponse.getId())) { - difyDatasetId = difyResponse.getId(); - knowledge.setDifyDatasetId(difyDatasetId); - } else { - return ResultDomain.failure("创建Dify知识库失败"); - } - } catch (Exception e) { - logger.error("创建Dify知识库异常: {}", e.getMessage(), e); - return ResultDomain.failure("创建Dify知识库异常: " + e.getMessage()); - } - - // 5. 插入数据库 - int rows = knowledgeMapper.insertKnowledge(knowledge); - if (rows > 0) { - logger.info("创建知识库成功: knowledgeId={}, title={}", knowledge.getKnowledgeId(), knowledge.getTitle()); - return ResultDomain.success("创建知识库成功", knowledge); - } - - // 数据库保存失败,补偿删除Dify知识库 - if (StringUtils.hasText(difyDatasetId)) { - try { - difyApiClient.deleteDataset(difyDatasetId); - logger.info("补偿删除Dify知识库成功: difyDatasetId={}", difyDatasetId); - } catch (Exception e) { - logger.warn("补偿删除Dify知识库失败: {}", e.getMessage()); - } - } - return ResultDomain.failure("创建知识库失败"); - } - - /** - * @description 内部创建知识库(不检查登录状态,用于系统初始化) - * 注意:调用方需要自行设置knowledgeId和creator - * @param knowledge 知识库信息 - * @return ResultDomain 创建结果 - * @author yslg - * @since 2025-12-20 - */ - @Override - public ResultDomain createKnowledgeInternal(TbKnowledge knowledge) { - // 1. 参数校验 - if (!StringUtils.hasText(knowledge.getTitle())) { - return ResultDomain.failure("知识库标题不能为空"); - } - if (!StringUtils.hasText(knowledge.getKnowledgeId())) { - return ResultDomain.failure("知识库ID不能为空"); - } - - // 2. 设置默认值 - if (!StringUtils.hasText(knowledge.getOptsn())) { - knowledge.setOptsn(IdUtil.getOptsn()); - } - if (!StringUtils.hasText(knowledge.getCreator())) { - knowledge.setCreator("system"); - } - - // 3. 创建Dify知识库 - String difyDatasetId = null; - try { - DatasetCreateRequest createRequest = new DatasetCreateRequest(); - createRequest.setName(knowledge.getTitle()); - createRequest.setDescription(knowledge.getDescription()); - if (StringUtils.hasText(knowledge.getDifyIndexingTechnique())) { - createRequest.setIndexingTechnique(knowledge.getDifyIndexingTechnique()); - } - - DatasetCreateResponse difyResponse = difyApiClient.createDataset(createRequest); - if (difyResponse != null && StringUtils.hasText(difyResponse.getId())) { - difyDatasetId = difyResponse.getId(); - knowledge.setDifyDatasetId(difyDatasetId); - } else { - return ResultDomain.failure("创建Dify知识库失败"); - } - } catch (Exception e) { - logger.error("创建Dify知识库异常: {}", e.getMessage(), e); - return ResultDomain.failure("创建Dify知识库异常: " + e.getMessage()); - } - - // 4. 插入数据库 - int rows = knowledgeMapper.insertKnowledge(knowledge); - if (rows > 0) { - logger.info("内部创建知识库成功: knowledgeId={}, title={}", knowledge.getKnowledgeId(), knowledge.getTitle()); - return ResultDomain.success("创建知识库成功", knowledge); - } - - // 数据库保存失败,补偿删除Dify知识库 - if (StringUtils.hasText(difyDatasetId)) { - try { - difyApiClient.deleteDataset(difyDatasetId); - logger.info("补偿删除Dify知识库成功: difyDatasetId={}", difyDatasetId); - } catch (Exception e) { - logger.warn("补偿删除Dify知识库失败: {}", e.getMessage()); - } - } - return ResultDomain.failure("创建知识库失败"); - } - - /** - * @description 更新知识库,包含dify知识库各种参数的配置 - * @param knowledge 知识库信息 - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain updateKnowledge(TbKnowledge knowledge) { - // 1. 参数校验 - if (!StringUtils.hasText(knowledge.getKnowledgeId())) { - return ResultDomain.failure("知识库ID不能为空"); - } - - // 2. 检查是否存在 - TbKnowledge existing = knowledgeMapper.selectKnowledgeById(knowledge.getKnowledgeId()); - if (existing == null) { - return ResultDomain.failure("知识库不存在"); - } - - // 3. 设置更新者 - String userId = LoginUtil.getCurrentUserId(); - if (StringUtils.hasText(userId)) { - knowledge.setUpdater(userId); - } - - // 4. 更新数据库 - int rows = knowledgeMapper.updateKnowledge(knowledge); - if (rows > 0) { - logger.info("更新知识库成功: knowledgeId={}", knowledge.getKnowledgeId()); - TbKnowledge updated = knowledgeMapper.selectKnowledgeById(knowledge.getKnowledgeId()); - return ResultDomain.success("更新知识库成功", updated); - } - - return ResultDomain.failure("更新知识库失败"); - } - - /** - * @description 删除知识库,同时删除dify知识库 - * 注意:Dify删除失败不影响本地删除 - * @param knowledgeId 知识库ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain deleteKnowledge(String knowledgeId) { - // 1. 参数校验 - if (!StringUtils.hasText(knowledgeId)) { - return ResultDomain.failure("知识库ID不能为空"); - } - - // 2. 检查是否存在 - TbKnowledge existing = knowledgeMapper.selectKnowledgeById(knowledgeId); - if (existing == null) { - return ResultDomain.failure("知识库不存在"); - } - - // 3. 删除Dify知识库 - if (StringUtils.hasText(existing.getDifyDatasetId())) { - try { - difyApiClient.deleteDataset(existing.getDifyDatasetId()); - } catch (Exception e) { - logger.warn("删除Dify知识库失败: {}", e.getMessage()); - } - } - - // 4. 设置更新者并软删除 - TbKnowledge delete = new TbKnowledge(); - delete.setKnowledgeId(knowledgeId); - String userId = LoginUtil.getCurrentUserId(); - if (StringUtils.hasText(userId)) { - delete.setUpdater(userId); - } - - int rows = knowledgeMapper.deleteKnowledge(delete); - if (rows > 0) { - logger.info("删除知识库成功: knowledgeId={}", knowledgeId); - return ResultDomain.success("删除知识库成功", true); - } - - return ResultDomain.failure("删除知识库失败"); - } - - /** - * @description 获取知识库详情,包含dify知识库各种参数的配置 - * @param knowledgeId 知识库ID - * @return ResultDomain 知识库信息 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain getKnowledgeById(String knowledgeId) { - if (!StringUtils.hasText(knowledgeId)) { - return ResultDomain.failure("知识库ID不能为空"); - } - - TbKnowledge knowledge = knowledgeMapper.selectKnowledgeById(knowledgeId); - if (knowledge == null) { - return ResultDomain.failure("知识库不存在"); - } - - return ResultDomain.success("查询成功", knowledge); - } - - /** - * @description 查询知识库列表 - * @param filter 过滤条件 - * @return ResultDomain 知识库列表 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain listKnowledges(TbKnowledge filter) { - List list = knowledgeMapper.selectKnowledgeList(filter); - return ResultDomain.success("查询成功", list); - } - - /** - * @description 分页查询知识库 - * @param filter 过滤条件 - * @param pageParam 分页参数 - * @return ResultDomain 分页结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain pageKnowledges(TbKnowledge filter, PageParam pageParam) { - List list = knowledgeMapper.selectKnowledgePage(filter, pageParam); - long total = knowledgeMapper.countKnowledges(filter); - pageParam.setTotal((int) total); - return ResultDomain.success("查询成功", list); - } - - /** - * @description 获取知识库统计信息(从Dify同步文档数量和分段数量) - * @param knowledgeId 知识库ID - * @return ResultDomain 统计信息 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain getKnowledgeStats(String knowledgeId) { - TbKnowledge knowledge = knowledgeMapper.selectKnowledgeById(knowledgeId); - if (knowledge == null) { - return ResultDomain.failure("知识库不存在"); - } - - // 从Dify同步统计信息 - if (StringUtils.hasText(knowledge.getDifyDatasetId())) { - try { - DatasetDetailResponse detail = difyApiClient.getDatasetDetail(knowledge.getDifyDatasetId()); - if (detail != null) { - TbKnowledge update = new TbKnowledge(); - update.setKnowledgeId(knowledgeId); - update.setDocumentCount(detail.getDocumentCount()); - update.setTotalChunks(detail.getWordCount()); - knowledgeMapper.updateKnowledge(update); - - knowledge.setDocumentCount(detail.getDocumentCount()); - knowledge.setTotalChunks(detail.getWordCount()); - } - } catch (Exception e) { - logger.warn("同步Dify统计信息失败: {}", e.getMessage()); - } - } - - return ResultDomain.success("查询成功", knowledge); - } - - /** - * @description 获取可用的嵌入模型列表 - * @return ResultDomain> 嵌入模型列表 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain> getAvailableEmbeddingModels() { - try { - var response = difyApiClient.getAvailableEmbeddingModels(); - Map result = new HashMap<>(); - result.put("data", response.getData()); - return ResultDomain.success("查询成功", result); - } catch (Exception e) { - logger.error("获取嵌入模型列表失败: {}", e.getMessage(), e); - return ResultDomain.failure("获取嵌入模型列表失败: " + e.getMessage()); - } - } - - /** - * @description 获取可用的Rerank模型列表 - * @return ResultDomain> Rerank模型列表 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain> getAvailableRerankModels() { - try { - var response = difyApiClient.getAvailableRerankModels(); - Map result = new HashMap<>(); - result.put("data", response.getData()); - return ResultDomain.success("查询成功", result); - } catch (Exception e) { - logger.error("获取Rerank模型列表失败: {}", e.getMessage(), e); - return ResultDomain.failure("获取Rerank模型列表失败: " + e.getMessage()); - } - } - - /** - * @description 获取知识库文档列表(查询本地数据库文件) - * @param pageRequest 分页请求,filter 中包含 knowledgeId - * @return ResultDomain 文档列表 - * @author yslg - * @since 2025-12-20 - */ - @Override - public ResultDomain getDocumentList(PageRequest pageRequest) { - TbKnowledgeFile filter = pageRequest.getFilter(); - if (filter == null || !StringUtils.hasText(filter.getKnowledgeId())) { - return ResultDomain.failure("知识库ID不能为空"); - } - - String knowledgeId = filter.getKnowledgeId(); - - // 验证知识库是否存在 - TbKnowledge knowledge = knowledgeMapper.selectKnowledgeById(knowledgeId); - if (knowledge == null) { - return ResultDomain.failure("知识库不存在"); - } - - try { - // 分页查询知识库文件(已通过 SQL JOIN 关联文件详细信息) - PageParam pageParam = pageRequest.getPageParam(); - List files = knowledgeFileMapper.selectFilePage(knowledgeId, pageParam); - long total = knowledgeFileMapper.countFiles(knowledgeId); - - // 设置总数 - pageParam.setTotal((int) total); - - // 创建分页结果 - PageDomain pageDomain = new PageDomain<>(pageParam, files); - - return ResultDomain.success("查询成功", pageDomain); - } catch (Exception e) { - logger.error("获取知识库文件列表失败: knowledgeId={}, error={}", knowledgeId, e.getMessage(), e); - return ResultDomain.failure("获取文件列表失败: " + e.getMessage()); - } - } - - // ================================= 文件管理 ================================= - - /** - * @description 上传文件到知识库(完整流程:minio + Dify + 数据库) - * @param knowledgeId 知识库ID - * @param file 上传的文件 - * @param indexingTechnique 索引方式 - * @return ResultDomain 上传结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain uploadKnowledgeFile(String knowledgeId, MultipartFile file, String indexingTechnique) { - // 1. 参数校验 - if (!StringUtils.hasText(knowledgeId)) { - return ResultDomain.failure("知识库ID不能为空"); - } - if (file == null || file.isEmpty()) { - return ResultDomain.failure("文件不能为空"); - } - - // 2. 获取知识库 - TbKnowledge knowledge = knowledgeMapper.selectKnowledgeById(knowledgeId); - if (knowledge == null) { - return ResultDomain.failure("知识库不存在"); - } - if (!StringUtils.hasText(knowledge.getDifyDatasetId())) { - return ResultDomain.failure("知识库未关联Dify"); - } - - // 3. 调用FileService上传到minio(使用字节数组方式,支持跨模块Dubbo调用) - byte[] fileBytes; - try { - fileBytes = file.getBytes(); - } catch (Exception e) { - logger.error("读取文件字节失败", e); - return ResultDomain.failure("读取文件失败: " + e.getMessage()); - } - ResultDomain fileResult = fileService.uploadFileBytes( - fileBytes, file.getOriginalFilename(), file.getContentType(), "knowledge", knowledgeId); - if (!fileResult.getSuccess() || fileResult.getData() == null) { - return ResultDomain.failure("上传文件到存储服务失败: " + fileResult.getMessage()); - } - TbSysFileDTO sysFile = fileResult.getData(); - String fileId = sysFile.getFileId(); - logger.info("上传文件到minio成功: fileId={}, path={}", fileId, sysFile.getPath()); - - // 4. 上传到Dify知识库 - String difyFileId = null; - File tempFile = null; - try { - tempFile = File.createTempFile("knowledge_", "_" + file.getOriginalFilename()); - file.transferTo(tempFile); - - String technique = StringUtils.hasText(indexingTechnique) ? indexingTechnique : knowledge.getDifyIndexingTechnique(); - ResultDomain difyResult = aiFileUploadService.uploadFileToDify( - knowledge.getDifyDatasetId(), tempFile, file.getOriginalFilename(), technique); - - if (difyResult.getSuccess() && StringUtils.hasText(difyResult.getData())) { - difyFileId = difyResult.getData(); - logger.info("上传文件到Dify成功: difyFileId={}", difyFileId); - } else { - logger.error("上传文件到Dify失败: {}", difyResult.getMessage()); - fileService.deleteFile(fileId); - return ResultDomain.failure("上传文件到Dify失败: " + difyResult.getMessage()); - } - } catch (Exception e) { - logger.error("上传文件到Dify异常: {}", e.getMessage(), e); - fileService.deleteFile(fileId); - return ResultDomain.failure("上传文件到Dify异常: " + e.getMessage()); - } finally { - if (tempFile != null && tempFile.exists()) { - tempFile.delete(); - } - } - - // 5. 保存tb_knowledge_file - TbKnowledgeFile knowledgeFile = new TbKnowledgeFile(); - knowledgeFile.setOptsn(IdUtil.getOptsn()); - knowledgeFile.setKnowledgeId(knowledgeId); - knowledgeFile.setFileRootId(fileId); - knowledgeFile.setFileId(fileId); - knowledgeFile.setDifyFileId(difyFileId); - knowledgeFile.setVersion(1); - - knowledgeMapper.updateKnowledgeFileCount(knowledgeId, 1); - int rows = knowledgeFileMapper.insertKnowledgeFile(knowledgeFile); - if (rows > 0) { - logger.info("保存知识库文件记录成功: knowledgeId={}, fileId={}, difyFileId={}", knowledgeId, fileId, difyFileId); - // 记录日志 - TbKnowledgeFileLog log = new TbKnowledgeFileLog(); - log.setKnowledgeId(knowledgeId); - log.setFileRootId(fileId); - log.setFileId(fileId); - log.setFileName(file.getOriginalFilename()); - log.setVersion(1); - log.setAction(KnowledgeFileLogAction.UPLOAD.getAction()); - log.setService("workcase"); - log.setCreator(LoginUtil.getCurrentUserId()); - log.setCreatorName(LoginUtil.getCurrentUserName()); - knowledgeFileLogService.addKnowledgeFileLog(log); - return ResultDomain.success("上传成功", knowledgeFile); - } - - // 补偿删除 - fileService.deleteFile(fileId); - aiFileUploadService.deleteFileFromDify(knowledge.getDifyDatasetId(), difyFileId); - return ResultDomain.failure("保存知识库文件记录失败"); - } - - /** - * @description 批量上传文件到知识库 - * @param knowledgeId 知识库ID - * @param files 文件列表 - * @param indexingTechnique 索引方式 - * @return ResultDomain 上传结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain batchUploadKnowledgeFile(String knowledgeId, List files, String indexingTechnique) { - if (!StringUtils.hasText(knowledgeId)) { - return ResultDomain.failure("知识库ID不能为空"); - } - if (files == null || files.isEmpty()) { - return ResultDomain.failure("文件列表不能为空"); - } - - List successList = new ArrayList<>(); - List failedFiles = new ArrayList<>(); - - for (MultipartFile file : files) { - ResultDomain result = uploadKnowledgeFile(knowledgeId, file, indexingTechnique); - if (result.getSuccess() && result.getData() != null) { - successList.add(result.getData()); - } else { - failedFiles.add(file.getOriginalFilename() + "(" + result.getMessage() + ")"); - } - } - - if (failedFiles.isEmpty()) { - return ResultDomain.success("批量上传成功", successList); - } else if (successList.isEmpty()) { - return ResultDomain.failure("批量上传全部失败: " + String.join(", ", failedFiles)); - } else { - return ResultDomain.success("部分上传成功,失败: " + String.join(", ", failedFiles), successList); - } - } - - /** - * @description 上传新版本文件(fileRootId一致,version递增) - * @param knowledgeId 知识库ID - * @param file 新文件 - * @param fileRootId 文件根ID - * @return ResultDomain 新版本文件信息 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain updateKnowledgeFileVersion(String knowledgeId, MultipartFile file, String fileRootId) { - // 1. 参数校验 - if (!StringUtils.hasText(knowledgeId)) { - return ResultDomain.failure("知识库ID不能为空"); - } - if (file == null || file.isEmpty()) { - return ResultDomain.failure("文件不能为空"); - } - if (!StringUtils.hasText(fileRootId)) { - return ResultDomain.failure("文件根ID不能为空"); - } - - // 2. 获取知识库 - TbKnowledge knowledge = knowledgeMapper.selectKnowledgeById(knowledgeId); - if (knowledge == null) { - return ResultDomain.failure("知识库不存在"); - } - if (!StringUtils.hasText(knowledge.getDifyDatasetId())) { - return ResultDomain.failure("知识库未关联Dify"); - } - - // 3. 获取最大版本的旧文件 - TbKnowledgeFile latestOldFile = knowledgeFileMapper.selectLatestVersionFile(fileRootId); - if (latestOldFile == null) { - return ResultDomain.failure("原文件不存在"); - } - - // 4. 上传新版本到minio(使用字节数组避免 Dubbo 序列化问题) - byte[] fileBytes; - try { - fileBytes = file.getBytes(); - } catch (java.io.IOException e) { - logger.error("读取文件字节失败", e); - return ResultDomain.failure("读取文件字节失败: " + e.getMessage()); - } - ResultDomain fileResult = fileService.uploadFileBytesVersion( - fileBytes, file.getOriginalFilename(), file.getContentType(), "knowledge", knowledgeId, fileRootId); - if (!fileResult.getSuccess() || fileResult.getData() == null) { - return ResultDomain.failure("上传新版本文件失败: " + fileResult.getMessage()); - } - TbSysFileDTO sysFile = fileResult.getData(); - String newFileId = sysFile.getFileId(); - int newVersion = sysFile.getVersion(); - logger.info("上传新版本到minio成功: fileId={}, version={}", newFileId, newVersion); - - // 5. 删除Dify最大版本的旧文档 - if (StringUtils.hasText(latestOldFile.getDifyFileId())) { - aiFileUploadService.deleteFileFromDify(knowledge.getDifyDatasetId(), latestOldFile.getDifyFileId()); - } - - // 6. 上传新文件到Dify - String newDifyFileId = null; - File tempFile = null; - try { - tempFile = File.createTempFile("knowledge_update_", "_" + file.getOriginalFilename()); - file.transferTo(tempFile); - - ResultDomain difyResult = aiFileUploadService.uploadFileToDify( - knowledge.getDifyDatasetId(), tempFile, file.getOriginalFilename(), knowledge.getDifyIndexingTechnique()); - - if (difyResult.getSuccess() && StringUtils.hasText(difyResult.getData())) { - newDifyFileId = difyResult.getData(); - } else { - fileService.deleteFile(newFileId); - return ResultDomain.failure("上传新文件到Dify失败: " + difyResult.getMessage()); - } - } catch (Exception e) { - logger.error("上传新文件到Dify异常: {}", e.getMessage(), e); - fileService.deleteFile(newFileId); - return ResultDomain.failure("上传新文件到Dify异常: " + e.getMessage()); - } finally { - if (tempFile != null && tempFile.exists()) { - tempFile.delete(); - } - } - - // 7. 保存tb_knowledge_file - TbKnowledgeFile newKnowledgeFile = new TbKnowledgeFile(); - newKnowledgeFile.setOptsn(IdUtil.getOptsn()); - newKnowledgeFile.setKnowledgeId(knowledgeId); - newKnowledgeFile.setFileRootId(fileRootId); - newKnowledgeFile.setFileId(newFileId); - newKnowledgeFile.setDifyFileId(newDifyFileId); - newKnowledgeFile.setVersion(newVersion); - - int rows = knowledgeFileMapper.insertKnowledgeFile(newKnowledgeFile); - if (rows > 0) { - logger.info("保存新版本记录成功: knowledgeId={}, fileRootId={}, newVersion={}", knowledgeId, fileRootId, newVersion); - // 记录日志 - TbKnowledgeFileLog log = new TbKnowledgeFileLog(); - log.setKnowledgeId(knowledgeId); - log.setFileRootId(fileRootId); - log.setFileId(newFileId); - log.setFileName(file.getOriginalFilename()); - log.setVersion(newVersion); - log.setAction(KnowledgeFileLogAction.UPDATE.getAction()); - log.setService("workcase"); - log.setCreator(LoginUtil.getCurrentUserId()); - log.setCreatorName(LoginUtil.getCurrentUserName()); - knowledgeFileLogService.addKnowledgeFileLog(log); - return ResultDomain.success("更新成功", newKnowledgeFile); - } - - // 补偿 - fileService.deleteFile(newFileId); - aiFileUploadService.deleteFileFromDify(knowledge.getDifyDatasetId(), newDifyFileId); - return ResultDomain.failure("保存新版本记录失败"); - } - - /** - * @description 删除知识库文件(根据fileRootId删除所有版本) - * @param fileRootId 文件根ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain deleteKnowledgeFileById(String fileRootId) { - if (!StringUtils.hasText(fileRootId)) { - return ResultDomain.failure("文件根ID不能为空"); - } - - // 1. 获取所有版本 - List versions = knowledgeFileMapper.selectFileVersions(fileRootId); - if (versions == null || versions.isEmpty()) { - return ResultDomain.failure("文件不存在"); - } - - // 2. 删除Dify中的文档 - TbKnowledge knowledge = knowledgeMapper.selectKnowledgeById(versions.get(0).getKnowledgeId()); - if (knowledge != null && StringUtils.hasText(knowledge.getDifyDatasetId())) { - List difyDocIds = new ArrayList<>(); - for (TbKnowledgeFile file : versions) { - if (StringUtils.hasText(file.getDifyFileId())) { - difyDocIds.add(file.getDifyFileId()); - } - } - if (!difyDocIds.isEmpty()) { - aiFileUploadService.batchDeleteFilesFromDify(knowledge.getDifyDatasetId(), difyDocIds); - } - }else{ - return ResultDomain.failure("知识库未关联Dify"); - } - - // 3. 软删除本地记录和minio文件 - int rows = knowledgeFileMapper.deleteFilesByRootId(fileRootId); - knowledgeMapper.updateKnowledgeFileCount(knowledge.getKnowledgeId(), -1); - if (rows > 0) { - logger.info("删除知识库文件成功: fileRootId={}", fileRootId); - for (TbKnowledgeFile file : versions) { - fileService.deleteFile(file.getFileId()); - } - // 记录日志 - TbKnowledgeFileLog log = new TbKnowledgeFileLog(); - log.setKnowledgeId(knowledge.getKnowledgeId()); - log.setFileRootId(fileRootId); - log.setAction(KnowledgeFileLogAction.DELETE.getAction()); - log.setService("workcase"); - log.setCreator(LoginUtil.getCurrentUserId()); - log.setCreatorName(LoginUtil.getCurrentUserName()); - knowledgeFileLogService.addKnowledgeFileLog(log); - return ResultDomain.success("删除成功", true); - } - - return ResultDomain.failure("删除文件失败"); - } - - /** - * @description 获取文件历史版本 - * @param fileRootId 文件根ID - * @return ResultDomain 文件历史版本列表(dataList) - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain getKnowledgeFileHistory(String fileRootId) { - if (!StringUtils.hasText(fileRootId)) { - return ResultDomain.failure("文件根ID不能为空"); - } - - List versions = knowledgeFileMapper.selectFileVersionsWithDetail(fileRootId); - ResultDomain result = ResultDomain.success("查询成功"); - result.setDataList(versions); - return result; - } -} diff --git a/urbanLifelineServ/ai/src/main/resources/application.yml b/urbanLifelineServ/ai/src/main/resources/application.yml deleted file mode 100644 index 8c201a0e..00000000 --- a/urbanLifelineServ/ai/src/main/resources/application.yml +++ /dev/null @@ -1,44 +0,0 @@ -# ================== AI 服务配置 ================== -server: - port: 8090 - -spring: - application: - name: ai-service - servlet: - multipart: - enabled: true - max-file-size: 500MB - max-request-size: 500MB - -# ================== Auth ================== -auth: - enabled: true - gateway-mode: true - whitelist: - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - /favicon.ico - - /error - - /actuator/health - - /actuator/info - - /ai/chat/** - -# ================== SpringDoc ================== -springdoc: - group-configs: - - group: 'default' - display-name: 'AI代理服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-agent - qos-enable: false - protocol: - payload: 110100480 - scan: - base-packages: org.xyzh.ai.service.impl diff --git a/urbanLifelineServ/ai/src/main/resources/bootstrap.yml b/urbanLifelineServ/ai/src/main/resources/bootstrap.yml deleted file mode 100644 index 60998f2b..00000000 --- a/urbanLifelineServ/ai/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,64 +0,0 @@ -# ================================================ -# Urban Lifeline - 通用 Bootstrap 配置 -# 所有微服务共享的基础配置 -# ================================================ - -# ================== Spring Cloud Nacos ================== -spring: - cloud: - nacos: - discovery: - server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} - namespace: ${NACOS_NAMESPACE:dev} - group: ${NACOS_GROUP:DEFAULT_GROUP} - - # ================== DataSource ================== - datasource: - url: ${DB_URL:jdbc:postgresql://127.0.0.1:5432/urban_lifeline} - username: ${DB_USERNAME:postgres} - password: ${DB_PASSWORD:postgres} - driver-class-name: org.postgresql.Driver - - # ================== Redis ================== - data: - redis: - host: ${REDIS_HOST:127.0.0.1} - port: ${REDIS_PORT:6379} - database: ${REDIS_DATABASE:0} - password: ${REDIS_PASSWORD:123456} - -# ================== Security AES ================== -security: - aes: - # AES-256 密钥(Base64编码,必须与所有服务保持一致) - # 警告:这是开发环境密钥,生产环境请使用密钥管理系统 - secret-key: ${AES_SECRET_KEY:MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=} - -# ================== Dubbo ================== -dubbo: - protocol: - name: dubbo - port: -1 - registry: - address: nacos://${NACOS_SERVER_ADDR:127.0.0.1:8848} - -# ================== MyBatis-Plus ================== -mybatis-plus: - mapper-locations: classpath:mapper/**/*.xml - type-aliases-package: org.xyzh.common.dto, org.xyzh.api - -# ================== SpringDoc 基础配置 ================== -springdoc: - api-docs: - enabled: true - path: /v3/api-docs - swagger-ui: - enabled: true - path: /swagger-ui.html - -# ================== Logging ================== -logging: - config: classpath:log4j2.xml - charset: - console: UTF-8 - file: UTF-8 diff --git a/urbanLifelineServ/ai/src/main/resources/log4j2.xml b/urbanLifelineServ/ai/src/main/resources/log4j2.xml deleted file mode 100644 index d99f9f0c..00000000 --- a/urbanLifelineServ/ai/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/ai/src/main/resources/mapper/TbAgentMapper.xml b/urbanLifelineServ/ai/src/main/resources/mapper/TbAgentMapper.xml deleted file mode 100644 index 97b97387..00000000 --- a/urbanLifelineServ/ai/src/main/resources/mapper/TbAgentMapper.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - optsn, agent_id, name, description, link, api_key, is_outer, introduce, prompt_cards, - category, creator, updater, create_time, update_time, delete_time, deleted - - - - INSERT INTO ai.tb_agent ( - optsn, agent_id, name, api_key, introduce, category - , is_outer - , description - , link - , prompt_cards - , creator - ) VALUES ( - #{optsn}, #{agentId}, #{name}, #{apiKey}, #{introduce}, #{category} - , #{isOuter} - , #{description} - , #{link} - , #{promptCards, typeHandler=org.xyzh.ai.handler.PromptCardsTypeHandler} - , #{creator} - ) - - - - UPDATE ai.tb_agent - - name = #{name}, - description = #{description}, - link = #{link}, - api_key = #{apiKey}, - is_outer = #{isOuter}, - introduce = #{introduce}, - prompt_cards = #{promptCards, typeHandler=org.xyzh.ai.handler.PromptCardsTypeHandler}, - category = #{category}, - updater = #{updater}, - update_time = now() - - WHERE agent_id = #{agentId} AND deleted = false - - - - UPDATE ai.tb_agent - SET deleted = true, - delete_time = now(), - updater = #{updater} - WHERE agent_id = #{agentId} AND deleted = false - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/ai/src/main/resources/mapper/TbChatMapper.xml b/urbanLifelineServ/ai/src/main/resources/mapper/TbChatMapper.xml deleted file mode 100644 index f643544f..00000000 --- a/urbanLifelineServ/ai/src/main/resources/mapper/TbChatMapper.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - optsn, chat_id, agent_id, user_id, user_type, title, - create_time, update_time, delete_time, deleted - - - - INSERT INTO ai.tb_chat ( - optsn, chat_id, agent_id, user_id, title - , user_type - ) VALUES ( - #{optsn}, #{chatId}, #{agentId}, #{userId}, #{title} - , #{userType} - ) - - - - UPDATE ai.tb_chat - - title = #{title}, - update_time = now() - - WHERE chat_id = #{chatId} AND deleted = false - - - - UPDATE ai.tb_chat - SET deleted = true, - delete_time = now() - WHERE chat_id = #{chatId} AND deleted = false - - - - - - - - - - diff --git a/urbanLifelineServ/ai/src/main/resources/mapper/TbChatMessageMapper.xml b/urbanLifelineServ/ai/src/main/resources/mapper/TbChatMessageMapper.xml deleted file mode 100644 index 9edc64e1..00000000 --- a/urbanLifelineServ/ai/src/main/resources/mapper/TbChatMessageMapper.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - optsn, message_id, dify_message_id, chat_id, role, content, files, comment, - create_time, update_time, delete_time, deleted - - - - INSERT INTO ai.tb_chat_message ( - optsn, message_id, chat_id, role, content - , dify_message_id - , files - , comment - ) VALUES ( - #{optsn}, #{messageId}, #{chatId}, #{role}, #{content} - , #{difyMessageId} - , #{files, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler} - , #{comment} - ) - - - - UPDATE ai.tb_chat_message - - content = #{content}, - comment = #{comment}, - update_time = now() - - WHERE message_id = #{messageId} AND deleted = false - - - - UPDATE ai.tb_chat_message - SET deleted = true, - delete_time = now() - WHERE message_id = #{messageId} AND deleted = false - - - - - - - - - - - - UPDATE ai.tb_chat_message - SET deleted = true, - delete_time = now() - WHERE chat_id = #{chatId} AND deleted = false - - diff --git a/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeFileLogMapper.xml b/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeFileLogMapper.xml deleted file mode 100644 index 69b270d8..00000000 --- a/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeFileLogMapper.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - - optsn, log_id, knowledge_id, file_root_id, file_id, file_name, version, - action, creator, creator_name, create_time - - - - INSERT INTO ai.tb_knowledge_file_log ( - optsn, log_id, knowledge_id, file_root_id, file_id, file_name, version, - action, service, creator, creator_name, create_time - ) VALUES ( - #{optsn}, #{logId}, #{knowledgeId}, #{fileRootId}, #{fileId}, - - - - (SELECT COALESCE(file_name, '') FROM ai.tb_knowledge_file_log WHERE file_id = #{fileId} LIMIT 1) - - - - #{fileName} - - , - #{version}, #{action}, #{service}, #{creator}, #{creatorName}, NOW() - ) - - - - - - - - diff --git a/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeFileMapper.xml b/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeFileMapper.xml deleted file mode 100644 index cf988eed..00000000 --- a/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeFileMapper.xml +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - optsn, knowledge_id, file_root_id, file_id, dify_file_id, version, - create_time, update_time, delete_time, deleted - - - - INSERT INTO ai.tb_knowledge_file ( - optsn, knowledge_id, file_root_id, file_id, dify_file_id - , version - ) VALUES ( - #{optsn}, #{knowledgeId}, #{fileRootId}, #{fileId}, #{difyFileId} - , #{version} - ) - - - - UPDATE ai.tb_knowledge_file - - dify_file_id = #{difyFileId}, - version = #{version}, - update_time = now() - - WHERE knowledge_id = #{knowledgeId} AND file_id = #{fileId} AND deleted = false - - - - UPDATE ai.tb_knowledge_file - SET deleted = true, - delete_time = now() - WHERE knowledge_id = #{knowledgeId} AND file_id = #{fileId} AND deleted = false - - - - - - - - - - - - - - UPDATE ai.tb_knowledge_file - SET deleted = true, - delete_time = now() - WHERE file_root_id = #{fileRootId} AND deleted = false - - - - - - - - diff --git a/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeMapper.xml b/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeMapper.xml deleted file mode 100644 index 7c27ab65..00000000 --- a/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeMapper.xml +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - optsn, knowledge_id, title, avatar, description, dify_dataset_id, - dify_indexing_technique, embedding_model, embedding_model_provider, - rerank_model, rerank_model_provider, reranking_enable, - retrieval_top_k, retrieval_score_threshold, document_count, total_chunks, - service, project_id, category, creator, dept_path, updater, - create_time, update_time, delete_time, deleted - - - - INSERT INTO ai.tb_knowledge ( - optsn, knowledge_id, title, creator - , avatar - , description - , dify_dataset_id - , dify_indexing_technique - , embedding_model - , embedding_model_provider - , rerank_model - , rerank_model_provider - , reranking_enable - , retrieval_top_k - , retrieval_score_threshold - , service - , project_id - , category - , dept_path - ) VALUES ( - #{optsn}, #{knowledgeId}, #{title}, #{creator} - , #{avatar} - , #{description} - , #{difyDatasetId} - , #{difyIndexingTechnique} - , #{embeddingModel} - , #{embeddingModelProvider} - , #{rerankModel} - , #{rerankModelProvider} - , #{rerankingEnable} - , #{retrievalTopK} - , #{retrievalScoreThreshold} - , #{service} - , #{projectId} - , #{category} - , #{deptPath} - ) - - - - UPDATE ai.tb_knowledge - - title = #{title}, - avatar = #{avatar}, - description = #{description}, - dify_dataset_id = #{difyDatasetId}, - dify_indexing_technique = #{difyIndexingTechnique}, - embedding_model = #{embeddingModel}, - embedding_model_provider = #{embeddingModelProvider}, - rerank_model = #{rerankModel}, - rerank_model_provider = #{rerankModelProvider}, - reranking_enable = #{rerankingEnable}, - retrieval_top_k = #{retrievalTopK}, - retrieval_score_threshold = #{retrievalScoreThreshold}, - document_count = #{documentCount}, - total_chunks = #{totalChunks}, - service = #{service}, - project_id = #{projectId}, - category = #{category}, - updater = #{updater}, - update_time = now() - - WHERE knowledge_id = #{knowledgeId} AND deleted = false - - - - UPDATE ai.tb_knowledge - SET deleted = true, - delete_time = now(), - updater = #{updater} - WHERE knowledge_id = #{knowledgeId} AND deleted = false - - - - UPDATE ai.tb_knowledge - SET document_count = document_count + #{num} - WHERE knowledge_id = #{knowledgeId} AND deleted = false - - - - - - - - - - - - diff --git a/urbanLifelineServ/apis/api-ai/pom.xml b/urbanLifelineServ/apis/api-ai/pom.xml deleted file mode 100644 index 223cf561..00000000 --- a/urbanLifelineServ/apis/api-ai/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh.apis - api-ai - 1.0.0 - - - 21 - 21 - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/constance/KnowledgeFileLogAction.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/constance/KnowledgeFileLogAction.java deleted file mode 100644 index 8c49c21b..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/constance/KnowledgeFileLogAction.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.api.ai.constance; - - -public enum KnowledgeFileLogAction { - UPLOAD("upload", "上传文件"), - DELETE("delete", "删除文件"), - DOWNLOAD("download", "下载文件"), - UPDATE("update", "更新文件"), - SEGMENT_CREATE("segment_create", "创建分段"), - SEGMENT_UPDATE("segment_update", "更新分段"), - SEGMENT_DELETE("segment_delete", "更新分段"); - - private String action; - private String description; - private KnowledgeFileLogAction(String action, String description) { - this.action = action; - this.description = description; - } - - public String getAction() { - return action; - } - - public String getDescription(){ - return description; - } - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/ChatPrepareData.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/ChatPrepareData.java deleted file mode 100644 index 000fd330..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/ChatPrepareData.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.xyzh.api.ai.dto; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "对话消息数据预处理对象") -public class ChatPrepareData implements Serializable { - private final static long serialVersionUID = 1L; - - @Schema(description = "智能体Id") - private String agentId; - - @Schema(description = "对话Id") - private String chatId; - - @Schema(description = "用户问题") - private String query; - - @Schema(description = "本次对话携带的dify文件对象") - private List files; - - @Schema(description = "用户ID(来客传wechatId,员工传userId)") - private String userId; - - @Schema(description = "用户类型(false=来客,true=员工)") - private Boolean userType; - - @Schema(description = "服务名称") - private String service; - - @Schema(description = "智能体输入参数,不同智能体可能需要不同的输入参数") - private Map inputsMap; - - @Schema(description = "应用类型(chat=对话应用,workflow=工作流应用),默认为chat") - private String appType = "chat"; -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/DifyFileInfo.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/DifyFileInfo.java deleted file mode 100644 index 0da42c19..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/DifyFileInfo.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.xyzh.api.ai.dto; - -import com.alibaba.fastjson2.annotation.JSONField; -import lombok.Data; - -/** - * @description Dify文件信息(用于对话文件上传和请求) - * @filename DifyFileInfo.java - * @author AI Assistant - * @copyright xyzh - * @since 2025-12-15 - */ -@Data -public class DifyFileInfo { - /** - * 文件ID(Dify返回) - */ - private String id; - - /** - * 文件名 - */ - private String name; - - /** - * 文件大小(字节) - */ - private Integer size; - - /** - * 文件扩展名 - */ - private String extension; - - /** - * 文件MIME类型 - */ - @JSONField(name = "mime_type") - private String mimeType; - - /** - * 上传人ID - */ - @JSONField(name = "created_by") - private String createdBy; - - /** - * 上传时间(时间戳) - */ - @JSONField(name = "created_at") - private Long createdAt; - - /** - * 预览URL - */ - @JSONField(name = "preview_url") - private String previewUrl; - - /** - * 源文件URL - */ - @JSONField(name = "source_url") - private String sourceUrl; - - /** - * 文件类型:image、document、audio、video、file - */ - private String type; - - /** - * 传输方式:remote_url、local_file - */ - @JSONField(name = "transfer_method") - private String transferMethod; - - /** - * 文件URL或ID - */ - private String url; - - /** - * 本地文件上传ID - */ - @JSONField(name = "upload_file_id") - private String uploadFileId; - - /** - * 系统文件ID - */ - @JSONField(name = "sys_file_id") - private String sysFileId; - - /** - * 文件路径(从系统文件表获取) - */ - @JSONField(name = "file_path") - private String filePath; -} - diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/KnowledgeFileVO.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/KnowledgeFileVO.java deleted file mode 100644 index e69de29b..00000000 diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/PromptCard.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/PromptCard.java deleted file mode 100644 index de2049fa..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/PromptCard.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.xyzh.api.ai.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "智能体提示卡") -public class PromptCard { - @Schema(description = "文件ID") - private String fileId; - - @Schema(description = "提示词") - private String prompt; -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbAgent.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbAgent.java deleted file mode 100644 index 6146d25c..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbAgent.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.xyzh.api.ai.dto; - -import java.util.List; - -import org.xyzh.common.dto.BaseDTO; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import io.swagger.v3.oas.annotations.media.Schema; - -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统文件DTO") -public class TbAgent extends BaseDTO{ - private static final long serialVersionUID = 1L; - - @Schema(description = "智能体ID") - private String agentId; - - @Schema(description = "智能体名称") - private String name; - - @Schema(description = "智能体描述") - private String description; - - @Schema(description = "智能体url") - private String link; - - @Schema(description = "智能体APIKEY") - private String apiKey; - - @Schema(description = "是否是对外智能体,未登录可用") - private Boolean isOuter; - - @Schema(description = "引导词") - private String introduce; - - @Schema(description = "提示卡片数组") - private List promptCards; - - @Schema(description = "分类") - private String category; - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbChat.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbChat.java deleted file mode 100644 index f4bc797d..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbChat.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.api.ai.dto; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "AI智能体对话") -public class TbChat extends BaseDTO{ - private static final long serialVersionUID = 1L; - - @Schema(description = "对话ID") - private String chatId; - - @Schema(description = "智能体ID") - private String agentId; - - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "用户类型 true-系统内部人员 false-系统外部人员") - private Boolean userType; - - @Schema(description = "对话标题") - private String title; - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbChatMessage.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbChatMessage.java deleted file mode 100644 index e8f84710..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbChatMessage.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.xyzh.api.ai.dto; - -import java.util.List; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "AI智能体对话消息") -public class TbChatMessage extends BaseDTO{ - private static final long serialVersionUID = 1L; - - @Schema(description = "消息ID") - private String messageId; - - @Schema(description = "Dify消息ID") - private String difyMessageId; - - @Schema(description = "对话ID") - private String chatId; - - @Schema(description = "角色") - private String role; - - @Schema(description = "内容") - private String content; - - @Schema(description = "文件ID数组") - private List files; - - @Schema(description = "评价") - private String comment; - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledge.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledge.java deleted file mode 100644 index 2489abf2..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledge.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.xyzh.api.ai.dto; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "知识库配置") -public class TbKnowledge extends BaseDTO{ - private static final long serialVersionUID = 1L; - - @Schema(description = "知识库ID") - private String knowledgeId; - - @Schema(description = "知识库标题") - private String title; - - @Schema(description = "知识库头像") - private String avatar; - - @Schema(description = "知识库描述") - private String description; - - @Schema(description = "Dify知识库ID(Dataset ID)") - private String difyDatasetId; - - @Schema(description = "Dify索引方式(high_quality/economy)") - private String difyIndexingTechnique; - - @Schema(description = "向量模型名称") - private String embeddingModel; - - @Schema(description = "向量模型提供商") - private String embeddingModelProvider; - - @Schema(description = "Rerank模型名称") - private String rerankModel; - - @Schema(description = "Rerank模型提供商") - private String rerankModelProvider; - - @Schema(description = "是否启用Rerank(false否 true是)") - private Boolean rerankingEnable; - - @Schema(description = "检索Top K(返回前K个结果)") - private Integer retrievalTopK; - - @Schema(description = "检索分数阈值(0.00-1.00)") - private Double retrievalScoreThreshold; - - @Schema(description = "文档数量") - private Integer documentCount; - - @Schema(description = "总分段数") - private Integer totalChunks; - - @Schema(description = "所属服务 workcase、bidding") - private String service; - - @Schema(description = "bidding所属项目ID") - private String projectId; - - @Schema(description = "所属分类 workcase的内部知识库、外部知识库,其他服务default") - private String category; - - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledgeFile.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledgeFile.java deleted file mode 100644 index 43846089..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledgeFile.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.api.ai.dto; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "知识库文件") -public class TbKnowledgeFile extends BaseDTO{ - private final static long serialVersionUID = 1L; - - @Schema(description = "知识库ID") - private String knowledgeId; - - @Schema(description = "文件ID") - private String fileId; - - @Schema(description = "文件根ID") - private String fileRootId; - - @Schema(description = "Dify文件ID") - private String difyFileId; - - @Schema(description = "文件版本") - private Integer version; - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledgeFileLog.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledgeFileLog.java deleted file mode 100644 index 1ca97c0c..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/dto/TbKnowledgeFileLog.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.xyzh.api.ai.dto; - -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "知识库文件日志") -public class TbKnowledgeFileLog extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "日志Id") - private String logId; - - @Schema(description = "知识库Id") - private String knowledgeId; - - @Schema(description = "文件根Id") - private String fileRootId; - - @Schema(description = "文件Id") - private String fileId; - - @Schema(description = "文件名称") - private String fileName; - - @Schema(description = "服务名称") - private String service; - - @Schema(description = "文件版本") - private Integer version; - - @Schema(description = "操作") - private String action; - - @Schema(description = "操作人用户名") - private String creatorName; -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AIFileUploadService.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AIFileUploadService.java deleted file mode 100644 index 1f7addac..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AIFileUploadService.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.xyzh.api.ai.service; - -import java.io.File; -import java.util.List; -import java.util.Map; - -import org.springframework.web.multipart.MultipartFile; -import org.xyzh.common.core.domain.ResultDomain; - -/** - * @description AI文件上传服务(只负责与Dify交互,不处理minio和数据库) - * @author yslg - * @since 2025-12-18 - */ -public interface AIFileUploadService { - - // ============================ 对话文件管理 ============================ - - /** - * @description 上传文件用于对话(图文多模态) - * @param file 上传的文件 - * @param agentId 智能体ID - * @return ResultDomain> Dify文件信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain> uploadFileForChat(MultipartFile file, String agentId); - - // ============================ 知识库Dify文档管理 ============================ - - /** - * @description 上传文件到Dify知识库(只负责Dify上传,不处理minio和数据库) - * @param difyDatasetId Dify知识库ID - * @param file 文件 - * @param fileName 文件名 - * @param indexingTechnique 索引方式 - * @return ResultDomain Dify文档ID - * @author yslg - * @since 2025-12-18 - */ - ResultDomain uploadFileToDify(String difyDatasetId, File file, String fileName, String indexingTechnique); - - /** - * @description 从Dify知识库删除文档 - * @param difyDatasetId Dify知识库ID - * @param difyDocumentId Dify文档ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain deleteFileFromDify(String difyDatasetId, String difyDocumentId); - - /** - * @description 批量从Dify知识库删除文档 - * @param difyDatasetId Dify知识库ID - * @param difyDocumentIds Dify文档ID列表 - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain batchDeleteFilesFromDify(String difyDatasetId, List difyDocumentIds); -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AgentChatService.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AgentChatService.java deleted file mode 100644 index 97d0b6f3..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AgentChatService.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.xyzh.api.ai.service; - -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; -import org.xyzh.api.ai.dto.ChatPrepareData; -import org.xyzh.api.ai.dto.TbChat; -import org.xyzh.api.ai.dto.TbChatMessage; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageRequest; - -public interface AgentChatService { - - // ====================== 智能体会话管理 ====================== - /** - * 创建新会话 - * @param agentId 智能体ID - * @param title 会话标题(可选) - * @return 会话信息 - */ - ResultDomain createChat(TbChat chat); - - /** - * 更新会话名称 - * @param agentId 智能体ID - * @param chatId 会话ID - * @param title 会话标题(可选) - * @return 会话信息 - */ - ResultDomain updateChat(TbChat chat); - - /** - * 删除会话 - * @param agentId 智能体ID - * @param chatId 会话ID - * @return 会话信息 - */ - ResultDomain deleteChat(TbChat chat); - - /** - * 获取会话列表 - * @param agentId 智能体ID - * @return 会话列表 - */ - ResultDomain getChatList(TbChat filter); - - /** - * 分页获取会话列表 - * @param pageRequest 分页请求参数 - * @return 分页会话列表 - */ - ResultDomain getChatPage(PageRequest pageRequest); - - - // ====================== 智能体聊天管理 ====================== - - /** - * 获取会话消息列表 - * @param filter 会话过滤条件(包含agentId, chatId, userId, userType) - * @return 会话消息列表 - */ - ResultDomain getChatMessageList(TbChat filter); - - /** - * 准备聊天数据(POST传递复杂参数) - * @param prepareData 对话准备数据(包含agentId, chatId, query, files, userId, userType) - * @return ResultDomain 返回sessionId - */ - ResultDomain prepareChatMessageSession(ChatPrepareData prepareData); - - /** - * 流式对话(SSE)- 使用sessionId建立SSE连接 产生chatMessage - * @param sessionId 会话标识 - * @return SseEmitter 流式推送对象 - */ - SseEmitter streamChatMessageWithSse(String sessionId); - - /** - * 阻塞式对话 - 使用sessionId进行同步调用,等待完整结果返回 - * @param sessionId 会话标识 - * @return ResultDomain 返回AI回复的完整内容 - */ - ResultDomain blockingChatMessageWithSession(String sessionId); - - /** - * 停止对话生成(通过Dify TaskID) - * @param filter 会话过滤条件(包含agentId, userId, userType) - * @param taskId Dify任务ID - * @return 停止结果 - */ - ResultDomain stopChatMessageByTaskId(TbChat filter, String taskId); - - /** - * 评价 - * @param filter 会话过滤条件(包含agentId, chatId, userId, userType) - * @param messageId 消息ID - * @param comment 评价 - * @return 评价结果 - */ - ResultDomain commentChatMessage(TbChat filter, String messageId, String comment); - - // ====================== 工作流执行 ====================== - - /** - * 工作流执行(阻塞模式)- 使用sessionId进行同步调用,等待完整结果返回 - * @param sessionId 会话标识(从prepareChatMessageSession返回) - * @return ResultDomain 返回工作流输出结果的JSON字符串 - */ - ResultDomain runWorkflowWithSession(String sessionId); - - /** - * 执行工作流(阻塞模式)- 直接传入inputs执行工作流 - * @param agentId 智能体ID(用于获取API Key) - * @param inputs 工作流输入参数 - * @param userId 用户标识 - * @return ResultDomain 返回工作流输出结果的JSON字符串 - */ - ResultDomain runWorkflowBlocking(String agentId, java.util.Map inputs, String userId); - - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AgentService.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AgentService.java deleted file mode 100644 index 17d2ecb2..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/AgentService.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.xyzh.api.ai.service; - -import org.xyzh.api.ai.dto.TbAgent; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; - -/** - * Agent服务接口 - * 用于知识库和文档管理 - */ -public interface AgentService { - - /** - * 添加Agent, 用户自己在dify搭建发布后,在本服务进行接入 - * @param tbAgent - * @author yslg - * @since 2025-12-17 - * @return - */ - ResultDomain addAgent(TbAgent tbAgent); - - /** - * 更新Agent - * @param tbAgent - * @author yslg - * @since 2025-12-17 - * @return - */ - ResultDomain updateAgent(TbAgent tbAgent); - - /** - * 删除Agent - * @param tbAgent - * @author yslg - * @since 2025-12-17 - * @return - */ - ResultDomain deleteAgent(TbAgent tbAgent); - - ResultDomain selectAgentById(String agentId); - - /** - * @description 分页获取当前用户可用的agent智能体 - * @param pageRequest - * @author yslg - * @since 2025-12-17 - */ - ResultDomain getAgentPage(PageRequest pageRequest); - - /** - * @description 获取当前用户所有可用智能体列表 - * @param tbAgent - * @author yslg - * @since 2025-12-17 - */ - ResultDomain getAgentList(TbAgent tbAgent); -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/DifyProxyService.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/DifyProxyService.java deleted file mode 100644 index 82be43ed..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/DifyProxyService.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.xyzh.api.ai.service; - -import java.util.Map; - -import org.xyzh.common.core.domain.ResultDomain; - -import com.alibaba.fastjson2.JSONObject; - -/** - * @description Dify代理服务接口 - * @filename DifyProxyService.java - * @author yslg - * @copyright xyzh - * @since 2025-12-15 - */ -public interface DifyProxyService { - - /** - * 获取某个知识库的某个文档的所有分段 - * @param datasetId 数据集ID - * @param documentId 文档ID - * @return 文档分段列表 - */ - ResultDomain getDocumentSegments(String datasetId, String documentId); - - /** - * @description 更新某个知识库的某个文档的某个分段 - * @param datasetId 数据集ID - * @param documentId 文档ID - * @param segmentId 分段ID - * @param requestBody 更新请求体 - * @return 更新结果 - */ - ResultDomain updateSegment(String datasetId, String documentId, String segmentId, Map requestBody); - - /** - * @description 创建某个知识库的某个文档的某个分段 - * @param datasetId 数据集ID - * @param documentId 文档ID - * @param requestBody 创建请求体 - * @return 创建结果 - */ - ResultDomain createSegment(String datasetId, String documentId, Map requestBody); - - /** - * @description 删除某个知识库的某个文档的某个分段 - * @param datasetId 数据集ID - * @param documentId 文档ID - * @param segmentId 分段ID - * @return 删除结果 - */ - ResultDomain deleteSegment(String datasetId, String documentId, String segmentId); - - /** - * @description 更新文档启用/禁用状态 - * @param datasetId Dify数据集ID - * @param action 操作类型(enable/disable/archive/un_archive) - * @param requestBody 请求体(包含document_ids数组) - * @return ResultDomain 更新结果 - */ - ResultDomain updateDocumentStatus(String datasetId, String action, Map requestBody); -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/KnowledgeFileLogService.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/KnowledgeFileLogService.java deleted file mode 100644 index 13eaff1f..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/KnowledgeFileLogService.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.xyzh.api.ai.service; - -import org.xyzh.api.ai.dto.TbKnowledgeFileLog; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; - -/** - * @description 知识库文件操作日志 - * @filename KnowledgeFileLogService.java - * @author yslg - * @copyright yslg - * @since 2025-12-31 - */ -public interface KnowledgeFileLogService { - - /** - * @description 新增知识库文件操作日志 - * @param knowledgeFileLog - * @return 日志 - * @author yslg - * @since 2025-12-31 - */ - ResultDomain addKnowledgeFileLog(TbKnowledgeFileLog knowledgeFileLog); - - /** - * @description 查询知识库日志操作列表 - * @param filter - * @return 日志列表 - * @author yslg - * @since 2025-12-31 - */ - ResultDomain getKnowledgeFileLogList(TbKnowledgeFileLog filter); - - /** - * @description 查询知识库日志操作分页 - * @param pageRequest - * @return 日志分页数据 - * @author yslg - * @since 2025-12-31 - */ - ResultDomain getKnowledgeFileLogPage(PageRequest pageRequest); - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/KnowledgeService.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/KnowledgeService.java deleted file mode 100644 index 51bd7858..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/service/KnowledgeService.java +++ /dev/null @@ -1,171 +0,0 @@ -package org.xyzh.api.ai.service; - -import java.util.List; -import java.util.Map; - -import org.springframework.web.multipart.MultipartFile; -import org.xyzh.api.ai.dto.TbKnowledge; -import org.xyzh.api.ai.dto.TbKnowledgeFile; -import org.xyzh.api.ai.vo.KnowledgeFileVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; - -public interface KnowledgeService { - - // ================================= 知识库管理 ================================= - - /** - * @description 创建知识库基础信息,包含dify知识库各种参数的配置 - * @param knowledge 知识库信息 - * @param deptIds 部门ID列表(DEPARTMENT类型需要) - * @param roleIds 角色ID列表(ROLE/PRIVATE类型需要) - * @return ResultDomain 创建结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain createKnowledge(TbKnowledge knowledge); - - /** - * @description 内部创建知识库(不检查登录状态,用于系统初始化) - * @param knowledge 知识库信息(需要包含knowledgeId和creator) - * @return ResultDomain 创建结果 - * @author yslg - * @since 2025-12-20 - */ - ResultDomain createKnowledgeInternal(TbKnowledge knowledge); - - /** - * @description 更新知识库,包含dify知识库各种参数的配置 - * @param knowledge 知识库信息 - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain updateKnowledge(TbKnowledge knowledge); - - /** - * @description 删除知识库,同时删除dify知识库 - * @param knowledgeId 知识库ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain deleteKnowledge(String knowledgeId); - - /** - * @description 获取知识库详情,包含dify知识库各种参数的配置 - * @param knowledgeId 知识库ID - * @return ResultDomain 知识库信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain getKnowledgeById(String knowledgeId); - - /** - * @description 查询知识库列表 - * @param filter 过滤条件 - * @return ResultDomain 知识库列表 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain listKnowledges(TbKnowledge filter); - - /** - * @description 分页查询知识库 - * @param filter 过滤条件 - * @param pageParam 分页参数 - * @return ResultDomain 分页结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain pageKnowledges(TbKnowledge filter, PageParam pageParam); - - /** - * @description 获取知识库统计信息(从Dify同步文档数量和分段数量) - * @param knowledgeId 知识库ID - * @return ResultDomain 统计信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain getKnowledgeStats(String knowledgeId); - - /** - * @description 获取可用的嵌入模型列表 - * @return ResultDomain> 嵌入模型列表 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain> getAvailableEmbeddingModels(); - - /** - * @description 获取可用的Rerank模型列表 - * @return ResultDomain> Rerank模型列表 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain> getAvailableRerankModels(); - - // ================================= 文件管理 ================================= - - /** - * @description 获取知识库文档列表(查询本地数据库,关联文件详细信息) - * @param pageRequest 分页请求,filter 中包含 knowledgeId - * @return ResultDomain 文档列表(含文件详细信息) - * @author yslg - * @since 2025-12-20 - */ - ResultDomain getDocumentList(PageRequest pageRequest); - - /** - * @description 上传文件到知识库(完整流程:minio + Dify + 数据库) - * @param knowledgeId 知识库ID - * @param file 上传的文件 - * @param indexingTechnique 索引方式 - * @return ResultDomain 上传结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain uploadKnowledgeFile(String knowledgeId, MultipartFile file, String indexingTechnique); - - /** - * @description 批量上传文件到知识库 - * @param knowledgeId 知识库ID - * @param files 文件列表 - * @param indexingTechnique 索引方式 - * @return ResultDomain 上传结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain batchUploadKnowledgeFile(String knowledgeId, List files, String indexingTechnique); - - /** - * @description 上传新版本文件(fileRootId一致,version递增) - * @param knowledgeId 知识库ID - * @param file 新文件 - * @param fileRootId 文件根ID - * @return ResultDomain 新版本文件信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain updateKnowledgeFileVersion(String knowledgeId, MultipartFile file, String fileRootId); - - /** - * @description 删除知识库文件(根据fileRootId删除所有版本) - * @param fileRootId 文件根ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain deleteKnowledgeFileById(String fileRootId); - - /** - * @description 获取文件历史版本 - * @param fileRootId 文件根ID - * @return ResultDomain 文件历史版本列表(dataList) - * @author yslg - * @since 2025-12-18 - */ - ResultDomain getKnowledgeFileHistory(String fileRootId); - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/vo/AgentVO.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/vo/AgentVO.java deleted file mode 100644 index c44a1e05..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/vo/AgentVO.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.xyzh.api.ai.vo; - -import java.util.List; - -import org.xyzh.api.ai.dto.PromptCard; -import org.xyzh.common.vo.BaseVO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description Agent视图 - * @filename AgentVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@Schema(description = "Agent视图") -public class AgentVO extends BaseVO{ - private static final long serialVersionUID = 1L; - - @Schema(description = "智能体ID") - private String agentId; - - @Schema(description = "智能体名称") - private String name; - - @Schema(description = "智能体描述") - private String description; - - @Schema(description = "智能体url") - private String link; - - @Schema(description = "智能体APIKEY") - private String apiKey; - - @Schema(description = "是否是对外智能体,未登录可用") - private Boolean isOuter; - - @Schema(description = "引导词") - private String introduce; - - @Schema(description = "提示卡片数组") - private List promptCards; - - @Schema(description = "分类") - private String category; - -} diff --git a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/vo/KnowledgeFileVO.java b/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/vo/KnowledgeFileVO.java deleted file mode 100644 index 648755ca..00000000 --- a/urbanLifelineServ/apis/api-ai/src/main/java/org/xyzh/api/ai/vo/KnowledgeFileVO.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.xyzh.api.ai.vo; - -import org.xyzh.api.ai.dto.TbKnowledgeFile; -import org.xyzh.common.vo.BaseVO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description 知识库文件视图对象(关联文件信息) - * @filename KnowledgeFileVO.java - * @author yslg - * @copyright xyzh - * @since 2025-12-20 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "知识库文件视图对象") -public class KnowledgeFileVO extends BaseVO { - private static final long serialVersionUID = 1L; - - // TbKnowledgeFile 的字段 - @Schema(description = "知识库ID") - private String knowledgeId; - - @Schema(description = "文件ID") - private String fileId; - - @Schema(description = "文件根ID") - private String fileRootId; - - @Schema(description = "Dify文件ID") - private String difyFileId; - - @Schema(description = "文件版本") - private Integer version; - - // TbSysFile 的字段 - @Schema(description = "文件名") - private String fileName; - - @Schema(description = "文件路径") - private String filePath; - - @Schema(description = "文件大小(字节)") - private Long fileSize; - - @Schema(description = "文件MIME类型") - private String fileMimeType; - - @Schema(description = "文件访问URL") - private String fileUrl; - - @Schema(description = "文件扩展名") - private String fileExtension; - - @Schema(description = "文件MD5值") - private String fileMd5Hash; - - @Schema(description = "上传人员名称") - private String uploaderName; -} diff --git a/urbanLifelineServ/apis/api-all/pom.xml b/urbanLifelineServ/apis/api-all/pom.xml deleted file mode 100644 index e52af95d..00000000 --- a/urbanLifelineServ/apis/api-all/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh.apis - api-all - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - org.xyzh.apis - api-auth - - - org.xyzh.apis - api-file - - - org.xyzh.apis - api-message - - - org.xyzh.apis - api-system - - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-auth/pom.xml b/urbanLifelineServ/apis/api-auth/pom.xml deleted file mode 100644 index 8fc7dfce..00000000 --- a/urbanLifelineServ/apis/api-auth/pom.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh.apis - api-auth - ${urban-lifeline.version} - jar - - - 21 - 21 - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-auth/src/main/java/org/xyzh/api/auth/service/AuthService.java b/urbanLifelineServ/apis/api-auth/src/main/java/org/xyzh/api/auth/service/AuthService.java deleted file mode 100644 index 84e8e6fb..00000000 --- a/urbanLifelineServ/apis/api-auth/src/main/java/org/xyzh/api/auth/service/AuthService.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.xyzh.api.auth.service; - -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.core.domain.ResultDomain; - -/** - * @description 认证服务接口 - * @filename AuthService.java - * @author yslg - * @copyright yslg - * @since 2025-11-03 - */ -public interface AuthService { - - /** - * @description 登录(用于Dubbo远程调用,clientIp需提前设置到loginParam中) - * @param LoginParam loginParam 登录参数(包含clientIp) - * @return ResultDomain 登录结果 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain login(LoginParam loginParam); - - /** - * @description 刷新token - * @param token 当前token - * @param clientIp 客户端IP - * @return ResultDomain 刷新token结果 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain refreshToken(String token, String clientIp); - - /** - * @description 登出 - * @param token 当前token - * @return ResultDomain 登出结果 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain logout(String token); - - /** - * @description 根据验证码类型获取验证码 - * @param LoginParam loginParam 登录参数 - * @return ResultDomain 获取验证码结果 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain getCaptcha(LoginParam loginParam); - - /** - * @description 根据 token 获取登录信息,供其他服务调用以判定用户登录状态 - * @param token 鉴权 token(例如 JWT 或会话 token) - * @return ResultDomain 登录信息,若 token 无效或未登录则在 ResultDomain 中返回相应状态/错误 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain getLoginByToken(String token); - - /** - * @description 简单校验 token 是否有效(用于快速判断是否已登录) - * @param token 鉴权 token - * @return ResultDomain true 表示有效/已登录,false 表示无效/未登录 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain isTokenValid(String token); - - -} diff --git a/urbanLifelineServ/apis/api-bidding/pom.xml b/urbanLifelineServ/apis/api-bidding/pom.xml deleted file mode 100644 index 37afad8f..00000000 --- a/urbanLifelineServ/apis/api-bidding/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh - api-bidding - 1.0.0 - - - 21 - 21 - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/BiddingService.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/BiddingService.java deleted file mode 100644 index 7bd7f8c2..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/BiddingService.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.xyzh.api.bidding; - -public interface BiddingService { - -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BidResponseDTO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BidResponseDTO.java deleted file mode 100644 index f288d35a..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BidResponseDTO.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.api.bidding.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * 投标文件DTO - * 用于创建和更新投标文件 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "投标文件DTO") -public class BidResponseDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "响应文件ID(更新时需要)") - private String responseId; - - @Schema(description = "所属项目ID") - private String projectId; - - @Schema(description = "响应类型:technical-技术标/commercial-商务标/comprehensive-综合标") - private String responseType; - - @Schema(description = "文档名称") - private String docName; - - @Schema(description = "文档大纲") - private String outline; - - @Schema(description = "文档内容") - private String content; - - @Schema(description = "生成方式:ai-AI生成/template-模板生成/manual-人工编写") - private String generationMethod; - - @Schema(description = "使用的模板ID") - private String templateId; - - @Schema(description = "使用的AI模型") - private String aiModel; - - @Schema(description = "生成状态:draft-草稿/reviewing-审核中/approved-已批准/rejected-已拒绝/submitted-已提交") - private String generationStatus; - - @Schema(description = "版本号") - private Integer version; - - @Schema(description = "父版本ID") - private String parentVersionId; - - @Schema(description = "审核意见") - private String reviewComments; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingDocumentDTO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingDocumentDTO.java deleted file mode 100644 index 73636874..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingDocumentDTO.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.xyzh.api.bidding.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * 招标文档DTO - * 用于创建和更新招标文档 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "招标文档DTO") -public class BiddingDocumentDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "文档ID(更新时需要)") - private String docId; - - @Schema(description = "所属项目ID") - private String projectId; - - @Schema(description = "文档类型:tender-招标文件/technical-技术标/commercial-商务标/clarification-澄清文件/other-其他") - private String docType; - - @Schema(description = "文档名称") - private String docName; - - @Schema(description = "关联文件ID") - private String fileId; - - @Schema(description = "文件路径") - private String filePath; - - @Schema(description = "文件大小") - private Long fileSize; - - @Schema(description = "MIME类型") - private String mimeType; - - @Schema(description = "版本号") - private Integer version; - - @Schema(description = "语言") - private String language; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingProjectDTO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingProjectDTO.java deleted file mode 100644 index e948f4a1..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingProjectDTO.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.xyzh.api.bidding.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - -/** - * 招标项目DTO - * 用于创建和更新招标项目 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "招标项目DTO") -public class BiddingProjectDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "项目ID(更新时需要)") - private String projectId; - - @Schema(description = "项目编号") - private String projectNo; - - @Schema(description = "项目名称") - private String projectName; - - @Schema(description = "项目类型:public-公开招标/invitation-邀请招标/competitive_negotiation-竞争性谈判") - private String projectType; - - @Schema(description = "所属行业") - private String industry; - - @Schema(description = "来源平台") - private String sourcePlatform; - - @Schema(description = "来源URL") - private String sourceUrl; - - @Schema(description = "发布日期", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date publishDate; - - @Schema(description = "投标截止日期", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date deadline; - - @Schema(description = "开标日期", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date openingDate; - - @Schema(description = "预算金额") - private BigDecimal budgetAmount; - - @Schema(description = "货币单位") - private String currency; - - @Schema(description = "项目状态") - private String projectStatus; - - @Schema(description = "中标状态") - private String winningStatus; - - @Schema(description = "中标金额") - private BigDecimal winningAmount; - - @Schema(description = "客户名称") - private String clientName; - - @Schema(description = "客户联系方式") - private String clientContact; - - @Schema(description = "联系人") - private String contactPerson; - - @Schema(description = "项目地点") - private String projectLocation; - - @Schema(description = "项目描述") - private String description; - - @Schema(description = "关键词") - private List keywords; - - @Schema(description = "负责人") - private String responsibleUser; - - @Schema(description = "团队成员") - private List teamMembers; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingRequirementDTO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingRequirementDTO.java deleted file mode 100644 index 9141b991..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/BiddingRequirementDTO.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.xyzh.api.bidding.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.fasterxml.jackson.databind.JsonNode; -import java.math.BigDecimal; - -/** - * 招标要素DTO - * 用于创建和更新招标要素 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "招标要素DTO") -public class BiddingRequirementDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "要素ID(更新时需要)") - private String reqId; - - @Schema(description = "所属项目ID") - private String projectId; - - @Schema(description = "来源文档ID") - private String docId; - - @Schema(description = "要素类别:commercial-商务要素/technical-技术参数/veto-否决项/qualification-资质要求/delivery-交付要求/payment-付款条件/scoring-评分标准") - private String reqCategory; - - @Schema(description = "要素名称") - private String reqName; - - @Schema(description = "要素内容") - private String reqContent; - - @Schema(description = "要素值") - private String reqValue; - - @Schema(description = "是否必填", defaultValue = "false") - private Boolean isMandatory; - - @Schema(description = "是否为否决项", defaultValue = "false") - private Boolean isVeto; - - @Schema(description = "优先级") - private Integer priority; - - @Schema(description = "提取方式:ai-AI提取/manual-人工录入") - private String extractionMethod; - - @Schema(description = "置信度分数") - private BigDecimal confidenceScore; - - @Schema(description = "来源位置") - private JsonNode sourceLocation; - - @Schema(description = "合规状态:compliant-符合/non_compliant-不符合/pending-待确认") - private String complianceStatus; - - @Schema(description = "响应内容") - private String responseContent; - - @Schema(description = "备注") - private String notes; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/ProcessNodeDTO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/ProcessNodeDTO.java deleted file mode 100644 index 2e868bc3..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/dto/ProcessNodeDTO.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.xyzh.api.bidding.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; -import java.util.List; - -/** - * 项目流程节点DTO - * 用于创建和更新流程节点 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "项目流程节点DTO") -public class ProcessNodeDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "流程节点ID(更新时需要)") - private String processId; - - @Schema(description = "所属项目ID") - private String projectId; - - @Schema(description = "节点名称") - private String nodeName; - - @Schema(description = "节点类型:collection-文件收集/analysis-需求分析/preparation-文件准备/review-内部审核/submission-投标提交/opening-开标/result-结果通知") - private String nodeType; - - @Schema(description = "节点顺序") - private Integer nodeOrder; - - @Schema(description = "节点状态:pending-待处理/in_progress-进行中/completed-已完成/skipped-已跳过") - private String nodeStatus; - - @Schema(description = "计划开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date plannedStartTime; - - @Schema(description = "计划结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date plannedEndTime; - - @Schema(description = "实际开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date actualStartTime; - - @Schema(description = "实际结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date actualEndTime; - - @Schema(description = "负责人") - private String responsibleUser; - - @Schema(description = "参与人员") - private List participants; - - @Schema(description = "节点备注") - private String notes; - - @Schema(description = "附件ID数组") - private List attachments; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BidResponseVO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BidResponseVO.java deleted file mode 100644 index c6332f0b..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BidResponseVO.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.xyzh.api.bidding.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; - -/** - * 投标文件VO - * 用于前端展示投标文件信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "投标文件VO") -public class BidResponseVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "响应文件ID") - private String responseId; - - @Schema(description = "所属项目ID") - private String projectId; - - @Schema(description = "项目名称") - private String projectName; - - @Schema(description = "响应类型") - private String responseType; - - @Schema(description = "响应类型名称(中文)") - private String responseTypeName; - - @Schema(description = "文档名称") - private String docName; - - @Schema(description = "文档大纲") - private String outline; - - @Schema(description = "文档内容") - private String content; - - @Schema(description = "内容字数") - private Integer contentWordCount; - - @Schema(description = "生成方式") - private String generationMethod; - - @Schema(description = "生成方式名称") - private String generationMethodName; - - @Schema(description = "使用的模板ID") - private String templateId; - - @Schema(description = "使用的模板名称") - private String templateName; - - @Schema(description = "使用的AI模型") - private String aiModel; - - @Schema(description = "生成状态") - private String generationStatus; - - @Schema(description = "生成状态名称") - private String generationStatusName; - - @Schema(description = "生成状态颜色标签") - private String statusColor; - - @Schema(description = "关联文件ID") - private String fileId; - - @Schema(description = "文件路径") - private String filePath; - - @Schema(description = "文件下载URL") - private String fileUrl; - - @Schema(description = "版本号") - private Integer version; - - @Schema(description = "父版本ID") - private String parentVersionId; - - @Schema(description = "是否有历史版本", defaultValue = "false") - private Boolean hasHistory; - - @Schema(description = "审核意见") - private String reviewComments; - - @Schema(description = "创建者姓名") - private String creatorName; - - @Schema(description = "更新者姓名") - private String updaterName; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingDocumentVO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingDocumentVO.java deleted file mode 100644 index 047860d1..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingDocumentVO.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.xyzh.api.bidding.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import com.fasterxml.jackson.databind.JsonNode; -import java.util.Date; - -/** - * 招标文档VO - * 用于前端展示招标文档信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "招标文档VO") -public class BiddingDocumentVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "文档ID") - private String docId; - - @Schema(description = "所属项目ID") - private String projectId; - - @Schema(description = "项目名称") - private String projectName; - - @Schema(description = "文档类型") - private String docType; - - @Schema(description = "文档类型名称(中文)") - private String docTypeName; - - @Schema(description = "文档名称") - private String docName; - - @Schema(description = "关联文件ID") - private String fileId; - - @Schema(description = "文件路径") - private String filePath; - - @Schema(description = "文件下载URL") - private String fileUrl; - - @Schema(description = "文件大小") - private Long fileSize; - - @Schema(description = "文件大小格式化显示") - private String fileSizeFormatted; - - @Schema(description = "MIME类型") - private String mimeType; - - @Schema(description = "文件类型图标") - private String fileIcon; - - @Schema(description = "版本号") - private Integer version; - - @Schema(description = "语言") - private String language; - - @Schema(description = "页数") - private Integer pageCount; - - @Schema(description = "解析状态") - private String parseStatus; - - @Schema(description = "解析状态名称") - private String parseStatusName; - - @Schema(description = "解析结果") - private JsonNode parseResult; - - @Schema(description = "提取的结构化数据") - private JsonNode extractionData; - - @Schema(description = "AI分析结果") - private String aiAnalysis; - - @Schema(description = "上传日期", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date uploadDate; - - @Schema(description = "创建者姓名") - private String creatorName; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingProjectVO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingProjectVO.java deleted file mode 100644 index 29dc8925..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingProjectVO.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.xyzh.api.bidding.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - -/** - * 招标项目VO - * 用于前端展示招标项目详细信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "招标项目VO") -public class BiddingProjectVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "项目ID") - private String projectId; - - @Schema(description = "项目编号") - private String projectNo; - - @Schema(description = "项目名称") - private String projectName; - - @Schema(description = "项目类型") - private String projectType; - - @Schema(description = "项目类型名称(中文)") - private String projectTypeName; - - @Schema(description = "所属行业") - private String industry; - - @Schema(description = "来源平台") - private String sourcePlatform; - - @Schema(description = "来源URL") - private String sourceUrl; - - @Schema(description = "发布日期", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date publishDate; - - @Schema(description = "投标截止日期", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date deadline; - - @Schema(description = "开标日期", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date openingDate; - - @Schema(description = "距离截止日期剩余天数") - private Long daysUntilDeadline; - - @Schema(description = "预算金额") - private BigDecimal budgetAmount; - - @Schema(description = "货币单位") - private String currency; - - @Schema(description = "预算金额格式化显示") - private String budgetAmountFormatted; - - @Schema(description = "项目状态") - private String projectStatus; - - @Schema(description = "项目状态名称(中文)") - private String projectStatusName; - - @Schema(description = "中标状态") - private String winningStatus; - - @Schema(description = "中标状态名称(中文)") - private String winningStatusName; - - @Schema(description = "中标金额") - private BigDecimal winningAmount; - - @Schema(description = "中标金额格式化显示") - private String winningAmountFormatted; - - @Schema(description = "客户名称") - private String clientName; - - @Schema(description = "客户联系方式") - private String clientContact; - - @Schema(description = "联系人") - private String contactPerson; - - @Schema(description = "项目地点") - private String projectLocation; - - @Schema(description = "项目描述") - private String description; - - @Schema(description = "关键词") - private List keywords; - - @Schema(description = "负责人ID") - private String responsibleUser; - - @Schema(description = "负责人姓名") - private String responsibleUserName; - - @Schema(description = "团队成员") - private List teamMembers; - - @Schema(description = "团队成员姓名列表") - private List teamMemberNames; - - @Schema(description = "部门名称") - private String deptName; - - @Schema(description = "文档数量") - private Integer documentCount; - - @Schema(description = "要素数量") - private Integer requirementCount; - - @Schema(description = "否决项数量") - private Integer vetoCount; - - @Schema(description = "投标文件数量") - private Integer responseCount; - - @Schema(description = "完成进度(百分比)") - private Integer progressPercentage; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingRequirementVO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingRequirementVO.java deleted file mode 100644 index 1fd7b22a..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/BiddingRequirementVO.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.xyzh.api.bidding.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import com.fasterxml.jackson.databind.JsonNode; -import java.math.BigDecimal; -import java.util.Date; - -/** - * 招标要素VO - * 用于前端展示招标要素信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "招标要素VO") -public class BiddingRequirementVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "要素ID") - private String reqId; - - @Schema(description = "所属项目ID") - private String projectId; - - @Schema(description = "项目名称") - private String projectName; - - @Schema(description = "来源文档ID") - private String docId; - - @Schema(description = "来源文档名称") - private String docName; - - @Schema(description = "要素类别") - private String reqCategory; - - @Schema(description = "要素类别名称(中文)") - private String reqCategoryName; - - @Schema(description = "要素名称") - private String reqName; - - @Schema(description = "要素内容") - private String reqContent; - - @Schema(description = "要素值") - private String reqValue; - - @Schema(description = "是否必填", defaultValue = "false") - private Boolean isMandatory; - - @Schema(description = "是否为否决项", defaultValue = "false") - private Boolean isVeto; - - @Schema(description = "优先级") - private Integer priority; - - @Schema(description = "优先级标签(高/中/低)") - private String priorityLabel; - - @Schema(description = "提取方式") - private String extractionMethod; - - @Schema(description = "提取方式名称") - private String extractionMethodName; - - @Schema(description = "置信度分数") - private BigDecimal confidenceScore; - - @Schema(description = "置信度百分比") - private Integer confidencePercentage; - - @Schema(description = "来源位置") - private JsonNode sourceLocation; - - @Schema(description = "来源位置描述") - private String sourceLocationDesc; - - @Schema(description = "合规状态") - private String complianceStatus; - - @Schema(description = "合规状态名称") - private String complianceStatusName; - - @Schema(description = "合规状态标签颜色") - private String complianceStatusColor; - - @Schema(description = "响应内容") - private String responseContent; - - @Schema(description = "是否已响应", defaultValue = "false") - private Boolean hasResponse; - - @Schema(description = "备注") - private String notes; - - @Schema(description = "创建者姓名") - private String creatorName; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProcessNodeVO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProcessNodeVO.java deleted file mode 100644 index fefad0f6..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProcessNodeVO.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.xyzh.api.bidding.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; -import java.util.List; - -/** - * 项目流程节点VO - * 用于前端展示流程节点信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "项目流程节点VO") -public class ProcessNodeVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "流程节点ID") - private String processId; - - @Schema(description = "所属项目ID") - private String projectId; - - @Schema(description = "项目名称") - private String projectName; - - @Schema(description = "节点名称") - private String nodeName; - - @Schema(description = "节点类型") - private String nodeType; - - @Schema(description = "节点类型名称") - private String nodeTypeName; - - @Schema(description = "节点顺序") - private Integer nodeOrder; - - @Schema(description = "节点状态") - private String nodeStatus; - - @Schema(description = "节点状态名称") - private String nodeStatusName; - - @Schema(description = "节点状态颜色") - private String statusColor; - - @Schema(description = "节点图标") - private String nodeIcon; - - @Schema(description = "计划开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date plannedStartTime; - - @Schema(description = "计划结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date plannedEndTime; - - @Schema(description = "实际开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date actualStartTime; - - @Schema(description = "实际结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date actualEndTime; - - @Schema(description = "计划耗时(天)") - private Integer plannedDuration; - - @Schema(description = "实际耗时(天)") - private Integer actualDuration; - - @Schema(description = "是否延期", defaultValue = "false") - private Boolean isDelayed; - - @Schema(description = "延期天数") - private Integer delayedDays; - - @Schema(description = "负责人ID") - private String responsibleUser; - - @Schema(description = "负责人姓名") - private String responsibleUserName; - - @Schema(description = "参与人员ID列表") - private List participants; - - @Schema(description = "参与人员姓名列表") - private List participantNames; - - @Schema(description = "节点备注") - private String notes; - - @Schema(description = "附件ID数组") - private List attachments; - - @Schema(description = "附件数量") - private Integer attachmentCount; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProjectListVO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProjectListVO.java deleted file mode 100644 index ba501238..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProjectListVO.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.xyzh.api.bidding.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - -/** - * 招标项目列表VO(简化版) - * 用于前端列表展示 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "招标项目列表VO") -public class ProjectListVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "项目ID") - private String projectId; - - @Schema(description = "项目编号") - private String projectNo; - - @Schema(description = "项目名称") - private String projectName; - - @Schema(description = "项目类型") - private String projectType; - - @Schema(description = "项目类型名称") - private String projectTypeName; - - @Schema(description = "所属行业") - private String industry; - - @Schema(description = "投标截止日期", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date deadline; - - @Schema(description = "距离截止日期剩余天数") - private Long daysUntilDeadline; - - @Schema(description = "是否即将截止(<3天)", defaultValue = "false") - private Boolean isUrgent; - - @Schema(description = "预算金额格式化显示") - private String budgetAmountFormatted; - - @Schema(description = "项目状态") - private String projectStatus; - - @Schema(description = "项目状态名称") - private String projectStatusName; - - @Schema(description = "中标状态") - private String winningStatus; - - @Schema(description = "客户名称") - private String clientName; - - @Schema(description = "负责人姓名") - private String responsibleUserName; - - @Schema(description = "完成进度(百分比)") - private Integer progressPercentage; -} diff --git a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProjectStatisticsVO.java b/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProjectStatisticsVO.java deleted file mode 100644 index 4d51bbaa..00000000 --- a/urbanLifelineServ/apis/api-bidding/src/main/java/org/xyzh/api/bidding/vo/ProjectStatisticsVO.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.xyzh.api.bidding.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import java.math.BigDecimal; -import java.util.Map; - -/** - * 项目统计VO - * 用于前端展示项目统计数据 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "项目统计VO") -public class ProjectStatisticsVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "总项目数") - private Long totalProjects; - - @Schema(description = "进行中的项目数") - private Long ongoingProjects; - - @Schema(description = "已提交的项目数") - private Long submittedProjects; - - @Schema(description = "已中标的项目数") - private Long wonProjects; - - @Schema(description = "未中标的项目数") - private Long lostProjects; - - @Schema(description = "中标率(百分比)") - private BigDecimal winRate; - - @Schema(description = "即将截止的项目数(<3天)") - private Long urgentProjects; - - @Schema(description = "总预算金额") - private BigDecimal totalBudget; - - @Schema(description = "总中标金额") - private BigDecimal totalWinningAmount; - - @Schema(description = "按状态分组统计") - private Map projectsByStatus; - - @Schema(description = "按类型分组统计") - private Map projectsByType; - - @Schema(description = "按行业分组统计") - private Map projectsByIndustry; - - @Schema(description = "按月份分组统计(最近12个月)") - private Map projectsByMonth; - - @Schema(description = "按负责人分组统计") - private Map projectsByUser; - - @Schema(description = "平均项目周期(天)") - private Integer avgProjectCycle; - - @Schema(description = "最近7天新增项目数") - private Long recentNewProjects; -} diff --git a/urbanLifelineServ/apis/api-crontab/pom.xml b/urbanLifelineServ/apis/api-crontab/pom.xml deleted file mode 100644 index e7ba4476..00000000 --- a/urbanLifelineServ/apis/api-crontab/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh - api-crontab - 1.0.0 - - - 21 - 21 - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabLogDTO.java b/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabLogDTO.java deleted file mode 100644 index e675ad76..00000000 --- a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabLogDTO.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.xyzh.api.crontab.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; - -/** - * 定时任务执行日志DTO - * 用于记录任务执行情况 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "定时任务执行日志DTO") -public class TbCrontabLogDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "任务ID") - private String taskId; - - @Schema(description = "任务名称") - private String taskName; - - @Schema(description = "任务分组") - private String taskGroup; - - @Schema(description = "Bean名称") - private String beanName; - - @Schema(description = "方法名称") - private String methodName; - - @Schema(description = "方法参数") - private String methodParams; - - @Schema(description = "执行状态:0-失败/1-成功") - private Integer executeStatus; - - @Schema(description = "执行结果信息") - private String executeMessage; - - @Schema(description = "异常信息") - private String exceptionInfo; - - @Schema(description = "开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date startTime; - - @Schema(description = "结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date endTime; - - @Schema(description = "执行时长(毫秒)") - private Integer executeDuration; -} diff --git a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabTaskDTO.java b/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabTaskDTO.java deleted file mode 100644 index b03b40fb..00000000 --- a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabTaskDTO.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.api.crontab.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * 定时任务DTO - * 用于创建和更新定时任务 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "定时任务DTO") -public class TbCrontabTaskDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "任务ID(更新时需要)") - private String taskId; - - @Schema(description = "任务名称") - private String taskName; - - @Schema(description = "任务分组", defaultValue = "DEFAULT") - private String taskGroup; - - @Schema(description = "任务元数据ID") - private String metaId; - - @Schema(description = "是否使用默认接收人", defaultValue = "false") - private Boolean defaultRecipient; - - @Schema(description = "Bean名称") - private String beanName; - - @Schema(description = "方法名称") - private String methodName; - - @Schema(description = "方法参数") - private String methodParams; - - @Schema(description = "Cron表达式") - private String cronExpression; - - @Schema(description = "任务状态:0-暂停/1-运行中", defaultValue = "0") - private Integer status; - - @Schema(description = "任务描述") - private String description; - - @Schema(description = "是否允许并发执行", defaultValue = "false") - private Boolean concurrent; - - @Schema(description = "错过执行策略:1-立即执行/2-执行一次/3-放弃执行", defaultValue = "1") - private Integer misfirePolicy; -} diff --git a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabTaskMetaDTO.java b/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabTaskMetaDTO.java deleted file mode 100644 index b088d459..00000000 --- a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/dto/TbCrontabTaskMetaDTO.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.xyzh.api.crontab.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * 定时任务元数据DTO - * 用于创建和更新任务元数据配置 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "定时任务元数据DTO") -public class TbCrontabTaskMetaDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "元数据ID(更新时需要)") - private String metaId; - - @Schema(description = "任务名称") - private String name; - - @Schema(description = "任务描述") - private String description; - - @Schema(description = "任务分类") - private String category; - - @Schema(description = "Bean名称(执行器类名)") - private String beanName; - - @Schema(description = "执行方法名") - private String methodName; - - @Schema(description = "Python脚本路径") - private String scriptPath; - - @Schema(description = "参数模板(JSON格式)") - private String paramSchema; - - @Schema(description = "是否自动发布", defaultValue = "false") - private Boolean autoPublish; - - @Schema(description = "排序号", defaultValue = "0") - private Integer sortOrder; -} diff --git a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/service/CrontabService.java b/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/service/CrontabService.java deleted file mode 100644 index 000f6c1d..00000000 --- a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/service/CrontabService.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.xyzh.api.crontab.service; - -/** - * 定时任务服务接口 - * 用于定时任务管理 - */ -public interface CrontabService { - -} diff --git a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabLogVO.java b/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabLogVO.java deleted file mode 100644 index a57e33ee..00000000 --- a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabLogVO.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.xyzh.api.crontab.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; - -/** - * 定时任务执行日志VO - * 用于前端展示任务执行日志 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "定时任务执行日志VO") -public class CrontabLogVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "日志ID") - private String logId; - - @Schema(description = "任务ID") - private String taskId; - - @Schema(description = "任务名称") - private String taskName; - - @Schema(description = "任务分组") - private String taskGroup; - - @Schema(description = "Bean名称") - private String beanName; - - @Schema(description = "方法名称") - private String methodName; - - @Schema(description = "方法参数") - private String methodParams; - - @Schema(description = "执行状态:0-失败/1-成功") - private Integer executeStatus; - - @Schema(description = "执行状态名称") - private String executeStatusName; - - @Schema(description = "执行状态颜色") - private String executeStatusColor; - - @Schema(description = "执行结果信息") - private String executeMessage; - - @Schema(description = "异常信息") - private String exceptionInfo; - - @Schema(description = "是否有异常", defaultValue = "false") - private Boolean hasException; - - @Schema(description = "开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date startTime; - - @Schema(description = "结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date endTime; - - @Schema(description = "执行时长(毫秒)") - private Integer executeDuration; - - @Schema(description = "执行时长格式化显示") - private String executeDurationFormatted; -} diff --git a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskListVO.java b/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskListVO.java deleted file mode 100644 index 4b00e7bc..00000000 --- a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskListVO.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.xyzh.api.crontab.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; - -/** - * 定时任务列表VO - * 用于前端列表展示(简化版) - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "定时任务列表VO") -public class CrontabTaskListVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "任务ID") - private String taskId; - - @Schema(description = "任务名称") - private String taskName; - - @Schema(description = "任务分组") - private String taskGroup; - - @Schema(description = "Cron表达式") - private String cronExpression; - - @Schema(description = "Cron表达式描述") - private String cronDescription; - - @Schema(description = "任务状态") - private Integer status; - - @Schema(description = "任务状态名称") - private String statusName; - - @Schema(description = "下次执行时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date nextExecuteTime; - - @Schema(description = "最后执行时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date lastExecuteTime; - - @Schema(description = "最后执行状态") - private Integer lastExecuteStatus; - - @Schema(description = "创建者姓名") - private String creatorName; -} diff --git a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskMetaVO.java b/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskMetaVO.java deleted file mode 100644 index 98766766..00000000 --- a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskMetaVO.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.api.crontab.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * 定时任务元数据VO - * 用于前端展示任务元数据信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "定时任务元数据VO") -public class CrontabTaskMetaVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "元数据ID") - private String metaId; - - @Schema(description = "任务名称") - private String name; - - @Schema(description = "任务描述") - private String description; - - @Schema(description = "任务分类") - private String category; - - @Schema(description = "Bean名称(执行器类名)") - private String beanName; - - @Schema(description = "执行方法名") - private String methodName; - - @Schema(description = "Python脚本路径") - private String scriptPath; - - @Schema(description = "参数模板(JSON格式)") - private String paramSchema; - - @Schema(description = "是否自动发布", defaultValue = "false") - private Boolean autoPublish; - - @Schema(description = "排序号") - private Integer sortOrder; - - @Schema(description = "关联的任务数量") - private Integer taskCount; - - @Schema(description = "创建者姓名") - private String creatorName; - - @Schema(description = "更新者姓名") - private String updaterName; -} diff --git a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskVO.java b/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskVO.java deleted file mode 100644 index 444952bf..00000000 --- a/urbanLifelineServ/apis/api-crontab/src/main/java/org/xyzh/api/crontab/vo/CrontabTaskVO.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.api.crontab.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; - -/** - * 定时任务VO - * 用于前端展示定时任务信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "定时任务VO") -public class CrontabTaskVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "任务ID") - private String taskId; - - @Schema(description = "任务名称") - private String taskName; - - @Schema(description = "任务分组") - private String taskGroup; - - @Schema(description = "任务元数据ID") - private String metaId; - - @Schema(description = "元数据名称") - private String metaName; - - @Schema(description = "是否使用默认接收人", defaultValue = "false") - private Boolean defaultRecipient; - - @Schema(description = "Bean名称") - private String beanName; - - @Schema(description = "方法名称") - private String methodName; - - @Schema(description = "方法参数") - private String methodParams; - - @Schema(description = "Cron表达式") - private String cronExpression; - - @Schema(description = "Cron表达式描述(中文)") - private String cronDescription; - - @Schema(description = "任务状态") - private Integer status; - - @Schema(description = "任务状态名称") - private String statusName; - - @Schema(description = "任务描述") - private String description; - - @Schema(description = "是否允许并发执行", defaultValue = "false") - private Boolean concurrent; - - @Schema(description = "错过执行策略") - private Integer misfirePolicy; - - @Schema(description = "错过执行策略名称") - private String misfirePolicyName; - - @Schema(description = "下次执行时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date nextExecuteTime; - - @Schema(description = "最后执行时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date lastExecuteTime; - - @Schema(description = "最后执行状态:0-失败/1-成功") - private Integer lastExecuteStatus; - - @Schema(description = "创建者姓名") - private String creatorName; - - @Schema(description = "更新者姓名") - private String updaterName; -} diff --git a/urbanLifelineServ/apis/api-file/pom.xml b/urbanLifelineServ/apis/api-file/pom.xml deleted file mode 100644 index 3d4df966..00000000 --- a/urbanLifelineServ/apis/api-file/pom.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh.apis - api-file - ${urban-lifeline.version} - jar - - - 21 - 21 - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-file/src/main/java/org/xyzh/api/file/dto/TbSysFileDTO.java b/urbanLifelineServ/apis/api-file/src/main/java/org/xyzh/api/file/dto/TbSysFileDTO.java deleted file mode 100644 index e726e2ce..00000000 --- a/urbanLifelineServ/apis/api-file/src/main/java/org/xyzh/api/file/dto/TbSysFileDTO.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.xyzh.api.file.dto; - -import org.xyzh.common.dto.BaseDTO; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统文件DTO - * @filename TbSysFileDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统文件DTO") -public class TbSysFileDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "文件ID (主键)") - private String fileId; - - @Schema(description = "文件根ID") - private String fileRootId; - - @Schema(description = "文件版本") - private Integer version; - - @Schema(description = "文件名") - private String name; - - @Schema(description = "文件路径") - private String path; - - @Schema(description = "文件大小(字节)") - private Long size; - - @Schema(description = "文件类型") - private String type; - - @Schema(description = "存储类型") - private String storageType; - - @Schema(description = "MIME 类型") - private String mimeType; - - @Schema(description = "文件访问 URL") - private String url; - - @Schema(description = "文件状态") - private String status; - - @Schema(description = "所属模块") - private String module; - - @Schema(description = "业务ID") - private String businessId; - - @Schema(description = "上传者用户ID") - private String uploader; - - @Schema(description = "MinIO对象名称") - private String objectName; - - @Schema(description = "MinIO存储桶名称") - private String bucketName; - - @Schema(description = "文件MD5值") - private String md5Hash; - - @Schema(description = "文件扩展名") - private String extension; - -} diff --git a/urbanLifelineServ/apis/api-file/src/main/java/org/xyzh/api/file/service/FileService.java b/urbanLifelineServ/apis/api-file/src/main/java/org/xyzh/api/file/service/FileService.java deleted file mode 100644 index 792ee8f0..00000000 --- a/urbanLifelineServ/apis/api-file/src/main/java/org/xyzh/api/file/service/FileService.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.xyzh.api.file.service; - -import org.springframework.web.multipart.MultipartFile; -import org.xyzh.api.file.dto.TbSysFileDTO; -import org.xyzh.common.core.domain.ResultDomain; - -/** - * @description 文件服务接口 - * @filename FileService.java - * @author yslg - * @copyright yslg - * @since 2025-11-03 - */ -public interface FileService { - - /** - * @description 上传文件 - * @param file 文件对象 - * @param module 所属模块 - * @param businessId 业务ID - * @return ResultDomain 上传结果,包含文件信息 - * @author yslg - * @since 2025-10-16 - */ - ResultDomain uploadFile(MultipartFile file, String module, String businessId); - - /** - * @description 批量上传文件 - * @param files 文件对象列表 - * @param module 所属模块 - * @param businessId 业务ID - * @param uploader 上传者用户ID(可选) - * @return ResultDomain 上传结果,包含文件信息列表 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain batchUploadFiles(MultipartFile[] files, String module, String businessId, String uploader); - - /** - * @description 删除文件 - * @param fileId 文件ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain deleteFile(String fileId); - - /** - * @description 批量删除文件(逻辑删除) - * @param fileIds 文件ID列表 - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-10-16 - */ - ResultDomain batchDeleteFiles(String[] fileIds); - - /** - * @description 下载文件 - * @param fileId 文件ID - * @return ResultDomain 文件字节数组 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain downloadFile(String fileId); - - /** - * @description 根据文件ID查询文件信息 - * @param fileId 文件ID - * @return ResultDomain 文件信息 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain getFileById(String fileId); - - /** - * @description 保存临时文件 - * @param file 文件对象 - * @param module 所属模块 - * @param businessId 业务ID - * @return ResultDomain 保存结果 - * @author yslg - * @since 2025-11-03 - */ - ResultDomain saveTempFile(MultipartFile file, String module, String businessId); - - /** - * @description 上传新版本文件(用于文件更新,fileRootId保持一致,version递增) - * @param file 文件对象 - * @param module 所属模块 - * @param businessId 业务ID - * @param fileRootId 文件根ID(多版本一致) - * @return ResultDomain 上传结果,包含新版本文件信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain uploadFileVersion(MultipartFile file, String module, String businessId, String fileRootId); - - /** - * @description 通过字节数组上传文件(用于跨模块 Dubbo 调用) - * @param fileBytes 文件字节数组 - * @param fileName 文件名 - * @param contentType 文件类型 - * @param module 所属模块 - * @param businessId 业务ID - * @return ResultDomain 上传结果 - * @author yslg - * @since 2025-12-20 - */ - ResultDomain uploadFileBytes(byte[] fileBytes, String fileName, String contentType, String module, String businessId); - - /** - * @description 通过字节数组上传文件(支持直接指定上传者,用于未登录用户场景如AIChat) - * @param fileBytes 文件字节数组 - * @param fileName 文件名 - * @param contentType 文件类型 - * @param module 所属模块 - * @param businessId 业务ID - * @param uploaderUserId 上传者用户ID(可为null) - * @return ResultDomain 上传结果 - * @author yslg - * @since 2025-12-20 - */ - ResultDomain uploadFileBytesWithUser(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String uploaderUserId); - - /** - * @description 通过字节数组上传新版本文件(用于跨模块 Dubbo 调用的文件版本更新) - * @param fileBytes 文件字节数组 - * @param fileName 文件名 - * @param contentType 文件类型 - * @param module 所属模块 - * @param businessId 业务ID - * @param fileRootId 文件根ID(多版本一致) - * @return ResultDomain 上传结果,包含新版本文件信息 - * @author yslg - * @since 2025-12-20 - */ - ResultDomain uploadFileBytesVersion(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String fileRootId); - - /** - * @description 通过字节数组上传新版本文件(支持直接指定上传者) - * @param fileBytes 文件字节数组 - * @param fileName 文件名 - * @param contentType 文件类型 - * @param module 所属模块 - * @param businessId 业务ID - * @param fileRootId 文件根ID(多版本一致) - * @param uploaderUserId 上传者用户ID(可为null) - * @return ResultDomain 上传结果,包含新版本文件信息 - * @author yslg - * @since 2025-12-20 - */ - ResultDomain uploadFileBytesVersionWithUser(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String fileRootId, String uploaderUserId); - -} diff --git a/urbanLifelineServ/apis/api-message/pom.xml b/urbanLifelineServ/apis/api-message/pom.xml deleted file mode 100644 index aac432d9..00000000 --- a/urbanLifelineServ/apis/api-message/pom.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh.apis - api-message - ${urban-lifeline.version} - jar - - - 21 - 21 - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageChannelDTO.java b/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageChannelDTO.java deleted file mode 100644 index 73974a49..00000000 --- a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageChannelDTO.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.xyzh.api.message.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 消息渠道配置DTO - * @filename TbMessageChannelDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "消息渠道配置DTO") -public class TbMessageChannelDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "渠道ID") - private String channelId; - - @Schema(description = "渠道编码:app/sms/email/wechat/dingtalk等") - private String channelCode; - - @Schema(description = "渠道名称") - private String channelName; - - @Schema(description = "渠道描述") - private String channelDesc; - - @Schema(description = "渠道配置(JSON格式)") - private String config; - - @Schema(description = "渠道状态:enabled-启用/disabled-禁用/maintenance-维护中") - private String status; - - @Schema(description = "优先级(数字越大优先级越高)") - private Integer priority; -} - diff --git a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageDTO.java b/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageDTO.java deleted file mode 100644 index ce2895f8..00000000 --- a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageDTO.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.xyzh.api.message.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 消息DTO - * @filename TbMessageDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "消息DTO") -public class TbMessageDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "消息ID") - private String messageId; - - - @Schema(description = "消息标题") - private String title; - - @Schema(description = "消息内容") - private String content; - - @Schema(description = "消息类型") - private String type; - - @Schema(description = "消息状态") - private String status; -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageRangeDTO.java b/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageRangeDTO.java deleted file mode 100644 index ee357ac4..00000000 --- a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageRangeDTO.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.xyzh.api.message.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 消息发送范围DTO - * @filename TbMessageRangeDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "消息发送范围DTO") -public class TbMessageRangeDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "消息ID") - private String messageId; - - @Schema(description = "目标类型:user-指定用户/dept-部门/role-角色/all-全员") - private String targetType; - - @Schema(description = "目标ID(用户、部门、角色ID等,all类型时为空)") - private String targetId; - - @Schema(description = "发送渠道:app/sms/email/wechat/dingtalk等") - private String channel; -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageReceiverDTO.java b/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageReceiverDTO.java deleted file mode 100644 index acc3f941..00000000 --- a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/dto/TbMessageReceiverDTO.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.xyzh.api.message.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; - -import java.time.ZonedDateTime; - -/** - * @description 用户消息接收记录DTO - * @filename TbMessageReceiverDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "用户消息接收记录DTO") -public class TbMessageReceiverDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "消息ID") - private String messageId; - - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "接收渠道:app/sms/email/wechat/dingtalk等") - private String channel; - - @Schema(description = "消息状态:unread-未读/read-已读/handled-已处理/deleted-已删除") - private String status; - - @Schema(description = "阅读时间") - private ZonedDateTime readTime; - - @Schema(description = "处理时间") - private ZonedDateTime handleTime; -} diff --git a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/service/MessageService.java b/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/service/MessageService.java deleted file mode 100644 index d6928831..00000000 --- a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/service/MessageService.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.xyzh.api.message.service; - -import org.xyzh.api.message.dto.TbMessageDTO; -import org.xyzh.api.message.vo.MessageVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageParam; - - -/** - * @description 消息服务接口 - * @filename MessageService.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -public interface MessageService { - - // ================ 发送邮件 ================== - ResultDomain sendSimpleEmail(String to, String subject, String content); - - ResultDomain sendHtmlEmail(String to, String subject, String content); - - ResultDomain sendEmailVerificationCode(String to, String code); - - // ================ 发送短信 ================== - - //================= 用户查看消息列表 ================= - ResultDomain sendPhoneVerificationCode(String phone, String code); - - - - /** - * @description 获取我的消息列表 - * @param userId 用户ID - * @return ResultDomain 消息列表 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getMyMessageList(TbMessageDTO filter); - - /** - * @description 获取我的消息分页列表 - * @param TbMessageDTO filter 消息过滤条件 - * @param PageParam pageParam 分页参数 - * @return ResultDomain 消息分页列表 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getMyMessagePage(TbMessageDTO filter, PageParam pageParam); - - /** - * @description 获取我的消息详情 - * @param messageId 消息ID - * @return ResultDomain 消息详情 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getMyMessageDetail(String messageId); - - // ================= 用户处理消息 ================= - /** - * @description 用户处理消息 - * @param messageId 消息ID - * @param status 消息状态 - * @return ResultDomain 消息处理结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain handleMessage(String messageId, String status); - - // ================= 管理员查看消息列表 ================= - /** - * @description 获取消息列表 - * @param TbMessageDTO filter 消息过滤条件 - * @return ResultDomain 消息列表 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getMessageList(TbMessageDTO filter); - - /** - * @description 获取消息分页列表 - * @param TbMessageDTO filter 消息过滤条件 - * @param PageParam pageParam 分页参数 - * @return ResultDomain 消息分页列表 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getMessagePage(TbMessageDTO filter, PageParam pageParam); - - - /** - * @description 获取消息详情 - * @param messageId 消息ID - * @return ResultDomain 消息详情 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getMessageDetail(String messageId); - - // ================= 管理员处理消息 ================= - - /** - * @description 创建消息 - * @param MessageVO messageVO 消息VO - * @return ResultDomain 创建结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain createMessage(MessageVO messageVO); - - /** - * @description 更新消息 - * @param MessageVO messageVO 消息VO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateMessage(MessageVO messageVO); - - /** - * @description 删除消息 - * @param messageId 消息ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain deleteMessage(String messageId); - - /** - * @description 发送消息 - * @param MessageVO messageVO 消息VO - * @return ResultDomain 发送结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain sendMessage(MessageVO messageVO); - - /** - * @description 撤回消息 - * @param messageId 消息ID - * @return ResultDomain 撤回结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain withdrawMessage(String messageId); -} diff --git a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageRangeChannelVO.java b/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageRangeChannelVO.java deleted file mode 100644 index f38780d3..00000000 --- a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageRangeChannelVO.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.xyzh.api.message.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; - -/** - * @description 消息发送范围和渠道VO(Range和Channel的平铺组合) - * @filename MessageRangeChannelVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "消息发送范围和渠道VO") -public class MessageRangeChannelVO extends BaseVO { - - // ========== Range相关字段 ========== - @Schema(description = "消息ID") - private String messageId; - - @Schema(description = "目标类型:user-指定用户/dept-部门/role-角色/all-全员") - private String targetType; - - @Schema(description = "目标ID(用户、部门、角色ID等,all类型时为空)") - private String targetId; - - @Schema(description = "目标名称(用户名、部门名、角色名等,用于前端展示)") - private String targetName; - - // ========== Channel相关字段 ========== - @Schema(description = "渠道编码:app/sms/email/wechat/dingtalk等") - private String channelCode; - - @Schema(description = "渠道名称") - private String channelName; - - @Schema(description = "渠道描述") - private String channelDesc; - - @Schema(description = "渠道状态:enabled-启用/disabled-禁用/maintenance-维护中") - private String channelStatus; - - @Schema(description = "渠道优先级(数字越大优先级越高)") - private Integer channelPriority; -} diff --git a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageReceiverVO.java b/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageReceiverVO.java deleted file mode 100644 index edbf95c8..00000000 --- a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageReceiverVO.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.xyzh.api.message.vo; - -import lombok.Data; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; -import org.xyzh.common.vo.BaseVO; - -/** - * 用户消息接收记录VO - * 用于前端展示用户消息信息 - */ -@Data -@Schema(description = "用户消息接收记录VO") -public class MessageReceiverVO extends BaseVO { - - @Schema(description = "消息ID") - private String messageId; - - @Schema(description = "消息标题") - private String title; - - @Schema(description = "消息内容") - private String content; - - @Schema(description = "消息类型") - private String type; - - @Schema(description = "消息类型名称") - private String typeName; - - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "用户姓名") - private String userName; - - @Schema(description = "接收渠道") - private String channel; - - @Schema(description = "渠道名称") - private String channelName; - - @Schema(description = "消息状态:unread-未读/read-已读/handled-已处理/deleted-已删除") - private String status; - - @Schema(description = "状态名称") - private String statusName; - - @Schema(description = "状态颜色") - private String statusColor; - - @Schema(description = "阅读时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date readTime; - - @Schema(description = "处理时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date handleTime; - - @Schema(description = "服务类型") - private String service; -} diff --git a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageVO.java b/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageVO.java deleted file mode 100644 index 06deceff..00000000 --- a/urbanLifelineServ/apis/api-message/src/main/java/org/xyzh/api/message/vo/MessageVO.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.xyzh.api.message.vo; - -import java.util.List; - -import org.xyzh.api.message.dto.TbMessageReceiverDTO; -import org.xyzh.common.vo.BaseVO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description 消息VO(包含消息详情和发送范围) - * @filename MessageVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "消息VO") -public class MessageVO extends BaseVO { - - @Schema(description = "消息ID") - private String messageId; - - @Schema(description = "消息标题") - private String title; - - @Schema(description = "消息内容") - private String content; - - @Schema(description = "消息类型") - private String type; - - @Schema(description = "消息状态") - private String status; - - @Schema(description = "消息发送范围列表") - private List messageRanges; - - @Schema(description = "消息接收记录列表(管理员查看时使用)") - private List messageReceivers; -} diff --git a/urbanLifelineServ/apis/api-message/消息系统设计说明.md b/urbanLifelineServ/apis/api-message/消息系统设计说明.md deleted file mode 100644 index e0d53c5d..00000000 --- a/urbanLifelineServ/apis/api-message/消息系统设计说明.md +++ /dev/null @@ -1,238 +0,0 @@ -# 消息系统设计说明 - -## 📊 数据表结构 - -### 1. tb_message - 消息主表 -存储消息的基本信息 - -**主要字段:** -- `message_id` - 消息ID(主键) -- `title` - 消息标题 -- `content` - 消息内容 -- `type` - 消息类型 -- `status` - 消息状态 - -### 2. tb_message_range - 消息发送范围定义表 -定义消息要发送给哪些对象,通过什么渠道 - -**主要字段:** -- `message_id` - 消息ID -- `target_type` - 目标类型(user/dept/role/all) -- `target_id` - 目标ID(用户、部门、角色ID等) -- `channel` - 发送渠道(app/sms/email/wechat等) -- **唯一约束:** (message_id, target_type, target_id, channel) - -**使用示例:** -- 发送给部门001,通过app:`{target_type: 'dept', target_id: 'D001', channel: 'app'}` -- 发送给部门001,通过sms:`{target_type: 'dept', target_id: 'D001', channel: 'sms'}` -- 发送给全员,通过app:`{target_type: 'all', target_id: null, channel: 'app'}` - -### 3. tb_message_receiver - 用户消息接收记录表 -记录每个用户实际收到的消息及处理状态 - -**主要字段:** -- `message_id` - 消息ID -- `user_id` - 用户ID -- `channel` - 接收渠道 -- `status` - 消息状态(unread/read/handled/deleted) -- `read_time` - 阅读时间 -- `handle_time` - 处理时间 -- **唯一约束:** (message_id, user_id, channel) - -**索引:** -- `idx_message_user_user_status` - 快速查询用户消息列表 -- `idx_message_user_message` - 快速查询消息的接收情况 - -### 4. tb_message_channel - 消息渠道配置表 -管理各种消息发送渠道的配置 - -**主要字段:** -- `channel_id` - 渠道ID(主键) -- `channel_code` - 渠道编码(app/sms/email/wechat/dingtalk) -- `channel_name` - 渠道名称 -- `config` - 渠道配置(JSON格式,存储API密钥等) -- `status` - 渠道状态(enabled/disabled/maintenance) -- `priority` - 优先级 - -**预置渠道:** -- app - 应用内消息(已启用) -- sms - 短信通知(已禁用) -- email - 邮件通知(已禁用) -- wechat - 微信通知(已禁用) -- dingtalk - 钉钉通知(已禁用) - -## 📦 DTO/VO 结构 - -### TbMessageDTO -消息基本信息DTO - -**字段:** -- messageId -- title -- content -- type -- status - -### TbMessageRangeDTO -消息发送范围DTO - -**字段:** -- messageId -- targetType - 目标类型 -- targetId - 目标ID -- channel - 发送渠道 - -### TbMessageReceiverDTO -用户消息接收记录DTO - -**字段:** -- messageId -- userId -- channel -- status -- readTime -- handleTime - -### TbMessageChannelDTO -消息渠道配置DTO - -**字段:** -- channelId -- channelCode -- channelName -- channelDesc -- config -- status -- priority - -### MessageVO -消息视图对象(用于创建和查看消息) - -**字段:** -- messageId -- title -- content -- type -- status -- createTime -- creator -- messageRanges - 消息发送范围列表 -- messageReceivers - 消息接收记录列表(管理员查看时使用) - -## 🔄 业务流程 - -### 1. 创建并发送消息 - -```java -// 创建消息 -MessageVO messageVO = new MessageVO(); -messageVO.setTitle("系统维护通知"); -messageVO.setContent("系统将于今晚22:00进行维护"); -messageVO.setType("notice"); - -// 定义发送范围(发给IT部门,通过app和email) -List ranges = new ArrayList<>(); -ranges.add(new TbMessageRangeDTO() {{ - setTargetType("dept"); - setTargetId("DEPT_IT"); - setChannel("app"); -}}); -ranges.add(new TbMessageRangeDTO() {{ - setTargetType("dept"); - setTargetId("DEPT_IT"); - setChannel("email"); -}}); -messageVO.setMessageRanges(ranges); - -// 发送消息 -messageService.sendMessage(messageVO); -``` - -**系统处理:** -1. 在 `tb_message` 中创建消息记录 -2. 在 `tb_message_range` 中保存发送范围 -3. 根据 `target_type` 和 `target_id` 查询具体用户列表 -4. 在 `tb_message_receiver` 中为每个用户创建接收记录 -5. 根据 `channel` 调用相应的渠道服务发送消息 - -### 2. 用户查看消息列表 - -```sql --- 查询用户未读消息 -SELECT m.*, r.status, r.read_time, r.channel -FROM message.tb_message m -JOIN message.tb_message_receiver r ON m.message_id = r.message_id -WHERE r.user_id = 'USER_001' - AND r.status = 'unread' - AND r.deleted = false -ORDER BY m.create_time DESC; -``` - -### 3. 用户处理消息 - -```java -// 标记消息为已读 -messageService.handleMessage(messageId, "read"); - -// 标记消息为已处理 -messageService.handleMessage(messageId, "handled"); -``` - -**系统处理:** -- 更新 `tb_message_receiver` 表的 `status` 字段 -- 根据状态更新 `read_time` 或 `handle_time` - -### 4. 管理员查看消息统计 - -```sql --- 查询某条消息的发送统计 -SELECT - r.channel, - r.status, - COUNT(*) as count -FROM message.tb_message_receiver r -WHERE r.message_id = 'MSG_001' - AND r.deleted = false -GROUP BY r.channel, r.status; -``` - -## 🎯 设计优势 - -1. **职责分离** - - `tb_message_range` - 定义发送规则 - - `tb_message_receiver` - 记录实际接收情况 - -2. **多渠道支持** - - 同一消息可通过多个渠道发送 - - 渠道配置独立管理 - - 易于扩展新渠道 - -3. **灵活的目标定义** - - 支持按用户、部门、角色、全员发送 - - 同一目标可使用不同渠道 - -4. **完整的状态跟踪** - - 记录阅读时间、处理时间 - - 支持已读/未读/已处理/已删除等状态 - -5. **性能优化** - - 合理的索引设计 - - 支持高效的用户消息查询 - -## 📝 注意事项 - -1. **数据一致性** - - 发送消息时,确保 `tb_message_range` 和 `tb_message_receiver` 的事务一致性 - -2. **渠道验证** - - 发送前检查 `tb_message_channel` 中渠道是否启用 - - 根据 `priority` 选择备用渠道 - -3. **性能考虑** - - 全员消息(target_type='all')需要异步处理 - - 大量用户时分批创建 `tb_message_receiver` 记录 - -4. **软删除** - - 所有表都使用软删除(deleted字段) - - 查询时注意添加 `WHERE deleted = false` 条件 - diff --git a/urbanLifelineServ/apis/api-platform/pom.xml b/urbanLifelineServ/apis/api-platform/pom.xml deleted file mode 100644 index bc1ad5f7..00000000 --- a/urbanLifelineServ/apis/api-platform/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh - api-platform - 1.0.0 - - - 21 - 21 - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-platform/src/main/java/org/xyzh/Main.java b/urbanLifelineServ/apis/api-platform/src/main/java/org/xyzh/Main.java deleted file mode 100644 index f660b7a0..00000000 --- a/urbanLifelineServ/apis/api-platform/src/main/java/org/xyzh/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.xyzh; - -public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-system/pom.xml b/urbanLifelineServ/apis/api-system/pom.xml deleted file mode 100644 index 3f6de234..00000000 --- a/urbanLifelineServ/apis/api-system/pom.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh.apis - api-system - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - org.xyzh.common - common-dto - ${urban-lifeline.version} - - - org.xyzh.common - common-utils - ${urban-lifeline.version} - - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/constance/SysConfigRedisPrefix.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/constance/SysConfigRedisPrefix.java deleted file mode 100644 index f3f5990f..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/constance/SysConfigRedisPrefix.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.xyzh.api.system.constance; - -import java.util.HashMap; -import java.util.Map; - -/** - * 通过redis事件,实现数据库更新配置,更新其他服务的bean数据 - * 按配置分组定义Redis前缀 - * - * 注意:其他服务接收到事件后需延时2秒再查询数据库,等待发布方事务提交 - * - * @see org.xyzh.common.redis.listener.AbstractSysConfigListener - */ -public class SysConfigRedisPrefix { - - /** 配置变更频道前缀(用于订阅所有配置变更) */ - public static final String SYS_CONFIG_PREFIX = "sys:config:"; - - /** 站点与品牌配置 */ - public static final String SYS_CONFIG_SITE = "sys:config:site"; - - /** 国际化与时区配置 */ - public static final String SYS_CONFIG_I18N = "sys:config:i18n"; - - /** 安全与认证配置 */ - public static final String SYS_CONFIG_SECURITY = "sys:config:security"; - - /** 存储与上传配置(含MinIO、文件管理) */ - public static final String SYS_CONFIG_STORAGE = "sys:config:storage"; - - /** 通知配置(邮件/短信) */ - public static final String SYS_CONFIG_NOTIFY = "sys:config:notify"; - - /** Dify AI配置 */ - public static final String SYS_CONFIG_DIFY = "sys:config:dify"; - - /** 日志与审计配置 */ - public static final String SYS_CONFIG_LOG = "sys:config:log"; - - /** 平台特性配置 */ - public static final String SYS_CONFIG_PLATFORM = "sys:config:platform"; - - /** 微信客服配置 */ - public static final String SYS_CONFIG_WECHAT = "sys:config:wechat"; - - /** group到channel的映射 */ - private static final Map GROUP_CHANNEL_MAP = new HashMap<>(); - - static { - GROUP_CHANNEL_MAP.put("site", SYS_CONFIG_SITE); - GROUP_CHANNEL_MAP.put("i18n", SYS_CONFIG_I18N); - GROUP_CHANNEL_MAP.put("security", SYS_CONFIG_SECURITY); - GROUP_CHANNEL_MAP.put("storage", SYS_CONFIG_STORAGE); - GROUP_CHANNEL_MAP.put("notify", SYS_CONFIG_NOTIFY); - GROUP_CHANNEL_MAP.put("dify", SYS_CONFIG_DIFY); - GROUP_CHANNEL_MAP.put("log", SYS_CONFIG_LOG); - GROUP_CHANNEL_MAP.put("platform", SYS_CONFIG_PLATFORM); - GROUP_CHANNEL_MAP.put("wechat", SYS_CONFIG_WECHAT); - } - - /** - * 根据group获取对应的Redis channel - * @param group 配置分组(对应数据库中的group字段) - * @return channel名称,未匹配则返回 sys:config:{group} - */ - public static String getChannelByGroup(String group) { - if (group == null || group.isEmpty()) { - return null; - } - return GROUP_CHANNEL_MAP.getOrDefault(group, SYS_CONFIG_PREFIX + group); - } - - /** - * 判断group是否有效 - * @param group 配置分组 - * @return 是否为已知的分组 - */ - public static boolean isValidGroup(String group) { - return group != null && GROUP_CHANNEL_MAP.containsKey(group); - } -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/constance/SysLogContants.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/constance/SysLogContants.java deleted file mode 100644 index c34facea..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/constance/SysLogContants.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.xyzh.api.system.constance; - -public class SysLogContants { - - private final static String LOG_LEVEL_DEBUG = "DEBUG"; - private final static String LOG_LEVEL_INFO = "INFO"; - private final static String LOG_LEVEL_WARN = "WARN"; - private final static String LOG_LEVEL_ERROR = "ERROR"; - - - private final static String LOG_MODULE_SYSTEM = "系统"; - private final static String LOG_MODULE_AI = "AI服务"; - private final static String LOG_MODULE_AUTH = "日志"; - private final static String LOG_MODULE_WORKCASE = "工单"; - private final static String LOG_MODULE_KNOWLEDGE = "知识库"; - private final static String LOG_MODULE_FILE = "文件"; - -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/dto/TbSysLogDTO.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/dto/TbSysLogDTO.java deleted file mode 100644 index 6d0e88b1..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/dto/TbSysLogDTO.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.xyzh.api.system.dto; - -import com.alibaba.fastjson2.JSONObject; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -/** - * @description 系统日志DTO - * @filename TbSysLogDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统日志DTO") -public class TbSysLogDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "日志ID") - private String logId; - - @Schema(description = "日志类型") - private Integer type; - - @Schema(description = "日志级别") - private String level; - - @Schema(description = "模块") - private String module; - - @Schema(description = "IP地址") - private String ipAddress; - - @Schema(description = "IP来源") - private String ip_source; - - @Schema(description = "浏览器") - private String browser; - - @Schema(description = "操作系统") - private String os; - - @Schema(description = "日志消息") - private String message; - - @Schema(description = "日志数据") - private JSONObject data; - - @Schema(description = "创建人姓名") - private String creatorName; - - @Schema(description = "服务") - private String servce; -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/dto/TbSysLoginLogDTO.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/dto/TbSysLoginLogDTO.java deleted file mode 100644 index e275ece8..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/dto/TbSysLoginLogDTO.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.api.system.dto; - -import java.util.Date; -import com.alibaba.fastjson2.annotation.JSONField; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -/** - * @description 系统登录日志DTO - * @filename TbSysLoginLogDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统登录日志DTO") -public class TbSysLoginLogDTO extends BaseDTO { - - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "用户名") - private String username; - - @Schema(description = "IP地址") - private String ipAddress; - - @Schema(description = "IP来源") - private String ipSource; - - @Schema(description = "浏览器") - private String browser; - - @Schema(description = "操作系统") - private String os; - - @Schema(description = "密码") - private String password; - - @Schema(description = "登录时间") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date loginTime; - - @Schema(description = "状态") - private Integer status; - - @Schema(description = "错误次数") - private Integer errorCount; - - @Schema(description = "消息") - private String message; -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/AclService.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/AclService.java deleted file mode 100644 index d8a3fc86..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/AclService.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.xyzh.api.system.service; - -import org.xyzh.api.system.vo.AclVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysAclDTO; -import org.xyzh.common.dto.sys.TbSysAclPolicyDTO; - -/** - * @description 访问控制列表服务接口 - * @filename AclService.java - * @author yslg - * @copyright yslg - * @since 2025-12-05 - */ -public interface AclService { - - // ================= ACL 管理 ================= - /** - * @description 插入访问控制列表 - * @param aclDTO 访问控制列表DTO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain insertAcl(TbSysAclDTO aclDTO); - - /** - * @description 更新访问控制列表 - * @param aclDTO 访问控制列表DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain updateAcl(TbSysAclDTO aclDTO); - - /** - * @description 删除访问控制列表 - * @param aclDTO 访问控制列表DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain deleteAcl(TbSysAclDTO aclDTO); - - /** - * @description 根据条件查询访问控制列表分页数据 - * @param pageRequest 分页请求 - * @return ResultDomain 分页结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain getAclPage(PageRequest pageRequest); - - /** - * @description 根据条件查询访问控制列表 - * @param filter 过滤条件 - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain getAclList(AclVO filter); - - /** - * @description 根据对象ID查询访问控制列表 - * @param objectId 对象ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain getAclByObjectId(String objectId); - - // ================= ACL Policy 管理 ================= - /** - * @description 插入访问控制策略 - * @param aclPolicyDTO 访问控制策略DTO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain insertAclPolicy(TbSysAclPolicyDTO aclPolicyDTO); - - /** - * @description 更新访问控制策略 - * @param aclPolicyDTO 访问控制策略DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain updateAclPolicy(TbSysAclPolicyDTO aclPolicyDTO); - - /** - * @description 删除访问控制策略 - * @param aclPolicyDTO 访问控制策略DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain deleteAclPolicy(TbSysAclPolicyDTO aclPolicyDTO); - - /** - * @description 根据条件查询访问控制策略分页数据 - * @param pageRequest 分页请求 - * @return ResultDomain 分页结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain getAclPolicyPage(PageRequest pageRequest); - - /** - * @description 根据条件查询访问控制策略列表 - * @param filter 过滤条件 - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-12-05 - */ - ResultDomain getAclPolicyList(AclVO filter); -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/DeptRoleService.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/DeptRoleService.java deleted file mode 100644 index 1db670de..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/DeptRoleService.java +++ /dev/null @@ -1,176 +0,0 @@ -package org.xyzh.api.system.service; - -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.api.system.vo.UserDeptRoleVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysDeptDTO; -import org.xyzh.common.dto.sys.TbSysDeptRoleDTO; -import org.xyzh.common.dto.sys.TbSysRoleDTO; - -/** - * @description 部门角色服务接口 - * @filename DeptRoleService.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -public interface DeptRoleService { - - // ================= 部门管理 ================= - /** - * @description 插入部门 - * @param deptDTO 部门DTO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain insertDept(TbSysDeptDTO deptDTO); - - /** - * @description 更新部门 - * @param deptDTO 部门DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateDept(TbSysDeptDTO deptDTO); - - /** - * @description 根据ID删除部门 - * @param deptDTO 部门DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain deleteDept(TbSysDeptDTO deptDTO); - - /** - * @description 根据ID查询部门 - * @param filter 部门VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getDept(UserDeptRoleVO filter); - - /** - * @description 根据条件查询部门列表 - * @param filter 部门VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getDeptList(UserDeptRoleVO filter); - - /** - * @description 根据条件查询部门分页列表 - * @param pageRequest 部门VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getDeptPage(PageRequest pageRequest); - - /** - * @description 获取部门树 - * @param filter 部门VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getDeptTree(UserDeptRoleVO filter); - - // ================= 角色管理 ================= - /** - * @description 插入角色 - * @param roleDTO 角色DTO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain insertRole(TbSysRoleDTO roleDTO); - - /** - * @description 更新角色 - * @param roleDTO 角色DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateRole(TbSysRoleDTO roleDTO); - - /** - * @description 根据ID删除角色 - * @param roleDTO 角色DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain deleteRole(TbSysRoleDTO roleDTO); - - /** - * @description 根据ID查询角色 - * @param filter 角色VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getRole(UserDeptRoleVO filter); - - /** - * @description 根据条件查询角色列表 - * @param filter 角色VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getRoleList(UserDeptRoleVO filter); - - /** - * @description 根据条件查询角色分页列表 - * @param pageRequest 角色VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getRolePage(PageRequest pageRequest); - - /** - * @description 根据部门ID获取角色列表 - * @param deptId 部门ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getRoleListByDeptId(String deptId); - - /** - * @description 根据用户ID获取角色列表 - * @param userId 用户ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getRoleListByUserId(String userId); - - - // ==================== 角色权限关联 ================================ - /** - * @description 设置角色的权限 - * @param permissionVO 权限VO roleId对应多个permissionId - * @return 返回值描述 - * @author yslg - * @since 2025-11-10 - */ - ResultDomain setRolePermission(PermissionVO permissionVO); - - /** - * @description 获取角色的权限列表 - * @param permissionVO 权限VO - * @return 返回值描述 - * @author yslg - * @since 2025-11-10 - */ - ResultDomain getRolePermissionList(PermissionVO permissionVO); -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/GuestService.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/GuestService.java deleted file mode 100644 index d4301160..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/GuestService.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.xyzh.api.system.service; - -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbGuestDTO; - -/** - * @description 来客服务接口 - * @filename GuestService.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -public interface GuestService { - - /** - * @description 创建来客 - * @param guest 来客信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain createGuest(TbGuestDTO guest); - - /** - * @description 更新来客 - * @param guest 来客信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain updateGuest(TbGuestDTO guest); - - /** - * @description 删除来客 - * @param userId 来客ID - * @author yslg - * @since 2025-12-18 - */ - ResultDomain deleteGuest(String userId); - - /** - * @description 查询单个来客 - * @param guest 来客信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain selectGuestOne(TbGuestDTO guest); - - /** - * @description 根据微信id查询来客 - * @param wechatId - * @author yslg - * @since 2025-12-18 - */ - ResultDomain selectGuestByWechatId(String wechatId); - - /** - * @description 查询来客列表 - * @param guest 来客信息 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain selectGuestList(TbGuestDTO guest); - - /** - * @description 查询来客分页列表 - * @param pageRequest 分页请求 - * @author yslg - * @since 2025-12-18 - */ - ResultDomain selectGuestPage(PageRequest pageRequest); -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/LogService.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/LogService.java deleted file mode 100644 index 685bf9c2..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/LogService.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.xyzh.api.system.service; - - -import java.util.List; - -import org.xyzh.api.system.dto.TbSysLogDTO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; - -/** - * @description 系统日志服务 - * @filename LogService.java - * @author yslg - * @copyright yslg - * @since 2026-01-01 - */ -public interface LogService { - - /** - * @description 统计系统日志 - * @param sysLog - * @return 返回值描述 - * @author yslg - * @since 2026-01-01 - */ - ResultDomain addSysLog(TbSysLogDTO sysLog); - - /** - * @description 统计日志数量 - * @param filter - * @return 返回值描述 - * @author yslg - * @since 2026-01-01 - */ - ResultDomain countSysLog(TbSysLogDTO filter); - - /** - * @description 获取日志列表 - * @param filter - * @return 日志列表 - * @author yslg - * @since 2026-01-01 - */ - ResultDomain getSysLogList(TbSysLogDTO filter); - - /** - * @description 获取日志分页 - * @param pageRequest - * @return 日志分页 - * @author yslg - * @since 2026-01-01 - */ - ResultDomain getSysLogPage(PageRequest pageRequest); -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/ModulePermissionService.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/ModulePermissionService.java deleted file mode 100644 index c2db4fc1..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/ModulePermissionService.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.xyzh.api.system.service; - -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.dto.sys.TbSysModuleDTO; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; -import org.xyzh.common.core.page.PageRequest; - -/** - * @description 模块权限服务接口 - * @filename ModulePermissionService.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -public interface ModulePermissionService { - - // ================= 模块管理 ================= - /** - * @description 插入模块 - * @param moduleDTO 模块DTO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain insertModule(TbSysModuleDTO moduleDTO); - - /** - * @description 更新模块 - * @param moduleDTO 模块DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateModule(TbSysModuleDTO moduleDTO); - - /** - * @description 根据ID删除模块 - * @param moduleDTO 模块DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain deleteModule(TbSysModuleDTO moduleDTO); - - /** - * @description 获取模块分页数据 - * @param - * @return 返回值描述 - * @author yslg - * @since 2025-11-10 - */ - ResultDomain getModulePage(PageRequest pageRequest); - - /** - * @description 查询模块列表 - * @param filter 模块VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getModuleList(PermissionVO filter); - - // ================= 权限管理 ================= - /** - * @description 插入权限 - * @param permissionDTO 权限DTO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain insertPermission(TbSysPermissionDTO permissionDTO); - - /** - * @description 更新权限 - * @param permissionDTO 权限DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updatePermission(TbSysPermissionDTO permissionDTO); - - /** - * @description 根据ID删除权限 - * @param permissionDTO 权限DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain deletePermission(TbSysPermissionDTO permissionDTO); - - /** - * @description 根据模块ID获取权限列表 - * @param moduleId 模块ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getPermissionListByModuleId(String moduleId); - - - // ================= 模块权限查询 ================= - /** - * @description 根据条件查询模块权限 - * @param filter 模块权限VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getModulePermission(PermissionVO filter); - - /** - * @description 根据条件查询模块权限列表 - * @param filter 模块权限VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getModulePermissionList(PermissionVO filter); - - /** - * @description 根据条件查询模块权限分页列表 - * @param pageRequest 模块权限VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getModulePermissionPage(PageRequest pageRequest); - - /** - * @description 根据角色ID获取模块权限列表 - * @param roleId 角色ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getModulePermissionListByRoleId(String roleId); - - /** - * @description 根据用户ID获取用户的所有权限 - * @param userId 用户ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getUserPermissions(String userId); -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/SysConfigService.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/SysConfigService.java deleted file mode 100644 index 4ab9fa47..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/SysConfigService.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.xyzh.api.system.service; - -import org.xyzh.api.system.vo.SysConfigVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysConfigDTO; - -/** - * @description 系统配置服务接口 - * @filename SysConfigService.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -public interface SysConfigService { - // ================== 读取配置 ======================== - /** - * 获取字符串类型配置 - * @param key 配置键 - * @return 配置值 - */ - String getStringConfig(String key); - - /** - * 获取整数类型配置 - * @param key 配置键 - * @return 配置值,如果不存在或解析失败返回null - */ - Integer getIntConfig(String key); - - /** - * 获取布尔类型配置 - * @param key 配置键 - * @return 配置值,如果不存在或解析失败返回null - */ - Boolean getBooleanConfig(String key); - - /** - * 获取浮点数类型配置 - * @param key 配置键 - * @return 配置值,如果不存在或解析失败返回null - */ - Double getDoubleConfig(String key); - - /** - * 获取长整数类型配置 - * @param key 配置键 - * @return 配置值,如果不存在或解析失败返回null - */ - Long getLongConfig(String key); - - // ===================================================== - - /** - * @description 插入系统配置 - * @param configDTO 系统配置DTO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain insertConfig(TbSysConfigDTO configDTO); - - /** - * @description 更新系统配置 - * @param configDTO 系统配置DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateConfig(TbSysConfigDTO configDTO); - - /** - * @description 根据ID删除系统配置 - * @param configDTO 系统配置DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain deleteConfig(TbSysConfigDTO configDTO); - - /** - * @description 根据ID查询系统配置 - * @param filter 系统配置VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getConfig(SysConfigVO filter); - - /** - * @description 根据条件查询系统配置列表 - * @param filter 系统配置VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getConfigList(SysConfigVO filter); - - /** - * @description 根据条件查询系统配置分页列表 - * @param filter 系统配置VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getConfigPage(PageRequest filter); - - /** - * @description 根据配置键获取配置值 - * @param key 配置键 - * @return ResultDomain 配置值 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getConfigValueByKey(String key); - - /** - * @description 根据模块ID获取配置列表 - * @param moduleId 模块ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getConfigListByModuleId(String moduleId); -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/SysUserService.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/SysUserService.java deleted file mode 100644 index b787aa4a..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/SysUserService.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.xyzh.api.system.service; - -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.api.system.vo.UserDeptRoleVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; -import org.xyzh.common.dto.sys.TbSysUserRoleDTO; - -/** - * @description 用户服务接口 - * @filename SysUserService.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -public interface SysUserService { - - // ================= 用户基本信息管理 ================= - - ResultDomain registerUser(SysUserVO userVO); - - - /** - * @description 插入用户 - * @param userVO 用户VO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain insertUser(SysUserVO userVO); - - /** - * @description 更新用户 - * @param userVO 用户VO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateUser(SysUserVO userVO); - - /** - * @description 根据ID删除用户 - * @param TbSysUserDTO userDTO 用户DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain deleteUser(TbSysUserDTO userDTO); - - /** - * @description 根据ID查询用户 - * @param filter 用户VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getUser(SysUserVO filter); - - /** - * @description 用户登录查询 - * @param filter 用户VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getLoginUser(SysUserVO filter); - - /** - * @description 根据条件查询用户列表 - * @param filter 用户VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getUserList(SysUserVO filter); - - /** - * @description 根据条件查询用户分页列表 - * @param filter 用户VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getUserPage(PageRequest pageRequest); - - /** - * @description 根据用户名查询用户 - * @param username 用户名 - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getUserByUsername(String username); - - /** - * @description 更新用户密码 - * @param userId 用户ID - * @param oldPassword 旧密码 - * @param newPassword 新密码 - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateUserPassword(String userId, String oldPassword, String newPassword); - - /** - * @description 重置用户密码 - * @param userId 用户ID - * @return ResultDomain 新密码 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain resetUserPassword(String userId); - - /** - * @description 更新用户状态 - * @param userId 用户ID - * @param status 状态 - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateUserStatus(String userId, String status); - - // ================= 用户详细信息管理 ================= - /** - * @description 更新用户详细信息 - * @param userInfoDTO 用户详细信息DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateUserInfo(TbSysUserInfoDTO userInfoDTO); - - /** - * @description 根据用户ID获取用户详细信息 - * @param userId 用户ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getUserInfo(String userId); - - // ================= 用户角色关联管理 ================= - /** - * @description 添加用户角色关联 - * @param userRoleDTO 用户角色DTO - * @return ResultDomain 添加结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain addUserRole(TbSysUserRoleDTO userRoleDTO); - - /** - * @description 删除用户角色关联 - * @param userRoleDTO 用户角色DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain removeUserRole(TbSysUserRoleDTO userRoleDTO); - - /** - * @description 批量设置用户角色 - * @param userId 用户ID - * @param[] roleIds 角色ID数组 - * @return ResultDomain 设置结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain setUserRoles(String userId, String[] roleIds); - - // ================= 用户完整信息查询 ================= - /** - * @description 获取用户完整信息(包含部门和角色) - * @param userId 用户ID - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getUserWithDeptRole(String userId); -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/ViewService.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/ViewService.java deleted file mode 100644 index aae0176d..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/service/ViewService.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.xyzh.api.system.service; - -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.dto.sys.TbSysViewDTO; -import org.xyzh.common.dto.sys.TbSysViewPermissionDTO; -import org.xyzh.common.core.page.PageRequest; -/** - * @description 视图服务接口 - * @filename ViewService.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -public interface ViewService { - - // ================= 视图管理 ================= - /** - * @description 插入视图 - * @param viewDTO 视图DTO - * @return ResultDomain 插入结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain insertView(TbSysViewDTO viewDTO); - - /** - * @description 更新视图 - * @param viewDTO 视图DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain updateView(TbSysViewDTO viewDTO); - - /** - * @description 根据ID删除视图 - * @param viewDTO 视图DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain deleteView(TbSysViewDTO viewDTO); - - /** - * @description 根据ID查询视图 - * @param filter 视图VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getView(PermissionVO filter); - - /** - * @description 根据条件查询视图列表 - * @param filter 视图VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getViewList(PermissionVO filter); - - /** - * @description 根据条件查询视图分页列表 - * @param filter 视图VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getViewPage(PageRequest filter); - - /** - * @description 获取视图树(包含子视图) - * @param filter 视图VO - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getViewTree(PermissionVO filter); - - // ================= 视图权限关联管理 ================= - /** - * @description 设置视图权限 - * @param permissionVO 视图ID 和权限ID数组 - * @return ResultDomain 设置结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain setViewPermissions(PermissionVO permissionVO); - - /** - * @description 获取视图的权限列表 - * @param permissionVO 视图 - * @return ResultDomain 查询结果 - * @author yslg - * @since 2025-11-05 - */ - ResultDomain getViewPermissionList(PermissionVO permissionVO); -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/AclVO.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/AclVO.java deleted file mode 100644 index eafceeeb..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/AclVO.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.xyzh.api.system.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; - -/** - * @description 访问控制列表视图对象 - * @filename AclVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "访问控制列表视图对象") -public class AclVO extends BaseVO { - // TbSysAclDTO对应字段 - @Schema(description = "权限ID") - private String aclId; - - @Schema(description = "对象类型:article/file/course/...") - private String objectType; - - @Schema(description = "对象ID") - private String objectId; - - @Schema(description = "主体类型:user/dept/role") - private String principalType; - - @Schema(description = "主体ID") - private String principalId; - - @Schema(description = "当主体为role且限定到某部门时的部门ID(支持某部门的某角色)") - private String principalDeptId; - - @Schema(description = "权限位:1读 2写 4执行") - private Integer permission; - - @Schema(description = "允许或显式拒绝", defaultValue = "true") - private Boolean allow = true; - - @Schema(description = "是否包含子级(对dept/role生效)", defaultValue = "false") - private Boolean includeDescendants = false; - - // TbSysAclPolicyDTO对应字段 - @Schema(description = "策略ID") - private String policyId; - - @Schema(description = "策略名称") - private String policyName; - - @Schema(description = "对象类型:article/file/course/..") - private String policyObjectType; - - @Schema(description = "编辑层级规则:parent_only/parent_or_same_admin/owner_only/none") - private String editHierarchyRule; - - @Schema(description = "可见层级规则 children_all/children_specified/none") - private String viewHierarchyRule; - - @Schema(description = "默认权限(无显式ACL时应用)", defaultValue = "0") - private Integer defaultPermission = 0; - - @Schema(description = "默认是否允许", defaultValue = "true") - private Boolean defaultAllow = true; - - @Schema(description = "是否默认应用到子级", defaultValue = "true") - private Boolean applyToChildren = true; -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/PermissionVO.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/PermissionVO.java deleted file mode 100644 index 6b2aff31..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/PermissionVO.java +++ /dev/null @@ -1,236 +0,0 @@ -package org.xyzh.api.system.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; - -import java.util.List; -import org.xyzh.common.dto.sys.TbSysModuleDTO; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; -import org.xyzh.common.dto.sys.TbSysViewDTO; - -/** - * @description 权限视图对象 - * @filename PermissionVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "权限视图对象") -public class PermissionVO extends BaseVO { - // TbSysDeptDTO对应字段 - @Schema(description = "部门ID") - private String deptId; - - @Schema(description = "部门名称") - private String deptName; - - @Schema(description = "父级部门ID") - private String deptParentId; - - @Schema(description = "部门描述") - private String deptDescription; - - // TbSysRoleDTO对应字段 - @Schema(description = "角色ID") - private String roleId; - - @Schema(description = "角色名称") - private String roleName; - - @Schema(description = "角色描述") - private String roleDescription; - - @Schema(description = "角色作用域") - private String roleScope; - - @Schema(description = "所属部门ID") - private String roleOwnerDeptId; - - @Schema(description = "角色状态") - private Boolean roleStatus; - - // TbSysModuleDTO对应字段 - @Schema(description = "模块ID") - private String moduleId; - - @Schema(description = "模块名称") - private String moduleName; - - @Schema(description = "模块描述") - private String moduleDescription; - - // TbSysPermissionDTO对应字段 - @Schema(description = "权限ID") - private String permissionId; - - @Schema(description = "权限名称") - private String permissionName; - - @Schema(description = "权限代码") - private String permissionCode; - - @Schema(description = "权限描述") - private String permissionDescription; - - @Schema(description = "权限状态") - private Boolean permissionStatus; - - // TbSysViewDTO对应字段 - @Schema(description = "视图ID") - private String viewId; - - @Schema(description = "视图名称") - private String viewName; - - @Schema(description = "父视图ID") - private String viewParentId; - - @Schema(description = "URL") - private String viewUrl; - - @Schema(description = "组件") - private String viewComponent; - - @Schema(description = "图标") - private String viewIcon; - - @Schema(description = "类型") - private Integer viewType; - - @Schema(description = "视图类型") - private String viewViewType; - - @Schema(description = "iframe URL") - private String viewIframeUrl; - - @Schema(description = "所属服务:platform=平台应用 bidding=招标应用 workcase=客服应用") - private String viewService; - - @Schema(description = "布局") - private String viewLayout; - - @Schema(description = "排序") - private Integer viewOrderNum; - - @Schema(description = "视图描述") - private String viewDescription; - - // 角色权限数组 - @Schema(description = "用户视图权限列表") - private List permissionIdList; - - public static TbSysModuleDTO toModuleDTO(PermissionVO vo) { - if (vo == null) { - return null; - } - TbSysModuleDTO dto = new TbSysModuleDTO(); - dto.setModuleId(vo.getModuleId()); - dto.setName(vo.getModuleName()); - dto.setDescription(vo.getModuleDescription()); - dto.setOptsn(vo.getOptsn()); - dto.setCreator(vo.getCreator()); - dto.setUpdater(vo.getUpdater()); - dto.setDeptPath(vo.getDeptPath()); - dto.setRemark(vo.getRemark()); - dto.setCreateTime(vo.getCreateTime()); - dto.setUpdateTime(vo.getUpdateTime()); - dto.setDeleteTime(vo.getDeleteTime()); - dto.setDeleted(vo.getDeleted()); - return dto; - } - - public static TbSysPermissionDTO toPermissionDTO(PermissionVO vo) { - if (vo == null) { - return null; - } - TbSysPermissionDTO dto = new TbSysPermissionDTO(); - dto.setPermissionId(vo.getPermissionId()); - dto.setModuleId(vo.getModuleId()); - dto.setCode(vo.getPermissionCode()); - dto.setName(vo.getPermissionName()); - dto.setDescription(vo.getPermissionDescription()); - dto.setOptsn(vo.getOptsn()); - dto.setCreator(vo.getCreator()); - dto.setUpdater(vo.getUpdater()); - dto.setDeptPath(vo.getDeptPath()); - dto.setRemark(vo.getRemark()); - dto.setCreateTime(vo.getCreateTime()); - dto.setUpdateTime(vo.getUpdateTime()); - dto.setDeleteTime(vo.getDeleteTime()); - dto.setDeleted(vo.getDeleted()); - return dto; - } - - public static TbSysViewDTO toViewDTO(PermissionVO vo) { - if (vo == null) { - return null; - } - TbSysViewDTO dto = new TbSysViewDTO(); - dto.setViewId(vo.getViewId()); - dto.setName(vo.getViewName()); - dto.setParentId(vo.getViewParentId()); - dto.setUrl(vo.getViewUrl()); - dto.setComponent(vo.getViewComponent()); - dto.setIcon(vo.getViewIcon()); - dto.setType(vo.getViewType()); - dto.setViewType(vo.getViewViewType()); - dto.setIframeUrl(vo.getViewIframeUrl()); - dto.setService(vo.getViewService()); - dto.setLayout(vo.getViewLayout()); - dto.setOrderNum(vo.getViewOrderNum()); - dto.setDescription(vo.getViewDescription()); - dto.setOptsn(vo.getOptsn()); - dto.setCreator(vo.getCreator()); - dto.setUpdater(vo.getUpdater()); - dto.setDeptPath(vo.getDeptPath()); - dto.setRemark(vo.getRemark()); - dto.setCreateTime(vo.getCreateTime()); - dto.setUpdateTime(vo.getUpdateTime()); - dto.setDeleteTime(vo.getDeleteTime()); - dto.setDeleted(vo.getDeleted()); - return dto; - } - - public static PermissionVO fromViewDTO(TbSysViewDTO dto) { - if (dto == null) { - return null; - } - PermissionVO vo = new PermissionVO(); - vo.setViewId(dto.getViewId()); - vo.setViewName(dto.getName()); - vo.setViewParentId(dto.getParentId()); - vo.setViewUrl(dto.getUrl()); - vo.setViewComponent(dto.getComponent()); - vo.setViewIcon(dto.getIcon()); - vo.setViewType(dto.getType()); - vo.setViewViewType(dto.getViewType()); - vo.setViewIframeUrl(dto.getIframeUrl()); - vo.setViewService(dto.getService()); - vo.setViewLayout(dto.getLayout()); - vo.setViewOrderNum(dto.getOrderNum()); - vo.setViewDescription(dto.getDescription()); - vo.setOptsn(dto.getOptsn()); - vo.setCreator(dto.getCreator()); - vo.setUpdater(dto.getUpdater()); - vo.setDeptPath(dto.getDeptPath()); - vo.setRemark(dto.getRemark()); - vo.setCreateTime(dto.getCreateTime()); - vo.setUpdateTime(dto.getUpdateTime()); - vo.setDeleteTime(dto.getDeleteTime()); - vo.setDeleted(dto.getDeleted()); - return vo; - } - - public static List fromViewDTOList(List dtoList) { - if (dtoList == null || dtoList.isEmpty()) { - return java.util.Collections.emptyList(); - } - return dtoList.stream() - .map(PermissionVO::fromViewDTO) - .toList(); - } -} diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/SysConfigVO.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/SysConfigVO.java deleted file mode 100644 index ed9fb8b6..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/SysConfigVO.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.xyzh.api.system.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import org.xyzh.common.dto.sys.TbSysConfigDTO; -import com.alibaba.fastjson2.JSONObject; - -/** - * @description 系统配置视图对象 - * @filename SysConfigVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统配置视图对象") -public class SysConfigVO extends BaseVO { - - - @Schema(description = "配置ID") - private String configId; - - @Schema(description = "配置键") - private String key; - - @Schema(description = "配置名称") - private String name; - - @Schema(description = "配置值") - private String value; - - @Schema(description = "数据类型(String, Integer, Boolean, Float, Double)") - private String configType; - - @Schema(description = "配置渲染类型(select, input, textarea, checkbox, radio, switch)") - private String renderType; - - @Schema(description = "配置描述") - private String description; - - @Schema(description = "正则表达式校验规则(JSON)") - private JSONObject re; - - @Schema(description = "可选项(JSON),render_type为select、checkbox、radio时使用") - private JSONObject options; - - @Schema(description = "配置组") - private String group; - - @Schema(description = "模块ID") - private String moduleId; - - @Schema(description = "模块名称") - private String moduleName; - - @Schema(description = "模块描述") - private String moduleDescription; - - @Schema(description = "配置顺序") - private Integer orderNum; - - @Schema(description = "状态") - private Integer status; - - public static TbSysConfigDTO toDTO(SysConfigVO vo) { - if (vo == null) { - return null; - } - TbSysConfigDTO dto = new TbSysConfigDTO(); - dto.setConfigId(vo.getConfigId()); - dto.setKey(vo.getKey()); - dto.setName(vo.getName()); - dto.setValue(vo.getValue()); - dto.setConfigType(vo.getConfigType()); - dto.setRenderType(vo.getRenderType()); - dto.setDescription(vo.getDescription()); - dto.setRe(vo.getRe()); - dto.setOptions(vo.getOptions()); - dto.setGroup(vo.getGroup()); - dto.setModuleId(vo.getModuleId()); - dto.setOrderNum(vo.getOrderNum()); - dto.setStatus(vo.getStatus()); - // 基础字段 - dto.setOptsn(vo.getOptsn()); - dto.setCreator(vo.getCreator()); - dto.setUpdater(vo.getUpdater()); - dto.setDeptPath(vo.getDeptPath()); - dto.setRemark(vo.getRemark()); - dto.setCreateTime(vo.getCreateTime()); - dto.setUpdateTime(vo.getUpdateTime()); - dto.setDeleteTime(vo.getDeleteTime()); - dto.setDeleted(vo.getDeleted()); - return dto; - } - -} - diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/SysUserVO.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/SysUserVO.java deleted file mode 100644 index 700e8903..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/SysUserVO.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.xyzh.api.system.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; - -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; -import org.xyzh.common.utils.crypto.AesEncryptUtil; - -import java.util.List; - -/** - * @description 系统用户视图对象 - * @filename SysUserVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统用户视图对象") -public class SysUserVO extends BaseVO { - - // TbSysUserDTO对应字段 - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "用户编码") - private String usercode; - - @Schema(description = "密码(敏感信息,仅用于创建/修改)") - private String password; - - @Schema(description = "邮箱") - private String email; - - @Schema(description = "手机") - private String phone; - - @Schema(description = "手机号哈希码") - private String phoneHash; - - @Schema(description = "微信ID") - private String wechatId; - - @Schema(description = "用户状态") - private String status; - - @Schema(description = "创建人") - private String creator; - - // TbSysUserInfoDTO对应字段 - @Schema(description = "用户名") - private String username; - - @Schema(description = "头像") - private String avatar; - - @Schema(description = "性别") - private Integer gender; - - @Schema(description = "等级") - private Integer level; - - @Schema(description = "身份证号") - private String idCard; - - @Schema(description = "地址") - private String address; - - // 关联信息 - @Schema(description = "用户部门角色列表") - private List deptRoles; - - @Schema(description = "用户角色权限列表") - private List rolePermissions; - - @Schema(description = "用户视图权限列表") - private List viewPermissions; - - public void setPhone(String phone){ - this.phone = phone; - this.phoneHash = AesEncryptUtil.maskPhone(phone); - } - - public static TbSysUserDTO toDTO(SysUserVO vo) { - if (vo == null) { - return null; - } - TbSysUserDTO dto = new TbSysUserDTO(); - dto.setUserId(vo.getUserId()); - dto.setUsercode(vo.getUsercode()); - dto.setPassword(vo.getPassword()); - dto.setEmail(vo.getEmail()); - dto.setPhone(vo.getPhone()); - dto.setWechatId(vo.getWechatId()); - dto.setStatus(vo.getStatus()); - dto.setOptsn(vo.getOptsn()); - dto.setCreator(vo.getCreator()); - dto.setDeptPath(vo.getDeptPath()); - dto.setRemark(vo.getRemark()); - dto.setCreateTime(vo.getCreateTime()); - dto.setUpdateTime(vo.getUpdateTime()); - dto.setDeleteTime(vo.getDeleteTime()); - dto.setDeleted(vo.getDeleted()); - return dto; - } - - /** - * 将 SysUserVO 转换为 TbSysUserInfoDTO - */ - public static TbSysUserInfoDTO toUserInfoDTO(SysUserVO userVO) { - TbSysUserInfoDTO userInfoDTO = new TbSysUserInfoDTO(); - userInfoDTO.setUserId(userVO.getUserId()); - userInfoDTO.setUsername(userVO.getUsername()); - userInfoDTO.setAvatar(userVO.getAvatar()); - userInfoDTO.setGender(userVO.getGender()); - userInfoDTO.setLevel(userVO.getLevel()); - userInfoDTO.setIdCard(userVO.getIdCard()); - userInfoDTO.setAddress(userVO.getAddress()); - - // 继承自 BaseDTO 的字段 - userInfoDTO.setOptsn(userVO.getOptsn()); - userInfoDTO.setCreator(userVO.getCreator()); - userInfoDTO.setDeptPath(userVO.getDeptPath()); - userInfoDTO.setRemark(userVO.getRemark()); - userInfoDTO.setCreateTime(userVO.getCreateTime()); - userInfoDTO.setUpdateTime(userVO.getUpdateTime()); - userInfoDTO.setDeleteTime(userVO.getDeleteTime()); - userInfoDTO.setDeleted(userVO.getDeleted()); - - return userInfoDTO; - } -} - diff --git a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/UserDeptRoleVO.java b/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/UserDeptRoleVO.java deleted file mode 100644 index fdc08c45..00000000 --- a/urbanLifelineServ/apis/api-system/src/main/java/org/xyzh/api/system/vo/UserDeptRoleVO.java +++ /dev/null @@ -1,186 +0,0 @@ -package org.xyzh.api.system.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import org.xyzh.common.dto.sys.TbSysDeptDTO; -import org.xyzh.common.dto.sys.TbSysRoleDTO; -import org.xyzh.common.dto.sys.TbSysDeptRoleDTO; - -/** - * @description 用户部门角色视图对象 - * @filename UserDeptRoleVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "用户部门角色视图对象") -public class UserDeptRoleVO extends BaseVO { - - // TbSysUserDTO对应字段 - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "密码") - private String password; - - @Schema(description = "邮箱") - private String email; - - @Schema(description = "手机") - private String phone; - - @Schema(description = "微信ID") - private String wechatId; - - @Schema(description = "用户状态") - private String status; - - @Schema(description = "用户类型") - private String userType; - - // TbSysUserInfoDTO对应字段 - @Schema(description = "头像") - private String avatar; - - @Schema(description = "用户名") - private String username; - - @Schema(description = "性别") - private Integer gender; - - @Schema(description = "等级") - private Integer level; - - @Schema(description = "身份证号") - private String idCard; - - @Schema(description = "地址") - private String address; - - // TbSysDeptDTO对应字段 - @Schema(description = "部门ID") - private String deptId; - - @Schema(description = "部门名称") - private String deptName; - - @Schema(description = "父级部门ID") - private String parentId; - - @Schema(description = "部门描述") - private String deptDescription; - - // TbSysRoleDTO对应字段(SysRoleVO的字段) - @Schema(description = "角色ID") - private String roleId; - - @Schema(description = "角色名称") - private String roleName; - - @Schema(description = "角色描述") - private String roleDescription; - - @Schema(description = "角色作用域") - private String scope; - - @Schema(description = "所属部门ID") - private String ownerDeptId; - - @Schema(description = "角色状态") - private Boolean roleStatus; - - - public static TbSysDeptDTO toDeptDTO(UserDeptRoleVO vo) { - if (vo == null) { - return null; - } - TbSysDeptDTO dto = new TbSysDeptDTO(); - dto.setDeptId(vo.getDeptId()); - dto.setName(vo.getDeptName()); - dto.setParentId(vo.getParentId()); - dto.setDescription(vo.getDeptDescription()); - dto.setOptsn(vo.getOptsn()); - dto.setCreator(vo.getCreator()); - dto.setUpdater(vo.getUpdater()); - dto.setDeptPath(vo.getDeptPath()); - dto.setRemark(vo.getRemark()); - dto.setCreateTime(vo.getCreateTime()); - dto.setUpdateTime(vo.getUpdateTime()); - dto.setDeleteTime(vo.getDeleteTime()); - dto.setDeleted(vo.getDeleted()); - return dto; - } - - public static TbSysRoleDTO toRoleDTO(UserDeptRoleVO vo) { - if (vo == null) { - return null; - } - TbSysRoleDTO dto = new TbSysRoleDTO(); - dto.setRoleId(vo.getRoleId()); - dto.setName(vo.getRoleName()); - dto.setDescription(vo.getRoleDescription()); - dto.setScope(vo.getScope()); - dto.setOwnerDeptId(vo.getOwnerDeptId()); - dto.setStatus(vo.getRoleStatus()); - dto.setOptsn(vo.getOptsn()); - dto.setCreator(vo.getCreator()); - dto.setUpdater(vo.getUpdater()); - dto.setDeptPath(vo.getDeptPath()); - dto.setRemark(vo.getRemark()); - dto.setCreateTime(vo.getCreateTime()); - dto.setUpdateTime(vo.getUpdateTime()); - dto.setDeleteTime(vo.getDeleteTime()); - dto.setDeleted(vo.getDeleted()); - return dto; - } - - public static TbSysDeptRoleDTO toDeptRoleDTO(UserDeptRoleVO vo) { - if (vo == null) { - return null; - } - TbSysDeptRoleDTO dto = new TbSysDeptRoleDTO(); - dto.setDeptId(vo.getDeptId()); - dto.setRoleId(vo.getRoleId()); - dto.setOptsn(vo.getOptsn()); - dto.setCreator(vo.getCreator()); - dto.setUpdater(vo.getUpdater()); - dto.setDeptPath(vo.getDeptPath()); - dto.setRemark(vo.getRemark()); - dto.setCreateTime(vo.getCreateTime()); - dto.setUpdateTime(vo.getUpdateTime()); - dto.setDeleteTime(vo.getDeleteTime()); - dto.setDeleted(vo.getDeleted()); - return dto; - } - - public static UserDeptRoleVO fromPermission(PermissionVO permissionVO) { - if (permissionVO == null) { - return null; - } - UserDeptRoleVO vo = new UserDeptRoleVO(); - vo.setDeptId(permissionVO.getDeptId()); - vo.setDeptName(permissionVO.getDeptName()); - vo.setParentId(permissionVO.getDeptParentId()); - vo.setDeptDescription(permissionVO.getDeptDescription()); - vo.setRoleId(permissionVO.getRoleId()); - vo.setRoleName(permissionVO.getRoleName()); - vo.setRoleDescription(permissionVO.getRoleDescription()); - vo.setScope(permissionVO.getRoleScope()); - vo.setOwnerDeptId(permissionVO.getRoleOwnerDeptId()); - vo.setRoleStatus(permissionVO.getRoleStatus()); - vo.setOptsn(permissionVO.getOptsn()); - vo.setCreator(permissionVO.getCreator()); - vo.setUpdater(permissionVO.getUpdater()); - vo.setDeptPath(permissionVO.getDeptPath()); - vo.setRemark(permissionVO.getRemark()); - vo.setCreateTime(permissionVO.getCreateTime()); - vo.setUpdateTime(permissionVO.getUpdateTime()); - vo.setDeleteTime(permissionVO.getDeleteTime()); - vo.setDeleted(permissionVO.getDeleted()); - return vo; - } -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-workcase/pom.xml b/urbanLifelineServ/apis/api-workcase/pom.xml deleted file mode 100644 index d8c42550..00000000 --- a/urbanLifelineServ/apis/api-workcase/pom.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - 4.0.0 - - org.xyzh - apis - 1.0.0 - - - org.xyzh.apis - api-workcase - 1.0.0 - - - 21 - 21 - - - - - org.xyzh.apis - api-ai - - - \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/constant/WorkcaseConstant.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/constant/WorkcaseConstant.java deleted file mode 100644 index eb442f1f..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/constant/WorkcaseConstant.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.xyzh.api.workcase.constant; - -/** - * @description 工单模块常量类 - * @filename WorkcaseConstant.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -public class WorkcaseConstant { - - private WorkcaseConstant() { - } - - // ========================= Redis Key 前缀 ========================== - - /** - * 聊天室Redis key前缀 - */ - public static final String REDIS_CHAT_PREFIX = "chat:room:"; - - /** - * 聊天室在线用户 chat:room:online:{roomId} - */ - public static final String REDIS_CHAT_ONLINE = REDIS_CHAT_PREFIX + "online:"; - - /** - * 聊天室消息锁 chat:room:lock:{roomId} - */ - public static final String REDIS_CHAT_LOCK = REDIS_CHAT_PREFIX + "lock:"; - - /** - * 聊天室最后消息时间 chat:room:lasttime:{roomId} - */ - public static final String REDIS_CHAT_LASTTIME = REDIS_CHAT_PREFIX + "lasttime:"; - - /** - * 聊天室列表更新通知频道 - */ - public static final String REDIS_CHAT_LIST_UPDATE = "chat:list:update"; - - /** - * 会议Redis key前缀 - */ - public static final String REDIS_MEET_PREFIX = "meet:"; - - // ========================= 用户类型 ========================== - - /** - * 用户类型:来客 - */ - public static final String USER_TYPE_GUEST = "guest"; - - /** - * 用户类型:客服 - */ - public static final String USER_TYPE_STAFF = "staff"; - - /** - * 用户类型:AI助手 - */ - public static final String USER_TYPE_AI = "ai"; - - // ========================= 状态常量 ========================== - - /** - * 聊天室状态:活跃 - */ - public static final String ROOM_STATUS_ACTIVE = "active"; - - /** - * 聊天室状态:已关闭 - */ - public static final String ROOM_STATUS_CLOSED = "closed"; - - /** - * 成员状态:活跃 - */ - public static final String MEMBER_STATUS_ACTIVE = "active"; - - /** - * 成员状态:已离开 - */ - public static final String MEMBER_STATUS_LEFT = "left"; - - /** - * 成员状态:被移除 - */ - public static final String MEMBER_STATUS_REMOVED = "removed"; - - /** - * 消息状态:已发送 - */ - public static final String MESSAGE_STATUS_SENT = "sent"; - - /** - * 消息状态:已撤回 - */ - public static final String MESSAGE_STATUS_RECALLED = "recalled"; - - // ========================= 会议状态 ========================== - - /** - * 会议状态:已计划 - */ - public static final String MEETING_STATUS_SCHEDULED = "scheduled"; - - /** - * 会议状态:进行中 - */ - public static final String MEETING_STATUS_ONGOING = "ongoing"; - - /** - * 会议状态:已结束 - */ - public static final String MEETING_STATUS_ENDED = "ended"; - - // ========================= 客服状态 ========================== - - /** - * 客服状态:在线 - */ - public static final String SERVICE_STATUS_ONLINE = "online"; - - /** - * 客服状态:离线 - */ - public static final String SERVICE_STATUS_OFFLINE = "offline"; - - /** - * 客服状态:忙碌 - */ - public static final String SERVICE_STATUS_BUSY = "busy"; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/ChatRoomSummaryRequest.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/ChatRoomSummaryRequest.java deleted file mode 100644 index 8d503720..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/ChatRoomSummaryRequest.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.io.Serializable; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 聊天室总结请求参数 - * @filename ChatRoomSummaryRequest.java - * @author system - * @copyright xyzh - * @since 2026-01-01 - */ -@Data -@Schema(description = "聊天室总结请求参数") -public class ChatRoomSummaryRequest implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "聊天室ID", required = true) - private String roomId; - - @Schema(description = "是否包含系统消息", defaultValue = "false") - private Boolean includeSystemMessages = false; - - @Schema(description = "是否包含会议消息", defaultValue = "false") - private Boolean includeMeetingMessages = false; -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/ChatRoomSummaryResponse.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/ChatRoomSummaryResponse.java deleted file mode 100644 index 1fad457d..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/ChatRoomSummaryResponse.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.io.Serializable; -import java.util.List; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 聊天室总结响应结果 - * @filename ChatRoomSummaryResponse.java - * @author system - * @copyright xyzh - * @since 2026-01-01 - */ -@Data -@Schema(description = "聊天室总结响应结果") -public class ChatRoomSummaryResponse implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "用户提出的核心问题") - private String question; - - @Schema(description = "用户的核心诉求列表") - private List needs; - - @Schema(description = "解决方案或答案") - private String answer; - - @Schema(description = "词云关键词列表") - private List workcloud; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "总结生成时间") - private String summaryTime; - - @Schema(description = "参与总结的消息数量") - private Integer messageCount; -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomDTO.java deleted file mode 100644 index 202d73bc..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomDTO.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.Date; - -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 聊天室表数据对象DTO - * @filename TbChatRoomDTO.java - * @author cascade - * @copyright xyzh - * @since 2025-12-20 - */ -@Data -@Schema(description = "聊天室表对象") -public class TbChatRoomDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "关联工单ID") - private String workcaseId; - - @Schema(description = "聊天室名称") - private String roomName; - - @Schema(description = "聊天室类型:workcase-工单客服") - private String roomType; - - @Schema(description = "状态:active-活跃 closed-已关闭 archived-已归档") - private String status; - - @Schema(description = "来客ID(创建者)") - private String guestId; - - @Schema(description = "来客姓名") - private String guestName; - - @Schema(description = "AI对话会话ID") - private String aiSessionId; - - @Schema(description = "当前负责客服ID") - private String currentAgentId; - - @Schema(description = "已加入的客服人数") - private Integer agentCount; - - @Schema(description = "消息总数") - private Integer messageCount; - - @Schema(description = "未读消息数(客服端)") - private Integer unreadCount; - - @Schema(description = "最后消息时间") - private Date lastMessageTime; - - @Schema(description = "最后一条消息内容") - private String lastMessage; - - @Schema(description = "服务评分(1-5星)") - private Integer commentLevel; - - @Schema(description = "设备代码") - private String deviceCode; - - @Schema(description = "关闭人") - private String closedBy; - - @Schema(description = "关闭时间") - private Date closedTime; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomMemberDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomMemberDTO.java deleted file mode 100644 index 4af83f2b..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomMemberDTO.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.Date; - -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 聊天室成员表数据对象DTO - * @filename TbChatRoomMemberDTO.java - * @author cascade - * @copyright xyzh - * @since 2025-12-20 - */ -@Data -@Schema(description = "聊天室成员表对象") -public class TbChatRoomMemberDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "成员记录ID") - private String memberId; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "用户ID(来客ID或员工ID)") - private String userId; - - @Schema(description = "用户类型:guest-来客 staff-客服 ai-AI助手") - private String userType; - - @Schema(description = "用户名称") - private String userName; - - @Schema(description = "状态:active-活跃 left-已离开 removed-被移除") - private String status; - - @Schema(description = "该成员的未读消息数") - private Integer unreadCount; - - @Schema(description = "最后阅读时间") - private Date lastReadTime; - - @Schema(description = "最后阅读的消息ID") - private String lastReadMsgId; - - @Schema(description = "加入时间") - private Date joinTime; - - @Schema(description = "离开时间") - private Date leaveTime; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomMessageDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomMessageDTO.java deleted file mode 100644 index 4fe3f00c..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomMessageDTO.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.Date; -import java.util.List; - -import com.alibaba.fastjson2.JSONObject; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 聊天消息表数据对象DTO - * @filename TbChatMessageDTO.java - * @author cascade - * @copyright xyzh - * @since 2025-12-20 - */ -@Data -@Schema(description = "聊天消息表对象") -public class TbChatRoomMessageDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "消息ID") - private String messageId; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "发送者ID") - private String senderId; - - @Schema(description = "发送者类型:guest-来客 agent-客服 ai-AI助手 system-系统消息") - private String senderType; - - @Schema(description = "发送者名称") - private String senderName; - - @Schema(description = "消息类型:text-文本 image-图片 file-文件 voice-语音 video-视频 system-系统消息 meeting-会议通知") - private String messageType; - - @Schema(description = "消息内容") - private String content; - - @Schema(description = "附件文件ID数组") - private List files; - - @Schema(description = "扩展内容(会议链接、引用信息等)") - private JSONObject contentExtra; - - @Schema(description = "回复的消息ID") - private String replyToMsgId; - - @Schema(description = "是否AI消息") - private Boolean isAiMessage; - - @Schema(description = "AI原始消息ID") - private String aiMessageId; - - @Schema(description = "状态:sending-发送中 sent-已发送 delivered-已送达 read-已读 failed-失败 recalled-已撤回") - private String status; - - @Schema(description = "已读人数") - private Integer readCount; - - @Schema(description = "发送时间") - private Date sendTime; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomSummaryDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomSummaryDTO.java deleted file mode 100644 index b58377ad..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbChatRoomSummaryDTO.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.util.List; - -/** - * @description 聊天室总结表对象 - * @filename TbChatRoomSummaryDTO.java - * @author system - * @copyright xyzh - * @since 2026-01-01 - */ -@Data -@Schema(description = "聊天室总结表对象") -public class TbChatRoomSummaryDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "总结ID") - private String summaryId; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "核心问题") - private String question; - - @Schema(description = "核心诉求数组") - private List needs; - - @Schema(description = "解决方案") - private String answer; - - @Schema(description = "词云关键词数组") - private List workcloud; - - @Schema(description = "参与总结的消息数量") - private Integer messageCount; - - @Schema(description = "总结生成时间") - private String summaryTime; - -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbCustomerServiceDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbCustomerServiceDTO.java deleted file mode 100644 index e41ce185..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbCustomerServiceDTO.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.List; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 客服人员配置表数据对象DTO - * @filename TbCustomerServiceDTO.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Data -@Schema(description = "客服人员配置表对象") -public class TbCustomerServiceDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "员工ID(关联sys用户ID)") - private String userId; - - @Schema(description = "员工姓名") - private String username; - - @Schema(description = "员工工号") - private String userCode; - - @Schema(description = "状态:online-在线 busy-忙碌 offline-离线") - private String status; - - @Schema(description = "技能标签") - private List skillTags; - - @Schema(description = "最大并发接待数") - private Integer maxConcurrent; - - @Schema(description = "当前工作量") - private Integer currentWorkload; - - @Schema(description = "累计服务次数") - private Integer totalServed; - - @Schema(description = "平均响应时间(秒)") - private Integer avgResponseTime; - - @Schema(description = "满意度评分(0-5)") - private Double satisfactionScore; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbMeetingParticipantDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbMeetingParticipantDTO.java deleted file mode 100644 index 015c2b9b..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbMeetingParticipantDTO.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.Date; - -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 会议参与记录表数据对象DTO - * @filename TbMeetingParticipantDTO.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Data -@Schema(description = "会议参与记录表对象") -public class TbMeetingParticipantDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "参与记录ID") - private String participantId; - - @Schema(description = "会议ID") - private String meetingId; - - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "用户类型:guest-来客 agent-客服") - private String userType; - - @Schema(description = "用户名称") - private String userName; - - @Schema(description = "加入时间") - private Date joinTime; - - @Schema(description = "离开时间") - private Date leaveTime; - - @Schema(description = "参与时长(秒)") - private Integer durationSeconds; - - @Schema(description = "是否主持人") - private Boolean isModerator; - - @Schema(description = "加入方式:web-网页 mobile-移动端 desktop-桌面端") - private String joinMethod; - - @Schema(description = "设备信息") - private String deviceInfo; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbMeetingTranscriptionDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbMeetingTranscriptionDTO.java deleted file mode 100644 index a91e9aee..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbMeetingTranscriptionDTO.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.Date; - -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 会议转录记录表数据对象DTO - * @filename TbMeetingTranscriptionDTO.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Data -@Schema(description = "会议转录记录表对象") -public class TbMeetingTranscriptionDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "转录记录ID") - private String transcriptionId; - - @Schema(description = "会议ID") - private String meetingId; - - @Schema(description = "说话人ID") - private String speakerId; - - @Schema(description = "说话人名称") - private String speakerName; - - @Schema(description = "说话人类型:guest-来客 agent-客服") - private String speakerType; - - @Schema(description = "转录文本内容") - private String content; - - @Schema(description = "原始转录结果") - private String contentRaw; - - @Schema(description = "语言") - private String language; - - @Schema(description = "识别置信度(0-1)") - private Double confidence; - - @Schema(description = "语音开始时间") - private Date speechStartTime; - - @Schema(description = "语音结束时间") - private Date speechEndTime; - - @Schema(description = "语音时长(毫秒)") - private Integer durationMs; - - @Schema(description = "音频片段URL") - private String audioUrl; - - @Schema(description = "片段序号") - private Integer segmentIndex; - - @Schema(description = "是否最终结果") - private Boolean isFinal; - - @Schema(description = "服务提供商") - private String serviceProvider; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbVideoMeetingDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbVideoMeetingDTO.java deleted file mode 100644 index 13d91dc8..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbVideoMeetingDTO.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.Date; - -import com.alibaba.fastjson2.JSONObject; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 视频会议表数据对象DTO - * @filename TbVideoMeetingDTO.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Data -@Schema(description = "视频会议表对象") -public class TbVideoMeetingDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "会议ID") - private String meetingId; - - @Schema(description = "关联聊天室ID") - private String roomId; - - @Schema(description = "关联工单ID") - private String workcaseId; - - @Schema(description = "会议名称") - private String meetingName; - - @Schema(description = "会议密码") - private String meetingPassword; - - @Schema(description = "会议模式") - private String description; - - @Schema(description = "JWT Token") - private String jwtToken; - - @Schema(description = "Jitsi房间名") - private String jitsiRoomName; - - @Schema(description = "Jitsi服务器地址") - private String jitsiServerUrl; - - @Schema(description = "状态:scheduled-已安排 ongoing-进行中 ended-已结束 cancelled-已取消") - private String status; - - @Schema(description = "创建者类型:guest-来客 agent-客服") - private String creatorType; - - @Schema(description = "创建者名称") - private String creatorName; - - @Schema(description = "参与人数") - private Integer participantCount; - - @Schema(description = "最大参与人数") - private Integer maxParticipants; - - @Schema(description = "定义会议开始时间") - private Date startTime; - - @Schema(description = "定义会议结束时间") - private Date endTime; - - @Schema(description = "提前入会时间(分钟)") - private Integer advance; - - @Schema(description = "实际开始时间") - private Date actualStartTime; - - @Schema(description = "实际结束时间") - private Date actualEndTime; - - @Schema(description = "会议时长(秒)") - private Integer durationSeconds; - - @Schema(description = "iframe嵌入URL") - private String iframeUrl; - - @Schema(description = "Jitsi配置项") - private JSONObject config; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWordCloudDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWordCloudDTO.java deleted file mode 100644 index 4e676176..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWordCloudDTO.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "词云表对象") -public class TbWordCloudDTO extends BaseDTO{ - private static final long serialVersionUID = 1L; - - @Schema(description = "词条ID") - private String wordId; - - @Schema(description = "词语") - private String word; - - @Schema(description = "词频") - private String frequency; - - @Schema(description = "分类") - private String category; - - @Schema(description = "统计日期") - private String statDate; - -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDTO.java deleted file mode 100644 index 9ae90763..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDTO.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.List; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 工单表数据对象DTO - * @filename TbWorkcaseDTO.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Data -@Schema(description = "工单表对象") -public class TbWorkcaseDTO extends BaseDTO{ - private static final long serialVersionUID = 1L; - - @Schema(description = "工单ID") - private String workcaseId; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "来客ID") - private String userId; - - @Schema(description = "来客姓名") - private String username; - - @Schema(description = "来客电话") - private String phone; - - @Schema(description = "故障类型") - private String type; - - @Schema(description = "设备名称") - private String device; - - @Schema(description = "设备名称牌") - private String deviceNamePlate; - - @Schema(description = "设备名称牌图片") - private String deviceNamePlateImg; - - @Schema(description = "设备代码") - private String deviceCode; - - @Schema(description = "地址") - private String address; - - @Schema(description = "故障描述") - private String description; - - @Schema(description = "工单图片列表") - private List imgs; - - @Schema(description = "紧急程度 normal-普通 emergency-紧急") - private String emergency; - - @Schema(description = "状态 pending-待处理 processing-处理中 done-已完成") - private String status; - - @Schema(description = "处理人ID") - private String processor; - - @Schema(description = "处理人姓名") - private String processorName; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDeviceDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDeviceDTO.java deleted file mode 100644 index 8ef5930b..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDeviceDTO.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 工单设备涉及的文件DTO - * @filename TbWorkcaseDeviceDTO.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Data -@Schema(description = "工单设备涉及的文件DTO") -public class TbWorkcaseDeviceDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "工单ID") - private String workcaseId; - - @Schema(description = "设备名称") - private String device; - - @Schema(description = "设备代码") - private String deviceCode; - - @Schema(description = "文件ID") - private String fileId; - - @Schema(description = "文件名") - private String fileName; - - @Schema(description = "文件根ID") - private String fileRootId; - -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseProcessDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseProcessDTO.java deleted file mode 100644 index c8b960c3..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseProcessDTO.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.xyzh.api.workcase.dto; - -import java.util.List; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @description 工单过程表DTO - * @filename TbWorkcaseProcessDTO.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Data -@Schema(description = "工单过程表DTO") -public class TbWorkcaseProcessDTO extends BaseDTO { - private static final long serialVersionUID = 1L; - - @Schema(description = "工单ID") - private String workcaseId; - - @Schema(description = "过程ID") - private String processId; - - @Schema(description = "动作 info:记录,assign:指派,redeploy:转派,repeal:撤销,finish:完成") - private String action; - - @Schema(description = "消息") - private String message; - - @Schema(description = "携带文件列表") - private List files; - - @Schema(description = "处理人(指派、转派专属)") - private String processor; - -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/AgentService.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/AgentService.java deleted file mode 100644 index 8da41d02..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/AgentService.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.xyzh.api.workcase.service; - -import org.xyzh.api.workcase.dto.ChatRoomSummaryRequest; -import org.xyzh.api.workcase.dto.ChatRoomSummaryResponse; -import org.xyzh.common.core.domain.ResultDomain; - -/** - * @description 智能体服务接口,提供AI相关的业务功能 - * @filename AgentService.java - * @author system - * @copyright xyzh - * @since 2026-01-01 - */ -public interface AgentService { - - /** - * @description 总结聊天室对话内容 - * @param request 聊天室总结请求参数 - * @return 总结结果 - * @author system - * @since 2026-01-01 - */ - ResultDomain summaryChatRoom(ChatRoomSummaryRequest request); - - /** - * @description 获取聊天室最新的总结 - * @param roomId 聊天室ID - * @return 总结结果 - * @author system - * @since 2026-01-01 - */ - ResultDomain getLatestSummary(String roomId); -} \ No newline at end of file diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/ChatRoomService.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/ChatRoomService.java deleted file mode 100644 index 03867adc..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/ChatRoomService.java +++ /dev/null @@ -1,231 +0,0 @@ -package org.xyzh.api.workcase.service; - -import org.xyzh.api.workcase.dto.TbChatRoomDTO; -import org.xyzh.api.workcase.dto.TbChatRoomMemberDTO; -import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO; -import org.xyzh.api.workcase.dto.TbCustomerServiceDTO; -import org.xyzh.api.workcase.vo.ChatRoomVO; -import org.xyzh.api.workcase.vo.ChatMemberVO; -import org.xyzh.api.workcase.vo.ChatRoomMessageVO; -import org.xyzh.api.workcase.vo.CustomerServiceVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; - -/** - * @description 聊天室服务接口,管理聊天室、成员和消息 - * @filename ChatRoomService.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -public interface ChatRoomService { - - // ========================= 聊天室管理 ========================== - - /** - * @description 创建聊天室 - * @param chatRoom 聊天室信息 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain createChatRoom(TbChatRoomDTO chatRoom); - - /** - * @description 更新聊天室 - * @param chatRoom 聊天室信息 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain updateChatRoom(TbChatRoomDTO chatRoom); - - /** - * @description 关闭聊天室 - * @param roomId 聊天室ID - * @param closedBy 关闭人 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain closeChatRoom(String roomId, String closedBy); - - /** - * @description 删除聊天室 - * @param roomId 聊天室ID - * @author cascade - * @since 2025-12-22 - */ - ResultDomain deleteChatRoom(String roomId); - - /** - * @description 根据ID获取聊天室 - * @param roomId 聊天室ID - * @author cascade - * @since 2025-12-22 - */ - ResultDomain getChatRoomById(String roomId); - - /** - * @description 分页查询聊天室(含当前用户未读数) - * @param pageRequest 分页请求参数 - * @param userId 当前用户ID(用于查询未读数) - * @author cascade - * @since 2025-12-22 - */ - ResultDomain getChatRoomPage(PageRequest pageRequest, String userId); - - /** - * @description 统计聊天室数量 - * @param filter 筛选条件 - * @author yslg - * @since 2026-01-01 - */ - ResultDomain countChatRooms(TbChatRoomDTO filter); - - // ========================= 聊天室成员管理 ========================== - - /** - * @description 添加聊天室成员 - * @param member 成员信息 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain addChatRoomMember(TbChatRoomMemberDTO member); - - /** - * @description 移除聊天室成员 - * @param memberId 成员ID - * @author cascade - * @since 2025-12-22 - */ - ResultDomain removeChatRoomMember(String memberId); - - /** - * @description 更新成员信息(如角色、状态) - * @param member 成员信息 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain updateChatRoomMember(TbChatRoomMemberDTO member); - - /** - * @description 获取聊天室成员列表 - * @param roomId 聊天室ID - * @author cascade - * @since 2025-12-22 - */ - ResultDomain getChatRoomMemberList(String roomId); - - /** - * @description 更新成员已读状态 - * @param memberId 成员ID - * @param lastReadMsgId 最后已读消息ID - * @author cascade - * @since 2025-12-22 - */ - ResultDomain updateMemberReadStatus(String memberId, String lastReadMsgId); - - /** - * @description 获取当前用户在指定聊天室的未读消息数 - * @param roomId 聊天室ID - * @param userId 用户ID - * @author cascade - * @since 2025-12-24 - */ - ResultDomain getUnreadCount(String roomId, String userId); - - // ========================= 聊天消息管理 ========================== - - /** - * @description 发送消息 - * @param message 消息内容 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain sendMessage(TbChatRoomMessageDTO message); - - /** - * @description 获取聊天室消息列表/分页 - * @param pageRequest 分页请求 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain getChatMessagePage(PageRequest pageRequest); - - /** - * @description 删除消息 - * @param messageId 消息ID - * @author cascade - * @since 2025-12-22 - */ - ResultDomain deleteMessage(String messageId); - - // ========================= 客服人员管理 ========================== - - /** - * @description 添加客服人员配置 - * @param customerService 客服人员信息 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain addCustomerService(TbCustomerServiceDTO customerService); - - /** - * @description 更新客服人员配置 - * @param customerService 客服人员信息 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain updateCustomerService(TbCustomerServiceDTO customerService); - - /** - * @description 删除客服人员配置 - * @param userId 员工ID - * @author cascade - * @since 2025-12-22 - */ - ResultDomain deleteCustomerService(String userId); - - /** - * @description 获取客服人员列表/分页 - * @param pageRequest 分页请求 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain getCustomerServicePage(PageRequest pageRequest); - - /** - * @description 更新客服人员在线状态 - * @param userId 员工ID - * @param status 状态:online-在线 busy-忙碌 offline-离线 - * @author cascade - * @since 2025-12-22 - */ - ResultDomain updateCustomerServiceStatus(String userId, String status); - - /** - * @description 获取可接待的客服人员(在线且工作量未满) - * @author cascade - * @since 2025-12-22 - */ - ResultDomain getAvailableCustomerServices(); - - /** - * @description 自动分配客服人员 - * @param roomId 聊天室ID - * @author cascade - * @since 2025-12-22 - */ - ResultDomain assignCustomerService(String roomId); - - // ========================= 聊天室评分管理 ========================== - - /** - * @description 提交聊天室服务评分 - * @param roomId 聊天室ID - * @param commentLevel 评分(1-5星) - * @param userId 评分用户ID - * @author cascade - * @since 2025-12-29 - */ - ResultDomain submitCommentLevel(String roomId, Integer commentLevel, String userId); - -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/JitsiTokenService.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/JitsiTokenService.java deleted file mode 100644 index a54e56cd..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/JitsiTokenService.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.xyzh.api.workcase.service; - -import com.alibaba.fastjson2.JSONObject; - -/** - * @description Jitsi Meet JWT Token服务接口 - * @filename JitsiTokenService.java - * @author claude - * @copyright xyzh - * @since 2025-12-25 - */ -public interface JitsiTokenService { - - /** - * @description 生成Jitsi Meet JWT Token - * @param roomName Jitsi房间名 - * @param userId 用户ID - * @param userName 用户名称 - * @param isModerator 是否为主持人 - * @return JWT Token字符串 - * @author claude - * @since 2025-12-25 - */ - String generateJwtToken(String roomName, String userId, String userName, boolean isModerator); - - /** - * @description 验证JWT Token是否有效 - * @param token JWT Token - * @return boolean - * @author claude - * @since 2025-12-25 - */ - boolean validateJwtToken(String token); - - /** - * @description 构建Jitsi Meet iframe URL - * @param roomName Jitsi房间名 - * @param jwtToken JWT Token - * @param config Jitsi配置项(可选) - * @return iframe URL字符串 - * @author claude - * @since 2025-12-25 - */ - String buildIframeUrl(String roomName, String jwtToken, JSONObject config); - - /** - * @description 生成唯一的Jitsi房间名 - * @param workcaseId 工单ID - * @return 房间名字符串 - * @author claude - * @since 2025-12-25 - */ - String generateRoomName(String workcaseId); -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/VideoMeetingService.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/VideoMeetingService.java deleted file mode 100644 index bbcc1fed..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/VideoMeetingService.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.xyzh.api.workcase.service; - -import org.xyzh.api.workcase.dto.TbVideoMeetingDTO; -import org.xyzh.api.workcase.vo.VideoMeetingVO; -import org.xyzh.common.core.domain.ResultDomain; - -/** - * @description 视频会议服务接口,管理Jitsi Meet视频会议 - * @filename VideoMeetingService.java - * @author claude - * @copyright xyzh - * @since 2025-12-25 - */ -public interface VideoMeetingService { - - /** - * @description 创建视频会议 - * @param meetingDTO 会议信息 - * @param userId 创建者用户ID - * @return ResultDomain - * @author claude - * @since 2025-12-25 - */ - ResultDomain createMeeting(TbVideoMeetingDTO meetingDTO); - - /** - * @description 获取会议信息 - * @param meetingId 会议ID - * @param userId 请求用户ID(用于权限验证) - * @return ResultDomain - * @author claude - * @since 2025-12-25 - */ - ResultDomain getMeetingInfo(String meetingId, String userId); - - /** - * @description 验证用户是否有权访问会议 - * @param meetingId 会议ID - * @param userId 用户ID - * @return ResultDomain - * @author claude - * @since 2025-12-25 - */ - ResultDomain validateMeetingAccess(String meetingId, String userId); - - /** - * @description 生成用户专属的会议访问URL(包含用户专属JWT Token) - * @param meetingId 会议ID - * @param userId 用户ID - * @return ResultDomain - * @author claude - * @since 2025-12-25 - */ - ResultDomain generateUserMeetingUrl(String meetingId, String userId); - - /** - * @description 开始会议(更新状态为ongoing) - * @param meetingId 会议ID - * @return ResultDomain - * @author claude - * @since 2025-12-25 - */ - ResultDomain startMeeting(String meetingId); - - /** - * @description 结束会议(更新状态为ended) - * @param meetingId 会议ID - * @return ResultDomain - * @author claude - * @since 2025-12-25 - */ - ResultDomain endMeeting(String meetingId); - - /** - * @description 获取聊天室当前活跃的会议 - * @param roomId 聊天室ID - * @return ResultDomain - * @author claude - * @since 2025-12-25 - */ - ResultDomain getActiveMeetingByRoom(String roomId); - - /** - * @description 检查用户是否为聊天室成员(内部方法) - * @param roomId 聊天室ID - * @param userId 用户ID - * @return boolean - * @author claude - * @since 2025-12-25 - */ - boolean isMemberOfRoom(String roomId, String userId); - - /** - * @description 通过token获取会议入口信息(用于小程序和外部链接访问) - * 此接口在gateway白名单中,通过URL参数token进行认证 - * @param meetingId 会议ID - * @param token 用户认证token - * @return ResultDomain 包含会议信息和用户专属的iframe URL - * @author yslg - * @since 2025-12-27 - */ - ResultDomain getMeetingEntryByToken(String meetingId, String token); - - /** - * @description 生成会议入口URL(用于分享给小程序用户) - * @param meetingId 会议ID - * @param baseUrl 基础URL(如 https://example.com/workcase) - * @return ResultDomain 完整的会议入口URL(包含token参数) - * @author yslg - * @since 2025-12-27 - */ - ResultDomain generateMeetingEntryUrl(String meetingId, String baseUrl); -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WordCloudService.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WordCloudService.java deleted file mode 100644 index 14b71287..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WordCloudService.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.xyzh.api.workcase.service; - -import org.xyzh.api.workcase.dto.TbWordCloudDTO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; - -/** - * @description 词云服务接口 - * @filename WordCloudService.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -public interface WordCloudService { - - /** - * 查询词云列表 - * @param filter 筛选条件 - * @return 词云列表 - */ - ResultDomain getWordCloudList(TbWordCloudDTO filter); - - /** - * 分页查询词云 - * @param pageRequest 分页请求 - * @return 词云分页数据 - */ - ResultDomain getWordCloudPage(PageRequest pageRequest); -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WorkcaseChatService.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WorkcaseChatService.java deleted file mode 100644 index c4e97cb3..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WorkcaseChatService.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.xyzh.api.workcase.service; - -import org.xyzh.api.workcase.dto.TbWordCloudDTO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; - -/** - * @description 客服聊天服务,涉及agent回答客户和微信客服回答客户 - * @filename WorkcaseChatService.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -public interface WorkcaseChatService { - - // =============================== 对话、工单等词云管理 ========================== - - /** - * @description 添加词云 - * @param wordCloud 词云对象 - * @author yslg - * @since 2025-12-19 - */ - ResultDomain addWordCloud(TbWordCloudDTO wordCloud); - - /** - * @description 更新词云 - * @param wordCloud 词云对象 - * @author yslg - * @since 2025-12-19 - */ - ResultDomain updateWordCloud(TbWordCloudDTO wordCloud); - - /** - * @description 获取词云列表 - * @param filter 词云过滤条件 - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWordCloudList(TbWordCloudDTO filter); - - /** - * @description 获取词云分页 - * @param pageRequest 分页请求 - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWordCloudPage(PageRequest pageRequest); - -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WorkcaseService.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WorkcaseService.java deleted file mode 100644 index 34eee9dd..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/service/WorkcaseService.java +++ /dev/null @@ -1,178 +0,0 @@ -package org.xyzh.api.workcase.service; - -import org.xyzh.api.workcase.dto.TbWorkcaseDTO; -import org.xyzh.api.workcase.dto.TbWorkcaseDeviceDTO; -import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO; -import org.xyzh.api.workcase.vo.WorkcaseProcessVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; - -import com.alibaba.fastjson2.JSONObject; - -/** - * 工单服务接口 - * 用于客服工单管理 - */ -public interface WorkcaseService { - - // ====================== 工单管理 ====================== - /** - * @description 创建工单 - * @param workcase - * @author yslg - * @since 2025-12-19 - */ - ResultDomain createWorkcase(TbWorkcaseDTO workcase); - /** - * @description 更新工单 - * @param workcase - * @author yslg - * @since 2025-12-19 - */ - ResultDomain updateWorkcase(TbWorkcaseDTO workcase); - - /** - * @description 删除工单 - * @param workcase - * @author yslg - * @since 2025-12-19 - */ - ResultDomain deleteWorkcase(TbWorkcaseDTO workcase); - - /** - * @description 获取工单列表 - * @param filter - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWorkcaseList(TbWorkcaseDTO filter); - - /** - * @description 获取工单分页 - * @param pageRequest - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWorkcasePage(PageRequest pageRequest); - - /** - * @description 统计各个类型的工单数量 - * @param filter - * @author yslg - * @since 2026-01-01 - */ - ResultDomain countWorkcasesByType(TbWorkcaseDTO filter); - - /** - * @description 统计工单数量 - * @param filter - * @author yslg - * @since 2026-01-01 - */ - ResultDomain countWorkcases(TbWorkcaseDTO filter); - - /** - * @description 获取工单详情 - * @param workcaseId - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWorkcaseById(String workcaseId); - - // ====================== 同步到CRM和接收 =================== - /** - * @description 同步工单到CRM - * @param workcase - * @author yslg - * @since 2025-12-19 - */ - ResultDomain syncWorkcaseToCrm(TbWorkcaseDTO workcase); - - /** - * @description 接收CRM的工单处理结果 - * @param json - * @author yslg - * @since 2025-12-19 - */ - ResultDomain receiveWorkcaseFromCrm(JSONObject json); - - // ====================== 工单处理过程 ====================== - /** - * @description 创建工单处理过程 - * @param workcaseProcess - * @author yslg - * @since 2025-12-19 - */ - ResultDomain createWorkcaseProcess(TbWorkcaseProcessDTO workcaseProcess); - - /** - * @description 更新工单处理过程 - * @param workcaseProcess - * @author yslg - * @since 2025-12-19 - */ - ResultDomain updateWorkcaseProcess(TbWorkcaseProcessDTO workcaseProcess); - - /** - * @description 删除工单处理过程 - * @param workcaseProcess - * @author yslg - * @since 2025-12-19 - */ - ResultDomain deleteWorkcaseProcess(TbWorkcaseProcessDTO workcaseProcess); - - /** - * @description 获取工单处理过程列表 - * @param filter - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWorkcaseProcessList(TbWorkcaseProcessDTO filter); - - /** - * @description 获取工单处理过程分页 - * @param pageRequest - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWorkcaseProcessPage(PageRequest pageRequest); - - // ====================== 工单设备管理 ====================== - /** - * @description 创建工单设备 - * @param workcaseDevice - * @author yslg - * @since 2025-12-19 - */ - ResultDomain createWorkcaseDevice(TbWorkcaseDeviceDTO workcaseDevice); - /** - * @description 更新工单设备 - * @param workcaseDevice - * @author yslg - * @since 2025-12-19 - */ - ResultDomain updateWorkcaseDevice(TbWorkcaseDeviceDTO workcaseDevice); - /** - * @description 删除工单设备 - * @param workcaseDevice - * @author yslg - * @since 2025-12-19 - */ - ResultDomain deleteWorkcaseDevice(TbWorkcaseDeviceDTO workcaseDevice); - /** - * @description 获取工单设备列表 - * @param filter - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWorkcaseDeviceList(TbWorkcaseDeviceDTO filter); - /** - * @description 获取工单设备分页 - * @param pageRequest - * @author yslg - * @since 2025-12-19 - */ - ResultDomain getWorkcaseDevicePage(PageRequest pageRequest); - - -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatMemberVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatMemberVO.java deleted file mode 100644 index 8c019ce8..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatMemberVO.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; - -/** - * 聊天室成员VO - * 用于前端展示聊天室成员信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "聊天室成员VO") -public class ChatMemberVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "成员记录ID") - private String memberId; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "用户ID(来客ID或员工ID)") - private String userId; - - @Schema(description = "用户类型:guest-来客 agent-客服 ai-AI助手") - private String userType; - - @Schema(description = "用户名称") - private String userName; - - @Schema(description = "用户头像") - private String userAvatar; - - @Schema(description = "状态:active-活跃 left-已离开 removed-被移除") - private String status; - - @Schema(description = "该成员的未读消息数") - private Integer unreadCount; - - @Schema(description = "最后阅读时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date lastReadTime; - - @Schema(description = "最后阅读的消息ID") - private String lastReadMsgId; - - @Schema(description = "加入时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date joinTime; - - @Schema(description = "离开时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date leaveTime; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatRoomMessageVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatRoomMessageVO.java deleted file mode 100644 index 72fcb5ad..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatRoomMessageVO.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import com.alibaba.fastjson2.JSONObject; -import java.util.Date; -import java.util.List; - -/** - * 聊天消息VO - * 用于前端展示聊天消息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "聊天消息VO") -public class ChatRoomMessageVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "消息ID") - private String messageId; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "发送者ID") - private String senderId; - - @Schema(description = "发送者类型:guest-来客 agent-客服 ai-AI助手 system-系统消息") - private String senderType; - - @Schema(description = "发送者名称") - private String senderName; - - @Schema(description = "发送者头像") - private String senderAvatar; - - @Schema(description = "消息类型:text-文本 image-图片 file-文件 voice-语音 video-视频 system-系统消息 meeting-会议通知") - private String messageType; - - @Schema(description = "消息内容") - private String content; - - @Schema(description = "附件文件ID数组") - private List files; - - @Schema(description = "附件数量") - private Integer fileCount; - - @Schema(description = "扩展内容(会议链接、引用信息等)") - private JSONObject contentExtra; - - @Schema(description = "回复的消息ID") - private String replyToMsgId; - - @Schema(description = "回复的消息内容") - private String replyToMsgContent; - - @Schema(description = "是否AI消息") - private Boolean isAiMessage; - - @Schema(description = "AI原始消息ID") - private String aiMessageId; - - @Schema(description = "状态:sending-发送中 sent-已发送 delivered-已送达 read-已读 failed-失败 recalled-已撤回") - private String status; - - @Schema(description = "已读人数") - private Integer readCount; - - @Schema(description = "发送时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date sendTime; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatRoomVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatRoomVO.java deleted file mode 100644 index 6d396cf6..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ChatRoomVO.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.util.Date; - -/** - * 聊天室VO - * 用于前端展示聊天室信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "聊天室VO") -public class ChatRoomVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "聊天室ID") - private String roomId; - - @Schema(description = "关联工单ID") - private String workcaseId; - - @Schema(description = "聊天室名称") - private String roomName; - - @Schema(description = "聊天室类型:workcase-工单客服") - private String roomType; - - @Schema(description = "状态:active-活跃 closed-已关闭 archived-已归档") - private String status; - - @Schema(description = "来客ID(创建者)") - private String guestId; - - @Schema(description = "来客姓名") - private String guestName; - - @Schema(description = "AI对话会话ID") - private String aiSessionId; - - @Schema(description = "当前负责客服ID") - private String currentAgentId; - - @Schema(description = "当前负责客服名称") - private String currentAgentName; - - @Schema(description = "已加入的客服人数") - private Integer agentCount; - - @Schema(description = "消息总数") - private Integer messageCount; - - @Schema(description = "未读消息数(客服端)") - private Integer unreadCount; - - @Schema(description = "最后消息时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date lastMessageTime; - - @Schema(description = "最后一条消息内容") - private String lastMessage; - - @Schema(description = "服务评分(1-5星)") - private Integer commentLevel; - - @Schema(description = "设备代码") - private String deviceCode; - - @Schema(description = "关闭人") - private String closedBy; - - @Schema(description = "关闭人姓名") - private String closedByName; - - @Schema(description = "关闭时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date closedTime; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ConversationVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ConversationVO.java deleted file mode 100644 index 8ed13934..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/ConversationVO.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import com.fasterxml.jackson.databind.JsonNode; -import java.util.Date; -import java.util.List; - -/** - * 会话VO - * 用于前端展示会话信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "会话VO") -public class ConversationVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "会话ID") - private String conversationId; - - @Schema(description = "客户ID") - private String customerId; - - @Schema(description = "客户姓名") - private String customerName; - - @Schema(description = "客户头像") - private String customerAvatar; - - @Schema(description = "会话类型") - private String conversationType; - - @Schema(description = "会话类型名称") - private String conversationTypeName; - - @Schema(description = "渠道") - private String channel; - - @Schema(description = "渠道名称") - private String channelName; - - @Schema(description = "智能体ID或客服人员ID") - private String agentId; - - @Schema(description = "座席名称") - private String agentName; - - @Schema(description = "座席类型") - private String agentType; - - @Schema(description = "座席类型名称") - private String agentTypeName; - - @Schema(description = "会话开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date sessionStartTime; - - @Schema(description = "会话结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date sessionEndTime; - - @Schema(description = "会话时长(秒)") - private Integer durationSeconds; - - @Schema(description = "会话时长格式化显示") - private String durationFormatted; - - @Schema(description = "消息数量") - private Integer messageCount; - - @Schema(description = "会话状态") - private String conversationStatus; - - @Schema(description = "会话状态名称") - private String conversationStatusName; - - @Schema(description = "会话状态颜色") - private String statusColor; - - @Schema(description = "满意度评分(1-5星)") - private Integer satisfactionRating; - - @Schema(description = "满意度反馈") - private String satisfactionFeedback; - - @Schema(description = "会话摘要") - private String summary; - - @Schema(description = "会话标签") - private List tags; - - @Schema(description = "会话元数据") - private JsonNode metadata; - - @Schema(description = "最后一条消息内容") - private String lastMessageContent; - - @Schema(description = "最后一条消息时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date lastMessageTime; - - @Schema(description = "创建者姓名") - private String creatorName; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/CustomerServiceVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/CustomerServiceVO.java deleted file mode 100644 index 34cc7169..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/CustomerServiceVO.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; - -/** - * 客服人员配置VO - * 用于前端展示客服人员信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "客服人员配置VO") -public class CustomerServiceVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "员工ID(关联sys用户ID)") - private String userId; - - @Schema(description = "员工姓名") - private String username; - - @Schema(description = "员工工号") - private String userCode; - - @Schema(description = "员工头像") - private String avatar; - - @Schema(description = "状态:online-在线 busy-忙碌 offline-离线") - private String status; - - @Schema(description = "状态名称") - private String statusName; - - @Schema(description = "技能标签") - private List skillTags; - - @Schema(description = "最大并发接待数") - private Integer maxConcurrent; - - @Schema(description = "当前工作量") - private Integer currentWorkload; - - @Schema(description = "累计服务次数") - private Integer totalServed; - - @Schema(description = "平均响应时间(秒)") - private Integer avgResponseTime; - - @Schema(description = "平均响应时间(格式化)") - private String avgResponseTimeFormatted; - - @Schema(description = "满意度评分(0-5)") - private Double satisfactionScore; - - @Schema(description = "是否可接待(工作量未满)") - private Boolean isAvailable; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/CustomerVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/CustomerVO.java deleted file mode 100644 index a413fa5c..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/CustomerVO.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - -/** - * 客户信息VO - * 用于前端展示客户信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "客户信息VO") -public class CustomerVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "客户ID") - private String customerId; - - @Schema(description = "客户编号") - private String customerNo; - - @Schema(description = "客户姓名") - private String customerName; - - @Schema(description = "客户类型") - private String customerType; - - @Schema(description = "客户类型名称") - private String customerTypeName; - - @Schema(description = "公司名称") - private String companyName; - - @Schema(description = "电话") - private String phone; - - @Schema(description = "邮箱") - private String email; - - @Schema(description = "微信OpenID") - private String wechatOpenid; - - @Schema(description = "头像URL") - private String avatar; - - @Schema(description = "性别") - private Integer gender; - - @Schema(description = "性别名称") - private String genderName; - - @Schema(description = "地址") - private String address; - - @Schema(description = "客户等级") - private String customerLevel; - - @Schema(description = "客户等级名称") - private String customerLevelName; - - @Schema(description = "客户来源") - private String customerSource; - - @Schema(description = "客户来源名称") - private String customerSourceName; - - @Schema(description = "客户标签") - private List tags; - - @Schema(description = "备注") - private String notes; - - @Schema(description = "CRM系统客户ID") - private String crmCustomerId; - - @Schema(description = "最后联系时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date lastContactTime; - - @Schema(description = "咨询总次数") - private Integer totalConsultations; - - @Schema(description = "订单总数") - private Integer totalOrders; - - @Schema(description = "总消费金额") - private BigDecimal totalAmount; - - @Schema(description = "满意度评分") - private BigDecimal satisfactionScore; - - @Schema(description = "状态") - private String status; - - @Schema(description = "状态名称") - private String statusName; - - @Schema(description = "状态颜色") - private String statusColor; - - @Schema(description = "创建者姓名") - private String creatorName; - - @Schema(description = "更新者姓名") - private String updaterName; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/MeetingParticipantVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/MeetingParticipantVO.java deleted file mode 100644 index a2cffce1..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/MeetingParticipantVO.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import java.util.Date; -import com.alibaba.fastjson2.annotation.JSONField; - -/** - * 会议参与记录VO - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "会议参与记录VO") -public class MeetingParticipantVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "参与记录ID") - private String participantId; - - @Schema(description = "会议ID") - private String meetingId; - - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "用户类型:guest-来客 agent-客服") - private String userType; - - @Schema(description = "用户名称") - private String userName; - - @Schema(description = "加入时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date joinTime; - - @Schema(description = "离开时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date leaveTime; - - @Schema(description = "参与时长(秒)") - private Integer durationSeconds; - - @Schema(description = "参与时长(格式化)") - private String durationFormatted; - - @Schema(description = "是否主持人") - private Boolean isModerator; - - @Schema(description = "加入方式:web-网页 mobile-移动端 desktop-桌面端") - private String joinMethod; - - @Schema(description = "设备信息") - private String deviceInfo; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/MeetingTranscriptionVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/MeetingTranscriptionVO.java deleted file mode 100644 index 2cbc2c7b..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/MeetingTranscriptionVO.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import java.util.Date; -import com.alibaba.fastjson2.annotation.JSONField; - -/** - * 会议转录记录VO - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "会议转录记录VO") -public class MeetingTranscriptionVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "转录记录ID") - private String transcriptionId; - - @Schema(description = "会议ID") - private String meetingId; - - @Schema(description = "说话人ID") - private String speakerId; - - @Schema(description = "说话人名称") - private String speakerName; - - @Schema(description = "说话人类型:guest-来客 agent-客服") - private String speakerType; - - @Schema(description = "转录文本内容") - private String content; - - @Schema(description = "原始转录结果") - private String contentRaw; - - @Schema(description = "语言") - private String language; - - @Schema(description = "识别置信度(0-1)") - private Double confidence; - - @Schema(description = "语音开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date speechStartTime; - - @Schema(description = "语音结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date speechEndTime; - - @Schema(description = "语音时长(毫秒)") - private Integer durationMs; - - @Schema(description = "音频片段URL") - private String audioUrl; - - @Schema(description = "片段序号") - private Integer segmentIndex; - - @Schema(description = "是否最终结果") - private Boolean isFinal; - - @Schema(description = "服务提供商") - private String serviceProvider; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/VideoMeetingVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/VideoMeetingVO.java deleted file mode 100644 index 2241dd1f..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/VideoMeetingVO.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.vo.BaseVO; -import io.swagger.v3.oas.annotations.media.Schema; -import com.alibaba.fastjson2.annotation.JSONField; -import com.alibaba.fastjson2.JSONObject; -import java.util.Date; - -/** - * 视频会议VO - * 用于前端展示Jitsi Meet会议信息 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "视频会议VO") -public class VideoMeetingVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "会议ID") - private String meetingId; - - @Schema(description = "关联聊天室ID") - private String roomId; - - @Schema(description = "关联工单ID") - private String workcaseId; - - @Schema(description = "会议名称") - private String meetingName; - - @Schema(description = "会议密码") - private String meetingPassword; - - @Schema(description = "会议模式") - private String description; - - - @Schema(description = "JWT Token(用于身份验证)") - private String jwtToken; - - @Schema(description = "Jitsi房间名") - private String jitsiRoomName; - - @Schema(description = "Jitsi服务器地址") - private String jitsiServerUrl; - - @Schema(description = "状态:scheduled-已安排 ongoing-进行中 ended-已结束 cancelled-已取消") - private String status; - - @Schema(description = "创建者类型:guest-来客 agent-客服") - private String creatorType; - - @Schema(description = "创建者名称") - private String creatorName; - - @Schema(description = "参与人数") - private Integer participantCount; - - @Schema(description = "最大参与人数") - private Integer maxParticipants; - - @Schema(description = "定义会议开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date startTime; - - @Schema(description = "定义会议结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date endTime; - - @Schema(description = "提前入会时间(分钟)") - private Integer advance; - - @Schema(description = "实际开始时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date actualStartTime; - - @Schema(description = "实际结束时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date actualEndTime; - - @Schema(description = "会议时长(秒)") - private Integer durationSeconds; - - @Schema(description = "会议时长(格式化,如:1小时30分)") - private String durationFormatted; - - @Schema(description = "会议页面URL(用于路由跳转)") - private String iframeUrl; - - @Schema(description = "Jitsi真正的iframe URL(用于嵌入播放)") - private String jitsiIframeUrl; - - @Schema(description = "Jitsi配置项") - private JSONObject config; -} diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/WorkcaseProcessVO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/WorkcaseProcessVO.java deleted file mode 100644 index f7bc3761..00000000 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/vo/WorkcaseProcessVO.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.xyzh.api.workcase.vo; - -import java.util.List; - -import org.xyzh.common.vo.BaseVO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description 工单过程VO - * @filename WorkcaseProcessVO.java - * @author yslg - * @copyright xyzh - * @since 2025-12-31 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "工单过程VO") -public class WorkcaseProcessVO extends BaseVO { - private static final long serialVersionUID = 1L; - - @Schema(description = "工单ID") - private String workcaseId; - - @Schema(description = "过程ID") - private String processId; - - @Schema(description = "动作 info:记录,assign:指派,redeploy:转派,repeal:撤销,finish:完成") - private String action; - - @Schema(description = "消息") - private String message; - - @Schema(description = "携带文件列表") - private List files; - - @Schema(description = "处理人ID(指派、转派专属)") - private String processor; - - @Schema(description = "处理人名称") - private String processorName; -} diff --git a/urbanLifelineServ/apis/pom.xml b/urbanLifelineServ/apis/pom.xml deleted file mode 100644 index c0c760ff..00000000 --- a/urbanLifelineServ/apis/pom.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - apis - 1.0.0 - pom - - api-all - api-auth - api-file - api-message - api-system - api-crontab - api-ai - api-bidding - api-platform - api-workcase - - - - 21 - 21 - - - - - - org.xyzh.apis - api-all - ${urban-lifeline.version} - - - org.xyzh.apis - api-auth - ${urban-lifeline.version} - - - org.xyzh.apis - api-file - ${urban-lifeline.version} - - - org.xyzh.apis - api-message - ${urban-lifeline.version} - - - org.xyzh.apis - api-system - ${urban-lifeline.version} - - - - - - - org.xyzh.common - common-core - - - org.xyzh.common - common-dto - ${urban-lifeline.version} - - - - org.apache.dubbo - dubbo - - - - - jakarta.servlet - jakarta.servlet-api - provided - - - - - org.springframework - spring-web - provided - - - - - org.springframework - spring-webmvc - provided - - - - - io.swagger.core.v3 - swagger-annotations-jakarta - 2.2.36 - provided - - - - \ No newline at end of file diff --git a/urbanLifelineServ/auth/pom.xml b/urbanLifelineServ/auth/pom.xml deleted file mode 100644 index cf3cc5c9..00000000 --- a/urbanLifelineServ/auth/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - auth - ${urban-lifeline.version} - - - 21 - 21 - - - - - org.xyzh.apis - api-auth - - - org.xyzh.apis - api-system - - - org.xyzh.apis - api-message - - - org.xyzh.common - common-auth - - - org.xyzh.common - common-core - - - org.xyzh.common - common-utils - - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - - - - - auth - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/AuthApp.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/AuthApp.java deleted file mode 100644 index 5d9d2b93..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/AuthApp.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.xyzh.auth; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@EnableDiscoveryClient // 启用 Nacos 服务注册与发现(用于 Gateway 路由) -@ComponentScan(basePackages = { - "org.xyzh.auth", // 当前auth模块 - "org.xyzh.common" // 公共模块 -}) -public class AuthApp { - private static final Logger logger = LoggerFactory.getLogger(AuthApp.class); - - public static void main(String[] args) { - logger.info("======================== AuthApp 启动中 ========================="); - SpringApplication.run(AuthApp.class, args); - logger.info("======================== AuthApp 启动成功 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/config/OpenApiConfig.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/config/OpenApiConfig.java deleted file mode 100644 index 798218f1..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/config/OpenApiConfig.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.xyzh.auth.config; - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Contact; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.info.License; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import io.swagger.v3.oas.models.servers.Server; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.List; - -/** - * OpenAPI 配置类 - Auth 服务 - * 配置 Swagger/OpenAPI 文档,方便 Apifox 导入接口和对象进行测试 - * - * @author yslg - */ -@Configuration -public class OpenApiConfig { - - @Bean - public OpenAPI authOpenAPI() { - return new OpenAPI() - .info(new Info() - .title("认证服务 API 文档") - .description(""" - 认证服务接口文档,包括登录、登出、Token刷新等功能。 - - ## 使用说明 - 1. 访问 Swagger UI: http://localhost:8081/urban-lifeline/auth/swagger-ui.html - 2. 访问 OpenAPI JSON: http://localhost:8081/urban-lifeline/auth/v3/api-docs - 3. 在 Apifox 中导入 OpenAPI JSON 进行接口测试 - """) - .version("1.0.0") - .contact(new Contact() - .name("yslg") - .email("3401275564@qq.com")) - .license(new License() - .name("Apache 2.0") - .url("https://www.apache.org/licenses/LICENSE-2.0.html"))) - .servers(List.of( - new Server().url("http://localhost:8081/urban-lifeline/auth").description("本地开发环境") - )) - .addSecurityItem(new SecurityRequirement().addList("Bearer Authentication")) - .components(new Components() - .addSecuritySchemes("Bearer Authentication", - new SecurityScheme() - .type(SecurityScheme.Type.HTTP) - .scheme("bearer") - .bearerFormat("JWT") - .description("请输入JWT Token,格式:Bearer {token}"))); - } -} - diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/controller/AuthController.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/controller/AuthController.java deleted file mode 100644 index 3274d0d0..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/controller/AuthController.java +++ /dev/null @@ -1,375 +0,0 @@ -package org.xyzh.auth.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; -import org.xyzh.api.auth.service.AuthService; -import org.xyzh.api.message.service.MessageService; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.redis.service.RedisService; -import org.apache.dubbo.config.annotation.DubboReference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import jakarta.servlet.http.HttpServletRequest; -import java.util.Map; - -/** - * @description AuthController.java文件描述 认证控制器 - * @filename AuthController.java - * @author yslg - * @copyright xyzh - * @since 2025-09-28 - */ -@RestController -@RequestMapping("/auth") -public class AuthController { - - private static final Logger logger = LoggerFactory.getLogger(AuthController.class); - - @Autowired - private AuthService authService; - - @DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0) - private SysUserService userService; - - @DubboReference(version = "1.0.0", group = "message", timeout = 5000, check = false, retries = 0) - private MessageService messageService; - - @Autowired - private RedisService redisService; - - /** - * @description 用户登录 - * @param loginParam 登录参数 - * @return ResultDomain 登录结果 - * @author yslg - * @since 2025-09-28 - */ - @PostMapping("/login") - public ResultDomain login(@RequestBody LoginParam loginParam, HttpServletRequest request) { - // 从 request 中提取客户端 IP 并设置到 loginParam - loginParam.setClientIp(getClientIP(request)); - return authService.login(loginParam); - } - - /** - * @description 用户退出登录 - * @param loginDomain 登录域对象 - * @return ResultDomain 退出结果 - * @author yslg - * @since 2025-09-28 - */ - @PostMapping("/logout") - public ResultDomain logout(HttpServletRequest request) { - String token = extractTokenFromRequest(request); - return authService.logout(token); - } - - /** - * @description 获取验证码(统一接口,支持多种类型) - * @param loginParam 登录参数(包含验证码类型) - * @return ResultDomain 验证码结果 - * @author yslg - * @since 2025-12-09 - */ - @PostMapping("/captcha") - public ResultDomain getCaptcha(@RequestBody LoginParam loginParam) { - return authService.getCaptcha(loginParam); - } - - /** - * @description 刷新令牌 - * @param request HTTP请求 - * @return ResultDomain 新的登录信息 - * @author yslg - * @since 2025-12-09 - */ - @PostMapping("/refresh") - public ResultDomain refreshToken(HttpServletRequest request) { - String token = extractTokenFromRequest(request); - String clientIp = getClientIP(request); - return authService.refreshToken(token, clientIp); - } - - /** - * @description 健康检查 - * @return ResultDomain 健康状态 - * @author yslg - * @since 2025-09-28 - */ - @GetMapping("/health") - public ResultDomain health() { - return ResultDomain.success("认证服务运行正常", "OK"); - } - - /** - * @description 发送邮箱验证码 - * @param requestBody 包含email字段的请求体 - * @return ResultDomain 发送结果 - * @author yslg - * @since 2025-12-09 - */ - @PostMapping("/send-email-code") - public ResultDomain sendEmailCode(@RequestBody Map requestBody) { - String email = requestBody.get("email"); - - LoginParam loginParam = new LoginParam(); - loginParam.setEmail(email); - loginParam.setLoginType("email"); - - return authService.getCaptcha(loginParam); - } - - /** - * @description 发送手机验证码 - * @param requestBody 包含phone字段的请求体 - * @return ResultDomain 发送结果 - * @author yslg - * @since 2025-12-09 - */ - @PostMapping("/send-sms-code") - public ResultDomain sendSmsCode(@RequestBody Map requestBody) { - String phone = requestBody.get("phone"); - - LoginParam loginParam = new LoginParam(); - loginParam.setPhone(phone); - loginParam.setLoginType("sms"); - - return authService.getCaptcha(loginParam); - } - - /** - * @description 用户注册 - * @param requestBody 注册参数 - * @return ResultDomain 注册结果 - * @author yslg - * @since 2025-11-03 - */ - @PostMapping("/register") - public ResultDomain register(@RequestBody Map requestBody, HttpServletRequest request) { - try { - // 获取注册参数 - String registerType = (String) requestBody.get("registerType"); - String username = (String) requestBody.get("username"); - String phone = (String) requestBody.get("phone"); - String email = (String) requestBody.get("email"); - String password = (String) requestBody.get("password"); - String confirmPassword = (String) requestBody.get("confirmPassword"); - String smsCode = (String) requestBody.get("smsCode"); - String emailCode = (String) requestBody.get("emailCode"); - String smsSessionId = (String) requestBody.get("smsSessionId"); - String emailSessionId = (String) requestBody.get("emailSessionId"); - String studentId = (String) requestBody.get("studentId"); - - // 1. 参数验证 - if (password == null || password.trim().isEmpty()) { - return ResultDomain.failure("密码不能为空"); - } - - if (password.length() < 6) { - return ResultDomain.failure("密码至少6个字符"); - } - - if (!password.equals(confirmPassword)) { - return ResultDomain.failure("两次输入的密码不一致"); - } - - // 2. 根据注册类型进行不同的验证 - SysUserVO user = new SysUserVO(); - - switch (registerType) { - case "username": - // 用户名注册 - if (username == null || username.trim().isEmpty()) { - return ResultDomain.failure("用户名不能为空"); - } - if (username.length() < 3 || username.length() > 20) { - return ResultDomain.failure("用户名长度为3-20个字符"); - } - if (!username.matches("^[a-zA-Z0-9_]+$")) { - return ResultDomain.failure("用户名只能包含字母、数字和下划线"); - } - user.setUsername(username); - logger.info("用户名注册: {}", username); - break; - - case "phone": - // 手机号注册 - if (phone == null || phone.trim().isEmpty()) { - return ResultDomain.failure("手机号不能为空"); - } - if (!phone.matches("^1[3-9]\\d{9}$")) { - return ResultDomain.failure("手机号格式不正确"); - } - if (smsCode == null || smsCode.trim().isEmpty()) { - return ResultDomain.failure("请输入手机验证码"); - } - if (smsSessionId == null || smsSessionId.trim().isEmpty()) { - return ResultDomain.failure("会话已失效,请重新获取验证码"); - } - - // 通过sessionId验证手机验证码 - String smsCodeKey = "sms:code:" + smsSessionId; - String storedSmsValue = redisService.get(smsCodeKey, String.class); - if (storedSmsValue == null) { - return ResultDomain.failure("验证码已过期,请重新获取"); - } - - // 解析存储的值:手机号:验证码 - String[] smsParts = storedSmsValue.split(":"); - if (smsParts.length != 2) { - return ResultDomain.failure("验证码数据异常"); - } - - String storedPhone = smsParts[0]; - String storedSmsCode = smsParts[1]; - - // 验证手机号和验证码是否匹配 - if (!storedPhone.equals(phone)) { - logger.warn("手机号注册验证失败,提交手机号: {}, 验证码绑定手机号: {}", phone, storedPhone); - return ResultDomain.failure("手机号与验证码不匹配"); - } - if (!storedSmsCode.equals(smsCode)) { - return ResultDomain.failure("验证码错误"); - } - - // 验证码使用后删除 - redisService.delete(smsCodeKey); - - user.setPhone(phone); - user.setUsername(phone); // 使用手机号作为用户名 - logger.info("手机号注册: {}, sessionId: {}", phone, smsSessionId); - break; - - case "email": - // 邮箱注册 - if (email == null || email.trim().isEmpty()) { - return ResultDomain.failure("邮箱不能为空"); - } - if (!email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) { - return ResultDomain.failure("邮箱格式不正确"); - } - if (emailCode == null || emailCode.trim().isEmpty()) { - return ResultDomain.failure("请输入邮箱验证码"); - } - if (emailSessionId == null || emailSessionId.trim().isEmpty()) { - return ResultDomain.failure("会话已失效,请重新获取验证码"); - } - - // 通过sessionId验证邮箱验证码 - String emailCodeKey = "email:code:" + emailSessionId; - String storedEmailValue = redisService.get(emailCodeKey, String.class); - if (storedEmailValue == null) { - return ResultDomain.failure("验证码已过期,请重新获取"); - } - - // 解析存储的值:邮箱:验证码 - String[] emailParts = storedEmailValue.split(":"); - if (emailParts.length != 2) { - return ResultDomain.failure("验证码数据异常"); - } - - String storedEmail = emailParts[0]; - String storedEmailCode = emailParts[1]; - - // 验证邮箱和验证码是否匹配 - if (!storedEmail.equals(email)) { - logger.warn("邮箱注册验证失败,提交邮箱: {}, 验证码绑定邮箱: {}", email, storedEmail); - return ResultDomain.failure("邮箱与验证码不匹配"); - } - if (!storedEmailCode.equals(emailCode)) { - return ResultDomain.failure("验证码错误"); - } - - // 验证码使用后删除 - redisService.delete(emailCodeKey); - - user.setEmail(email); - user.setUsername(email.split("@")[0]); // 使用邮箱前缀作为用户名 - logger.info("邮箱注册: {}, sessionId: {}", email, emailSessionId); - break; - - default: - return ResultDomain.failure("未知的注册类型"); - } - - // 3. 设置密码(明文,Service层会加密) - user.setPassword(password); - - // 4. 设置用户状态为正常 - user.setStatus("0"); - - // 5. 调用UserService注册用户(Service层会加密密码) - ResultDomain registerResult = userService.registerUser(user); - - if (!registerResult.getSuccess()) { - return ResultDomain.failure(registerResult.getMessage()); - } - - logger.info("用户注册成功: {}", user.getUsername()); - - // 6. 注册成功后自动登录 - LoginParam loginParam = new LoginParam(); - loginParam.setUsername(user.getUsername()); - loginParam.setPassword(password); - loginParam.setLoginType("password"); - - if (phone != null && !phone.trim().isEmpty()) { - loginParam.setPhone(phone); - } - if (email != null && !email.trim().isEmpty()) { - loginParam.setEmail(email); - } - - loginParam.setClientIp(getClientIP(request)); - ResultDomain loginResult = authService.login(loginParam); - - if (loginResult.getSuccess()) { - return ResultDomain.success("注册成功", loginResult.getData()); - } else { - // 注册成功但登录失败,返回注册成功信息 - return ResultDomain.success("注册成功,请登录", loginResult.getData()); - } - - } catch (Exception e) { - logger.error("用户注册失败", e); - return ResultDomain.failure("注册失败: " + e.getMessage()); - } - } - - /** - * 从请求中提取Token - */ - private String extractTokenFromRequest(HttpServletRequest request) { - String authHeader = request.getHeader("Authorization"); - if (authHeader != null && authHeader.startsWith("Bearer ")) { - return authHeader.substring(7); - } - return null; - } - - /** - * 获取客户端IP地址 - */ - private String getClientIP(HttpServletRequest request) { - String ip = request.getHeader("X-Forwarded-For"); - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); - } - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); - } - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); - } - if (ip != null && ip.contains(",")) { - ip = ip.split(",")[0].trim(); - } - return ip; - } -} diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/enums/UserStatus.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/enums/UserStatus.java deleted file mode 100644 index 56e0547e..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/enums/UserStatus.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.xyzh.auth.enums; - -/** - * @description 用户状态枚举 - * @filename UserStatus.java - * @author yslg - * @copyright yslg - * @since 2025-12-09 - */ -public enum UserStatus { - - NORMAL("0", "正常"), - DISABLED("1", "禁用"), - LOCKED("2", "锁定"), - EXPIRED("3", "过期"); - - private final String code; - private final String name; - - UserStatus(String code, String name) { - this.code = code; - this.name = name; - } - - public String getCode() { - return code; - } - - public String getName() { - return name; - } - - /** - * 根据状态码获取用户状态 - * @param code 状态码 - * @return UserStatus - */ - public static UserStatus fromCode(String code) { - if (code == null) { - return DISABLED; - } - for (UserStatus status : values()) { - if (status.code.equals(code)) { - return status; - } - } - return DISABLED; // 默认返回禁用状态 - } - - /** - * 判断是否为正常状态 - * @return boolean - */ - public boolean isNormal() { - return this == NORMAL; - } -} diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/exception/AuthException.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/exception/AuthException.java deleted file mode 100644 index ae544c15..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/exception/AuthException.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.xyzh.auth.exception; -import org.xyzh.common.core.exception.BaseException; - -public class AuthException extends BaseException { - - public AuthException(Integer code, String description, String message){ - super(code, description, message); - } -} diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/service/impl/AuthServiceImpl.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/service/impl/AuthServiceImpl.java deleted file mode 100644 index 89ef6b80..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/service/impl/AuthServiceImpl.java +++ /dev/null @@ -1,615 +0,0 @@ -package org.xyzh.auth.service.impl; - -import com.alibaba.fastjson2.JSON; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.api.auth.service.AuthService; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.service.ModulePermissionService; -import org.xyzh.api.system.service.GuestService; -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.api.system.vo.UserDeptRoleVO; -import org.xyzh.common.dto.sys.TbGuestDTO; -import org.xyzh.auth.enums.UserStatus; -import org.xyzh.auth.strategy.LoginStrategyFactory; -import org.xyzh.auth.strategy.LoginStrategy; -import org.xyzh.auth.utils.CapcatUtils; -import org.xyzh.common.auth.utils.JwtTokenUtil; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; -import org.xyzh.common.dto.sys.TbSysUserRoleDTO; -import org.xyzh.common.dto.sys.TbSysDeptDTO; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; -import org.xyzh.common.dto.sys.TbSysViewDTO; -import org.xyzh.common.redis.service.RedisService; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.crypto.AesEncryptUtil; -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.TimeUnit; -import java.util.List; -import java.util.ArrayList; - -/** - * @description AuthServiceImpl.java文件描述 认证服务实现类 - * @filename AuthServiceImpl.java - * @author yslg - * @copyright yslg - * @since 2025-11-09 - */ -@DubboService( - version = "1.0.0", - group = "auth", - timeout = 3000, - retries = 0 -) -public class AuthServiceImpl implements AuthService{ - - private static final Logger logger = LoggerFactory.getLogger(AuthServiceImpl.class); - - @Autowired - private JwtTokenUtil jwtTokenUtil; - - @Autowired - private RedisService redisService; - - - @DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0) - private SysUserService userService; - - @DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0) - private ModulePermissionService modulePermissionService; - - @DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0) - private GuestService guestService; - - @Autowired - private LoginStrategyFactory loginStrategyFactory; - - @Autowired - private AesEncryptUtil aesEncryptUtil; - - @Override - public ResultDomain getCaptcha(LoginParam loginParam) { - try { - String captchaType = loginParam.getLoginType(); // "image", "sms", "email" - - switch (captchaType) { - case "image": - // 生成图片验证码 - String captchaId = IdUtil.generateID(); - String captchaCode = CapcatUtils.generateVerificationCode(); - - // 存储验证码到Redis,有效期5分钟 - String captchaKey = "captcha:image:" + captchaId; - redisService.set(captchaKey, captchaCode, 5, TimeUnit.MINUTES); - - LoginDomain captchaResult = new LoginDomain(); - captchaResult.setToken(captchaId); // 使用token字段存储captchaId - captchaResult.setLoginType("image"); - - return ResultDomain.success("图片验证码生成成功", captchaResult); - - case "sms": - if (loginParam.getPhone() == null || loginParam.getPhone().trim().isEmpty()) { - return ResultDomain.failure("手机号不能为空"); - } - - String smsSessionId = IdUtil.generateID(); - String smsCode = CapcatUtils.generateVerificationCode(); - - // 存储短信验证码到Redis,有效期5分钟 - String smsKey = "captcha:sms:" + smsSessionId; - String smsValue = loginParam.getPhone() + ":" + smsCode; - redisService.set(smsKey, smsValue, 5, TimeUnit.MINUTES); - - LoginDomain smsResult = new LoginDomain(); - smsResult.setToken(smsSessionId); - smsResult.setLoginType("sms"); - - // 这里应该调用短信服务发送验证码,暂时先返回 - logger.info("短信验证码已生成:phone={}, code={}", loginParam.getPhone(), smsCode); - - return ResultDomain.success("短信验证码发送成功", smsResult); - - case "email": - if (loginParam.getEmail() == null || loginParam.getEmail().trim().isEmpty()) { - return ResultDomain.failure("邮箱不能为空"); - } - - String emailSessionId = IdUtil.generateID(); - String emailCode = CapcatUtils.generateVerificationCode(); - - // 存储邮箱验证码到Redis,有效期5分钟 - String emailKey = "captcha:email:" + emailSessionId; - String emailValue = loginParam.getEmail() + ":" + emailCode; - redisService.set(emailKey, emailValue, 5, TimeUnit.MINUTES); - - LoginDomain emailResult = new LoginDomain(); - emailResult.setToken(emailSessionId); - emailResult.setLoginType("email"); - - // 这里应该调用邮件服务发送验证码,暂时先返回 - logger.info("邮箱验证码已生成:email={}, code={}", loginParam.getEmail(), emailCode); - - return ResultDomain.success("邮箱验证码发送成功", emailResult); - - default: - return ResultDomain.failure("不支持的验证码类型"); - } - - } catch (Exception e) { - logger.error("验证码生成失败", e); - return ResultDomain.failure("验证码生成失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain getLoginByToken(String token) { - try { - if (token == null || token.trim().isEmpty()) { - return ResultDomain.failure("Token不能为空"); - } - - // 1. 验证Token格式和是否过期 - if (jwtTokenUtil.isTokenExpired(token)) { - return ResultDomain.failure("Token已过期"); - } - - // 2. 从Redis获取登录信息 - String loginKey = "login:token:" + token; - String loginJson = redisService.get(loginKey, String.class); - if (loginJson == null) { - return ResultDomain.failure("登录信息已失效"); - } - - LoginDomain loginDomain = JSON.parseObject(loginJson, LoginDomain.class); - - // 3. 验证Token中的用户ID与Redis中的是否匹配 - if (loginDomain.getUser() != null) { - String tokenUserId = jwtTokenUtil.getUserIdFromToken(token); - if (!loginDomain.getUser().getUserId().equals(tokenUserId)) { - return ResultDomain.failure("Token验证失败"); - } - } - - return ResultDomain.success("获取登录信息成功", loginDomain); - - } catch (Exception e) { - logger.error("获取登录信息失败", e); - return ResultDomain.failure("获取登录信息失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain isTokenValid(String token) { - try { - if (token == null || token.trim().isEmpty()) { - return ResultDomain.success("Token验证", false); - } - - // 1. 检查Token格式和是否过期 - if (jwtTokenUtil.isTokenExpired(token)) { - return ResultDomain.success("Token验证", false); - } - - // 2. 检查Redis中是否存在登录信息 - String loginKey = "login:token:" + token; - boolean exists = redisService.hasKey(loginKey); - - return ResultDomain.success("Token验证", exists); - - } catch (Exception e) { - logger.error("Token验证失败", e); - return ResultDomain.success("Token验证", false); - } - } - - @Override - public ResultDomain login(LoginParam loginParam) { - String loginType = loginParam.getLoginType(); - String loginAttempt = IdUtil.generateID(); // 生成登录尝试ID - - try { - logger.info("用户登录请求:loginType={}, username={}, attempt={}", loginType, loginParam.getUsername(), loginAttempt); - - // 1. 获取对应的登录策略 - LoginStrategy strategy = loginStrategyFactory.getStrategy(loginType); - - // 2. 验证登录参数 - if (!strategy.validate(loginParam)) { - logLoginAttempt(loginParam, null, false, loginAttempt, "登录参数不正确"); - return ResultDomain.failure("登录参数不正确"); - } - - // 3. 查找用户 - SysUserVO user = strategy.findUser(loginParam); - if (user == null) { - logLoginAttempt(loginParam, null, false, loginAttempt, "用户不存在"); - return ResultDomain.failure("用户不存在"); - } - - // 4. 检查用户状态 - UserStatus userStatus = UserStatus.fromCode(user.getStatus()); - if (!userStatus.isNormal()) { - logLoginAttempt(loginParam, user, false, loginAttempt, "用户状态异常: " + userStatus.getName()); - return ResultDomain.failure("用户状态异常: " + userStatus.getName()); - } - - // 5. 验证凭据 - if ("password".equals(loginType)) { - String pwd = aesEncryptUtil.decrypt(loginParam.getPassword()); - if (!strategy.verifyCredential(pwd, user.getPassword())) { - logLoginAttempt(loginParam, user, false, loginAttempt, "密码错误"); - return ResultDomain.failure("密码错误"); - } - } else if ("email".equals(loginType) || "phone".equals(loginType)) { - if (!strategy.verifyCaptchaWithSession(loginParam)) { - logLoginAttempt(loginParam, user, false, loginAttempt, "验证码验证失败"); - return ResultDomain.failure("验证码错误或已过期"); - } - } - - // 6. 获取用户详细信息 - ResultDomain userInfoResult = userService.getUserInfo(user.getUserId()); - if (!userInfoResult.getSuccess() || userInfoResult.getData() == null) { - logLoginAttempt(loginParam, user, false, loginAttempt, "获取用户信息失败"); - return ResultDomain.failure("获取用户信息失败"); - } - - SysUserVO userInfo = userInfoResult.getData(); - - // 7. 构建完整的登录域对象 - LoginDomain loginDomain = buildLoginDomain(userInfo, loginType, loginParam.getClientIp()); - if (loginDomain == null) { - logLoginAttempt(loginParam, user, false, loginAttempt, "构建登录信息失败"); - return ResultDomain.failure("构建登录信息失败"); - } - - // 8. 生成 JWT Token - String token = jwtTokenUtil.generateToken(loginDomain); - loginDomain.setToken(token); - - // 9. 将登录信息存储到 Redis - String loginKey = "login:token:" + token; - redisService.set(loginKey, JSON.toJSONString(loginDomain), 24, TimeUnit.HOURS); - - // 10. 存储用户登录状态 - String userLoginKey = "login:user:" + user.getUserId(); - redisService.set(userLoginKey, token, 24, TimeUnit.HOURS); - - // 11. 记录成功日志 - logLoginAttempt(loginParam, user, true, loginAttempt, "登录成功"); - logger.info("用户登录成功:userId={}, username={}, loginType={}, attempt={}", user.getUserId(), userInfo.getUsername(), loginType, loginAttempt); - - return ResultDomain.success("登录成功", loginDomain); - - } catch (Exception e) { - logger.error("用户登录失败:attempt={}", loginAttempt, e); - logLoginAttempt(loginParam, null, false, loginAttempt, "系统异常: " + e.getMessage()); - return ResultDomain.failure("登录失败: " + e.getMessage()); - } - } - - /** - * 构建完整的LoginDomain对象 - * @param userInfo 用户信息 - * @param loginType 登录类型 - * @param clientIp 客户端IP地址 - * @return LoginDomain 登录域对象 - */ - public LoginDomain buildLoginDomain(SysUserVO userInfo, String loginType, String clientIp) { - try { - // 1. 转换为 DTO 对象 - TbSysUserDTO userDTO = SysUserVO.toDTO(userInfo); - TbSysUserInfoDTO userInfoDTO = SysUserVO.toUserInfoDTO(userInfo); - - // 2. 获取用户角色和部门信息 - List userRoles = new ArrayList<>(); - List userDepts = new ArrayList<>(); - - ResultDomain userDeptRoleResult = userService.getUserWithDeptRole(userInfo.getUserId()); - if (userDeptRoleResult.getSuccess() && userDeptRoleResult.getDataList() != null) { - for (UserDeptRoleVO deptRole : userDeptRoleResult.getDataList()) { - // 添加用户角色 - if (deptRole.getRoleId() != null) { - TbSysUserRoleDTO userRole = new TbSysUserRoleDTO(); - userRole.setUserId(deptRole.getUserId()); - userRole.setRoleId(deptRole.getRoleId()); - userRole.setCreateTime(deptRole.getCreateTime()); - userRole.setUpdateTime(deptRole.getUpdateTime()); - userRoles.add(userRole); - } - - // 添加用户部门 - if (deptRole.getDeptId() != null) { - TbSysDeptDTO userDept = new TbSysDeptDTO(); - userDept.setDeptId(deptRole.getDeptId()); - userDept.setName(deptRole.getDeptName()); - userDept.setParentId(deptRole.getParentId()); - userDept.setDescription(deptRole.getDeptDescription()); - userDepts.add(userDept); - } - } - } - - // 3. 获取用户权限信息 - List userPermissions = new ArrayList<>(); - List userViews = new ArrayList<>(); - - ResultDomain permissionsResult = modulePermissionService.getUserPermissions(userInfo.getUserId()); - if (permissionsResult.getSuccess() && permissionsResult.getDataList() != null) { - for (PermissionVO permission : permissionsResult.getDataList()) { - // 添加权限信息 - if (permission.getPermissionId() != null) { - TbSysPermissionDTO permissionDTO = PermissionVO.toPermissionDTO(permission); - if (permissionDTO != null) { - userPermissions.add(permissionDTO); - } - } - - // 添加视图信息 - if (permission.getViewId() != null) { - TbSysViewDTO viewDTO = PermissionVO.toViewDTO(permission); - if (viewDTO != null) { - userViews.add(viewDTO); - } - } - } - } - - // 4. 创建登录域对象 - LoginDomain loginDomain = new LoginDomain(); - loginDomain.setUser(userDTO); - loginDomain.setUserInfo(userInfoDTO); - loginDomain.setUserRoles(userRoles); - loginDomain.setUserDepts(userDepts); - loginDomain.setUserPermissions(userPermissions); - loginDomain.setUserViews(userViews); - loginDomain.setLoginType(loginType); - loginDomain.setIpAddress(clientIp); - - return loginDomain; - - } catch (Exception e) { - logger.error("构建LoginDomain失败:userId={}", userInfo.getUserId(), e); - return null; - } - } - - /** - * 记录登录尝试日志 - * @param loginParam 登录参数 - * @param user 用户信息(可能为null) - * @param success 是否成功 - * @param attemptId 尝试ID - * @param message 消息 - */ - private void logLoginAttempt(LoginParam loginParam, SysUserVO user, boolean success, String attemptId, String message) { - try { - String userId = user != null ? user.getUserId() : "unknown"; - String username = loginParam.getUsername() != null ? loginParam.getUsername() : - (loginParam.getPhone() != null ? loginParam.getPhone() : - (loginParam.getEmail() != null ? loginParam.getEmail() : "unknown")); - - if (success) { - logger.info("登录成功 - 用户ID: {}, 用户名: {}, 登录类型: {}, 尝试ID: {}, 消息: {}", - userId, username, loginParam.getLoginType(), attemptId, message); - } else { - logger.warn("登录失败 - 用户名: {}, 登录类型: {}, 尝试ID: {}, 原因: {}", - username, loginParam.getLoginType(), attemptId, message); - } - - } catch (Exception e) { - logger.error("记录登录日志失败:attemptId={}", attemptId, e); - } - } - - @Override - public ResultDomain refreshToken(String token, String clientIp) { - try { - if (token == null || token.trim().isEmpty()) { - return ResultDomain.failure("Token不能为空"); - } - - // 1. 验证当前Token是否有效 - if (jwtTokenUtil.isTokenExpired(token)) { - return ResultDomain.failure("Token已过期"); - } - - // 2. 从JWT中提取用户ID和登录类型 - String userId = jwtTokenUtil.getUserIdFromToken(token); - String loginType = jwtTokenUtil.getClaimFromToken(token, claims -> claims.get("loginType", String.class)); - - if (userId == null || userId.trim().isEmpty()) { - return ResultDomain.failure("Token信息不完整"); - } - - logger.info("Token刷新请求:userId={}, loginType={}", userId, loginType); - - // 3. 尝试从Redis获取登录信息(优先使用缓存) - String loginKey = "login:token:" + token; - String loginJson = redisService.get(loginKey, String.class); - LoginDomain oldLoginDomain = null; - - if (loginJson != null) { - oldLoginDomain = JSON.parseObject(loginJson, LoginDomain.class); - if (loginType == null && oldLoginDomain != null) { - loginType = oldLoginDomain.getLoginType(); - } - } - - // 4. 根据登录类型获取最新用户信息 - LoginDomain newLoginDomain; - - if ("wechat_miniprogram".equals(loginType)) { - // 来客(小程序)用户:从guest表获取信息 - TbGuestDTO guestDTO = new TbGuestDTO(); - guestDTO.setUserId(userId); - ResultDomain guestResult = guestService.selectGuestOne(guestDTO); - if (!guestResult.getSuccess() || guestResult.getData() == null) { - return ResultDomain.failure("获取来客信息失败"); - } - - TbGuestDTO guest = guestResult.getData(); - newLoginDomain = buildGuestLoginDomain(guest, loginType); - - } else { - // 普通用户:从sys_user表获取信息 - ResultDomain userInfoResult = userService.getUserInfo(userId); - if (!userInfoResult.getSuccess() || userInfoResult.getData() == null) { - return ResultDomain.failure("获取用户信息失败"); - } - - SysUserVO userInfo = userInfoResult.getData(); - String effectiveLoginType = (loginType != null) ? loginType : "password"; - newLoginDomain = buildLoginDomain(userInfo, effectiveLoginType, clientIp); - } - - if (newLoginDomain == null) { - return ResultDomain.failure("构建登录信息失败"); - } - - // 5. 生成新Token - String newToken = jwtTokenUtil.generateToken(newLoginDomain); - newLoginDomain.setToken(newToken); - - // 6. 删除旧的Token信息(如果存在) - if (loginJson != null) { - redisService.delete(loginKey); - } - - // 7. 存储新的登录信息 - String newLoginKey = "login:token:" + newToken; - redisService.set(newLoginKey, JSON.toJSONString(newLoginDomain), 24, TimeUnit.HOURS); - - // 8. 更新用户登录状态 - String userLoginKey = "login:user:" + userId; - redisService.set(userLoginKey, newToken, 24, TimeUnit.HOURS); - - logger.info("Token刷新成功:userId={}, loginType={}, oldToken={}, newToken={}", - userId, - loginType, - token.substring(0, Math.min(10, token.length())) + "...", - newToken.substring(0, Math.min(10, newToken.length())) + "..."); - - return ResultDomain.success("Token刷新成功", newLoginDomain); - - } catch (Exception e) { - logger.error("Token刷新失败", e); - return ResultDomain.failure("Token刷新失败: " + e.getMessage()); - } - } - - /** - * 从来客信息构造LoginDomain(用于token刷新) - */ - private LoginDomain buildGuestLoginDomain(TbGuestDTO guest, String loginType) { - try { - LoginDomain loginDomain = new LoginDomain(); - - // 构造TbSysUserDTO,status设为guest - TbSysUserDTO userDTO = new TbSysUserDTO(); - userDTO.setUserId(guest.getUserId()); - userDTO.setPhone(guest.getPhone()); - userDTO.setEmail(guest.getEmail()); - userDTO.setWechatId(guest.getWechatId()); - userDTO.setStatus("guest"); // 来客特殊状态 - loginDomain.setUser(userDTO); - - // 构造TbSysUserInfoDTO - TbSysUserInfoDTO userInfoDTO = new TbSysUserInfoDTO(); - userInfoDTO.setUserId(guest.getUserId()); - userInfoDTO.setUsername(guest.getName() != null ? guest.getName() : "来客"); - loginDomain.setUserInfo(userInfoDTO); - - // 设置角色信息 - List userRoles = new ArrayList<>(); - TbSysUserRoleDTO userRole = new TbSysUserRoleDTO(); - userRole.setUserId(guest.getUserId()); - userRole.setRoleId("role_guest"); - userRole.setDeptId("dept_root"); - userRoles.add(userRole); - loginDomain.setUserRoles(userRoles); - - // 获取用户权限信息 - List userPermissions = new ArrayList<>(); - List userViews = new ArrayList<>(); - - ResultDomain permissionsResult = modulePermissionService.getUserPermissions(guest.getUserId()); - if (permissionsResult.getSuccess() && permissionsResult.getDataList() != null) { - for (PermissionVO permission : permissionsResult.getDataList()) { - if (permission.getPermissionId() != null) { - TbSysPermissionDTO permissionDTO = PermissionVO.toPermissionDTO(permission); - if (permissionDTO != null) { - userPermissions.add(permissionDTO); - } - } - if (permission.getViewId() != null) { - TbSysViewDTO viewDTO = PermissionVO.toViewDTO(permission); - if (viewDTO != null) { - userViews.add(viewDTO); - } - } - } - } - loginDomain.setUserPermissions(userPermissions); - loginDomain.setUserViews(userViews); - - // 设置登录类型 - loginDomain.setLoginType(loginType != null ? loginType : "wechat_miniprogram"); - - logger.info("构建来客LoginDomain成功:userId={}, name={}", guest.getUserId(), guest.getName()); - - return loginDomain; - - } catch (Exception e) { - logger.error("构建来客LoginDomain失败:userId={}", guest.getUserId(), e); - return null; - } - } - - @Override - public ResultDomain logout(String token) { - try { - if (token == null || token.trim().isEmpty()) { - return ResultDomain.failure("Token不能为空"); - } - - // 1. 从Redis获取登录信息 - String loginKey = "login:token:" + token; - String loginJson = redisService.get(loginKey, String.class); - if (loginJson == null) { - return ResultDomain.success("登出成功", (LoginDomain) null); // 已经过期的token,直接返回成功 - } - - LoginDomain loginDomain = JSON.parseObject(loginJson, LoginDomain.class); - - // 2. 删除Redis中的登录信息 - redisService.delete(loginKey); - - // 3. 删除用户登录状态 - if (loginDomain.getUser() != null) { - String userLoginKey = "login:user:" + loginDomain.getUser().getUserId(); - redisService.delete(userLoginKey); - } - - logger.info("用户登出成功:userId={}, token={}", - loginDomain.getUser() != null ? loginDomain.getUser().getUserId() : "unknown", - token.substring(0, Math.min(10, token.length())) + "..."); - - return ResultDomain.success("登出成功", (LoginDomain)null); - - } catch (Exception e) { - logger.error("用户登出失败", e); - return ResultDomain.failure("登出失败: " + e.getMessage()); - } - } - -} diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/LoginStrategy.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/LoginStrategy.java deleted file mode 100644 index 583150eb..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/LoginStrategy.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.xyzh.auth.strategy; - -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.dto.sys.TbSysUserDTO; - -/** - * @description LoginStrategy.java文件描述 登录策略接口 - * @filename LoginStrategy.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -public interface LoginStrategy { - - /** - * @description 支持的登录类型 - * @return String 登录类型 - * @author yslg - * @since 2025-12-05 - */ - String getLoginType(); - - /** - * @description 验证登录参数 - * @param loginParam 登录参数 - * @return boolean 是否有效 - * @author yslg - * @since 2025-12-05 - */ - boolean validate(LoginParam loginParam); - - /** - * @description 根据登录参数查找用户 - * @param loginParam 登录参数 - * @return TbSysUser 用户对象 - * @author yslg - * @since 2025-12-05 - */ - SysUserVO findUser(LoginParam loginParam); - - /** - * @description 验证凭据(密码或验证码) - * @param inputCredential 输入凭据(密码或验证码) - * @param storedCredential 存储凭据(密码或验证码) - * @return boolean 是否匹配 - * @author yslg - * @since 2025-12-05 - */ - boolean verifyCredential(String inputCredential, String storedCredential); - - /** - * @description 验证验证码(从Redis获取并验证SessionID) - * @param loginParam 登录参数 - * @return boolean 是否验证成功 - * @author yslg - * @since 2025-12-05 - */ - default boolean verifyCaptchaWithSession(LoginParam loginParam) { - // 默认实现:不支持验证码登录 - return false; - } -} \ No newline at end of file diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/LoginStrategyFactory.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/LoginStrategyFactory.java deleted file mode 100644 index c468068c..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/LoginStrategyFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.xyzh.auth.strategy; - -import org.springframework.stereotype.Component; -import org.xyzh.auth.exception.AuthException; - -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * @description LoginStrategyFactory.java文件描述 登录策略工厂 - * @filename LoginStrategyFactory.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -@Component -public class LoginStrategyFactory { - - private final Map strategies; - - public LoginStrategyFactory(List loginStrategies) { - this.strategies = loginStrategies.stream() - .collect(Collectors.toMap(LoginStrategy::getLoginType, Function.identity())); - } - - /** - * @description 获取登录策略 - * @param loginType 登录类型 - * @return LoginStrategy 登录策略 - * @author yslg - * @since 2025-12-05 - */ - public LoginStrategy getStrategy(String loginType) { - LoginStrategy strategy = strategies.get(loginType); - if (strategy == null) { - throw new AuthException(1,"UNSUPPORTED_LOGIN_TYPE", "不支持的登录类型: " + loginType); - } - return strategy; - } - - /** - * @description 获取所有支持的登录类型 - * @return Set 登录类型集合 - * @author yslg - * @since 2025-12-05 - */ - public java.util.Set getSupportedLoginTypes() { - return strategies.keySet(); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/EmailLoginStrategy.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/EmailLoginStrategy.java deleted file mode 100644 index 145c4277..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/EmailLoginStrategy.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.xyzh.auth.strategy.impl; - -import org.springframework.stereotype.Component; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.auth.strategy.LoginStrategy; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.common.redis.service.RedisService; - -/** - * @description EmailLoginStrategy.java文件描述 邮箱登录策略 - * @filename EmailLoginStrategy.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -@Component -public class EmailLoginStrategy implements LoginStrategy { - - @Autowired - private SysUserService userService; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Override - public String getLoginType() { - return "email"; - } - - @Override - public boolean validate(LoginParam loginParam) { - if (loginParam.getEmail() == null || loginParam.getEmail().trim().isEmpty()) { - return false; - } - // 密码登录或验证码登录都可以 - return (loginParam.getPassword() != null && !loginParam.getPassword().trim().isEmpty()) - || (loginParam.getCaptcha() != null && !loginParam.getCaptcha().trim().isEmpty()); - } - - @Override - public SysUserVO findUser(LoginParam loginParam) { - SysUserVO filter = new SysUserVO(); - filter.setEmail(loginParam.getEmail()); - SysUserVO user = userService.getLoginUser(filter).getData(); - if(user == null) { - return null; - } - return user; - } - - @Autowired - private RedisService redisService; - - @Override - public boolean verifyCredential(String inputCredential, String storedCredential) { - // 密码验证 - return passwordEncoder.matches(inputCredential, storedCredential); - } - - @Override - public boolean verifyCaptchaWithSession(LoginParam loginParam) { - String captchaId = loginParam.getCaptchaId(); - String inputCaptcha = loginParam.getCaptcha(); - String email = loginParam.getEmail(); - - // 验证参数 - if (captchaId == null || captchaId.trim().isEmpty()) { - return false; - } - if (inputCaptcha == null || inputCaptcha.trim().isEmpty()) { - return false; - } - - // 从Redis获取验证码 - String codeKey = "email:code:" + captchaId; - String storedValue = redisService.get(codeKey, String.class); - - if (storedValue == null) { - return false; - } - - // 解析存储的值:邮箱:验证码 - String[] parts = storedValue.split(":"); - if (parts.length != 2) { - return false; - } - - String storedEmail = parts[0]; - String storedCaptcha = parts[1]; - - // 验证邮箱和验证码是否匹配 - if (!storedEmail.equals(email) || !storedCaptcha.equals(inputCaptcha)) { - return false; - } - - // 验证码使用后删除 - redisService.delete(codeKey); - return true; - } -} \ No newline at end of file diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/PasswordLoginStrategy.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/PasswordLoginStrategy.java deleted file mode 100644 index 75dab48c..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/PasswordLoginStrategy.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.xyzh.auth.strategy.impl; - -import org.springframework.stereotype.Component; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.auth.strategy.LoginStrategy; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.utils.NonUtils; -import org.xyzh.common.utils.crypto.AesEncryptUtil; -import org.xyzh.common.utils.validation.method.EmailValidateMethod; -import org.xyzh.common.utils.validation.method.PhoneValidateMethod; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @description PasswordLoginStrategy.java文件描述 密码登录策略 - * @filename PasswordLoginStrategy.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -@Component -public class PasswordLoginStrategy implements LoginStrategy { - - private static final Logger logger = LoggerFactory.getLogger(PasswordLoginStrategy.class); - - @Autowired - private SysUserService userService; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Override - public String getLoginType() { - return "password"; - } - - @Override - public boolean validate(LoginParam loginParam) { - if (NonUtils.isEmpty(loginParam.getPassword())) { - return false; - } - - if (NonUtils.isEmpty(loginParam.getUsername()) && NonUtils.isEmpty(loginParam.getEmail()) && NonUtils.isEmpty(loginParam.getPhone())) { - return false; - } - - return true; - } - - @Override - public SysUserVO findUser(LoginParam loginParam) { - SysUserVO filter = new SysUserVO(); - EmailValidateMethod emailValidateMethod = new EmailValidateMethod(); - PhoneValidateMethod phoneValidateMethod = new PhoneValidateMethod(); - if(emailValidateMethod.validate(loginParam.getUsername())){ - filter.setEmail(loginParam.getUsername()); - }else if (phoneValidateMethod.validate(loginParam.getUsername())){ - filter.setPhone(loginParam.getUsername()); - }else{ - filter.setUsername(loginParam.getUsername()); - } - // 【优化】删除无用的密码编码,SQL查询不使用password字段 - // 密码验证在 verifyCredential() 方法中进行 - SysUserVO user = userService.getLoginUser(filter).getData(); - if(user == null) { - return null; - } - return user; - } - - @Override - public boolean verifyCredential(String inputCredential, String storedCredential) { - // 使用BCrypt的matches方法验证密码(内部会自动处理salt) - logger.info(passwordEncoder.encode(inputCredential)); - return passwordEncoder.matches(inputCredential, storedCredential); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/PhoneLoginStrategy.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/PhoneLoginStrategy.java deleted file mode 100644 index e2046f41..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/PhoneLoginStrategy.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.xyzh.auth.strategy.impl; - -import org.springframework.stereotype.Component; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.auth.strategy.LoginStrategy; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.common.redis.service.RedisService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @description PhoneLoginStrategy.java文件描述 手机号登录策略 - * @filename PhoneLoginStrategy.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -@Component -public class PhoneLoginStrategy implements LoginStrategy { - private static final Logger logger = LoggerFactory.getLogger(PhoneLoginStrategy.class); - - @Autowired - private SysUserService userService; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Override - public String getLoginType() { - return "phone"; - } - - @Override - public boolean validate(LoginParam loginParam) { - if (loginParam.getPhone() == null || loginParam.getPhone().trim().isEmpty()) { - return false; - } - // 密码登录或验证码登录都可以 - return (loginParam.getPassword() != null && !loginParam.getPassword().trim().isEmpty()) - || (loginParam.getCaptcha() != null && !loginParam.getCaptcha().trim().isEmpty()); - } - - @Override - public SysUserVO findUser(LoginParam loginParam) { - SysUserVO filter = new SysUserVO(); - filter.setPhone(loginParam.getPhone()); - SysUserVO user = userService.getLoginUser(filter).getData(); - if(user == null) { - return null; - } - return user; - } - - @Autowired - private RedisService redisService; - - @Override - public boolean verifyCredential(String inputCredential, String storedCredential) { - return passwordEncoder.matches(inputCredential, storedCredential); - } - - @Override - public boolean verifyCaptchaWithSession(LoginParam loginParam) { - String captchaId = loginParam.getCaptchaId(); - String inputCaptcha = loginParam.getCaptcha(); - String phone = loginParam.getPhone(); - - // 验证参数 - if (captchaId == null || captchaId.trim().isEmpty()) { - return false; - } - if (inputCaptcha == null || inputCaptcha.trim().isEmpty()) { - return false; - } - - // 从Redis获取验证码 - String codeKey = "sms:code:" + captchaId; - String storedValue = redisService.get(codeKey, String.class); - - if (storedValue == null) { - return false; - } - - // 解析存储的值:手机号:验证码 - String[] parts = storedValue.split(":"); - if (parts.length != 2) { - return false; - } - - String storedPhone = parts[0]; - String storedCaptcha = parts[1]; - - // 验证手机号和验证码是否匹配 - if (!storedPhone.equals(phone) || !storedCaptcha.equals(inputCaptcha)) { - return false; - } - - // 验证码使用后删除 - redisService.delete(codeKey); - return true; - } -} \ No newline at end of file diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/UsernameLoginStrategy.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/UsernameLoginStrategy.java deleted file mode 100644 index 2f2e3dd3..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/UsernameLoginStrategy.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.xyzh.auth.strategy.impl; - -import org.springframework.stereotype.Component; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.auth.strategy.LoginStrategy; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; - -/** - * @description UsernameLoginStrategy.java文件描述 用户名登录策略 - * @filename UsernameLoginStrategy.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -@Component -public class UsernameLoginStrategy implements LoginStrategy { - - @Autowired - private SysUserService userService; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Override - public String getLoginType() { - return "username"; - } - - @Override - public boolean validate(LoginParam loginParam) { - return loginParam.getUsername() != null && !loginParam.getUsername().trim().isEmpty() - && loginParam.getPassword() != null && !loginParam.getPassword().trim().isEmpty(); - } - - @Override - public SysUserVO findUser(LoginParam loginParam) { - SysUserVO filter = new SysUserVO(); - filter.setUsername(loginParam.getUsername()); - SysUserVO user = userService.getLoginUser(filter).getData(); - if(user == null) { - return null; - } - return user; - } - - @Override - public boolean verifyCredential(String inputCredential, String storedCredential) { - return passwordEncoder.matches(inputCredential, storedCredential); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/WechatLoginStrategy.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/WechatLoginStrategy.java deleted file mode 100644 index 473ab161..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/WechatLoginStrategy.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.xyzh.auth.strategy.impl; - -import org.springframework.stereotype.Component; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.auth.strategy.LoginStrategy; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; - -/** - * @description 微信二维码登录策略(PC端扫码登录) - * @filename WechatLoginStrategy.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -@Component -public class WechatLoginStrategy implements LoginStrategy { - - @Autowired - private SysUserService userService; - - - @Override - public String getLoginType() { - return "wechat_qrcode"; - } - - @Override - public boolean validate(LoginParam loginParam) { - return loginParam.getWechatId() != null && !loginParam.getWechatId().trim().isEmpty(); - } - - @Override - public SysUserVO findUser(LoginParam loginParam) { - SysUserVO filter = new SysUserVO(); - filter.setWechatId(loginParam.getWechatId()); - SysUserVO user = userService.getLoginUser(filter).getData(); - if(user == null) { - return null; - } - return user; - } - - @Override - public boolean verifyCredential(String inputCredential, String storedCredential) { - // 微信登录通常不需要密码验证,通过微信授权码验证 - // 这里可以添加微信授权验证逻辑 - return true; - } -} diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/WechatMiniProgramLoginStrategy.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/WechatMiniProgramLoginStrategy.java deleted file mode 100644 index d1d9356e..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/strategy/impl/WechatMiniProgramLoginStrategy.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.xyzh.auth.strategy.impl; - -import org.springframework.stereotype.Component; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.auth.strategy.LoginStrategy; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; - -/** - * @description 微信小程序登录策略 - * @filename WechatMiniProgramLoginStrategy.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Component -public class WechatMiniProgramLoginStrategy implements LoginStrategy { - - @Autowired - private SysUserService userService; - - @Override - public String getLoginType() { - return "wechat_miniprogram"; - } - - @Override - public boolean validate(LoginParam loginParam) { - // 小程序登录需要wechatId或phone - boolean hasWechatId = loginParam.getWechatId() != null && !loginParam.getWechatId().trim().isEmpty(); - boolean hasPhone = loginParam.getPhone() != null && !loginParam.getPhone().trim().isEmpty(); - return hasWechatId || hasPhone; - } - - @Override - public SysUserVO findUser(LoginParam loginParam) { - SysUserVO filter = new SysUserVO(); - - // 优先使用wechatId查询 - if (loginParam.getWechatId() != null && !loginParam.getWechatId().trim().isEmpty()) { - filter.setWechatId(loginParam.getWechatId()); - SysUserVO user = userService.getLoginUser(filter).getData(); - if (user != null) { - return user; - } - } - - // 如果wechatId未找到,尝试用phone查询 - if (loginParam.getPhone() != null && !loginParam.getPhone().trim().isEmpty()) { - filter = new SysUserVO(); - filter.setPhone(loginParam.getPhone()); - SysUserVO user = userService.getLoginUser(filter).getData(); - if (user != null) { - // 如果用户存在但没有wechatId,需要更新wechatId - if (user.getWechatId() == null && loginParam.getWechatId() != null) { - SysUserVO updateUser = new SysUserVO(); - updateUser.setUserId(user.getUserId()); - updateUser.setWechatId(loginParam.getWechatId()); - userService.updateUser(updateUser); - user.setWechatId(loginParam.getWechatId()); - } - return user; - } - } - - return null; - } - - @Override - public boolean verifyCredential(String inputCredential, String storedCredential) { - // 微信小程序通过微信授权,不需要密码验证 - return true; - } -} diff --git a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/utils/CapcatUtils.java b/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/utils/CapcatUtils.java deleted file mode 100644 index 75e5582f..00000000 --- a/urbanLifelineServ/auth/src/main/java/org/xyzh/auth/utils/CapcatUtils.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.xyzh.auth.utils; - -public class CapcatUtils { - /** - * 生成6位数字验证码 - * @return 验证码 - */ - public static String generateVerificationCode() { - return String.valueOf((int)((Math.random() * 9 + 1) * 100000)); - } -} diff --git a/urbanLifelineServ/auth/src/main/resources/application.yml b/urbanLifelineServ/auth/src/main/resources/application.yml deleted file mode 100644 index e6ad1909..00000000 --- a/urbanLifelineServ/auth/src/main/resources/application.yml +++ /dev/null @@ -1,35 +0,0 @@ -# ================== Auth 认证服务配置 ================== -server: - port: 8081 - -spring: - application: - name: auth-service - -# ================== Auth ================== -auth: - enabled: false # 认证服务自己不需要认证 - gateway-mode: false - whitelist: - - /** - -# ================== SpringDoc ================== -springdoc: - group-configs: - - group: 'default' - display-name: '认证服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-auth - qos-enable: false - scan: - base-packages: org.xyzh.auth.service.impl - -# ================== JWT ================== -jwt: - secret: ${JWT_SECRET:urban-lifeline-secret-key-2025-xyzh} - expiration: 86400 # 24小时(秒) - refresh-expiration: 604800 # 7天(秒) diff --git a/urbanLifelineServ/auth/src/main/resources/bootstrap.yml b/urbanLifelineServ/auth/src/main/resources/bootstrap.yml deleted file mode 100644 index 60998f2b..00000000 --- a/urbanLifelineServ/auth/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,64 +0,0 @@ -# ================================================ -# Urban Lifeline - 通用 Bootstrap 配置 -# 所有微服务共享的基础配置 -# ================================================ - -# ================== Spring Cloud Nacos ================== -spring: - cloud: - nacos: - discovery: - server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} - namespace: ${NACOS_NAMESPACE:dev} - group: ${NACOS_GROUP:DEFAULT_GROUP} - - # ================== DataSource ================== - datasource: - url: ${DB_URL:jdbc:postgresql://127.0.0.1:5432/urban_lifeline} - username: ${DB_USERNAME:postgres} - password: ${DB_PASSWORD:postgres} - driver-class-name: org.postgresql.Driver - - # ================== Redis ================== - data: - redis: - host: ${REDIS_HOST:127.0.0.1} - port: ${REDIS_PORT:6379} - database: ${REDIS_DATABASE:0} - password: ${REDIS_PASSWORD:123456} - -# ================== Security AES ================== -security: - aes: - # AES-256 密钥(Base64编码,必须与所有服务保持一致) - # 警告:这是开发环境密钥,生产环境请使用密钥管理系统 - secret-key: ${AES_SECRET_KEY:MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=} - -# ================== Dubbo ================== -dubbo: - protocol: - name: dubbo - port: -1 - registry: - address: nacos://${NACOS_SERVER_ADDR:127.0.0.1:8848} - -# ================== MyBatis-Plus ================== -mybatis-plus: - mapper-locations: classpath:mapper/**/*.xml - type-aliases-package: org.xyzh.common.dto, org.xyzh.api - -# ================== SpringDoc 基础配置 ================== -springdoc: - api-docs: - enabled: true - path: /v3/api-docs - swagger-ui: - enabled: true - path: /swagger-ui.html - -# ================== Logging ================== -logging: - config: classpath:log4j2.xml - charset: - console: UTF-8 - file: UTF-8 diff --git a/urbanLifelineServ/auth/src/main/resources/log4j2.xml b/urbanLifelineServ/auth/src/main/resources/log4j2.xml deleted file mode 100644 index f80ae392..00000000 --- a/urbanLifelineServ/auth/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/bidding/pom.xml b/urbanLifelineServ/bidding/pom.xml deleted file mode 100644 index 9af9d6a1..00000000 --- a/urbanLifelineServ/bidding/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - bidding - 1.0.0 - - - 21 - 21 - - - - bidding - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/bidding/src/main/java/org/xyzh/bidding/BiddingApp.java b/urbanLifelineServ/bidding/src/main/java/org/xyzh/bidding/BiddingApp.java deleted file mode 100644 index 3b8dc40a..00000000 --- a/urbanLifelineServ/bidding/src/main/java/org/xyzh/bidding/BiddingApp.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.xyzh.bidding; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@ComponentScan(basePackages = { - "org.xyzh.bidding", // 当前bidding模块 - "org.xyzh.common" // 公共模块 -}) -public class BiddingApp { - private static final Logger logger = LoggerFactory.getLogger(BiddingApp.class); - - public static void main(String[] args) { - logger.info("======================== BiddingApp 启动中 ========================="); - SpringApplication.run(BiddingApp.class, args); - logger.info("======================== BiddingApp 启动成功 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/bidding/src/main/resources/application.yml b/urbanLifelineServ/bidding/src/main/resources/application.yml deleted file mode 100644 index 27fa9285..00000000 --- a/urbanLifelineServ/bidding/src/main/resources/application.yml +++ /dev/null @@ -1,36 +0,0 @@ -# ================== Bidding 招投标服务配置 ================== -server: - port: 8087 - -spring: - application: - name: bidding-service - -# ================== Auth ================== -auth: - enabled: true - gateway-mode: true - whitelist: - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - /favicon.ico - - /error - - /actuator/health - - /actuator/info - -# ================== SpringDoc ================== -springdoc: - group-configs: - - group: 'default' - display-name: '招投标服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-bidding - qos-enable: false - scan: - base-packages: org.xyzh.bidding.service.impl diff --git a/urbanLifelineServ/bidding/src/main/resources/log4j2.xml b/urbanLifelineServ/bidding/src/main/resources/log4j2.xml deleted file mode 100644 index 15161ff1..00000000 --- a/urbanLifelineServ/bidding/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/common/common-all/pom.xml b/urbanLifelineServ/common/common-all/pom.xml deleted file mode 100644 index 77a04afa..00000000 --- a/urbanLifelineServ/common/common-all/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-all - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - org.xyzh.common - common-auth - - - org.xyzh.common - common-exception - - - org.xyzh.common - common-core - - - org.xyzh.common - common-dto - - - org.xyzh.common - common-redis - - - org.xyzh.common - common-utils - - - org.xyzh.common - common-jdbc - - - - \ No newline at end of file diff --git a/urbanLifelineServ/common/common-auth/pom.xml b/urbanLifelineServ/common/common-auth/pom.xml deleted file mode 100644 index 55a80525..00000000 --- a/urbanLifelineServ/common/common-auth/pom.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-auth - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - - org.xyzh.common - common-redis - - - org.xyzh.common - common-core - - - org.xyzh.common - common-utils - - - org.xyzh.common - common-dto - - - - io.jsonwebtoken - jjwt-api - - - io.jsonwebtoken - jjwt-impl - runtime - - - io.jsonwebtoken - jjwt-jackson - runtime - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - org.springframework.boot - spring-boot-starter-security - - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - org.springframework.boot - spring-boot-starter-log4j2 - - - - io.jsonwebtoken - jjwt-api - - - io.jsonwebtoken - jjwt-impl - runtime - - - io.jsonwebtoken - jjwt-jackson - runtime - - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - - org.springframework.boot - spring-boot-starter-data-jdbc - - - - org.springframework.boot - spring-boot-starter-logging - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/annotation/HttpLogin.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/annotation/HttpLogin.java deleted file mode 100644 index 66acdaa1..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/annotation/HttpLogin.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.xyzh.common.auth.annotation; - -import java.lang.annotation.*; - -/** - * @description HttpLogin.java文件描述 HTTP登录注解 - * @filename HttpLogin.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Target(ElementType.PARAMETER) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface HttpLogin { - - /** - * @description 是否必需,默认为true - * @return boolean - * @author yslg - * @since 2025-11-02 - */ - boolean required() default true; - - /** - * @description 当token无效时的错误消息 - * @return String - * @author yslg - * @since 2025-11-02 - */ - String message() default "用户未登录或登录已过期"; -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/annotation/resovler/HttpLoginArgumentResolver.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/annotation/resovler/HttpLoginArgumentResolver.java deleted file mode 100644 index 077140f5..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/annotation/resovler/HttpLoginArgumentResolver.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.xyzh.common.auth.annotation.resovler; - -import org.springframework.core.MethodParameter; -import org.springframework.http.HttpHeaders; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; -import org.xyzh.common.auth.annotation.HttpLogin; -import org.xyzh.common.auth.token.TokenParser; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.redis.service.RedisService; -import org.xyzh.common.utils.NonUtils; - -import jakarta.servlet.http.HttpServletRequest; - -/** - * @description HttpLoginArgumentResolver.java文件描述 HTTP登录参数解析器 - * @filename HttpLoginArgumentResolver.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Component -public class HttpLoginArgumentResolver implements HandlerMethodArgumentResolver { - - private final TokenParser tokenParser; - private final RedisService redisService; - - /** - * 使用构造器注入,依赖TokenParser接口而非具体实现 - * 这样避免了与auth模块的直接依赖,解决循环依赖问题 - */ - public HttpLoginArgumentResolver(TokenParser tokenParser, - RedisService redisService) { - this.tokenParser = tokenParser; - this.redisService = redisService; - } - - private static final String TOKEN_PREFIX = "Bearer "; - private static final String REDIS_LOGIN_PREFIX = "login:token:"; - - @Override - public boolean supportsParameter(MethodParameter parameter) { - return parameter.hasParameterAnnotation(HttpLogin.class) - && LoginDomain.class.isAssignableFrom(parameter.getParameterType()); - } - - @Override - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - - HttpLogin httpLogin = parameter.getParameterAnnotation(HttpLogin.class); - if (httpLogin == null) { - return null; - } - - // 从请求头中获取token - String token = extractTokenFromRequest(webRequest); - - if (NonUtils.isEmpty(token)) { - if (httpLogin.required()) { - throw new IllegalArgumentException(httpLogin.message()); - } - return null; - } - - try { - // 验证token格式和有效性 - if (!tokenParser.validateToken(token, tokenParser.getUserIdFromToken(token))) { - if (httpLogin.required()) { - throw new IllegalArgumentException(httpLogin.message()); - } - return null; - } - - // 从Redis中获取LoginDomain - String userId = tokenParser.getUserIdFromToken(token); - String redisKey = REDIS_LOGIN_PREFIX + userId; - LoginDomain loginDomain = redisService.get(redisKey, LoginDomain.class); - - if (loginDomain == null) { - if (httpLogin.required()) { - throw new IllegalArgumentException(httpLogin.message()); - } - return null; - } - - // 更新token信息 - loginDomain.setToken(token); - return loginDomain; - - } catch (Exception e) { - if (httpLogin.required()) { - throw new IllegalArgumentException(httpLogin.message()); - } - return null; - } - } - - /** - * @description 从请求中提取token - * @param webRequest 请求对象 - * @return String token - * @author yslg - * @since 2025-11-02 - */ - private String extractTokenFromRequest(NativeWebRequest webRequest) { - HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); - if (request == null) { - return null; - } - - // 优先从Authorization头获取 - String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION); - if (NonUtils.isNotEmpty(authHeader) && authHeader.startsWith(TOKEN_PREFIX)) { - return authHeader.substring(TOKEN_PREFIX.length()); - } - - // 从请求参数中获取token - String token = request.getParameter("token"); - if (NonUtils.isNotEmpty(token)) { - return token; - } - - // 从请求头中获取token - token = request.getHeader("token"); - if (NonUtils.isNotEmpty(token)) { - return token; - } - - return null; - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/AuthProperties.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/AuthProperties.java deleted file mode 100644 index e20b84c6..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/AuthProperties.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.xyzh.common.auth.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import java.util.ArrayList; -import java.util.List; - -/** - * 认证配置属性类 - * 用于配置认证相关的属性,包括白名单路径 - * - * @author yslg - */ -@Component -@ConfigurationProperties(prefix = "auth") -public class AuthProperties { - - /** - * 是否启用认证过滤器 - * 默认启用 - */ - private Boolean enabled = true; - - /** - * 登录接口路径 - * 支持不同服务自定义登录地址 - */ - private String loginPath = "/urban-lifeline/auth/login"; - - /** - * 登出接口路径 - */ - private String logoutPath = "/urban-lifeline/auth/logout"; - - /** - * 验证码获取接口路径 - */ - private String captchaPath = "/urban-lifeline/auth/captcha"; - - /** - * 刷新 Token 接口路径 - */ - private String refreshPath = "/urban-lifeline/auth/refresh"; - - /** - * 通用白名单路径列表(非认证接口) - * 例如:Swagger、静态资源、健康检查等 - */ - private List whitelist = new ArrayList<>(); - - /** - * Token 请求头名称 - * 默认: Authorization - */ - private String tokenHeader = "Authorization"; - - /** - * Token 前缀 - * 默认: Bearer - */ - private String tokenPrefix = "Bearer "; - - public AuthProperties() { - // 默认通用白名单:Swagger 及静态资源等 - whitelist.add("/swagger-ui/**"); - whitelist.add("/swagger-ui.html"); - whitelist.add("/v3/api-docs/**"); - whitelist.add("/webjars/**"); - whitelist.add("/favicon.ico"); - whitelist.add("/error"); - } - - public Boolean isEnabled() { - return enabled; - } - - public void setEnabled(Boolean enabled) { - this.enabled = enabled; - } - - public String getLoginPath() { - return loginPath; - } - - public void setLoginPath(String loginPath) { - this.loginPath = loginPath; - } - - public String getLogoutPath() { - return logoutPath; - } - - public void setLogoutPath(String logoutPath) { - this.logoutPath = logoutPath; - } - - public String getCaptchaPath() { - return captchaPath; - } - - public void setCaptchaPath(String captchaPath) { - this.captchaPath = captchaPath; - } - - public String getRefreshPath() { - return refreshPath; - } - - public void setRefreshPath(String refreshPath) { - this.refreshPath = refreshPath; - } - - public List getWhitelist() { - return whitelist; - } - - public void setWhitelist(List whitelist) { - this.whitelist = whitelist; - } - - /** - * 认证相关接口路径集合(login / logout / captcha / refresh) - * 供 SecurityConfig 和 JwtAuthenticationFilter 统一放行 - */ - public List getAuthPaths() { - List authPaths = new ArrayList<>(); - if (StringUtils.hasText(loginPath)) { - authPaths.add(loginPath); - } - if (StringUtils.hasText(logoutPath)) { - authPaths.add(logoutPath); - } - if (StringUtils.hasText(captchaPath)) { - authPaths.add(captchaPath); - } - if (StringUtils.hasText(refreshPath)) { - authPaths.add(refreshPath); - } - return authPaths; - } - - public String getTokenHeader() { - return tokenHeader; - } - - public void setTokenHeader(String tokenHeader) { - this.tokenHeader = tokenHeader; - } - - public String getTokenPrefix() { - return tokenPrefix; - } - - public void setTokenPrefix(String tokenPrefix) { - this.tokenPrefix = tokenPrefix; - } -} - diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/GatewayAuthConfig.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/GatewayAuthConfig.java deleted file mode 100644 index d685a2e1..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/GatewayAuthConfig.java +++ /dev/null @@ -1,150 +0,0 @@ -package org.xyzh.common.auth.config; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.lang.NonNull; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.util.StringUtils; -import org.springframework.web.filter.OncePerRequestFilter; -import org.xyzh.common.auth.contants.AuthContants; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.springframework.beans.factory.annotation.Autowired; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; -import org.xyzh.common.redis.service.RedisService; - -/** - * @description Gateway 认证模式配置 - 信任 Gateway 传递的用户信息 - * @author yslg - * @since 2025-12-02 - * - * 当启用 gateway-mode 时,微服务不再独立验证 JWT,而是信任 Gateway 传递的用户信息 - * 配置项:auth.gateway-mode=true - */ -@Configuration -@ConditionalOnProperty(name = "auth.gateway-mode", havingValue = "true") -public class GatewayAuthConfig { - private static final Logger logger = LoggerFactory.getLogger(GatewayAuthConfig.class); - - /** - * Gateway 信任过滤器 - 从请求头获取用户信息 - * 替代 JwtAuthenticationFilter - */ - @Bean - public GatewayTrustFilter gatewayTrustFilter() { - logger.info("启用 Gateway 认证模式,微服务将信任 Gateway 传递的用户信息"); - return new GatewayTrustFilter(); - } - - /** - * Gateway 信任过滤器实现 - */ - public static class GatewayTrustFilter extends OncePerRequestFilter { - private static final Logger logger = LoggerFactory.getLogger(GatewayTrustFilter.class); - private static final String LOGIN_TOKEN_PREFIX = "login:token:"; - private static final String BEARER_PREFIX = "Bearer "; - - @Autowired - private RedisService redisService; - - @Override - protected void doFilterInternal(@NonNull HttpServletRequest request, - @NonNull HttpServletResponse response, - @NonNull FilterChain filterChain) - throws ServletException, IOException { - - // 从 Gateway 传递的请求头获取用户信息 - String userId = request.getHeader(AuthContants.USER_ID_ATTRIBUTE); - String username = request.getHeader(AuthContants.USERNAME_ATTRIBUTE); - - if (StringUtils.hasText(userId)) { - // 从 Redis 获取用户权限 - List authorities = loadUserAuthorities(request); - - // 设置到 Spring Security 上下文 - UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken(userId, null, authorities); - SecurityContextHolder.getContext().setAuthentication(authentication); - - // 同时将用户信息设置到 request attributes 中,供业务代码使用 - request.setAttribute(AuthContants.USER_ID_ATTRIBUTE, userId); - if (StringUtils.hasText(username)) { - request.setAttribute(AuthContants.USERNAME_ATTRIBUTE, username); - } - - logger.info("从 Gateway 获取用户信息: userId={}, username={}, 权限数={}", userId, username, authorities.size()); - } - - filterChain.doFilter(request, response); - } - - /** - * 从 Redis 加载用户权限列表 - */ - private List loadUserAuthorities(HttpServletRequest request) { - List authorities = new ArrayList<>(); - - try { - String token = extractToken(request); - logger.debug("提取到Token: {}", token != null ? "***" : "null"); - - if (StringUtils.hasText(token)) { - String cacheKey = LOGIN_TOKEN_PREFIX + token; - LoginDomain login = redisService.get(cacheKey, LoginDomain.class); - logger.debug("Redis key: {}, login: {}", cacheKey, login != null ? "loaded" : "null"); - - if (login != null) { - if (login.getUserPermissions() != null) { - for (TbSysPermissionDTO permission : login.getUserPermissions()) { - // status 为 null 或 true 时都视为有效权限 - if (permission.getCode() != null && !Boolean.FALSE.equals(permission.getStatus())) { - authorities.add(new SimpleGrantedAuthority(permission.getCode())); - } - } - } - logger.debug("加载用户权限: {} 个", authorities.size()); - } - } - } catch (Exception e) { - logger.warn("加载用户权限失败: {}", e.getMessage(), e); - } - - return authorities; - } - - /** - * 从请求头或URL参数提取Token - */ - private String extractToken(HttpServletRequest request) { - // 1. 优先从请求头获取 - String authHeader = request.getHeader("Authorization"); - if (StringUtils.hasText(authHeader) && authHeader.startsWith(BEARER_PREFIX)) { - return authHeader.substring(BEARER_PREFIX.length()).trim(); - } - - // 2. 从URL参数获取(用于WebSocket连接) - String tokenParam = request.getParameter("token"); - if (StringUtils.hasText(tokenParam)) { - logger.debug("从URL参数获取Token"); - return tokenParam.trim(); - } - - return null; - } - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/SecurityConfig.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/SecurityConfig.java deleted file mode 100644 index 9d1628de..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/SecurityConfig.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.common.auth.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.xyzh.common.auth.filter.JwtAuthenticationFilter; -import org.xyzh.common.auth.token.TokenParser; -import org.xyzh.common.redis.service.RedisService; - -@Configuration -@EnableMethodSecurity -public class SecurityConfig { - - /** - * 密码编码器 - 用于用户密码加密(使用 BCrypt) - */ - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - /** - * JWT 认证过滤器 - 仅在非 Gateway 模式下启用 - * 当 auth.gateway-mode=false 或未配置时使用 - */ - @Bean - @ConditionalOnProperty(name = "auth.gateway-mode", havingValue = "false", matchIfMissing = true) - public JwtAuthenticationFilter jwtAuthenticationFilter(TokenParser tokenParser, - AuthProperties authProperties, - RedisService redisService) { - return new JwtAuthenticationFilter(tokenParser, authProperties, redisService); - } - - /** - * Security 过滤器链配置 - * 根据是否启用 Gateway 模式决定是否添加 JWT 过滤器 - */ - @Bean - public SecurityFilterChain securityFilterChain( - HttpSecurity http, - AuthProperties authProperties, - @Autowired(required = false) JwtAuthenticationFilter jwtAuthenticationFilter, - @Autowired(required = false) GatewayAuthConfig.GatewayTrustFilter gatewayTrustFilter) throws Exception { - - http - .csrf(csrf -> csrf.disable()) - .formLogin(form -> form.disable()) - .httpBasic(basic -> basic.disable()) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(authz -> { - // 认证接口放行(login / logout / captcha / refresh) - if (authProperties.getAuthPaths() != null) { - authProperties.getAuthPaths().forEach(path -> authz.requestMatchers(path).permitAll()); - } - - // 通用白名单放行(Swagger、静态资源等) - if (authProperties.getWhitelist() != null) { - authProperties.getWhitelist().forEach(path -> authz.requestMatchers(path).permitAll()); - } - - authz - .requestMatchers("/error", "/favicon.ico").permitAll() - .anyRequest().authenticated(); - }); - - // 根据模式添加对应的过滤器 - if (jwtAuthenticationFilter != null) { - // 非 Gateway 模式:使用 JWT 过滤器 - http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); - } else if (gatewayTrustFilter != null) { - // Gateway 模式:使用信任过滤器 - http.addFilterBefore(gatewayTrustFilter, UsernamePasswordAuthenticationFilter.class); - } - - return http.build(); - } -} - - diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/WebMvcConfig.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/WebMvcConfig.java deleted file mode 100644 index 0484f064..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/config/WebMvcConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.xyzh.common.auth.config; - -import java.util.List; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.xyzh.common.auth.annotation.resovler.HttpLoginArgumentResolver; - -/** - * @description WebMvcConfig.java文件描述 WebMVC配置类 - * @filename WebMvcConfig.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Configuration -public class WebMvcConfig implements WebMvcConfigurer { - - private final HandlerMethodArgumentResolver httpLoginArgumentResolver; - - /** - * 使用构造器注入 - * 通过接口抽象解决了循环依赖问题,不再需要@Lazy注解 - */ - public WebMvcConfig(HttpLoginArgumentResolver httpLoginArgumentResolver) { - this.httpLoginArgumentResolver = httpLoginArgumentResolver; - } - - @Override - public void addArgumentResolvers(List resolvers) { - resolvers.add(httpLoginArgumentResolver); - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/contants/AuthContants.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/contants/AuthContants.java deleted file mode 100644 index a8c96769..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/contants/AuthContants.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.xyzh.common.auth.contants; - -/** - * @description 认证相关常量类 - * @filename AuthContants.java - * @author yslg - * @copyright yslg - * @since 2025-11-09 - */ -public class AuthContants { - - /** - * 用户ID请求属性键 - */ - public static final String USER_ID_ATTRIBUTE = "userId"; - - /** - * 用户名请求属性键 - */ - public static final String USERNAME_ATTRIBUTE = "username"; - - /** - * Token请求属性键 - */ - public static final String TOKEN_ATTRIBUTE = "token"; - - /** - * JWT Claims 中的用户名键 - */ - public static final String CLAIMS_USERNAME_KEY = "username"; - - /** - * JWT Claims 中的用户ID键 - */ - public static final String CLAIMS_USER_ID_KEY = "userId"; - - /** - * 私有构造函数,防止实例化 - */ - private AuthContants() { - throw new UnsupportedOperationException("常量类不允许实例化"); - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/DubboConsumerContextFilter.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/DubboConsumerContextFilter.java deleted file mode 100644 index 6749be87..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/DubboConsumerContextFilter.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.xyzh.common.auth.filter; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.rpc.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; -import org.xyzh.common.auth.utils.LoginUtil; - -/** - * Dubbo消费者端Filter:自动传递登录Token到RpcContext - * - * @author yslg - * @since 2025-12-20 - */ -@Activate(group = CommonConstants.CONSUMER, order = -9000) -public class DubboConsumerContextFilter implements Filter { - - private static final Logger logger = LoggerFactory.getLogger(DubboConsumerContextFilter.class); - private static final String AUTH_TOKEN_KEY = "auth-token"; - - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - // 从当前HTTP请求获取Token - String token = LoginUtil.getToken(); - - if (StringUtils.hasText(token)) { - // 将Token放入RpcContext,传递给提供者 - RpcContext.getClientAttachment().setAttachment(AUTH_TOKEN_KEY, token); - logger.debug("Dubbo消费者传递Token: {}", token.substring(0, Math.min(20, token.length())) + "..."); - } - - return invoker.invoke(invocation); - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/DubboProviderContextFilter.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/DubboProviderContextFilter.java deleted file mode 100644 index 6f2bd865..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/DubboProviderContextFilter.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.xyzh.common.auth.filter; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.rpc.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -/** - * Dubbo提供者端Filter:从RpcContext接收Token并存储到ThreadLocal - * - * @author yslg - * @since 2025-12-20 - */ -@Activate(group = CommonConstants.PROVIDER, order = -9000) -public class DubboProviderContextFilter implements Filter { - - private static final Logger logger = LoggerFactory.getLogger(DubboProviderContextFilter.class); - private static final String AUTH_TOKEN_KEY = "auth-token"; - - public static final ThreadLocal TOKEN_HOLDER = new ThreadLocal<>(); - - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - try { - // 从RpcContext获取消费者传递的Token - String token = RpcContext.getServerAttachment().getAttachment(AUTH_TOKEN_KEY); - - if (StringUtils.hasText(token)) { - // 存储到ThreadLocal供LoginUtil使用 - TOKEN_HOLDER.set(token); - logger.debug("Dubbo提供者接收Token: {}", token.substring(0, Math.min(20, token.length())) + "..."); - } - - return invoker.invoke(invocation); - } finally { - // 清理ThreadLocal避免内存泄漏 - TOKEN_HOLDER.remove(); - } - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/JwtAuthenticationFilter.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/JwtAuthenticationFilter.java deleted file mode 100644 index 43afd1f6..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/filter/JwtAuthenticationFilter.java +++ /dev/null @@ -1,237 +0,0 @@ -package org.xyzh.common.auth.filter; - -import com.alibaba.fastjson2.JSON; -import io.jsonwebtoken.Claims; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.util.AntPathMatcher; -import org.springframework.lang.NonNull; -import org.springframework.util.StringUtils; -import org.springframework.web.filter.OncePerRequestFilter; -import org.xyzh.common.auth.config.AuthProperties; -import org.xyzh.common.auth.contants.AuthContants; -import org.xyzh.common.auth.token.TokenParser; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; -import org.xyzh.common.redis.service.RedisService; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; - -/** - * @description JWT认证过滤器,用于检测用户请求是否登录,支持白名单配置 - * @filename JwtAuthenticationFilter.java - * @author yslg - * @copyright yslg - * @since 2025-11-09 - */ -public class JwtAuthenticationFilter extends OncePerRequestFilter { - private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationFilter.class); - - private final TokenParser tokenParser; - private final AuthProperties authProperties; - private final AntPathMatcher pathMatcher = new AntPathMatcher(); - private final RedisService redisService; - private static final String REDIS_LOGIN_PREFIX = "login:token:"; - - public JwtAuthenticationFilter(TokenParser tokenParser, AuthProperties authProperties) { - this.tokenParser = tokenParser; - this.authProperties = authProperties; - this.redisService = null; // 占位,使用另一个构造函数注入 - } - - public JwtAuthenticationFilter(TokenParser tokenParser, AuthProperties authProperties, RedisService redisService) { - this.tokenParser = tokenParser; - this.authProperties = authProperties; - this.redisService = redisService; - } - - @Override - protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) - throws ServletException, IOException { - - // 如果认证过滤器未启用,直接放行 - if (!authProperties.isEnabled()) { - filterChain.doFilter(request, response); - return; - } - - String requestPath = request.getRequestURI(); - if (requestPath == null) { - requestPath = ""; - } - - // 去掉 context-path,仅保留业务路径用于白名单匹配 - String contextPath = request.getContextPath(); - if (contextPath != null && !contextPath.isEmpty() && requestPath.startsWith(contextPath)) { - requestPath = requestPath.substring(contextPath.length()); - } - - // 检查是否在白名单中 - if (isWhitelisted(requestPath)) { - log.debug("请求路径在白名单中,跳过认证: {}", requestPath); - filterChain.doFilter(request, response); - return; - } - - // 从请求头获取Token - String token = extractToken(request); - - if (!StringUtils.hasText(token)) { - log.warn("请求缺少Token: {}", requestPath); - handleUnauthorized(response, "未提供认证令牌,请先登录"); - return; - } - - try { - // 验证Token - if (tokenParser.isTokenExpired(token)) { - log.warn("Token已过期: {}", requestPath); - handleUnauthorized(response, "认证令牌已过期,请重新登录"); - return; - } - - // 获取用户ID - String userId = tokenParser.getUserIdFromToken(token); - if (!StringUtils.hasText(userId)) { - log.warn("Token中未找到用户ID: {}", requestPath); - handleUnauthorized(response, "认证令牌无效"); - return; - } - - // 验证Token有效性 - if (!tokenParser.validateToken(token, userId)) { - log.warn("Token验证失败: userId={}, path={}", userId, requestPath); - handleUnauthorized(response, "认证令牌验证失败"); - return; - } - - // 将用户信息放入请求属性中,供后续使用 - Claims claims = tokenParser.getAllClaimsFromToken(token); - request.setAttribute(AuthContants.USER_ID_ATTRIBUTE, userId); - request.setAttribute(AuthContants.USERNAME_ATTRIBUTE, claims.get(AuthContants.CLAIMS_USERNAME_KEY, String.class)); - request.setAttribute(AuthContants.TOKEN_ATTRIBUTE, token); - - // 从Redis加载 LoginDomain,并将权限装配到 Spring Security 上下文 - if (redisService != null) { - Object obj = redisService.get(REDIS_LOGIN_PREFIX + token); - if (obj instanceof LoginDomain loginDomain) { - // 组装权限码 authorities(已存在) - List permAuthorities = null; - if (loginDomain.getUserPermissions() != null) { - permAuthorities = loginDomain.getUserPermissions().stream() - .filter(Objects::nonNull) - .map(TbSysPermissionDTO::getCode) - .filter(StringUtils::hasText) - .map(SimpleGrantedAuthority::new) - .toList(); - } - - // 组装角色 authorities(关键:ROLE_ 前缀) - List roleAuthorities = null; - if (loginDomain.getUserRoles() != null) { - roleAuthorities = loginDomain.getUserRoles().stream() - .filter(Objects::nonNull) - .map(r -> r.getRoleId()) // 若有角色code/名称,可替换为对应字段 - .filter(StringUtils::hasText) - .map(role -> new SimpleGrantedAuthority("ROLE_" + role)) - .toList(); - } - - // 合并权限与角色 - List authorities = Stream - .concat( - permAuthorities != null ? permAuthorities.stream() : Stream.empty(), - roleAuthorities != null ? roleAuthorities.stream() : Stream.empty() - ) - .toList(); - UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken(loginDomain, null, authorities); - SecurityContextHolder.getContext().setAuthentication(authentication); - } - } - - log.debug("Token验证成功: userId={}, path={}", userId, requestPath); - - // 继续执行过滤器链 - filterChain.doFilter(request, response); - - } catch (Exception e) { - log.error("Token解析或验证异常: path={}, error={}", requestPath, e.getMessage(), e); - handleUnauthorized(response, "认证令牌解析失败: " + e.getMessage()); - } - } - - /** - * 检查路径是否在白名单中 - */ - private Boolean isWhitelisted(@NonNull String path) { - // 1. 先检查认证相关接口(login / logout / captcha / refresh) - if (authProperties.getAuthPaths() != null) { - for (String pattern : authProperties.getAuthPaths()) { - if (pattern != null && pathMatcher.match(pattern, path)) { - return true; - } - } - } - - // 2. 再检查通用白名单 - if (authProperties.getWhitelist() != null) { - for (String pattern : authProperties.getWhitelist()) { - if (pattern != null && pathMatcher.match(pattern, path)) { - return true; - } - } - } - - return false; - } - - /** - * 从请求头中提取Token - */ - private String extractToken(HttpServletRequest request) { - String header = request.getHeader(authProperties.getTokenHeader()); - - if (!StringUtils.hasText(header)) { - return null; - } - - // 支持 Bearer 前缀 - String prefix = authProperties.getTokenPrefix(); - if (StringUtils.hasText(prefix) && header.startsWith(prefix)) { - return header.substring(prefix.length()).trim(); - } - - // 也支持直接传递Token(不带前缀) - return header.trim(); - } - - /** - * 处理未授权响应 - */ - private void handleUnauthorized(HttpServletResponse response, String message) throws IOException { - response.setStatus(HttpStatus.UNAUTHORIZED.value()); - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - response.setCharacterEncoding(StandardCharsets.UTF_8.name()); - - ResultDomain result = ResultDomain.failure(HttpStatus.UNAUTHORIZED.value(), message); - String json = JSON.toJSONString(result); - - response.getWriter().write(json); - response.getWriter().flush(); - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/token/JwtTokenParser.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/token/JwtTokenParser.java deleted file mode 100644 index ac89ffaa..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/token/JwtTokenParser.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.xyzh.common.auth.token; - -import io.jsonwebtoken.Claims; -import org.springframework.stereotype.Component; -import org.xyzh.common.auth.utils.JwtTokenUtil; - -/** - * @description JwtTokenParser.java文件描述 JWT令牌解析器实现类 - * @filename JwtTokenParser.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Component -public class JwtTokenParser implements TokenParser { - - private final JwtTokenUtil jwtTokenUtil; - - /** - * Spring会自动注入,无需@Autowired注解 - */ - public JwtTokenParser(JwtTokenUtil jwtTokenUtil) { - this.jwtTokenUtil = jwtTokenUtil; - } - - @Override - public String getUserIdFromToken(String token) { - return jwtTokenUtil.getUserIdFromToken(token); - } - - @Override - public Claims getAllClaimsFromToken(String token) { - return jwtTokenUtil.getAllClaimsFromToken(token); - } - - @Override - public Boolean validateToken(String token, String userId) { - return jwtTokenUtil.validateToken(token, userId); - } - - @Override - public Boolean isTokenExpired(String token) { - return jwtTokenUtil.isTokenExpired(token); - } -} - diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/token/TokenParser.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/token/TokenParser.java deleted file mode 100644 index c7384527..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/token/TokenParser.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.xyzh.common.auth.token; - -import io.jsonwebtoken.Claims; - -/** - * @description TokenParser.java文件描述 令牌解析器接口 - * @filename TokenParser.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public interface TokenParser { - - /** - * @description 从令牌中获取用户ID - * @param token 令牌 - * @return String 用户ID - * @author yslg - * @since 2025-11-02 - */ - String getUserIdFromToken(String token); - - /** - * @description 从令牌中获取所有声明信息 - * @param token 令牌 - * @return Claims 所有声明信息 - * @author yslg - * @since 2025-11-02 - */ - Claims getAllClaimsFromToken(String token); - - /** - * @description 验证令牌 - * @param token 令牌 - * @param userId 用户ID - * @return Boolean 是否有效 - * @author yslg - * @since 2025-11-02 - */ - Boolean validateToken(String token, String userId); - - /** - * @description 检查令牌是否过期 - * @param token 令牌 - * @return Boolean 是否过期 - * @author yslg - * @since 2025-11-02 - */ - Boolean isTokenExpired(String token); -} - diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/utils/JwtTokenUtil.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/utils/JwtTokenUtil.java deleted file mode 100644 index ac7e5b35..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/utils/JwtTokenUtil.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.xyzh.common.auth.utils; - -import io.jsonwebtoken.*; -import io.jsonwebtoken.security.Keys; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; -import org.xyzh.common.utils.id.IdUtil; - -import javax.crypto.SecretKey; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -/** - * @description JwtTokenUtil.java文件描述 JWT工具类 - * @filename JwtTokenUtil.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Component -public class JwtTokenUtil { - - @Value("${auth.jwt-secret:urbanLifelineDefaultSecretKeyForJWT2025}") - private String secret; - - @Value("${auth.jwt-expiration:86400}") - private Long expiration; - - private SecretKey getSigningKey() { - return Keys.hmacShaKeyFor(secret.getBytes()); - } - - /** - * @description 生成JWT令牌 - * @param loginDomain 登录域对象 - * @return String JWT令牌 - * @author yslg - * @since 2025-11-07 - */ - public String generateToken(LoginDomain loginDomain) { - Map claims = new HashMap<>(); - TbSysUserDTO user = loginDomain.getUser(); - TbSysUserInfoDTO userInfoDTO = loginDomain.getUserInfo(); - - claims.put("userId", user.getUserId()); - claims.put("username", userInfoDTO.getUsername()); - claims.put("email", user.getEmail()); - claims.put("loginType", loginDomain.getLoginType()); - claims.put("ipAddress", loginDomain.getIpAddress()); - - return Jwts.builder() - .setClaims(claims) - .setSubject(user.getUserId()) - .setId(IdUtil.generateID()) // 使用IdUtil生成JWT ID - .setIssuedAt(new Date()) - .setExpiration(generateExpirationDate()) - .signWith(getSigningKey()) - .compact(); - } - - /** - * @description 从令牌中获取用户ID - * @param token JWT令牌 - * @return String 用户ID - * @author yslg - * @since 2025-11-07 - */ - public String getUserIdFromToken(String token) { - return getClaimFromToken(token, Claims::getSubject); - } - - /** - * @description 从令牌中获取过期时间 - * @param token JWT令牌 - * @return Date 过期时间 - * @author yslg - * @since 2025-11-07 - */ - public Date getExpirationDateFromToken(String token) { - return getClaimFromToken(token, Claims::getExpiration); - } - - /** - * @description 从令牌中获取指定信息 - * @param token JWT令牌 - * @param claimsResolver 信息解析器 - * @return T 指定信息 - * @author yslg - * @since 2025-11-07 - */ - public T getClaimFromToken(String token, java.util.function.Function claimsResolver) { - final Claims claims = getAllClaimsFromToken(token); - return claimsResolver.apply(claims); - } - - /** - * @description 从令牌中获取所有信息 - * @param token JWT令牌 - * @return Claims 所有信息 - * @author yslg - * @since 2025-11-07 - */ - public Claims getAllClaimsFromToken(String token) { - return Jwts.parserBuilder() - .setSigningKey(getSigningKey()) - .build() - .parseClaimsJws(token) - .getBody(); - } - - /** - * @description 验证令牌 - * @param token JWT令牌 - * @param userId 用户ID - * @return Boolean 是否有效 - * @author yslg - * @since 2025-11-07 - */ - public Boolean validateToken(String token, String userId) { - try { - final String tokenUserId = getUserIdFromToken(token); - return (userId.equals(tokenUserId) && !isTokenExpired(token)); - } catch (Exception e) { - return false; - } - } - - /** - * @description 检查令牌是否过期 - * @param token JWT令牌 - * @return Boolean 是否过期 - * @author yslg - * @since 2025-11-07 - */ - public Boolean isTokenExpired(String token) { - final Date expiration = getExpirationDateFromToken(token); - return expiration.before(new Date()); - } - - /** - * @description 生成过期时间 - * @return Date 过期时间 - * @author yslg - * @since 2025-11-07 - */ - private Date generateExpirationDate() { - return new Date(System.currentTimeMillis() + expiration * 1000); - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/utils/LoginUtil.java b/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/utils/LoginUtil.java deleted file mode 100644 index e42425df..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/java/org/xyzh/common/auth/utils/LoginUtil.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.xyzh.common.auth.utils; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.redis.service.RedisService; - -import jakarta.annotation.PostConstruct; -import jakarta.servlet.http.HttpServletRequest; - -/** - * @description 登录用户工具类,从Redis获取当前登录用户信息 - * @filename LoginUtil.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -@Component -public class LoginUtil { - - private static final String AUTHORIZATION_HEADER = "Authorization"; - private static final String BEARER_PREFIX = "Bearer "; - private static final String LOGIN_TOKEN_PREFIX = "login:token:"; - - @Autowired - private RedisService redisService; - - private static LoginUtil instance; - - @PostConstruct - public void init() { - instance = this; - } - - /** - * 获取当前登录用户信息 - */ - public static LoginDomain getCurrentLogin() { - String token = getToken(); - if (!StringUtils.hasText(token)) { - return null; - } - - try { - String cacheKey = LOGIN_TOKEN_PREFIX + token; - return instance.redisService.get(cacheKey, LoginDomain.class); - } catch (Exception e) { - // 忽略异常 - } - - return null; - } - - /** - * 获取当前用户ID - */ - public static String getCurrentUserId() { - LoginDomain login = getCurrentLogin(); - if (login != null && login.getUser() != null) { - return login.getUser().getUserId(); - } - return null; - } - - /** - * 获取当前用户名 - */ - public static String getCurrentUserName() { - LoginDomain login = getCurrentLogin(); - if (login != null && login.getUserInfo() != null) { - return login.getUserInfo().getUsername(); - } - return null; - } - - /** - * 判断用户是否已登录 - */ - public static boolean isLoggedIn() { - return getCurrentLogin() != null; - } - - /** - * 从请求头或Dubbo RpcContext获取Token - */ - public static String getToken() { - // 1. 优先从HTTP请求头获取(正常Web请求) - HttpServletRequest request = getRequest(); - if (request != null) { - String authHeader = request.getHeader(AUTHORIZATION_HEADER); - if (StringUtils.hasText(authHeader) && authHeader.startsWith(BEARER_PREFIX)) { - return authHeader.substring(BEARER_PREFIX.length()); - } - } - - // 2. 从Dubbo Provider ThreadLocal获取(跨服务调用) - try { - Class filterClass = Class.forName("org.xyzh.common.auth.filter.DubboProviderContextFilter"); - ThreadLocal tokenHolder = (ThreadLocal) filterClass.getField("TOKEN_HOLDER").get(null); - String token = tokenHolder.get(); - if (StringUtils.hasText(token)) { - return token; - } - } catch (Exception e) { - // Dubbo Filter不存在或未加载,忽略 - } - - return null; - } - - /** - * 获取当前请求 - */ - private static HttpServletRequest getRequest() { - ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - if (attributes != null) { - return attributes.getRequest(); - } - return null; - } -} diff --git a/urbanLifelineServ/common/common-auth/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter b/urbanLifelineServ/common/common-auth/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter deleted file mode 100644 index 08ca23f0..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter +++ /dev/null @@ -1,2 +0,0 @@ -dubboConsumerContextFilter=org.xyzh.common.auth.filter.DubboConsumerContextFilter -dubboProviderContextFilter=org.xyzh.common.auth.filter.DubboProviderContextFilter diff --git a/urbanLifelineServ/common/common-auth/src/main/resources/application-auth.yml.example b/urbanLifelineServ/common/common-auth/src/main/resources/application-auth.yml.example deleted file mode 100644 index 7510c63d..00000000 --- a/urbanLifelineServ/common/common-auth/src/main/resources/application-auth.yml.example +++ /dev/null @@ -1,33 +0,0 @@ -# 认证配置示例文件 -# 将此配置添加到各服务的 application.yml 中 - -urban-lifeline: - auth: - enabled: true - - # 认证接口:可以按服务自定义 - login-path: /urban-lifeline/auth/login - logout-path: /urban-lifeline/auth/logout - captcha-path: /urban-lifeline/auth/captcha - refresh-path: /urban-lifeline/auth/refresh - - # 通用白名单(非认证接口) - whitelist: - # Swagger/OpenAPI 文档相关(建议不带 context-path) - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - # 静态资源 - - /favicon.ico - - /error - - # 健康检查 - - /actuator/health - - /actuator/info - - # 其他需要放行的路径 - # - /public/** - # - /api/public/** - diff --git a/urbanLifelineServ/common/common-core/pom.xml b/urbanLifelineServ/common/common-core/pom.xml deleted file mode 100644 index 5dadccad..00000000 --- a/urbanLifelineServ/common/common-core/pom.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-core - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - org.xyzh.common - common-dto - ${urban-lifeline.version} - - - \ No newline at end of file diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/constant/Constants.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/constant/Constants.java deleted file mode 100644 index 52ecabdb..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/constant/Constants.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.common.core.constant; - - -/** - * @description Constants.java文件描述 常量类 - * @filename Constants.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class Constants { - - /** - * @description 令牌前缀 - * @filename Constants.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ - public static final String TOKEN_PREFIX = "Bearer "; - - /** - * @description JSON_WHITELIST_STR JSON白名单 - * @author yslg - * @since 2025-11-02 - */ - public static final String JSON_WHITELIST_STR = "org.xyzh"; -} diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/LoginDomain.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/LoginDomain.java deleted file mode 100644 index bb91793f..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/LoginDomain.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.xyzh.common.core.domain; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.dto.sys.TbSysUserRoleDTO; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; -import org.xyzh.common.dto.sys.TbSysDeptDTO; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; -import org.xyzh.common.dto.sys.TbSysViewDTO; - -import lombok.Data; - -/** - * @description 登录域 - * @filename 登录域 - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Data -public class LoginDomain implements Serializable{ - private static final long serialVersionUID = 1L; - - private TbSysUserDTO user; - - private TbSysUserInfoDTO userInfo; - - private List userRoles; - - private List userDepts; - - private List userPermissions; - - private List userViews; - - private String token; - - private Date tokenExpireTime; - - private String loginTime; - - private String ipAddress; - - private String loginType; -} diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/LoginParam.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/LoginParam.java deleted file mode 100644 index f1c74630..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/LoginParam.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.xyzh.common.core.domain; - -import java.io.Serializable; -import java.util.Date; - -import lombok.Data; - -/** - * @description 登录参数 - * @filename 登录参数 - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Data -public class LoginParam implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * 用户名 - * @author yslg - * @since 2025-11-02 - */ - private String username; - /** - * 密码 - * @author yslg - * @since 2025-11-02 - */ - private String password; - /** - * 邮箱 - * @author yslg - * @since 2025-11-02 - */ - private String email; - /** - * 手机号 - * @author yslg - * @since 2025-11-02 - */ - private String phone; - /** - * 微信ID - * @author yslg - * @since 2025-11-02 - */ - private String wechatId; - - /** - * 验证码类型 - * @author yslg - * @since 2025-11-02 - */ - private String captchaType; - - /** - * 验证码 - * @author yslg - * @since 2025-11-02 - */ - private String captcha; - /** - * 验证码ID - * @author yslg - * @since 2025-11-02 - */ - private String captchaId; - /** - * 登录类型 - * @author yslg - * @since 2025-11-02 - */ - private String loginType; - /** - * 是否记住我 - * @author yslg - * @since 2025-11-02 - */ - private Boolean rememberMe; - - /** - * 客户端IP地址(用于Dubbo远程调用时传递,避免传递HttpServletRequest) - * @author yslg - * @since 2025-12-23 - */ - private String clientIp; - - /** - * 当前Token(用于Dubbo远程调用刷新/登出时传递) - * @author yslg - * @since 2025-12-23 - */ - private String token; - - // ========== 微信小程序登录相关字段 ========== - - /** - * 微信登录code(wx.login返回,用于换取openid和session_key) - * @since 2026-01-09 - */ - private String code; - - /** - * 手机号授权code(getPhoneNumber返回,新版API推荐使用) - * @since 2026-01-09 - */ - private String phoneCode; - - /** - * 加密数据(getPhoneNumber返回,旧版API用于解密手机号) - * @since 2026-01-09 - */ - private String encryptedData; - - /** - * 解密向量(getPhoneNumber返回,旧版API用于解密手机号) - * @since 2026-01-09 - */ - private String iv; - - private Boolean mockMode; - -} diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/ResultDomain.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/ResultDomain.java deleted file mode 100644 index d599003a..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/domain/ResultDomain.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.xyzh.common.core.domain; - -import java.io.Serializable; -import java.util.List; - -import org.springframework.http.HttpStatus; -import org.xyzh.common.core.page.PageDomain; - -import lombok.Data; - -/** - * @description 结果域 通用返回结果 - * @filename 结果域 - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Data -public class ResultDomain implements Serializable { - private static final long serialVersionUID = 1L; - - private Integer code; - private Boolean success; - private String message; - private T data; - private List dataList; - private PageDomain pageDomain; - - public ResultDomain(){ - } - - public ResultDomain(int code, String message) { - this.code = code; - this.message = message; - this.success = false; - } - - public ResultDomain(int code, String message, T data) { - this.code = code; - this.message = message; - this.success = false; - this.data = data; - } - - public ResultDomain(int code, String message, List dataList) { - this.code = code; - this.message = message; - this.success = false; - this.dataList = dataList; - } - - public ResultDomain(int code, String message, PageDomain pageDomain) { - this.code = code; - this.message = message; - this.success = false; - this.pageDomain = pageDomain; - if(pageDomain != null) this.dataList = pageDomain.getDataList(); - } - - public void setPageDomain(PageDomain pageDomain){ - this.pageDomain = pageDomain; - if(pageDomain != null) this.dataList = pageDomain.getDataList(); - } - - // 静态工厂方法 - 推荐使用(简洁、清晰) - public static ResultDomain success(String message) { - ResultDomain result = new ResultDomain<>(); - result.success = true; - result.message = message; - result.code = HttpStatus.OK.value(); - return result; - } - - public static ResultDomain success(String message, R data) { - ResultDomain result = new ResultDomain<>(); - result.success = true; - result.message = message; - result.data = data; - result.code = HttpStatus.OK.value(); - return result; - } - - public static ResultDomain success(String message, List dataList) { - ResultDomain result = new ResultDomain<>(); - result.success = true; - result.message = message; - result.dataList = dataList; - result.code = HttpStatus.OK.value(); - return result; - } - - public static ResultDomain success(String message, PageDomain pageDomain) { - ResultDomain result = new ResultDomain<>(); - result.success = true; - result.message = message; - result.pageDomain = pageDomain; - if(pageDomain != null) result.dataList = pageDomain.getDataList(); - result.code = HttpStatus.OK.value(); - return result; - } - - public static ResultDomain failure(String message) { - ResultDomain result = new ResultDomain<>(); - result.success = false; - result.message = message; - result.code = HttpStatus.INTERNAL_SERVER_ERROR.value(); - return result; - } - - public static ResultDomain failure(int code, String message) { - ResultDomain result = new ResultDomain<>(); - result.success = false; - result.message = message; - result.code = code; - return result; - } -} diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/enums/CaptchaType.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/enums/CaptchaType.java deleted file mode 100644 index cb5bcb0e..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/enums/CaptchaType.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.xyzh.common.core.enums; - -/** - * @description 验证码类型 - * @filename CaptchaType.java - * @author yslg - * @copyright yslg - * @since 2025-11-03 - */ -public enum CaptchaType { - - EMAIL(1, "EMAIL", "邮箱验证码"), - SMS(2, "SMS", "短信验证码"), - IMAGE(3, "IMAGE", "图形验证码"); - - /** - * 验证码类型编码 - */ - private int code; - - /** - * 验证码类型名称 - */ - private String name; - - /** - * 验证码类型描述 - */ - private String description; - - private CaptchaType(int code, String name, String description) { - this.code = code; - this.name = name; - this.description = description; - } - - public int getCode() { - return code; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - /** - * @description 根据名称获取验证码类型 - * @param name 验证码类型名称 - * @return 验证码类型 - * @author yslg - * @since 2025-11-03 - */ - public static CaptchaType fromName(String name) { - for (CaptchaType type : CaptchaType.values()) { - if (type.getName().equalsIgnoreCase(name)) { - return type; - } - } - return null; - } - -} diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/exception/BaseException.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/exception/BaseException.java deleted file mode 100644 index e0a27bf5..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/exception/BaseException.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.xyzh.common.core.exception; - -public class BaseException extends RuntimeException{ - private Integer code; - - private String description; - - public BaseException(Integer code, String description, String message) { - super(message); - this.code = code; - this.description = description; - } - - public Integer getCode(){ - return this.code; - } - - public String getDescription(){ - return this.description; - } - - public String getMessage(){ - return super.getMessage(); - } - - -} diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageDomain.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageDomain.java deleted file mode 100644 index 1c9b5aa2..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageDomain.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.xyzh.common.core.page; - -import java.io.Serializable; -import java.util.List; - -import lombok.Data; - -@Data -public class PageDomain implements Serializable { - private static final long serialVersionUID = 1L; - - /** - * 分页参数 - * @author yslg - * @since 2025-11-02 - */ - private PageParam pageParam; - - /** - * 数据列表 - * @author yslg - * @since 2025-11-02 - */ - private List dataList; - - public PageDomain() { - } - - public PageDomain(PageParam pageParam, List dataList) { - if (pageParam == null) { - throw new IllegalArgumentException("分页参数不能为空"); - } - - this.pageParam = pageParam; - this.dataList = dataList; - } -} diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageParam.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageParam.java deleted file mode 100644 index a41bb258..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageParam.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.xyzh.common.core.page; - -import java.io.Serializable; - -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * @description 分页参数 - * @filename 分页参数 - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Data -@NoArgsConstructor -public class PageParam implements Serializable { - private static final long serialVersionUID = 1L; - - /** - * 页码 - * @author yslg - * @since 2025-11-02 - */ - private int page; - /** - * 每页条数 - * @author yslg - * @since 2025-11-02 - */ - private int pageSize; - - private int total; - /** - * 总页数 - * @author yslg - * @since 2025-11-02 - */ - private int totalPages; - - private int offset; - - public PageParam(int page, int pageSize) { - if (page <= 0) { - throw new IllegalArgumentException("页码必须大于0"); - } - if (pageSize <= 0) { - throw new IllegalArgumentException("每页条数必须大于0"); - } - this.page = page; - this.pageSize = pageSize; - this.offset = (page - 1) * pageSize; - } - - public void setPage(int page){ - if (page <= 0) { - throw new IllegalArgumentException("页码必须大于0"); - } - this.page = page; - if (this.pageSize <= 0) { - this.pageSize = 10; - } - this.offset = (page - 1) * this.pageSize; - } - - public void setPageSize(int pageSize){ - if (pageSize <= 0) { - throw new IllegalArgumentException("每页条数必须大于0"); - } - this.pageSize = pageSize; - if (this.page <= 0) { - this.page = 1; - } - this.offset = (this.page - 1) * this.pageSize; - } - - public void setTotal(int total){ - this.total = total; - if (this.pageSize > 0) { - this.totalPages = (int) Math.ceil((double) total / pageSize); - } - } -} diff --git a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageRequest.java b/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageRequest.java deleted file mode 100644 index b4fe4b8f..00000000 --- a/urbanLifelineServ/common/common-core/src/main/java/org/xyzh/common/core/page/PageRequest.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.xyzh.common.core.page; - -import java.io.Serializable; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class PageRequest implements Serializable { - private static final long serialVersionUID = 1L; - - private PageParam pageParam; - private T filter; -} diff --git a/urbanLifelineServ/common/common-core/src/main/resources/bootstrap.yml b/urbanLifelineServ/common/common-core/src/main/resources/bootstrap.yml deleted file mode 100644 index bc9b9303..00000000 --- a/urbanLifelineServ/common/common-core/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,64 +0,0 @@ -# ================================================ -# Urban Lifeline - 通用 Bootstrap 配置 -# 所有微服务共享的基础配置 -# ================================================ - -# ================== Spring Cloud Nacos ================== -spring: - cloud: - nacos: - discovery: - server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} - namespace: ${NACOS_NAMESPACE:dev} - group: ${NACOS_GROUP:DEFAULT_GROUP} - - # ================== DataSource ================== - datasource: - url: ${DB_URL:jdbc:postgresql://127.0.0.1:5432/urban_lifeline} - username: ${DB_USERNAME:postgres} - password: ${DB_PASSWORD:postgres} - driver-class-name: org.postgresql.Driver - - # ================== Redis ================== - data: - redis: - host: ${REDIS_HOST:127.0.0.1} - port: ${REDIS_PORT:6379} - database: ${REDIS_DATABASE:0} - password: ${REDIS_PASSWORD:} - -# ================== Security AES ================== -security: - aes: - # AES-256 密钥(Base64编码,必须与所有服务保持一致) - # 警告:这是开发环境密钥,生产环境请使用密钥管理系统 - secret-key: ${AES_SECRET_KEY:MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=} - -# ================== Dubbo ================== -dubbo: - protocol: - name: dubbo - port: -1 - registry: - address: nacos://${NACOS_SERVER_ADDR:127.0.0.1:8848} - -# ================== MyBatis-Plus ================== -mybatis-plus: - mapper-locations: classpath:mapper/**/*.xml - type-aliases-package: org.xyzh.common.dto, org.xyzh.api - -# ================== SpringDoc 基础配置 ================== -springdoc: - api-docs: - enabled: true - path: /v3/api-docs - swagger-ui: - enabled: true - path: /swagger-ui.html - -# ================== Logging ================== -logging: - config: classpath:log4j2.xml - charset: - console: UTF-8 - file: UTF-8 diff --git a/urbanLifelineServ/common/common-dto/pom.xml b/urbanLifelineServ/common/common-dto/pom.xml deleted file mode 100644 index db5b34a0..00000000 --- a/urbanLifelineServ/common/common-dto/pom.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-dto - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - - com.alibaba.fastjson2 - fastjson2 - - - org.projectlombok - lombok - provided - - - org.xyzh.common - common-utils - ${urban-lifeline.version} - - - - - io.swagger.core.v3 - swagger-annotations-jakarta - 2.2.36 - provided - - - - \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/BaseDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/BaseDTO.java deleted file mode 100644 index 1cc25646..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/BaseDTO.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.xyzh.common.dto; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -import com.alibaba.fastjson2.annotation.JSONField; -import io.swagger.v3.oas.annotations.media.Schema; - -import lombok.Data; - -@Data -@Schema(description = "基础数据传输对象") -public class BaseDTO implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "操作流水号") - private String optsn; - - @Schema(description = "创建人") - private String creator; - - @Schema(description = "更新人") - private String updater; - - @Schema(description = "部门路径") - private String deptPath; - - @Schema(description = "备注") - private String remark; - - @Schema(description = "创建时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date createTime; - - @Schema(description = "更新时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; - - @Schema(description = "删除时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date deleteTime; - - @Schema(description = "是否已删除", defaultValue = "false") - private Boolean deleted = false; - - - // =============== 下方为筛选字段,非数据库字段 ================ - - @Schema(description = "数量限制") - private Integer limit; - - @Schema(description = "统计数量") - private Integer count; - - @Schema(description = "开始时间") - private Date startTime; - - @Schema(description = "结束时间") - private Date endTime; - - @Schema(description = "排序字段") - private List orderFields; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/OrderField.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/OrderField.java deleted file mode 100644 index a9fc928a..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/OrderField.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.xyzh.common.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "排序方式对象") -public class OrderField { - public static final String ASC = "ASC"; - public static final String DESC = "DESC"; - - @Schema(description = "排序字段") - private String field; - - @Schema(description = "排序方式") - private String order; - - public OrderField(String field, String order) { - this.field = field; - this.order = order; - } -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbGuestDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbGuestDTO.java deleted file mode 100644 index 75fd0201..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbGuestDTO.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.xyzh.common.dto.sys; - -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -@Schema(description = "来客信息") -public class TbGuestDTO extends BaseDTO{ - private static final long serialVersionUID = 1L; - - @Schema(description = "来客ID") - private String userId; - - @Schema(description = "姓名") - private String name; - - @Schema(description = "电话") - private String phone; - - @Schema(description = "邮箱") - private String email; - - @Schema(description = "微信ID") - private String wechatId; -} diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysAclDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysAclDTO.java deleted file mode 100644 index f1694bb1..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysAclDTO.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.xyzh.common.dto.sys; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -/** - * @description 系统访问控制列表DTO - * @filename TbSysAclDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统访问控制列表DTO") -public class TbSysAclDTO extends BaseDTO { - @Schema(description = "权限ID") - private String aclId; - - @Schema(description = "对象类型:article/file/course/...") - private String objectType; - - @Schema(description = "对象ID") - private String objectId; - - @Schema(description = "主体类型:user/dept/role") - private String principalType; - - @Schema(description = "主体ID") - private String principalId; - - @Schema(description = "当主体为role且限定到某部门时的部门ID(支持“某部门的某角色”)") - private String principalDeptId; - - @Schema(description = "权限位:1读 2写 4执行") - private Integer permission; - - @Schema(description = "允许或显式拒绝", defaultValue = "true") - private Boolean allow = true; - - @Schema(description = "是否包含子级(对dept/role生效)", defaultValue = "false") - private Boolean includeDescendants = false; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysAclPolicyDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysAclPolicyDTO.java deleted file mode 100644 index 23a97209..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysAclPolicyDTO.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.xyzh.common.dto.sys; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -/** - * @description ACL 策略表:定义对象类型的层级可见/可编辑规则 - * @filename 系统权限策略DTO - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统访问控制策略DTO") -public class TbSysAclPolicyDTO extends BaseDTO { - - @Schema(description = "策略ID") - private String policyId; - - @Schema(description = "策略名称") - private String name; - - @Schema(description = "对象类型:article/file/course/..") - private String objectType; - - @Schema(description = "编辑层级规则:parent_only/parent_or_same_admin/owner_only/none") - private String editHierarchyRule; - - @Schema(description = "可见层级规则 children_all/children_specified/none") - private String viewHierarchyRule; - - @Schema(description = "默认权限(无显式ACL时应用)", defaultValue = "0") - private Integer defaultPermission=0; - - @Schema(description = "默认是否允许", defaultValue = "true") - private Boolean defaultAllow=true; - - @Schema(description = "是否默认应用到子级", defaultValue = "true") - private Boolean applyToChildren=true; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysConfigDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysConfigDTO.java deleted file mode 100644 index 3aa16246..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysConfigDTO.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.xyzh.common.dto.sys; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import com.alibaba.fastjson2.JSONObject; - -/** - * @description 系统配置DTO - * @filename TbSysConfigDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统配置DTO") -public class TbSysConfigDTO extends BaseDTO { - // optsn、creator、updater、deptPath、remark、createTime、updateTime、deleteTime、deleted 继承自BaseDTO - - @Schema(description = "配置ID") - private String configId; - - @Schema(description = "配置键") - private String key; - - @Schema(description = "配置名称") - private String name; - - @Schema(description = "配置值") - private String value; - - @Schema(description = "数据类型(String, Integer, Boolean, Float, Double)") - private String configType; - - @Schema(description = "配置渲染类型(select, input, textarea, checkbox, radio, switch)") - private String renderType; - - @Schema(description = "配置描述") - private String description; - - @Schema(description = "正则表达式校验规则(JSON)") - private JSONObject re; - - @Schema(description = "可选项(JSON),render_type为select、checkbox、radio时使用") - private JSONObject options; - - @Schema(description = "配置组") - private String group; - - @Schema(description = "模块id") - private String moduleId; - - @Schema(description = "配置顺序") - private Integer orderNum; - - @Schema(description = "配置状态 0:启用 1:禁用", defaultValue = "0") - private Integer status = 0; - -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysDeptDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysDeptDTO.java deleted file mode 100644 index d59a23c5..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysDeptDTO.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.xyzh.common.dto.sys; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -/** - * @description 系统部门DTO - * @filename TbSysDeptDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统部门DTO") -public class TbSysDeptDTO extends BaseDTO { - @Schema(description = "部门ID") - private String deptId; - - @Schema(description = "部门名称") - private String name; - - @Schema(description = "父级部门ID") - private String parentId; - - @Schema(description = "部门描述") - private String description; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysDeptRoleDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysDeptRoleDTO.java deleted file mode 100644 index 807fbd18..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysDeptRoleDTO.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.xyzh.common.dto.sys; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -/** - * @description 系统部门角色关系DTO - * @filename TbSysDeptRoleDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统部门角色关系DTO") -public class TbSysDeptRoleDTO extends BaseDTO { - - @Schema(description = "部门ID") - private String deptId; - - @Schema(description = "角色ID") - private String roleId; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysModuleDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysModuleDTO.java deleted file mode 100644 index c6e8581c..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysModuleDTO.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统模块DTO - * @filename TbSysModuleDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统模块DTO") -public class TbSysModuleDTO extends BaseDTO { - - @Schema(description = "模块ID") - private String moduleId; - - @Schema(description = "模块名称") - private String name; - - @Schema(description = "模块描述") - private String description; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysPermissionDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysPermissionDTO.java deleted file mode 100644 index 5a3a5705..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysPermissionDTO.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统权限DTO - * @filename TbSysPermissionDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统权限DTO") -public class TbSysPermissionDTO extends BaseDTO { - - @Schema(description = "权限ID") - private String permissionId; - - @Schema(description = "权限名称") - private String name; - - @Schema(description = "权限代码") - private String code; - - @Schema(description = "权限描述") - private String description; - - @Schema(description = "模块ID") - private String moduleId; - - @Schema(description = "状态") - private Boolean status; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysRoleDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysRoleDTO.java deleted file mode 100644 index 4ea7e9af..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysRoleDTO.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统角色DTO - * @filename TbSysRoleDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统角色DTO") -public class TbSysRoleDTO extends BaseDTO { - - @Schema(description = "角色ID") - private String roleId; - - @Schema(description = "角色名称") - private String name; - - @Schema(description = "角色描述") - private String description; - - @Schema(description = "角色作用域 global 全局角色, dept 部门角色") - private String scope; - - @Schema(description = "所属部门ID") - private String ownerDeptId; - - @Schema(description = "角色状态 true 有效, false 无效") - private Boolean status; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysRolePermissionDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysRolePermissionDTO.java deleted file mode 100644 index c8768b6c..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysRolePermissionDTO.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统角色权限关系DTO - * @filename TbSysRolePermissionDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统角色权限关系DTO") -public class TbSysRolePermissionDTO extends BaseDTO { - - @Schema(description = "角色ID") - private String roleId; - - @Schema(description = "权限ID") - private String permissionId; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserDTO.java deleted file mode 100644 index 558621e8..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserDTO.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import org.xyzh.common.utils.crypto.AesEncryptUtil; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统用户DTO - * @filename TbSysUserDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统用户DTO") -public class TbSysUserDTO extends BaseDTO { - - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "用户编码") - private String usercode; - - @Schema(description = "密码") - private String password; - - @Schema(description = "邮箱") - private String email; - - @Schema(description = "手机(加密)") - private String phone; - - @Schema(description = "手机号哈希") - private String phoneHash; - - @Schema(description = "微信ID") - private String wechatId; - - @Schema(description = "用户状态") - private String status; - - - public void setPhone(String phone){ - this.phone = phone; - this.phoneHash = AesEncryptUtil.maskPhone(phone); - } - -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserInfoDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserInfoDTO.java deleted file mode 100644 index a044f1c4..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserInfoDTO.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统用户信息DTO - * @filename TbSysUserInfoDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统用户信息DTO") -public class TbSysUserInfoDTO extends BaseDTO { - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "头像") - private String avatar; - - @Schema(description = "性别") - private Integer gender; - - @Schema(description = "用户名称") - private String username; - - @Schema(description = "等级") - private Integer level; - - @Schema(description = "身份证号") - private String idCard; - - @Schema(description = "地址") - private String address; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserRoleDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserRoleDTO.java deleted file mode 100644 index 4f9bc1d4..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysUserRoleDTO.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统用户角色关系DTO - * @filename TbSysUserRoleDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统用户角色关系DTO") -public class TbSysUserRoleDTO extends BaseDTO { - - - @Schema(description = "用户ID") - private String userId; - - @Schema(description = "角色ID") - private String roleId; - - @Schema(description = "部门ID") - private String deptId; - - @Schema(description = "部门全路径") - private String deptPath; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysViewDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysViewDTO.java deleted file mode 100644 index 0ee70783..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysViewDTO.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统视图DTO - * @filename TbSysViewDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统视图DTO") -public class TbSysViewDTO extends BaseDTO { - - @Schema(description = "视图ID") - private String viewId; - - @Schema(description = "视图名称") - private String name; - - @Schema(description = "父视图ID") - private String parentId; - - @Schema(description = "URL") - private String url; - - @Schema(description = "组件") - private String component; - - @Schema(description = "图标") - private String icon; - - @Schema(description = "类型:0=目录 1=菜单页面 2=按钮") - private Integer type; - - @Schema(description = "页面类型:route=路由页面 iframe=嵌入页面") - private String viewType; - - @Schema(description = "iframe URL(仅当viewType=iframe时有效)") - private String iframeUrl; - - @Schema(description = "所属服务:platform=平台应用 bidding=招标应用 workcase=客服应用") - private String service; - - @Schema(description = "布局") - private String layout; - - @Schema(description = "排序") - private Integer orderNum; - - @Schema(description = "描述") - private String description; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysViewPermissionDTO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysViewPermissionDTO.java deleted file mode 100644 index bfebba4e..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/dto/sys/TbSysViewPermissionDTO.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.xyzh.common.dto.sys; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.xyzh.common.dto.BaseDTO; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * @description 系统视图权限关系DTO - * @filename TbSysViewPermissionDTO.java - * @author yslg - * @copyright yslg - * @since 2025-11-04 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@Schema(description = "系统视图权限关系DTO") -public class TbSysViewPermissionDTO extends BaseDTO { - - @Schema(description = "视图ID") - private String viewId; - - @Schema(description = "权限ID") - private String permissionId; -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/vo/BaseVO.java b/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/vo/BaseVO.java deleted file mode 100644 index 88f51697..00000000 --- a/urbanLifelineServ/common/common-dto/src/main/java/org/xyzh/common/vo/BaseVO.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.xyzh.common.vo; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -import org.xyzh.common.dto.OrderField; - -import com.alibaba.fastjson2.annotation.JSONField; -import io.swagger.v3.oas.annotations.media.Schema; - -import lombok.Data; - -/** - * @description 基础视图对象 - * @filename BaseVO.java - * @author yslg - * @copyright yslg - * @since 2025-11-05 - */ -@Data -@Schema(description = "基础视图对象") -public class BaseVO implements Serializable { - private static final long serialVersionUID = 1L; - - @Schema(description = "操作流水号") - private String optsn; - - @Schema(description = "创建人") - private String creator; - - @Schema(description = "创建人名称") - private String creatorName; - - @Schema(description = "更新人") - private String updater; - - @Schema(description = "更新人名称") - private String updaterName; - - @Schema(description = "部门路径") - private String deptPath; - - @Schema(description = "备注") - private String remark; - - @Schema(description = "创建时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date createTime; - - @Schema(description = "更新时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; - - @Schema(description = "删除时间", format = "date-time") - @JSONField(format = "yyyy-MM-dd HH:mm:ss") - private Date deleteTime; - - @Schema(description = "是否已删除", defaultValue = "false") - private Boolean deleted = false; - - @Schema(description = "数量限制") - private Integer limit; - - @Schema(description = "开始时间") - private Date startTime; - - @Schema(description = "结束时间") - private Date endTime; - - @Schema(description = "排序字段") - private List orderFields; -} - diff --git a/urbanLifelineServ/common/common-exception/pom.xml b/urbanLifelineServ/common/common-exception/pom.xml deleted file mode 100644 index 3f49f094..00000000 --- a/urbanLifelineServ/common/common-exception/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-exception - 1.0.0 - jar - - - 21 - 21 - - - - - org.xyzh.common - common-core - ${urban-lifeline.version} - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-validation - - - org.springframework.boot - spring-boot-starter-security - - - - org.projectlombok - lombok - provided - - - org.slf4j - slf4j-api - - - diff --git a/urbanLifelineServ/common/common-exception/src/main/java/org/xyzh/common/exception/BusinessException.java b/urbanLifelineServ/common/common-exception/src/main/java/org/xyzh/common/exception/BusinessException.java deleted file mode 100644 index 0153618d..00000000 --- a/urbanLifelineServ/common/common-exception/src/main/java/org/xyzh/common/exception/BusinessException.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.xyzh.common.exception; - -import lombok.Getter; - -/** - * @description 业务异常 - * @filename BusinessException.java - * @author yslg - * @copyright yslg - * @since 2025-12-17 - */ -@Getter -public class BusinessException extends RuntimeException { - private static final long serialVersionUID = 1L; - - private final Integer code; - private final String message; - - public BusinessException(String message) { - super(message); - this.code = 500; - this.message = message; - } - - public BusinessException(Integer code, String message) { - super(message); - this.code = code; - this.message = message; - } - - public BusinessException(String message, Throwable cause) { - super(message, cause); - this.code = 500; - this.message = message; - } -} diff --git a/urbanLifelineServ/common/common-exception/src/main/java/org/xyzh/common/exception/handler/GlobalExceptionHandler.java b/urbanLifelineServ/common/common-exception/src/main/java/org/xyzh/common/exception/handler/GlobalExceptionHandler.java deleted file mode 100644 index 17636708..00000000 --- a/urbanLifelineServ/common/common-exception/src/main/java/org/xyzh/common/exception/handler/GlobalExceptionHandler.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.xyzh.common.exception.handler; - -import jakarta.validation.ConstraintViolation; -import jakarta.validation.ConstraintViolationException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.security.authorization.AuthorizationDeniedException; -import org.springframework.validation.BindException; -import org.springframework.validation.FieldError; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.MissingServletRequestParameterException; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.multipart.MaxUploadSizeExceededException; -import org.springframework.web.multipart.support.MissingServletRequestPartException; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.exception.BusinessException; - -import java.util.Set; -import java.util.stream.Collectors; - -/** - * @description 全局异常处理器 - * @filename GlobalExceptionHandler.java - * @author yslg - * @copyright yslg - * @since 2025-12-17 - */ -@RestControllerAdvice -public class GlobalExceptionHandler { - private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); - /** - * 业务异常 - */ - @ExceptionHandler(BusinessException.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleBusinessException(BusinessException e) { - logger.warn("业务异常: {}", e.getMessage()); - return ResultDomain.failure(e.getCode(), e.getMessage()); - } - - /** - * 参数校验异常 - @RequestBody 参数校验失败 - */ - @ExceptionHandler(MethodArgumentNotValidException.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { - String message = e.getBindingResult().getFieldErrors().stream() - .map(FieldError::getDefaultMessage) - .collect(Collectors.joining("; ")); - logger.warn("参数校验失败: {}", message); - return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message); - } - - /** - * 参数校验异常 - @Validated 校验失败(方法参数直接校验) - */ - @ExceptionHandler(ConstraintViolationException.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleConstraintViolationException(ConstraintViolationException e) { - Set> violations = e.getConstraintViolations(); - String message = violations.stream() - .map(ConstraintViolation::getMessage) - .collect(Collectors.joining("; ")); - logger.warn("参数校验失败: {}", message); - return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message); - } - - /** - * 参数绑定异常 - */ - @ExceptionHandler(BindException.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleBindException(BindException e) { - String message = e.getFieldErrors().stream() - .map(FieldError::getDefaultMessage) - .collect(Collectors.joining("; ")); - logger.warn("参数绑定失败: {}", message); - return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message); - } - - /** - * 缺少请求参数 - */ - @ExceptionHandler(MissingServletRequestParameterException.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleMissingServletRequestParameterException(MissingServletRequestParameterException e) { - String message = "缺少必要参数: " + e.getParameterName(); - logger.warn(message); - return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message); - } - - /** - * 缺少请求Part(multipart/form-data) - */ - @ExceptionHandler(MissingServletRequestPartException.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleMissingServletRequestPartException(MissingServletRequestPartException e) { - String message = "缺少必要参数: " + e.getRequestPartName(); - logger.warn(message); - return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), message); - } - - /** - * 文件上传大小超限 - */ - @ExceptionHandler(MaxUploadSizeExceededException.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) { - logger.warn("文件上传大小超限: {}", e.getMessage()); - return ResultDomain.failure(HttpStatus.BAD_REQUEST.value(), "上传文件大小超过限制"); - } - - /** - * 权限不足异常 - */ - @ExceptionHandler(AuthorizationDeniedException.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleAuthorizationDeniedException(AuthorizationDeniedException e) { - logger.warn("权限不足: {}", e.getMessage()); - return ResultDomain.failure(HttpStatus.FORBIDDEN.value(), "权限不足"); - } - - /** - * 其他未捕获异常 - */ - @ExceptionHandler(Exception.class) - @ResponseStatus(HttpStatus.OK) - public ResultDomain handleException(Exception e) { - logger.error("系统异常: ", e); - return ResultDomain.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), "系统异常,请联系管理员"); - } -} diff --git a/urbanLifelineServ/common/common-jdbc/pom.xml b/urbanLifelineServ/common/common-jdbc/pom.xml deleted file mode 100644 index 9385ac12..00000000 --- a/urbanLifelineServ/common/common-jdbc/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-jdbc - ${urban-lifeline.version} - jar - JDBC相关工具:MyBatis类型处理器 - - - 21 - 21 - - - - - - org.mybatis - mybatis - provided - - - - - com.alibaba.fastjson2 - fastjson2-extension-spring6 - - - - - org.xyzh.common - common-utils - provided - - - diff --git a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/config/TypeHandlerConfig.java b/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/config/TypeHandlerConfig.java deleted file mode 100644 index 35dc0349..00000000 --- a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/config/TypeHandlerConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.xyzh.common.jdbc.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.context.annotation.Configuration; -import org.xyzh.common.jdbc.handler.EncryptedStringTypeHandler; -import org.xyzh.common.utils.crypto.AesEncryptUtil; - -import jakarta.annotation.PostConstruct; - -/** - * TypeHandler 配置类 - * 用于初始化 EncryptedStringTypeHandler 中的 AesEncryptUtil - * - * @author yslg - * @since 2025-12-11 - */ -@Configuration -@ConditionalOnClass(AesEncryptUtil.class) -public class TypeHandlerConfig { - - private final AesEncryptUtil aesEncryptUtil; - - @Autowired(required = false) - public TypeHandlerConfig(AesEncryptUtil aesEncryptUtil) { - this.aesEncryptUtil = aesEncryptUtil; - } - - @PostConstruct - public void init() { - // 初始化 TypeHandler 中的静态 AesEncryptUtil 实例 - if (aesEncryptUtil != null) { - EncryptedStringTypeHandler.setAesEncryptUtil(aesEncryptUtil); - System.out.println("✓ TypeHandler 已初始化 AES 加密工具"); - } else { - System.err.println("警告: AesEncryptUtil 未能注入,加密功能可能无法正常工作"); - } - } -} diff --git a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/EncryptedStringTypeHandler.java b/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/EncryptedStringTypeHandler.java deleted file mode 100644 index 60a9b3ed..00000000 --- a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/EncryptedStringTypeHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.xyzh.common.jdbc.handler; - -import org.apache.ibatis.type.BaseTypeHandler; -import org.apache.ibatis.type.JdbcType; -import org.apache.ibatis.type.MappedTypes; -import org.xyzh.common.utils.crypto.AesEncryptUtil; - -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * MyBatis 加密字段类型处理器 - * 自动对数据库字段进行加密/解密 - * - * 使用方式: - * 在实体类字段上添加注解: - * @TableField(typeHandler = EncryptedStringTypeHandler.class) - * private String phone; - * - * @author yslg - * @since 2025-12-05 - */ -@MappedTypes({String.class}) -public class EncryptedStringTypeHandler extends BaseTypeHandler { - - private static AesEncryptUtil aesEncryptUtil; - - /** - * 设置加密工具(由 Spring 注入) - */ - public static void setAesEncryptUtil(AesEncryptUtil util) { - aesEncryptUtil = util; - } - - @Override - public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { - // 写入数据库时加密 - if (aesEncryptUtil != null && parameter != null) { - ps.setString(i, aesEncryptUtil.encrypt(parameter)); - } else { - ps.setString(i, parameter); - } - } - - @Override - public String getNullableResult(ResultSet rs, String columnName) throws SQLException { - // 从数据库读取时解密 - String encrypted = rs.getString(columnName); - return decrypt(encrypted); - } - - @Override - public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - String encrypted = rs.getString(columnIndex); - return decrypt(encrypted); - } - - @Override - public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - String encrypted = cs.getString(columnIndex); - return decrypt(encrypted); - } - - private String decrypt(String encrypted) { - if (aesEncryptUtil != null && encrypted != null && !encrypted.isEmpty()) { - try { - return aesEncryptUtil.decrypt(encrypted); - } catch (Exception e) { - // 如果解密失败,可能是旧数据,返回原值 - return encrypted; - } - } - return encrypted; - } -} diff --git a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/EnumNameTypeHandler.java b/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/EnumNameTypeHandler.java deleted file mode 100644 index fd8226ec..00000000 --- a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/EnumNameTypeHandler.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.xyzh.common.jdbc.handler; - -import org.apache.ibatis.type.BaseTypeHandler; -import org.apache.ibatis.type.JdbcType; - -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * @description 通用枚举类型处理器,支持枚举类中定义 getName() 方法 - * 将枚举的 name 属性(自定义字符串)存储到数据库 - * @filename EnumNameTypeHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -public class EnumNameTypeHandler> extends BaseTypeHandler { - - private final Class type; - - public EnumNameTypeHandler(Class type) { - if (type == null) { - throw new IllegalArgumentException("Type argument cannot be null"); - } - this.type = type; - } - - @Override - public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { - String value = getEnumName(parameter); - ps.setString(i, value); - } - - @Override - public E getNullableResult(ResultSet rs, String columnName) throws SQLException { - String name = rs.getString(columnName); - return fromName(name); - } - - @Override - public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - String name = rs.getString(columnIndex); - return fromName(name); - } - - @Override - public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - String name = cs.getString(columnIndex); - return fromName(name); - } - - /** - * 获取枚举的 name 属性值 - * 优先调用 getName() 方法,如果不存在则使用 name() - */ - private String getEnumName(E enumValue) { - try { - java.lang.reflect.Method getNameMethod = type.getMethod("getName"); - return (String) getNameMethod.invoke(enumValue); - } catch (NoSuchMethodException e) { - return enumValue.name(); - } catch (Exception e) { - return enumValue.name(); - } - } - - /** - * 根据 name 属性值查找枚举 - * 优先匹配 getName(),如果不存在则匹配 name() - */ - private E fromName(String name) { - if (name == null) { - return null; - } - E[] enumConstants = type.getEnumConstants(); - - // 先尝试匹配 getName() - try { - java.lang.reflect.Method getNameMethod = type.getMethod("getName"); - for (E enumConstant : enumConstants) { - String enumName = (String) getNameMethod.invoke(enumConstant); - if (name.equals(enumName)) { - return enumConstant; - } - } - } catch (NoSuchMethodException e) { - // 没有 getName 方法,使用 name() - } catch (Exception e) { - // 其他异常,使用 name() - } - - // 回退到 name() 匹配 - for (E enumConstant : enumConstants) { - if (name.equals(enumConstant.name())) { - return enumConstant; - } - } - - return null; - } -} diff --git a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/FastJson2TypeHandler.java b/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/FastJson2TypeHandler.java deleted file mode 100644 index b30ad91c..00000000 --- a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/FastJson2TypeHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.xyzh.common.jdbc.handler; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; -import org.apache.ibatis.type.BaseTypeHandler; -import org.apache.ibatis.type.JdbcType; -import org.apache.ibatis.type.MappedTypes; - -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * @description FastJSON2 JSONObject 类型处理器 - * @filename FastJson2TypeHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-09 - */ -@MappedTypes({JSONObject.class}) -public class FastJson2TypeHandler extends BaseTypeHandler { - - @Override - public void setNonNullParameter(PreparedStatement ps, int i, JSONObject parameter, JdbcType jdbcType) throws SQLException { - ps.setString(i, parameter.toJSONString()); - } - - @Override - public JSONObject getNullableResult(ResultSet rs, String columnName) throws SQLException { - String jsonString = rs.getString(columnName); - return parseToJSONObject(jsonString); - } - - @Override - public JSONObject getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - String jsonString = rs.getString(columnIndex); - return parseToJSONObject(jsonString); - } - - @Override - public JSONObject getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - String jsonString = cs.getString(columnIndex); - return parseToJSONObject(jsonString); - } - - private JSONObject parseToJSONObject(String jsonString) { - if (jsonString == null || jsonString.trim().isEmpty()) { - return null; - } - try { - return JSON.parseObject(jsonString); - } catch (Exception e) { - return new JSONObject(); - } - } -} diff --git a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/StringArrayTypeHandler.java b/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/StringArrayTypeHandler.java deleted file mode 100644 index f6659759..00000000 --- a/urbanLifelineServ/common/common-jdbc/src/main/java/org/xyzh/common/jdbc/handler/StringArrayTypeHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.xyzh.common.jdbc.handler; - -import org.apache.ibatis.type.BaseTypeHandler; -import org.apache.ibatis.type.JdbcType; -import org.apache.ibatis.type.MappedTypes; - -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * @description PostgreSQL VARCHAR数组类型处理器 - * @filename StringArrayTypeHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-15 - */ -@MappedTypes({List.class}) -public class StringArrayTypeHandler extends BaseTypeHandler> { - - @Override - public void setNonNullParameter(PreparedStatement ps, int i, List parameter, JdbcType jdbcType) throws SQLException { - if (parameter == null || parameter.isEmpty()) { - ps.setArray(i, null); - } else { - ps.setArray(i, ps.getConnection().createArrayOf("varchar", parameter.toArray())); - } - } - - @Override - public List getNullableResult(ResultSet rs, String columnName) throws SQLException { - java.sql.Array array = rs.getArray(columnName); - return parseArray(array); - } - - @Override - public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - java.sql.Array array = rs.getArray(columnIndex); - return parseArray(array); - } - - @Override - public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - java.sql.Array array = cs.getArray(columnIndex); - return parseArray(array); - } - - private List parseArray(java.sql.Array array) throws SQLException { - if (array == null) { - return null; - } - Object[] objects = (Object[]) array.getArray(); - return new ArrayList<>(Arrays.asList((String[]) objects)); - } -} diff --git a/urbanLifelineServ/common/common-redis/pom.xml b/urbanLifelineServ/common/common-redis/pom.xml deleted file mode 100644 index 861dbf1e..00000000 --- a/urbanLifelineServ/common/common-redis/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-redis - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - - - org.springframework.boot - spring-boot-starter-data-redis - - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - org.springframework.data - spring-data-redis - - - - - com.alibaba.fastjson2 - fastjson2 - - - - - org.xyzh.common - common-core - - - - - org.springframework - spring-context - - - - - org.springframework.boot - spring-boot-autoconfigure - - - \ No newline at end of file diff --git a/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/config/FastJson2JsonRedisSerializer.java b/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/config/FastJson2JsonRedisSerializer.java deleted file mode 100644 index 73c6f8fa..00000000 --- a/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/config/FastJson2JsonRedisSerializer.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.common.redis.config; - -import org.xyzh.common.core.constant.Constants; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.data.redis.serializer.SerializationException; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONReader; -import com.alibaba.fastjson2.JSONWriter; -import com.alibaba.fastjson2.filter.Filter; - -/** - * @description FastJson2JsonRedisSerializer.java文件描述 - * @filename FastJson2JsonRedisSerializer.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class FastJson2JsonRedisSerializer implements RedisSerializer -{ - public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; - - static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR); - - private Class clazz; - - public FastJson2JsonRedisSerializer(Class clazz) - { - super(); - this.clazz = clazz; - } - - @Override - public byte[] serialize(T t) throws SerializationException - { - if (t == null) - { - return new byte[0]; - } - return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET); - } - - @Override - public T deserialize(byte[] bytes) throws SerializationException - { - if (bytes == null || bytes.length <= 0) - { - return null; - } - String str = new String(bytes, DEFAULT_CHARSET); - - return JSON.parseObject(str, clazz, AUTO_TYPE_FILTER); - } -} diff --git a/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/config/RedisConfig.java b/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/config/RedisConfig.java deleted file mode 100644 index b3933629..00000000 --- a/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/config/RedisConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.xyzh.common.redis.config; - -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -/** - * @description RedisConfig.java文件描述 Redis配置 - * @filename RedisConfig.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@Configuration -@EnableCaching -@AutoConfigureBefore(RedisAutoConfiguration.class) -public class RedisConfig { - - @Bean - @SuppressWarnings(value = { "unchecked", "rawtypes" }) - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) - { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); - - FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer<>(Object.class); - - // 使用StringRedisSerializer来序列化和反序列化redis的key值 - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(serializer); - - // Hash的key也采用StringRedisSerializer的序列化方式 - template.setHashKeySerializer(new StringRedisSerializer()); - template.setHashValueSerializer(serializer); - - template.afterPropertiesSet(); - return template; - } -} diff --git a/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/listener/AbstractSysConfigListener.java b/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/listener/AbstractSysConfigListener.java deleted file mode 100644 index 46b5f380..00000000 --- a/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/listener/AbstractSysConfigListener.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.xyzh.common.redis.listener; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.redis.connection.Message; -import org.springframework.data.redis.connection.MessageListener; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -/** - * 系统配置变更监听器抽象基类 - * 通过Redis Pub/Sub接收配置变更事件,延时2秒后执行刷新(等待事务提交) - * - * @author cascade - * @since 2026-01-01 - */ -public abstract class AbstractSysConfigListener implements MessageListener { - - private static final Logger logger = LoggerFactory.getLogger(AbstractSysConfigListener.class); - - /** 延时时间(毫秒),等待事务提交 */ - private static final long DELAY_MILLIS = 2000L; - - /** 调度线程池 */ - private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { - Thread t = new Thread(r, "sys-config-refresh"); - t.setDaemon(true); - return t; - }); - - @Override - public void onMessage(Message message, byte[] pattern) { - String channel = new String(message.getChannel()); - String body = new String(message.getBody()); - - logger.info("收到配置变更事件: channel={}, body={}", channel, body); - - // 延时2秒执行,等待发布方事务提交 - scheduler.schedule(() -> { - try { - logger.info("开始刷新配置: channel={}", channel); - doRefresh(channel, body); - logger.info("配置刷新完成: channel={}", channel); - } catch (Exception e) { - logger.error("配置刷新失败: channel={}", channel, e); - } - }, DELAY_MILLIS, TimeUnit.MILLISECONDS); - } - - /** - * 执行配置刷新,子类实现具体逻辑 - * - * @param channel 频道名称(对应配置分组) - * @param body 消息体(可选,可传递额外信息) - */ - protected abstract void doRefresh(String channel, String body); - - /** - * 获取监听的频道前缀 - * - * @return 频道前缀 - */ - public abstract String getChannelPattern(); -} diff --git a/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/service/RedisService.java b/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/service/RedisService.java deleted file mode 100644 index 1d43245f..00000000 --- a/urbanLifelineServ/common/common-redis/src/main/java/org/xyzh/common/redis/service/RedisService.java +++ /dev/null @@ -1,421 +0,0 @@ -package org.xyzh.common.redis.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.RedisCallback; -import java.util.*; -import java.util.concurrent.TimeUnit; -import org.springframework.stereotype.Component; - -import com.alibaba.fastjson2.JSON; - -/** - * @description RedisService.java Redis工具服务类,封装常用Redis操作 - * @filename RedisService.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -@SuppressWarnings(value = { "unchecked", "rawtypes" }) -@Component -public class RedisService { - - @Autowired - private RedisTemplate redisTemplate; - - /** - * @description 设置key-value - * @param key String 键 - * @param value Object 值 - * @author yslg - * @since 2025-11-02 - */ - public void set(String key, Object value) { - redisTemplate.opsForValue().set(key, value); - } - - /** - * @description 设置key-value并指定过期时间 - * @param key String 键 - * @param value Object 值 - * @param timeout long 过期时间 - * @param unit TimeUnit 时间单位 - * @author yslg - * @since 2025-11-02 - */ - public void set(String key, Object value, long timeout, TimeUnit unit) { - redisTemplate.opsForValue().set(key, value, timeout, unit); - } - - /** - * @description 如果key不存在则设置(分布式锁) - * @param key String 键 - * @param value Object 值 - * @param timeoutSeconds long 过期秒数 - * @return Boolean 是否设置成功 - * @author cascade - * @since 2025-12-22 - */ - public Boolean setIfAbsent(String key, Object value, long timeoutSeconds) { - return redisTemplate.opsForValue().setIfAbsent(key, value, timeoutSeconds, TimeUnit.SECONDS); - } - - /** - * @description 获取key对应的value - * @param key String 键 - * @return Object 值 - * @author yslg - * @since 2025-11-02 - */ - public Object get(String key) { - return redisTemplate.opsForValue().get(key); - } - - /** - * @description 获取key对应的value并反序列化为指定类型 - * @param key String 键 - * @param clazz Class 目标类型 - * @return T 反序列化后的对象 - * @author yslg - * @since 2025-12-19 - */ - public T get(String key, Class clazz) { - Object obj = redisTemplate.opsForValue().get(key); - if (obj == null) { - return null; - } - if (clazz.isInstance(obj)) { - return clazz.cast(obj); - } - if (obj instanceof String) { - return JSON.parseObject((String) obj, clazz); - } - return null; - } - - /** - * @description 删除key - * @param key String 键 - * @author yslg - * @since 2025-11-02 - */ - public void delete(String key) { - redisTemplate.delete(key); - } - - /** - * @description 批量删除key - * @param keys Collection 键集合 - * @author yslg - * @since 2025-11-02 - */ - public void delete(Collection keys) { - redisTemplate.delete(keys); - } - - /** - * @description 判断key是否存在 - * @param key String 键 - * @return Boolean 是否存在 - * @author yslg - * @since 2025-11-02 - */ - public Boolean hasKey(String key) { - return redisTemplate.hasKey(key); - } - - /** - * @description 设置key过期时间(秒) - * @param key String 键 - * @param timeout long 过期秒数 - * @author yslg - * @since 2025-11-02 - */ - public void setExpire(String key, long timeout) { - redisTemplate.expire(key, timeout, TimeUnit.SECONDS); - } - - /** - * @description 设置key过期时间(自定义单位) - * @param key String 键 - * @param timeout long 过期时间 - * @param unit TimeUnit 时间单位 - * @author yslg - * @since 2025-11-02 - */ - public void setExpire(String key, long timeout, TimeUnit unit) { - redisTemplate.expire(key, timeout, unit); - } - - /** - * @description 获取key剩余过期时间(秒) - * @param key String 键 - * @return long 剩余秒数 - * @author yslg - * @since 2025-11-02 - */ - public long getExpire(String key) { - return redisTemplate.getExpire(key, TimeUnit.SECONDS); - } - - /** - * @description 原子递增 - * @param key String 键 - * @param delta long 增量 - * @return long 递增后值 - * @author yslg - * @since 2025-11-02 - */ - public long incr(String key, long delta) { - Long result = redisTemplate.opsForValue().increment(key, delta); - return result != null ? result : 0L; - } - - /** - * @description 原子递减 - * @param key String 键 - * @param delta long 减量 - * @return long 递减后值 - * @author yslg - * @since 2025-11-02 - */ - public long decr(String key, long delta) { - Long result = redisTemplate.opsForValue().increment(key, -delta); - return result != null ? result : 0L; - } - - /** - * @description Hash操作-put - * @param key String 键 - * @param hashKey String 哈希键 - * @param value Object 值 - * @author yslg - * @since 2025-11-02 - */ - public void hSet(String key, String hashKey, Object value) { - redisTemplate.opsForHash().put(key, hashKey, value); - } - - /** - * @description Hash操作-get - * @param key String 键 - * @param hashKey String 哈希键 - * @return Object 值 - * @author yslg - * @since 2025-11-02 - */ - public Object hGet(String key, String hashKey) { - return redisTemplate.opsForHash().get(key, hashKey); - } - - /** - * @description Hash操作-获取所有 - * @param key String 键 - * @return Map 哈希所有键值对 - * @author yslg - * @since 2025-11-02 - */ - public Map hGetAll(String key) { - return redisTemplate.opsForHash().entries(key); - } - - /** - * @description Hash操作-删除 - * @param key String 键 - * @param hashKeys String[] 哈希键数组 - * @author yslg - * @since 2025-11-02 - */ - public void hDelete(String key, String... hashKeys) { - redisTemplate.opsForHash().delete(key, (Object[]) hashKeys); - } - - /** - * @description List操作-左入队 - * @param key String 键 - * @param value Object 值 - * @author yslg - * @since 2025-11-02 - */ - public void lPush(String key, Object value) { - redisTemplate.opsForList().leftPush(key, value); - } - - /** - * @description List操作-右入队 - * @param key String 键 - * @param value Object 值 - * @author yslg - * @since 2025-11-02 - */ - public void rPush(String key, Object value) { - redisTemplate.opsForList().rightPush(key, value); - } - - /** - * @description List操作-左出队 - * @param key String 键 - * @return Object 出队值 - * @author yslg - * @since 2025-11-02 - */ - public Object lPop(String key) { - return redisTemplate.opsForList().leftPop(key); - } - - /** - * @description List操作-右出队 - * @param key String 键 - * @return Object 出队值 - * @author yslg - * @since 2025-11-02 - */ - public Object rPop(String key) { - return redisTemplate.opsForList().rightPop(key); - } - - /** - * @description List操作-获取区间元素 - * @param key String 键 - * @param start long 起始索引 - * @param end long 结束索引 - * @return List 元素列表 - * @author yslg - * @since 2025-11-02 - */ - public List lRange(String key, long start, long end) { - return redisTemplate.opsForList().range(key, start, end); - } - - /** - * @description Set操作-添加元素 - * @param key String 键 - * @param values Object[] 元素数组 - * @author yslg - * @since 2025-11-02 - */ - public void sAdd(String key, Object... values) { - redisTemplate.opsForSet().add(key, values); - } - - /** - * @description Set操作-移除元素 - * @param key String 键 - * @param values Object[] 元素数组 - * @author yslg - * @since 2025-11-02 - */ - public void sRemove(String key, Object... values) { - redisTemplate.opsForSet().remove(key, values); - } - - /** - * @description Set操作-获取所有元素 - * @param key String 键 - * @return Set 元素集合 - * @author yslg - * @since 2025-11-02 - */ - public Set sMembers(String key) { - return redisTemplate.opsForSet().members(key); - } - - /** - * @description ZSet操作-添加元素 - * @param key String 键 - * @param value Object 元素 - * @param score double 分数 - * @author yslg - * @since 2025-11-02 - */ - public void zAdd(String key, Object value, double score) { - redisTemplate.opsForZSet().add(key, value, score); - } - - /** - * @description ZSet操作-移除元素 - * @param key String 键 - * @param values Object[] 元素数组 - * @author yslg - * @since 2025-11-02 - */ - public void zRemove(String key, Object... values) { - redisTemplate.opsForZSet().remove(key, values); - } - - /** - * @description ZSet操作-按分数区间获取元素 - * @param key String 键 - * @param min double 最小分数 - * @param max double 最大分数 - * @return Set 元素集合 - * @author yslg - * @since 2025-11-02 - */ - public Set zRangeByScore(String key, double min, double max) { - return redisTemplate.opsForZSet().rangeByScore(key, min, max); - } - - /** - * @description ZSet操作-获取全部元素 - * @param key String 键 - * @param start long 起始索引 - * @param end long 结束索引 - * @return Set 元素集合 - * @author yslg - * @since 2025-11-02 - */ - public Set zRange(String key, long start, long end) { - return redisTemplate.opsForZSet().range(key, start, end); - } - - /** - * @description 发布消息(Pub/Sub) - * @param channel String 通道 - * @param message Object 消息内容 - * @author yslg - * @since 2025-11-02 - */ - public void publish(String channel, Object message) { - redisTemplate.convertAndSend(channel, message); - } - - /** - * @description 执行Redis原生命令 - * @param action RedisCallback 回调命令 - * @return Object 执行结果 - * @author yslg - * @since 2025-11-02 - */ - public Object execute(RedisCallback action) { - return redisTemplate.execute(action); - } - - /** - * @description 获取所有key(慎用) - * @param pattern String 匹配模式 - * @return Set key集合 - * @author yslg - * @since 2025-11-02 - */ - public Set keys(String pattern) { - Set keys = redisTemplate.keys(pattern); - Set stringKeys = new HashSet<>(); - if (keys != null) { - for (String key : keys) { - stringKeys.add(key); - } - } - return stringKeys; - } - - /** - * @description 清空当前数据库(慎用) - * @author yslg - * @since 2025-11-02 - */ - public void flushDb() { - redisTemplate.execute((RedisCallback) connection -> { connection.flushDb(); return null; }); - } - -} diff --git a/urbanLifelineServ/common/common-utils/pom.xml b/urbanLifelineServ/common/common-utils/pom.xml deleted file mode 100644 index 31b6b205..00000000 --- a/urbanLifelineServ/common/common-utils/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-utils - ${urban-lifeline.version} - jar - - 21 - 21 - - - - - - jakarta.servlet - jakarta.servlet-api - provided - - - - - org.springframework - spring-web - provided - - - org.springframework - spring-webmvc - provided - - - - - org.apache.poi - poi - - - - org.apache.poi - poi-ooxml - - - - - org.springframework.boot - spring-boot-starter - provided - - - - org.springframework.boot - spring-boot-starter-mail - - - - - com.aliyun - dysmsapi20170525 - 4.2.0 - - - - com.alibaba.fastjson2 - fastjson2-extension-spring6 - - - \ No newline at end of file diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/NonUtils.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/NonUtils.java deleted file mode 100644 index 5136a7eb..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/NonUtils.java +++ /dev/null @@ -1,603 +0,0 @@ -package org.xyzh.common.utils; - -import java.lang.reflect.Array; -import java.util.*; -import java.util.function.Predicate; - -/** - * @description NonUtils.java文件描述 空值判断工具类 - * @filename NonUtils.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class NonUtils { - - private NonUtils() { - throw new UnsupportedOperationException("工具类不能被实例化"); - } - - // ======================== 基础null判断 ======================== - - /** - * 判断对象是否为null - * - * @param obj 待判断的对象 - * @return true-对象为null,false-对象不为null - */ - public static Boolean isNull(Object obj) { - return obj == null; - } - - /** - * 判断对象是否不为null - * - * @param obj 待判断的对象 - * @return true-对象不为null,false-对象为null - */ - public static Boolean isNotNull(Object obj) { - return obj != null; - } - - /** - * 判断多个对象是否都为null - * - * @param objects 待判断的对象数组 - * @return true-所有对象都为null,false-至少有一个对象不为null - */ - public static Boolean isAllNull(Object... objects) { - if (objects == null || objects.length == 0) { - return true; - } - for (Object obj : objects) { - if (isNotNull(obj)) { - return false; - } - } - return true; - } - - /** - * 判断多个对象是否都不为null - * - * @param objects 待判断的对象数组 - * @return true-所有对象都不为null,false-至少有一个对象为null - */ - public static Boolean isAllNotNull(Object... objects) { - if (objects == null || objects.length == 0) { - return false; - } - for (Object obj : objects) { - if (isNull(obj)) { - return false; - } - } - return true; - } - - /** - * 判断多个对象中是否存在null - * - * @param objects 待判断的对象数组 - * @return true-存在null对象,false-不存在null对象 - */ - public static Boolean hasNull(Object... objects) { - if (objects == null || objects.length == 0) { - return true; - } - for (Object obj : objects) { - if (isNull(obj)) { - return true; - } - } - return false; - } - - // ======================== 空值判断(包含null、空字符串、空集合等) ======================== - - /** - * 判断对象是否为空 - * - null -> true - * - "" -> true - * - " " -> true (仅包含空白字符) - * - 空集合 -> true - * - 空数组 -> true - * - * @param obj 待判断的对象 - * @return true-对象为空,false-对象不为空 - */ - public static Boolean isEmpty(Object obj) { - if (isNull(obj)) { - return true; - } - - // 字符串判断 - if (obj instanceof CharSequence) { - return ((CharSequence) obj).length() == 0 || obj.toString().trim().isEmpty(); - } - - // 集合判断 - if (obj instanceof Collection) { - return ((Collection) obj).isEmpty(); - } - - // Map判断 - if (obj instanceof Map) { - return ((Map) obj).isEmpty(); - } - - // 数组判断 - if (obj.getClass().isArray()) { - return Array.getLength(obj) == 0; - } - - // Optional判断 - if (obj instanceof Optional) { - return !((Optional) obj).isPresent(); - } - - return false; - } - - /** - * 判断对象是否不为空 - * - * @param obj 待判断的对象 - * @return true-对象不为空,false-对象为空 - */ - public static Boolean isNotEmpty(Object obj) { - return !isEmpty(obj); - } - - /** - * 判断多个对象是否都为空 - * - * @param objects 待判断的对象数组 - * @return true-所有对象都为空,false-至少有一个对象不为空 - */ - public static Boolean isAllEmpty(Object... objects) { - if (objects == null || objects.length == 0) { - return true; - } - for (Object obj : objects) { - if (isNotEmpty(obj)) { - return false; - } - } - return true; - } - - /** - * 判断多个对象是否都不为空 - * - * @param objects 待判断的对象数组 - * @return true-所有对象都不为空,false-至少有一个对象为空 - */ - public static Boolean isAllNotEmpty(Object... objects) { - if (objects == null || objects.length == 0) { - return false; - } - for (Object obj : objects) { - if (isEmpty(obj)) { - return false; - } - } - return true; - } - - /** - * 判断多个对象中是否存在空值 - * - * @param objects 待判断的对象数组 - * @return true-存在空值,false-不存在空值 - */ - public static Boolean hasEmpty(Object... objects) { - if (objects == null || objects.length == 0) { - return true; - } - for (Object obj : objects) { - if (isEmpty(obj)) { - return true; - } - } - return false; - } - - // ======================== 深度递归判断 ======================== - - /** - * 深度判断对象是否为空(递归检查) - * 对于集合、数组等容器类型,会递归检查其内部元素 - * - * @param obj 待判断的对象 - * @return true-对象为空(包括递归检查),false-对象不为空 - */ - public static Boolean isDeepEmpty(Object obj) { - return isDeepEmpty(obj, new HashSet<>()); - } - - /** - * 深度判断对象是否为空(递归检查,防止循环引用) - * - * @param obj 待判断的对象 - * @param visited 已访问对象集合,用于防止循环引用 - * @return true-对象为空(包括递归检查),false-对象不为空 - */ - private static Boolean isDeepEmpty(Object obj, Set visited) { - if (isEmpty(obj)) { - return true; - } - - // 防止循环引用 - if (visited.contains(obj)) { - return false; - } - visited.add(obj); - - try { - // 集合类型递归检查 - if (obj instanceof Collection) { - Collection collection = (Collection) obj; - for (Object item : collection) { - if (!isDeepEmpty(item, visited)) { - return false; - } - } - return true; - } - - // Map类型递归检查 - if (obj instanceof Map) { - Map map = (Map) obj; - for (Map.Entry entry : map.entrySet()) { - if (!isDeepEmpty(entry.getKey(), visited) || !isDeepEmpty(entry.getValue(), visited)) { - return false; - } - } - return true; - } - - // 数组类型递归检查 - if (obj.getClass().isArray()) { - int length = Array.getLength(obj); - for (int i = 0; i < length; i++) { - if (!isDeepEmpty(Array.get(obj, i), visited)) { - return false; - } - } - return true; - } - - // Optional类型递归检查 - if (obj instanceof Optional) { - Optional optional = (Optional) obj; - return !optional.isPresent() || isDeepEmpty(optional.get(), visited); - } - - // 其他类型认为不为空 - return false; - - } finally { - visited.remove(obj); - } - } - - /** - * 深度判断对象是否不为空(递归检查) - * - * @param obj 待判断的对象 - * @return true-对象不为空(包括递归检查),false-对象为空 - */ - public static Boolean isDeepNotEmpty(Object obj) { - return !isDeepEmpty(obj); - } - - // ======================== 集合专用方法 ======================== - - /** - * 判断集合是否为空或null - * - * @param collection 待判断的集合 - * @return true-集合为null或空,false-集合不为空 - */ - public static Boolean isEmptyCollection(Collection collection) { - return collection == null || collection.isEmpty(); - } - - /** - * 判断集合是否不为空且不为null - * - * @param collection 待判断的集合 - * @return true-集合不为null且不为空,false-集合为null或空 - */ - public static Boolean isNotEmptyCollection(Collection collection) { - return collection != null && !collection.isEmpty(); - } - - /** - * 判断集合是否包含有效元素(非null且非空的元素) - * - * @param collection 待判断的集合 - * @return true-集合包含有效元素,false-集合为空或只包含null/空元素 - */ - public static Boolean hasValidElements(Collection collection) { - if (isEmptyCollection(collection)) { - return false; - } - for (Object item : collection) { - if (isNotEmpty(item)) { - return true; - } - } - return false; - } - - /** - * 判断集合是否所有元素都有效(非null且非空) - * - * @param collection 待判断的集合 - * @return true-集合所有元素都有效,false-集合为空或包含null/空元素 - */ - public static Boolean allValidElements(Collection collection) { - if (isEmptyCollection(collection)) { - return false; - } - for (Object item : collection) { - if (isEmpty(item)) { - return false; - } - } - return true; - } - - /** - * 过滤集合中的空元素,返回新集合 - * - * @param collection 原集合 - * @param 集合元素类型 - * @return 过滤后的新集合 - */ - public static List filterEmpty(Collection collection) { - if (isEmptyCollection(collection)) { - return new ArrayList<>(); - } - List result = new ArrayList<>(); - for (T item : collection) { - if (isNotEmpty(item)) { - result.add(item); - } - } - return result; - } - - // ======================== Map专用方法 ======================== - - /** - * 判断Map是否为空或null - * - * @param map 待判断的Map - * @return true-Map为null或空,false-Map不为空 - */ - public static Boolean isEmptyMap(Map map) { - return map == null || map.isEmpty(); - } - - /** - * 判断Map是否不为空且不为null - * - * @param map 待判断的Map - * @return true-Map不为null且不为空,false-Map为null或空 - */ - public static Boolean isNotEmptyMap(Map map) { - return map != null && !map.isEmpty(); - } - - // ======================== 数组专用方法 ======================== - - /** - * 判断数组是否为空或null - * - * @param array 待判断的数组 - * @return true-数组为null或空,false-数组不为空 - */ - public static Boolean isEmptyArray(Object array) { - return array == null || !array.getClass().isArray() || Array.getLength(array) == 0; - } - - /** - * 判断数组是否不为空且不为null - * - * @param array 待判断的数组 - * @return true-数组不为null且不为空,false-数组为null或空 - */ - public static Boolean isNotEmptyArray(Object array) { - return array != null && array.getClass().isArray() && Array.getLength(array) > 0; - } - - // ======================== 字符串专用方法 ======================== - - /** - * 判断字符串是否为空或null(包括空白字符串) - * - * @param str 待判断的字符串 - * @return true-字符串为null、空或只包含空白字符,false-字符串有有效内容 - */ - public static Boolean isEmptyString(String str) { - return str == null || str.trim().isEmpty(); - } - - /** - * 判断字符串是否不为空且不为null - * - * @param str 待判断的字符串 - * @return true-字符串不为null且有有效内容,false-字符串为null、空或只包含空白字符 - */ - public static Boolean isNotEmptyString(String str) { - return str != null && !str.trim().isEmpty(); - } - - // ======================== 条件判断方法 ======================== - - /** - * 如果对象为空则返回默认值 - * - * @param obj 待判断的对象 - * @param defaultValue 默认值 - * @param 对象类型 - * @return 如果obj为空则返回defaultValue,否则返回obj - */ - @SuppressWarnings("unchecked") - public static T defaultIfEmpty(T obj, T defaultValue) { - return isEmpty(obj) ? defaultValue : obj; - } - - /** - * 如果对象为null则返回默认值 - * - * @param obj 待判断的对象 - * @param defaultValue 默认值 - * @param 对象类型 - * @return 如果obj为null则返回defaultValue,否则返回obj - */ - public static T defaultIfNull(T obj, T defaultValue) { - return isNull(obj) ? defaultValue : obj; - } - - /** - * 获取第一个非空的对象 - * - * @param objects 对象数组 - * @param 对象类型 - * @return 第一个非空的对象,如果都为空则返回null - */ - @SafeVarargs - public static T firstNotEmpty(T... objects) { - if (objects == null || objects.length == 0) { - return null; - } - for (T obj : objects) { - if (isNotEmpty(obj)) { - return obj; - } - } - return null; - } - - /** - * 获取第一个非null的对象 - * - * @param objects 对象数组 - * @param 对象类型 - * @return 第一个非null的对象,如果都为null则返回null - */ - @SafeVarargs - public static T firstNotNull(T... objects) { - if (objects == null || objects.length == 0) { - return null; - } - for (T obj : objects) { - if (isNotNull(obj)) { - return obj; - } - } - return null; - } - - // ======================== 统计方法 ======================== - - /** - * 统计数组中非空元素的个数 - * - * @param objects 对象数组 - * @return 非空元素个数 - */ - public static int countNotEmpty(Object... objects) { - if (objects == null || objects.length == 0) { - return 0; - } - int count = 0; - for (Object obj : objects) { - if (isNotEmpty(obj)) { - count++; - } - } - return count; - } - - /** - * 统计数组中非null元素的个数 - * - * @param objects 对象数组 - * @return 非null元素个数 - */ - public static int countNotNull(Object... objects) { - if (objects == null || objects.length == 0) { - return 0; - } - int count = 0; - for (Object obj : objects) { - if (isNotNull(obj)) { - count++; - } - } - return count; - } - - // ======================== 断言方法 ======================== - - /** - * 断言对象不为null,如果为null则抛出异常 - * - * @param obj 待断言的对象 - * @param message 异常消息 - * @throws IllegalArgumentException 如果对象为null - */ - public static void requireNotNull(Object obj, String message) { - if (isNull(obj)) { - throw new IllegalArgumentException(message != null ? message : "对象不能为null"); - } - } - - /** - * 断言对象不为空,如果为空则抛出异常 - * - * @param obj 待断言的对象 - * @param message 异常消息 - * @throws IllegalArgumentException 如果对象为空 - */ - public static void requireNotEmpty(Object obj, String message) { - if (isEmpty(obj)) { - throw new IllegalArgumentException(message != null ? message : "对象不能为空"); - } - } - - // ======================== 类型检查方法 ======================== - - /** - * 检查对象是否为指定类型且不为null - * - * @param obj 待检查的对象 - * @param clazz 目标类型 - * @param 目标类型 - * @return true-对象不为null且为指定类型,false-否则 - */ - public static Boolean isInstanceAndNotNull(Object obj, Class clazz) { - return isNotNull(obj) && clazz.isInstance(obj); - } - - /** - * 安全的类型转换,如果对象为null或不是目标类型则返回null - * - * @param obj 待转换的对象 - * @param clazz 目标类型 - * @param 目标类型 - * @return 转换后的对象,如果转换失败则返回null - */ - @SuppressWarnings("unchecked") - public static T safeCast(Object obj, Class clazz) { - if (isInstanceAndNotNull(obj, clazz)) { - return (T) obj; - } - return null; - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/ServletUtils.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/ServletUtils.java deleted file mode 100644 index e974bb7f..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/ServletUtils.java +++ /dev/null @@ -1,404 +0,0 @@ -package org.xyzh.common.utils; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpSession; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.BufferedReader; -import java.util.Enumeration; -import java.util.Map; -import java.util.HashMap; -import java.util.Set; -import java.util.HashSet; - -/** - * @description ServletUtils.java文件描述:Servlet相关常用工具方法 - * @filename ServletUtils.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ServletUtils { - - /** - * @description 获取请求的真实IP地址 - * @param request HTTP请求对象 - * @return 客户端真实IP地址 - * @author yslg - * @since 2025-11-02 - */ - public static String getClientIp(HttpServletRequest request) { - String ip = request.getHeader("X-Forwarded-For"); - if (ip != null && ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) { - // 多级代理时取第一个 - int idx = ip.indexOf(','); - if (idx > -1) { - ip = ip.substring(0, idx); - } - return ip.trim(); - } - ip = request.getHeader("Proxy-Client-IP"); - if (ip != null && ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) { - return ip; - } - ip = request.getHeader("WL-Proxy-Client-IP"); - if (ip != null && ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) { - return ip; - } - ip = request.getRemoteAddr(); - return ip; - } - - /** - * @description 向响应写出JSON字符串 - * @param response HTTP响应对象 - * @param json 要写出的JSON字符串 - * @return void - * @author yslg - * @since 2025-11-02 - */ - public static void writeJson(HttpServletResponse response, String json) throws IOException { - response.setContentType("application/json;charset=UTF-8"); - PrintWriter writer = response.getWriter(); - writer.write(json); - writer.flush(); - writer.close(); - } - - /** - * @description 获取请求参数(支持默认值) - * @param request HTTP请求对象 - * @param name 参数名 - * @param defaultValue 默认值 - * @return 参数值或默认值 - * @author yslg - * @since 2025-11-02 - */ - public static String getParameter(HttpServletRequest request, String name, String defaultValue) { - String value = request.getParameter(name); - return value != null ? value : defaultValue; - } - - /** - * @description 判断请求是否为Ajax - * @param request HTTP请求对象 - * @return 是否为Ajax请求 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isAjaxRequest(HttpServletRequest request) { - String header = request.getHeader("X-Requested-With"); - return "XMLHttpRequest".equalsIgnoreCase(header); - } - - /** - * @description 获取请求体内容 - * @param request HTTP请求对象 - * @return 请求体内容 - * @author yslg - * @since 2025-11-02 - */ - public static String getRequestBody(HttpServletRequest request) throws IOException { - StringBuilder sb = new StringBuilder(); - BufferedReader reader = request.getReader(); - String line; - while ((line = reader.readLine()) != null) { - sb.append(line); - } - return sb.toString(); - } - - /** - * @description 重定向到指定URL - * @param response HTTP响应对象 - * @param url 目标URL - * @return void - * @author yslg - * @since 2025-11-02 - */ - public static void redirect(HttpServletResponse response, String url) throws IOException { - response.sendRedirect(url); - } - - /** - * @description 获取完整请求URL - * @param request HTTP请求对象 - * @return 完整URL - * @author yslg - * @since 2025-11-02 - */ - public static String getFullUrl(HttpServletRequest request) { - StringBuilder url = new StringBuilder(); - url.append(request.getScheme()).append("://"); - url.append(request.getServerName()); - int port = request.getServerPort(); - if (("http".equals(request.getScheme()) && port != 80) || - ("https".equals(request.getScheme()) && port != 443)) { - url.append(":").append(port); - } - url.append(request.getRequestURI()); - String queryString = request.getQueryString(); - if (queryString != null) { - url.append("?").append(queryString); - } - return url.toString(); - } - - /** - * @description 判断请求是否为GET方法 - * @param request HTTP请求对象 - * @return 是否为GET请求 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isGet(HttpServletRequest request) { - return "GET".equalsIgnoreCase(request.getMethod()); - } - - /** - * @description 判断请求是否为POST方法 - * @param request HTTP请求对象 - * @return 是否为POST请求 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isPost(HttpServletRequest request) { - return "POST".equalsIgnoreCase(request.getMethod()); - } - - /** - * @description 判断请求是否为PUT方法 - * @param request HTTP请求对象 - * @return 是否为PUT请求 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isPut(HttpServletRequest request) { - return "PUT".equalsIgnoreCase(request.getMethod()); - } - - /** - * @description 判断请求是否为DELETE方法 - * @param request HTTP请求对象 - * @return 是否为DELETE请求 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isDelete(HttpServletRequest request) { - return "DELETE".equalsIgnoreCase(request.getMethod()); - } - - /** - * @description 获取所有请求参数 - * @param request HTTP请求对象 - * @return 参数Map - * @author yslg - * @since 2025-11-02 - */ - public static Map getParameterMap(HttpServletRequest request) { - Map paramMap = new HashMap<>(); - Enumeration parameterNames = request.getParameterNames(); - while (parameterNames.hasMoreElements()) { - String paramName = parameterNames.nextElement(); - String paramValue = request.getParameter(paramName); - paramMap.put(paramName, paramValue); - } - return paramMap; - } - - /** - * @description 获取请求头信息 - * @param request HTTP请求对象 - * @return 头信息Map - * @author yslg - * @since 2025-11-02 - */ - public static Map getHeaderMap(HttpServletRequest request) { - Map headerMap = new HashMap<>(); - Enumeration headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - String headerValue = request.getHeader(headerName); - headerMap.put(headerName, headerValue); - } - return headerMap; - } - - /** - * @description 获取Cookie值 - * @param request HTTP请求对象 - * @param name Cookie名 - * @return Cookie值 - * @author yslg - * @since 2025-11-02 - */ - public static String getCookieValue(HttpServletRequest request, String name) { - Cookie[] cookies = request.getCookies(); - if (cookies != null) { - for (Cookie cookie : cookies) { - if (name.equals(cookie.getName())) { - return cookie.getValue(); - } - } - } - return null; - } - - /** - * @description 设置Cookie - * @param response HTTP响应对象 - * @param name Cookie名 - * @param value Cookie值 - * @param maxAge 过期时间(秒) - * @return void - * @author yslg - * @since 2025-11-02 - */ - public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) { - Cookie cookie = new Cookie(name, value); - cookie.setMaxAge(maxAge); - cookie.setPath("/"); - cookie.setHttpOnly(true); - response.addCookie(cookie); - } - - /** - * @description 删除Cookie - * @param response HTTP响应对象 - * @param name Cookie名 - * @return void - * @author yslg - * @since 2025-11-02 - */ - public static void removeCookie(HttpServletResponse response, String name) { - Cookie cookie = new Cookie(name, null); - cookie.setMaxAge(0); - cookie.setPath("/"); - response.addCookie(cookie); - } - - /** - * @description 判断是否为HTTPS请求 - * @param request HTTP请求对象 - * @return 是否为HTTPS请求 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isHttps(HttpServletRequest request) { - return "https".equals(request.getScheme()) || request.isSecure() || - "443".equals(request.getHeader("X-Forwarded-Port")) || - "https".equals(request.getHeader("X-Forwarded-Proto")); - } - - /** - * @description 获取上下文路径 - * @param request HTTP请求对象 - * @return 上下文路径 - * @author yslg - * @since 2025-11-02 - */ - public static String getContextPath(HttpServletRequest request) { - return request.getContextPath(); - } - - /** - * @description 检测请求是否包含指定参数 - * @param request HTTP请求对象 - * @param paramName 参数名 - * @return 是否包含参数 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean hasParameter(HttpServletRequest request, String paramName) { - return request.getParameter(paramName) != null; - } - - /** - * @description 获取Session对象 - * @param request HTTP请求对象 - * @return HttpSession对象 - * @author yslg - * @since 2025-11-02 - */ - public static HttpSession getSession(HttpServletRequest request) { - return request.getSession(); - } - - /** - * @description 获取Session属性 - * @param request HTTP请求对象 - * @param attributeName 属性名 - * @return 属性值 - * @author yslg - * @since 2025-11-02 - */ - public static Object getSessionAttribute(HttpServletRequest request, String attributeName) { - HttpSession session = request.getSession(false); - return session != null ? session.getAttribute(attributeName) : null; - } - - /** - * @description 设置Session属性 - * @param request HTTP请求对象 - * @param attributeName 属性名 - * @param attributeValue 属性值 - * @return void - * @author yslg - * @since 2025-11-02 - */ - public static void setSessionAttribute(HttpServletRequest request, String attributeName, Object attributeValue) { - request.getSession().setAttribute(attributeName, attributeValue); - } - - /** - * @description 移除Session属性 - * @param request HTTP请求对象 - * @param attributeName 属性名 - * @return void - * @author yslg - * @since 2025-11-02 - */ - public static void removeSessionAttribute(HttpServletRequest request, String attributeName) { - HttpSession session = request.getSession(false); - if (session != null) { - session.removeAttribute(attributeName); - } - } - - /** - * @description 防止XSS攻击的字符串过滤 - * @param input 输入字符串 - * @return 过滤后的字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String escapeXss(String input) { - if (input == null) { - return null; - } - return input - .replace("<", "<") - .replace(">", ">") - .replace("'", "'") - .replace("\"", """) - .replace("&", "&"); - } - - /** - * @description 获取所有请求参数名 - * @param request HTTP请求对象 - * @return 参数名集合 - * @author yslg - * @since 2025-11-02 - */ - public static Set getParameterNames(HttpServletRequest request) { - Set paramNames = new HashSet<>(); - Enumeration names = request.getParameterNames(); - while (names.hasMoreElements()) { - paramNames.add(names.nextElement()); - } - return paramNames; - } -} \ No newline at end of file diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/StringUtils.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/StringUtils.java deleted file mode 100644 index bbdd1109..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/StringUtils.java +++ /dev/null @@ -1,235 +0,0 @@ -package org.xyzh.common.utils; - -/** - * @description StringUtils.java文件描述 字符串工具类 - * @filename StringUtils.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class StringUtils { - /** - * @description 字符串是否为空 - * @param str String 字符串 - * @return 是否为空 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isEmpty(String str) { - return str == null || str.isEmpty(); - } - - /** - * @description 字符串是否不为空 - * @param str String 字符串 - * @return 是否不为空 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isNotEmpty(String str) { - return !isEmpty(str); - } - - public static String format(String template, Object... args) { - if (template == null || args == null) return template; - return String.format(template, args); - } - - /** - * @description 去除字符串首尾空格 - * @param str String 字符串 - * @return 去除空格后的字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String trim(String str) { - return str == null ? null : str.trim(); - } - - /** - * @description 判断两个字符串是否相等(支持null) - * @param a String 字符串A - * @param b String 字符串B - * @return 是否相等 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean equals(String a, String b) { - return a == null ? b == null : a.equals(b); - } - - /** - * @description 判断字符串是否包含子串 - * @param str String 原字符串 - * @param sub String 子串 - * @return 是否包含 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean contains(String str, String sub) { - return str != null && sub != null && str.contains(sub); - } - - /** - * @description 字符串拼接(用分隔符) - * @param delimiter String 分隔符 - * @param elements String[] 待拼接字符串数组 - * @return 拼接后的字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String join(String delimiter, String... elements) { - if (elements == null) return null; - return String.join(delimiter, elements); - } - - /** - * @description 字符串分割 - * @param str String 原字符串 - * @param regex String 分割正则表达式 - * @return 分割后的字符串数组 - * @author yslg - * @since 2025-11-02 - */ - public static String[] split(String str, String regex) { - return str == null ? null : str.split(regex); - } - - /** - * @description 字符串替换 - * @param str String 原字符串 - * @param target String 替换目标 - * @param replacement String 替换内容 - * @return 替换后的字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String replace(String str, String target, String replacement) { - return str == null ? null : str.replace(target, replacement); - } - - /** - * @description 是否以指定前缀开头 - * @param str String 原字符串 - * @param prefix String 前缀 - * @return 是否以前缀开头 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean startsWith(String str, String prefix) { - return str != null && prefix != null && str.startsWith(prefix); - } - - /** - * @description 是否以指定后缀结尾 - * @param str String 原字符串 - * @param suffix String 后缀 - * @return 是否以后缀结尾 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean endsWith(String str, String suffix) { - return str != null && suffix != null && str.endsWith(suffix); - } - - /** - * @description 转为大写 - * @param str String 原字符串 - * @return 大写字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String toUpperCase(String str) { - return str == null ? null : str.toUpperCase(); - } - - /** - * @description 转为小写 - * @param str String 原字符串 - * @return 小写字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String toLowerCase(String str) { - return str == null ? null : str.toLowerCase(); - } - - /** - * @description 反转字符串 - * @param str String 原字符串 - * @return 反转后的字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String reverse(String str) { - if (str == null) return null; - return new StringBuilder(str).reverse().toString(); - } - - /** - * @description 重复字符串n次 - * @param str String 原字符串 - * @param n int 重复次数 - * @return 重复后的字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String repeat(String str, int n) { - if (str == null || n <= 0) return ""; - return str.repeat(n); - } - - /** - * @description 截取字符串 - * @param str String 原字符串 - * @param beginIndex int 起始索引 - * @param endIndex int 结束索引 - * @return 截取后的字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String substring(String str, int beginIndex, int endIndex) { - if (str == null) return null; - if (beginIndex < 0) beginIndex = 0; - if (endIndex > str.length()) endIndex = str.length(); - if (beginIndex > endIndex) return ""; - return str.substring(beginIndex, endIndex); - } - - /** - * @description 判断字符串是否为数字 - * @param str String 原字符串 - * @return 是否为数字 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isNumeric(String str) { - if (isEmpty(str)) return false; - for (int i = 0; i < str.length(); i++) { - if (!Character.isDigit(str.charAt(i))) return false; - } - return true; - } - - /** - * @description 字符串是否为空白 - * @param str String 原字符串 - * @return 是否为空白 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isBlank(String str) { - return str == null || str.isBlank(); - } - /** - * @description 字符串是否不为空白 - * @param str String 原字符串 - * @return 是否不为空白 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isNotBlank(String str) { - return !isBlank(str); - } - -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/TimeUtils.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/TimeUtils.java deleted file mode 100644 index 0f2a6d21..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/TimeUtils.java +++ /dev/null @@ -1,297 +0,0 @@ -package org.xyzh.common.utils; - -import java.text.DateFormat; -import java.time.Duration; -import java.time.format.DateTimeFormatter; -import java.util.Date; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.Instant; -import java.time.ZoneId; -import java.text.ParseException; -/** - * @description TimeUtils.java文件描述:时间相关的常用工具方法 - * @filename TimeUtils.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ - -public class TimeUtils { - - - /** - * @description 将时间戳字符串转为指定格式的日期时间字符串 - * @param time 毫秒时间戳字符串 - * @param format 日期格式化对象 - * @return 格式化后的日期时间字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String timeFormat(String time, DateFormat format){ - try { - Date date = format.parse(time); - return format.format(date); - } catch (ParseException e) { - return null; - } - } - - /** - * @description 格式化Date为指定格式字符串 - * @param date Date对象 - * @param pattern 格式化模式,如"yyyy-MM-dd HH:mm:ss" - * @return String 格式化后的字符串 - */ - public static String format(Date date, String pattern) { - if (date == null || pattern == null) return null; - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); - LocalDateTime ldt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); - return ldt.format(formatter); - } - - /** - * @description 格式化LocalDate为指定格式字符串 - * @param localDate LocalDate对象 - * @param pattern 格式化模式 - * @return 格式化后的字符串 - */ - public static String format(LocalDate localDate, String pattern) { - if (localDate == null || pattern == null) return null; - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); - return localDate.format(formatter); - } - - /** - * @description 格式化LocalDateTime为指定格式字符串 - * @param localDateTime LocalDateTime对象 - * @param pattern 格式化模式 - * @return 格式化后的字符串 - */ - public static String format(LocalDateTime localDateTime, String pattern) { - if (localDateTime == null || pattern == null) return null; - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); - return localDateTime.format(formatter); - } - - /** - * @description 格式化时间戳为指定格式字符串 - * @param timestampMillis 毫秒时间戳 - * @param pattern 格式化模式 - * @return 格式化后的字符串 - */ - public static String format(long timestampMillis, String pattern) { - if (pattern == null) return null; - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); - LocalDateTime ldt = Instant.ofEpochMilli(timestampMillis).atZone(ZoneId.systemDefault()).toLocalDateTime(); - return ldt.format(formatter); - } - - /** - * @description 将字符串按指定格式解析为LocalDateTime - * @param dateTimeStr 日期时间字符串 - * @param pattern 格式化模式 - * @return LocalDateTime对象,解析失败返回null - */ - public static LocalDateTime parseToLocalDateTime(String dateTimeStr, String pattern) { - if (dateTimeStr == null || pattern == null) return null; - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); - try { - return LocalDateTime.parse(dateTimeStr, formatter); - } catch (Exception e) { - return null; - } - } - - /** - * @description 将字符串按指定格式解析为LocalDate - * @param dateStr 日期字符串 - * @param pattern 格式化模式 - * @return LocalDate对象,解析失败返回null - */ - public static LocalDate parseToLocalDate(String dateStr, String pattern) { - if (dateStr == null || pattern == null) return null; - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); - try { - return LocalDate.parse(dateStr, formatter); - } catch (Exception e) { - return null; - } - } - - /** - * @description 将字符串或Date对象按指定DateTimeFormatter格式化为标准时间字符串(yyyy-MM-dd HH:mm:ss) - * @param input 可以为String类型的日期、Date对象或LocalDateTime对象 - * @param formatter 指定的DateTimeFormatter - * @return 标准化时间字符串,无法解析时返回null - */ - public static String normalizeToDateTimeString(Object input, DateTimeFormatter formatter) { - if (input == null || formatter == null) return null; - try { - if (input instanceof String str) { - LocalDateTime ldt; - try { - ldt = LocalDateTime.parse(str, formatter); - } catch (Exception e) { - LocalDate ld = LocalDate.parse(str, formatter); - ldt = ld.atStartOfDay(); - } - return ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - } - if (input instanceof Date date) { - LocalDateTime ldt = dateToLocalDateTime(date); - return ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - } - if (input instanceof LocalDateTime ldt) { - return ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - } - if (input instanceof LocalDate ld) { - return ld.atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - } - } catch (Exception e) { - return null; - } - return null; - } - - /** - * @description 获取当前时间戳,单位毫秒 - * @return 当前时间戳字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String getCurrentTimestamp() { - return String.valueOf(System.currentTimeMillis()); - } - - /** - * @description 获取当前时间戳,单位秒 - * @return 当前时间戳(秒)字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String getCurrentTimestampSeconds() { - return String.valueOf(System.currentTimeMillis() / 1000); - } - - /** - * @description 获取当前日期时间,格式:yyyy-MM-dd HH:mm:ss - * @return 当前日期时间字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String getCurrentDateTime() { - return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - } - - /** - * @description 获取当前日期,格式:yyyy-MM-dd - * @return 当前日期字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String getCurrentDate() { - return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); - } - - /** - * @description 获取当前时间,格式:HH:mm:ss - * @return 当前时间字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String getCurrentTime() { - return LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")); - } - - /** - * @description 将时间戳(毫秒)转为日期时间字符串,格式:yyyy-MM-dd HH:mm:ss - * @param timestampMillis 毫秒时间戳 - * @return 日期时间字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String timestampToDateTime(long timestampMillis) { - return Instant.ofEpochMilli(timestampMillis) - .atZone(ZoneId.systemDefault()) - .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - } - - /** - * @description 将日期时间字符串(yyyy-MM-dd HH:mm:ss)转为时间戳(毫秒) - * @param dateTimeStr 日期时间字符串 - * @return 毫秒时间戳 - * @author yslg - * @since 2025-11-02 - */ - public static long dateTimeToTimestamp(String dateTimeStr) { - LocalDateTime ldt = LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - return ldt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); - } - - /** - * @description 获取指定日期加减天数后的日期字符串(yyyy-MM-dd) - * @param dateStr 原始日期字符串 - * @param days 增加或减少的天数(可为负数) - * @return 计算后的日期字符串 - * @author yslg - * @since 2025-11-02 - */ - public static String plusDays(String dateStr, int days) { - LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - return date.plusDays(days).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); - } - - /** - * @description 获取两个日期之间的天数差 - * @param startDate 开始日期字符串(yyyy-MM-dd) - * @param endDate 结束日期字符串(yyyy-MM-dd) - * @return 天数差 - * @author yslg - * @since 2025-11-02 - */ - public static long daysBetween(String startDate, String endDate) { - LocalDate start = LocalDate.parse(startDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - LocalDate end = LocalDate.parse(endDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - return Duration.between(start.atStartOfDay(), end.atStartOfDay()).toDays(); - } - - /** - * @description 判断当前时间是否在指定时间段内 - * @param startTime 开始时间字符串(HH:mm:ss) - * @param endTime 结束时间字符串(HH:mm:ss) - * @return 是否在时间段内 - * @author yslg - * @since 2025-11-02 - */ - public static Boolean isNowBetween(String startTime, String endTime) { - LocalTime now = LocalTime.now(); - LocalTime start = LocalTime.parse(startTime, DateTimeFormatter.ofPattern("HH:mm:ss")); - LocalTime end = LocalTime.parse(endTime, DateTimeFormatter.ofPattern("HH:mm:ss")); - return !now.isBefore(start) && !now.isAfter(end); - } - - /** - * @description Date转LocalDateTime - * @param date java.util.Date对象 - * @return LocalDateTime对象 - * @author yslg - * @since 2025-11-02 - */ - public static LocalDateTime dateToLocalDateTime(Date date) { - return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); - } - - /** - * @description LocalDateTime转Date - * @param localDateTime LocalDateTime对象 - * @return java.util.Date对象 - * @author yslg - * @since 2025-11-02 - */ - public static Date localDateTimeToDate(LocalDateTime localDateTime) { - return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); - } - -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/config/FastJsonConfiguration.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/config/FastJsonConfiguration.java deleted file mode 100644 index c889bbae..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/config/FastJsonConfiguration.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.xyzh.common.utils.config; - -import com.alibaba.fastjson2.support.config.FastJsonConfig; -import com.alibaba.fastjson2.support.spring6.http.converter.FastJsonHttpMessageConverter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; - -/** - * @description FastJson配置类 - 统一处理日期时间格式序列化 - * @filename FastJsonConfig.java - * @author yslg - * @copyright xyzh - * @since 2025-11-28 - */ -@Configuration -@ConditionalOnClass(WebMvcConfigurer.class) -public class FastJsonConfiguration implements WebMvcConfigurer { - - /** - * 配置FastJson消息转换器 - */ - @Override - public void configureMessageConverters(List> converters) { - FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); - - // FastJson配置 - FastJsonConfig config = new FastJsonConfig(); - - // 设置日期格式 - config.setDateFormat("yyyy-MM-dd HH:mm:ss"); - - // 设置字符集 - converter.setDefaultCharset(StandardCharsets.UTF_8); - - // 设置支持的MediaType - converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON)); - - // 应用配置 - converter.setFastJsonConfig(config); - - // 添加到转换器列表(添加到最前面,优先使用) - converters.add(0, converter); - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/crypto/AesEncryptUtil.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/crypto/AesEncryptUtil.java deleted file mode 100644 index c841903a..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/crypto/AesEncryptUtil.java +++ /dev/null @@ -1,246 +0,0 @@ -package org.xyzh.common.utils.crypto; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.security.SecureRandom; -import java.util.Base64; - -/** - * AES-256-GCM 敏感数据加密工具类 - * 用于加密手机号、身份证号等敏感信息 - * - * @author yslg - * @since 2025-12-05 - */ -@Component -public class AesEncryptUtil { - - private static final String ALGORITHM = "AES"; - private static final String TRANSFORMATION = "AES/GCM/NoPadding"; - private static final int KEY_SIZE = 256; // AES-256 - private static final int GCM_IV_LENGTH = 12; // GCM 推荐 IV 长度 - private static final int GCM_TAG_LENGTH = 128; // GCM 认证标签长度 - - private SecretKey secretKey; - - /** - * 从配置文件读取密钥,如果没有则生成新密钥 - */ - public AesEncryptUtil(@Value("${security.aes.secret-key:}") String secretKeyString) { - try { - if (secretKeyString == null || secretKeyString.isEmpty()) { - // 生产环境应该从配置中心或密钥管理系统获取 - this.secretKey = generateKey(); - System.err.println("警告: 未配置 AES 密钥,使用临时生成的密钥。生产环境请配置 security.aes.secret-key"); - } else { - byte[] decodedKey = Base64.getDecoder().decode(secretKeyString); - if (decodedKey.length != 32) { - throw new IllegalArgumentException("AES-256 密钥长度必须是 32 字节,当前: " + decodedKey.length); - } - this.secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, ALGORITHM); - System.out.println("✓ AES-256 加密工具初始化成功"); - } - } catch (Exception e) { - System.err.println("❌ AES 密钥初始化失败: " + e.getMessage()); - // 生成临时密钥以避免启动失败 - this.secretKey = generateKey(); - System.err.println("已生成临时密钥,请尽快配置正确的 security.aes.secret-key"); - } - } - - /** - * 生成 AES-256 密钥 - */ - public static SecretKey generateKey() { - try { - KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM); - keyGen.init(KEY_SIZE, new SecureRandom()); - return keyGen.generateKey(); - } catch (Exception e) { - throw new RuntimeException("生成 AES 密钥失败", e); - } - } - - /** - * 将密钥转换为 Base64 字符串(用于配置) - */ - public static String keyToString(SecretKey key) { - return Base64.getEncoder().encodeToString(key.getEncoded()); - } - - /** - * 加密字符串 - * - * @param plaintext 明文 - * @return Base64 编码的密文(包含 IV) - */ - public String encrypt(String plaintext) { - if (plaintext == null || plaintext.isEmpty()) { - return plaintext; - } - - try { - // 生成随机 IV - byte[] iv = new byte[GCM_IV_LENGTH]; - new SecureRandom().nextBytes(iv); - - // 初始化加密器 - Cipher cipher = Cipher.getInstance(TRANSFORMATION); - GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); - cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec); - - // 加密 - byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)); - - // 将 IV 和密文组合在一起:[IV(12字节)][密文] - ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + ciphertext.length); - byteBuffer.put(iv); - byteBuffer.put(ciphertext); - - // Base64 编码 - return Base64.getEncoder().encodeToString(byteBuffer.array()); - } catch (Exception e) { - throw new RuntimeException("AES 加密失败", e); - } - } - - /** - * 解密字符串 - * - * @param ciphertext Base64 编码的密文(包含 IV) - * @return 明文 - */ - public String decrypt(String ciphertext) { - if (ciphertext == null || ciphertext.isEmpty()) { - return ciphertext; - } - - try { - // Base64 解码 - byte[] decoded = Base64.getDecoder().decode(ciphertext); - - // 提取 IV 和密文 - ByteBuffer byteBuffer = ByteBuffer.wrap(decoded); - byte[] iv = new byte[GCM_IV_LENGTH]; - byteBuffer.get(iv); - byte[] ciphertextBytes = new byte[byteBuffer.remaining()]; - byteBuffer.get(ciphertextBytes); - - // 初始化解密器 - Cipher cipher = Cipher.getInstance(TRANSFORMATION); - GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); - cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec); - - // 解密 - byte[] plaintext = cipher.doFinal(ciphertextBytes); - return new String(plaintext, StandardCharsets.UTF_8); - } catch (Exception e) { - throw new RuntimeException("AES 解密失败", e); - } - } - - /** - * 加密手机号(保留前3后4位) - * 例如:13812345678 -> 138****5678 - * 实际存储:加密后的完整手机号 - */ - public String encryptPhone(String phone) { - return encrypt(phone); - } - - /** - * 解密手机号 - */ - public String decryptPhone(String encryptedPhone) { - return decrypt(encryptedPhone); - } - - /** - * 加密身份证号(保留前6后4位) - * 例如:110101199001011234 -> 110101********1234 - * 实际存储:加密后的完整身份证号 - */ - public String encryptIdCard(String idCard) { - return encrypt(idCard); - } - - /** - * 解密身份证号 - */ - public String decryptIdCard(String encryptedIdCard) { - return decrypt(encryptedIdCard); - } - - /** - * 生成手机号Hash(用于数据库查询) - * 使用SHA-256生成固定Hash,相同手机号总是得到相同Hash - */ - public static String maskPhone(String phone) { - if (phone == null || phone.isEmpty()) { - return phone; - } - try { - java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256"); - byte[] hash = digest.digest(phone.getBytes(java.nio.charset.StandardCharsets.UTF_8)); - StringBuilder hexString = new StringBuilder(); - for (byte b : hash) { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) hexString.append('0'); - hexString.append(hex); - } - return hexString.toString(); - } catch (Exception e) { - throw new RuntimeException("生成手机号Hash失败", e); - } - } - - /** - * 脱敏显示手机号(用于前端显示) - */ - public static String maskPhoneDisplay(String phone) { - if (phone == null || phone.length() < 11) { - return phone; - } - return phone.substring(0, 3) + "****" + phone.substring(7); - } - - /** - * 脱敏显示身份证号 - */ - public static String maskIdCard(String idCard) { - if (idCard == null || idCard.length() < 18) { - return idCard; - } - return idCard.substring(0, 6) + "********" + idCard.substring(14); - } - - public static void main(String[] args) { - AesEncryptUtil aesEncryptUtil = new AesEncryptUtil("MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="); - String phone = "15170037929"; - - // 测试加密(每次都不同,不能用于查询) - String encryptedPhone1 = aesEncryptUtil.encryptPhone(phone); - String encryptedPhone2 = aesEncryptUtil.encryptPhone(phone); - System.out.println("第一次加密: " + encryptedPhone1); - System.out.println("第二次加密: " + encryptedPhone2); - System.out.println("两次加密相同? " + encryptedPhone1.equals(encryptedPhone2)); - - // 测试Hash(用于查询,相同手机号总是得到相同Hash) - String hash1 = AesEncryptUtil.maskPhone(phone); - String hash2 = AesEncryptUtil.maskPhone(phone); - System.out.println("\n第一次Hash: " + hash1); - System.out.println("第二次Hash: " + hash2); - System.out.println("两次Hash相同? " + hash1.equals(hash2)); - - // 测试脱敏显示 - System.out.println("\n脱敏显示: " + AesEncryptUtil.maskPhoneDisplay(phone)); - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/crypto/SensitiveDataUtil.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/crypto/SensitiveDataUtil.java deleted file mode 100644 index abcaebab..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/crypto/SensitiveDataUtil.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.xyzh.common.utils.crypto; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.util.Base64; - -/** - * 敏感数据处理工具类 - * 支持加密存储 + 哈希查询 - * - * 数据库设计: - * - phone_encrypted: 加密后的完整手机号(用于显示和解密) - * - phone_hash: 手机号的哈希值(用于查询,建立索引) - * - * @author yslg - * @since 2025-12-05 - */ -@Component -public class SensitiveDataUtil { - - @Autowired - private AesEncryptUtil aesEncryptUtil; - - /** - * 生成 SHA-256 哈希值(用于查询索引) - */ - public String hash(String plaintext) { - if (plaintext == null || plaintext.isEmpty()) { - return null; - } - try { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] hashBytes = digest.digest(plaintext.getBytes(StandardCharsets.UTF_8)); - return Base64.getEncoder().encodeToString(hashBytes); - } catch (Exception e) { - throw new RuntimeException("哈希计算失败", e); - } - } - - /** - * 处理手机号:返回加密值和哈希值 - */ - public PhoneData processPhone(String phone) { - if (phone == null || phone.isEmpty()) { - return new PhoneData(null, null); - } - return new PhoneData( - aesEncryptUtil.encryptPhone(phone), - hash(phone) - ); - } - - /** - * 处理身份证号:返回加密值和哈希值 - */ - public IdCardData processIdCard(String idCard) { - if (idCard == null || idCard.isEmpty()) { - return new IdCardData(null, null); - } - return new IdCardData( - aesEncryptUtil.encryptIdCard(idCard), - hash(idCard) - ); - } - - /** - * 手机号数据对象 - */ - public static class PhoneData { - private String encrypted; // 加密后的值(存储在 phone_encrypted) - private String hash; // 哈希值(存储在 phone_hash,用于查询) - - public PhoneData(String encrypted, String hash) { - this.encrypted = encrypted; - this.hash = hash; - } - - public String getEncrypted() { - return encrypted; - } - - public String getHash() { - return hash; - } - } - - /** - * 身份证号数据对象 - */ - public static class IdCardData { - private String encrypted; // 加密后的值 - private String hash; // 哈希值 - - public IdCardData(String encrypted, String hash) { - this.encrypted = encrypted; - this.hash = hash; - } - - public String getEncrypted() { - return encrypted; - } - - public String getHash() { - return hash; - } - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelColumnMapping.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelColumnMapping.java deleted file mode 100644 index ce42fd2d..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelColumnMapping.java +++ /dev/null @@ -1,208 +0,0 @@ -package org.xyzh.common.utils.excel; - -import org.xyzh.common.utils.validation.ValidationParam; - -import java.util.ArrayList; -import java.util.List; - -/** - * @description Excel列映射配置 - * @filename ExcelColumnMapping.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ExcelColumnMapping { - - /** - * @description Excel列名(表头名称) - */ - private String columnName; - - /** - * @description Excel列索引(从0开始,优先级高于列名) - */ - private Integer columnIndex; - - /** - * @description 对象字段名 - */ - private String fieldName; - - /** - * @description 字段类型 - */ - private Class fieldType; - - /** - * @description 是否必填 - */ - private Boolean required = false; - - /** - * @description 默认值 - */ - private String defaultValue; - - /** - * @description 日期格式(当字段类型为Date时使用) - */ - private String dateFormat = "yyyy-MM-dd"; - - /** - * @description 校验参数列表 - */ - private List validationParams; - - private ExcelColumnMapping() { - this.validationParams = new ArrayList<>(); - } - - public String getColumnName() { - return columnName; - } - - public Integer getColumnIndex() { - return columnIndex; - } - - public String getFieldName() { - return fieldName; - } - - public Class getFieldType() { - return fieldType; - } - - public Boolean isRequired() { - return required; - } - - public String getDefaultValue() { - return defaultValue; - } - - public String getDateFormat() { - return dateFormat; - } - - public List getValidationParams() { - return validationParams; - } - - /** - * @description Builder类 - */ - public static class Builder { - private ExcelColumnMapping mapping = new ExcelColumnMapping(); - - /** - * 设置Excel列名 - */ - public Builder columnName(String columnName) { - mapping.columnName = columnName; - return this; - } - - /** - * 设置Excel列索引(从0开始) - */ - public Builder columnIndex(int columnIndex) { - mapping.columnIndex = columnIndex; - return this; - } - - /** - * 设置对象字段名 - */ - public Builder fieldName(String fieldName) { - mapping.fieldName = fieldName; - return this; - } - - /** - * 设置字段类型 - */ - public Builder fieldType(Class fieldType) { - mapping.fieldType = fieldType; - return this; - } - - /** - * 设置是否必填 - */ - public Builder required(Boolean required) { - mapping.required = required; - return this; - } - - /** - * 设置为必填 - */ - public Builder required() { - mapping.required = true; - return this; - } - - /** - * 设置默认值 - */ - public Builder defaultValue(String defaultValue) { - mapping.defaultValue = defaultValue; - return this; - } - - /** - * 设置日期格式 - */ - public Builder dateFormat(String dateFormat) { - mapping.dateFormat = dateFormat; - return this; - } - - /** - * 添加校验参数 - */ - public Builder addValidation(ValidationParam param) { - mapping.validationParams.add(param); - return this; - } - - /** - * 设置校验参数列表 - */ - public Builder validations(List params) { - mapping.validationParams = params; - return this; - } - - public ExcelColumnMapping build() { - if (mapping.fieldName == null || mapping.fieldName.isEmpty()) { - throw new IllegalArgumentException("字段名不能为空"); - } - if (mapping.columnName == null && mapping.columnIndex == null) { - throw new IllegalArgumentException("必须指定列名或列索引"); - } - if (mapping.fieldType == null) { - mapping.fieldType = String.class; - } - return mapping; - } - } - - public static Builder builder() { - return new Builder(); - } - - @Override - public String toString() { - return "ExcelColumnMapping{" + - "columnName='" + columnName + '\'' + - ", columnIndex=" + columnIndex + - ", fieldName='" + fieldName + '\'' + - ", fieldType=" + (fieldType != null ? fieldType.getSimpleName() : "null") + - ", required=" + required + - '}'; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelReadResult.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelReadResult.java deleted file mode 100644 index 3e46fa40..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelReadResult.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.xyzh.common.utils.excel; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @description Excel读取结果 - * @filename ExcelReadResult.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ExcelReadResult { - - /** - * @description 是否成功 - */ - private Boolean success; - - /** - * @description 成功读取的数据列表 - */ - private List dataList; - - /** - * @description 失败的行数据(行号 -> 错误信息) - */ - private Map errorRowsMap; - - /** - * @description 总行数(不包括表头) - */ - private int totalRows; - - /** - * @description 成功行数 - */ - private int successRows; - - /** - * @description 失败行数 - */ - private int errorRowsCount; - - /** - * @description 错误信息 - */ - private String errorMessage; - - public ExcelReadResult() { - this.success = true; - this.dataList = new ArrayList<>(); - this.errorRowsMap = new HashMap<>(); - this.totalRows = 0; - this.successRows = 0; - this.errorRowsCount = 0; - } - - public Boolean isSuccess() { - return success; - } - - public void setSuccess(Boolean success) { - this.success = success; - } - - public List getDataList() { - return dataList; - } - - public void setDataList(List dataList) { - this.dataList = dataList; - } - - public Map getErrorRows() { - return errorRowsMap; - } - - public void setErrorRows(Map errorRowsMap) { - this.errorRowsMap = errorRowsMap; - } - - public int getTotalRows() { - return totalRows; - } - - public void setTotalRows(int totalRows) { - this.totalRows = totalRows; - } - - public int getSuccessRows() { - return successRows; - } - - public void setSuccessRows(int successRows) { - this.successRows = successRows; - } - - public int getErrorRowsCount() { - return errorRowsCount; - } - - public void setErrorRowsCount(int errorRowsCount) { - this.errorRowsCount = errorRowsCount; - } - - public String getErrorMessage() { - return errorMessage; - } - - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } - - public void addData(T data) { - this.dataList.add(data); - this.successRows++; - } - - public void addError(int rowNum, String error) { - this.errorRowsMap.put(rowNum, error); - this.errorRowsCount++; - } - - public Boolean hasErrors() { - return this.errorRowsCount > 0; - } - - @Override - public String toString() { - return "ExcelReadResult{" + - "success=" + success + - ", totalRows=" + totalRows + - ", successRows=" + successRows + - ", errorRows=" + errorRowsCount + - ", errorMessage='" + errorMessage + '\'' + - '}'; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelReaderUtils.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelReaderUtils.java deleted file mode 100644 index 0831112c..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelReaderUtils.java +++ /dev/null @@ -1,426 +0,0 @@ -package org.xyzh.common.utils.excel; - -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.*; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.xyzh.common.utils.validation.ValidationParam; -import org.xyzh.common.utils.validation.ValidationResult; -import org.xyzh.common.utils.validation.ValidationUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.text.SimpleDateFormat; -import java.util.*; - -/** - * @description Excel读取工具类(非泛型版本) - * @filename ExcelReaderUtils.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ExcelReaderUtils { - - /** - * @description 从文件读取Excel - * @param file Excel文件 - * @param targetClass 目标对象Class - * @param columnMappings Excel列映射配置列表 - * @return ExcelReadResult - */ - public static ExcelReadResult readExcel(File file, Class targetClass, List columnMappings) { - try (FileInputStream fis = new FileInputStream(file)) { - return readExcel(fis, file.getName(), targetClass, columnMappings, new HashMap<>()); - } catch (Exception e) { - ExcelReadResult result = new ExcelReadResult<>(); - result.setSuccess(false); - result.setErrorMessage("读取Excel文件失败: " + e.getMessage()); - return result; - } - } - - /** - * @description 从文件读取Excel(带配置) - * @param file Excel文件 - * @param targetClass 目标对象Class - * @param columnMappings Excel列映射配置列表 - * @param options 配置选项 - * @return ExcelReadResult - */ - public static ExcelReadResult readExcel(File file, Class targetClass, - List columnMappings, - Map options) { - try (FileInputStream fis = new FileInputStream(file)) { - return readExcel(fis, file.getName(), targetClass, columnMappings, options); - } catch (Exception e) { - ExcelReadResult result = new ExcelReadResult<>(); - result.setSuccess(false); - result.setErrorMessage("读取Excel文件失败: " + e.getMessage()); - return result; - } - } - - /** - * @description 从输入流读取Excel - * @param inputStream 输入流 - * @param fileName 文件名 - * @param targetClass 目标对象Class - * @param columnMappings Excel列映射配置列表 - * @return ExcelReadResult - */ - public static ExcelReadResult readExcel(InputStream inputStream, String fileName, - Class targetClass, - List columnMappings) { - return readExcel(inputStream, fileName, targetClass, columnMappings, new HashMap<>()); - } - - /** - * @description 从输入流读取Excel(带配置) - * @param inputStream 输入流 - * @param fileName 文件名 - * @param targetClass 目标对象Class - * @param columnMappings Excel列映射配置列表 - * @param options 配置选项(headerRowIndex, dataStartRowIndex, sheetIndex, sheetName, skipEmptyRow, maxRows, continueOnError) - * @return ExcelReadResult - */ - public static ExcelReadResult readExcel(InputStream inputStream, String fileName, - Class targetClass, - List columnMappings, - Map options) { - ExcelReadResult result = new ExcelReadResult<>(); - - try { - // 获取配置 - int headerRowIndex = (int) options.getOrDefault("headerRowIndex", 0); - int dataStartRowIndex = (int) options.getOrDefault("dataStartRowIndex", 1); - int sheetIndex = (int) options.getOrDefault("sheetIndex", 0); - String sheetName = (String) options.get("sheetName"); - Boolean skipEmptyRow = (Boolean) options.getOrDefault("skipEmptyRow", true); - int maxRows = (int) options.getOrDefault("maxRows", 0); - Boolean continueOnError = (Boolean) options.getOrDefault("continueOnError", true); - - // 创建Workbook - Workbook workbook = createWorkbook(inputStream, fileName); - - // 获取Sheet - Sheet sheet = getSheet(workbook, sheetIndex, sheetName); - if (sheet == null) { - result.setSuccess(false); - result.setErrorMessage("未找到指定的Sheet"); - return result; - } - - // 解析表头 - Map headerMap = parseHeader(sheet, headerRowIndex); - - // 读取数据 - readData(sheet, headerMap, targetClass, columnMappings, dataStartRowIndex, - skipEmptyRow, maxRows, continueOnError, result); - - workbook.close(); - - } catch (Exception e) { - result.setSuccess(false); - result.setErrorMessage("读取Excel失败: " + e.getMessage()); - } - - return result; - } - - /** - * @description 创建Workbook对象 - */ - private static Workbook createWorkbook(InputStream inputStream, String fileName) throws Exception { - if (fileName.endsWith(".xlsx")) { - return new XSSFWorkbook(inputStream); - } else if (fileName.endsWith(".xls")) { - return new HSSFWorkbook(inputStream); - } else { - throw new IllegalArgumentException("不支持的文件格式,仅支持.xls和.xlsx"); - } - } - - /** - * @description 获取Sheet - */ - private static Sheet getSheet(Workbook workbook, int sheetIndex, String sheetName) { - if (sheetName != null && !sheetName.isEmpty()) { - return workbook.getSheet(sheetName); - } else { - return workbook.getSheetAt(sheetIndex); - } - } - - /** - * @description 解析表头 - */ - private static Map parseHeader(Sheet sheet, int headerRowIndex) { - Map headerMap = new HashMap<>(); - Row headerRow = sheet.getRow(headerRowIndex); - - if (headerRow != null) { - for (Cell cell : headerRow) { - String headerName = getCellValue(cell).toString().trim(); - if (!headerName.isEmpty()) { - headerMap.put(headerName, cell.getColumnIndex()); - } - } - } - - return headerMap; - } - - /** - * @description 读取数据 - */ - private static void readData(Sheet sheet, Map headerMap, - Class targetClass, List columnMappings, - int startRow, Boolean skipEmptyRow, int maxRows, - Boolean continueOnError, ExcelReadResult result) { - int lastRowNum = sheet.getLastRowNum(); - int endRow = maxRows > 0 ? Math.min(startRow + maxRows, lastRowNum + 1) : lastRowNum + 1; - - for (int rowNum = startRow; rowNum < endRow; rowNum++) { - Row row = sheet.getRow(rowNum); - - // 跳过空行 - if (skipEmptyRow && isEmptyRow(row)) { - continue; - } - - result.setTotalRows(result.getTotalRows() + 1); - - try { - // 将行数据转换为对象 - Object data = convertRowToObject(row, headerMap, targetClass, columnMappings, rowNum + 1); - - // 数据校验 - List allValidations = new ArrayList<>(); - for (ExcelColumnMapping mapping : columnMappings) { - if (!mapping.getValidationParams().isEmpty()) { - allValidations.addAll(mapping.getValidationParams()); - } - } - - if (!allValidations.isEmpty()) { - ValidationResult validationResult = ValidationUtils.validate(data, allValidations); - if (!validationResult.isValid()) { - result.addError(rowNum + 1, validationResult.getFirstError()); - if (!continueOnError) { - break; - } - continue; - } - } - - result.addData(data); - - } catch (Exception e) { - result.addError(rowNum + 1, e.getMessage()); - if (!continueOnError) { - break; - } - } - } - } - - /** - * @description 判断是否为空行 - */ - private static Boolean isEmptyRow(Row row) { - if (row == null) { - return true; - } - - for (Cell cell : row) { - if (cell != null && cell.getCellType() != CellType.BLANK) { - String value = getCellValue(cell).toString().trim(); - if (!value.isEmpty()) { - return false; - } - } - } - - return true; - } - - /** - * @description 将行数据转换为对象 - */ - private static Object convertRowToObject(Row row, Map headerMap, - Class targetClass, List columnMappings, - int rowNum) throws Exception { - Object obj = targetClass.getDeclaredConstructor().newInstance(); - - for (ExcelColumnMapping mapping : columnMappings) { - // 获取单元格 - Cell cell = getCell(row, mapping, headerMap); - - // 获取单元格值 - Object cellValue = getCellValue(cell); - - // 处理空值 - if (cellValue == null || cellValue.toString().trim().isEmpty()) { - if (mapping.isRequired()) { - throw new IllegalArgumentException("第" + rowNum + "行,字段[" + - (mapping.getColumnName() != null ? mapping.getColumnName() : "索引" + mapping.getColumnIndex()) - + "]不能为空"); - } - // 使用默认值 - if (mapping.getDefaultValue() != null && !mapping.getDefaultValue().isEmpty()) { - cellValue = mapping.getDefaultValue(); - } else { - continue; - } - } - - // 类型转换 - Object fieldValue = convertValue(cellValue, mapping.getFieldType(), mapping.getDateFormat()); - - // 设置字段值 - Field field = getField(targetClass, mapping.getFieldName()); - field.setAccessible(true); - field.set(obj, fieldValue); - } - - return obj; - } - - /** - * @description 获取字段(支持父类) - */ - private static Field getField(Class clazz, String fieldName) throws NoSuchFieldException { - try { - return clazz.getDeclaredField(fieldName); - } catch (NoSuchFieldException e) { - // 尝试从父类获取 - Class superClass = clazz.getSuperclass(); - if (superClass != null) { - return getField(superClass, fieldName); - } - throw e; - } - } - - /** - * @description 获取单元格 - */ - private static Cell getCell(Row row, ExcelColumnMapping mapping, Map headerMap) { - if (row == null) { - return null; - } - - // 优先使用索引 - if (mapping.getColumnIndex() != null) { - return row.getCell(mapping.getColumnIndex()); - } - - // 使用列名 - Integer columnIndex = headerMap.get(mapping.getColumnName()); - if (columnIndex != null) { - return row.getCell(columnIndex); - } - - return null; - } - - /** - * @description 获取单元格值 - */ - private static Object getCellValue(Cell cell) { - if (cell == null) { - return null; - } - - switch (cell.getCellType()) { - case STRING: - return cell.getStringCellValue(); - case NUMERIC: - if (DateUtil.isCellDateFormatted(cell)) { - return cell.getDateCellValue(); - } else { - return cell.getNumericCellValue(); - } - case BOOLEAN: - return cell.getBooleanCellValue(); - case FORMULA: - return cell.getCellFormula(); - case BLANK: - return ""; - default: - return cell.toString(); - } - } - - /** - * @description 类型转换 - */ - private static Object convertValue(Object value, Class targetType, String dateFormat) throws Exception { - if (value == null) { - return null; - } - - String strValue = value.toString().trim(); - - // String类型 - if (targetType == String.class) { - return strValue; - } - - // INTEGER类型 - if (targetType == Integer.class || targetType == int.class) { - if (value instanceof Number) { - return ((Number) value).intValue(); - } - return Integer.parseInt(strValue); - } - - // Long类型 - if (targetType == Long.class || targetType == long.class) { - if (value instanceof Number) { - return ((Number) value).longValue(); - } - return Long.parseLong(strValue); - } - - // Double类型 - if (targetType == Double.class || targetType == double.class) { - if (value instanceof Number) { - return ((Number) value).doubleValue(); - } - return Double.parseDouble(strValue); - } - - // Float类型 - if (targetType == Float.class || targetType == float.class) { - if (value instanceof Number) { - return ((Number) value).floatValue(); - } - return Float.parseFloat(strValue); - } - - // BOOLEAN类型 - if (targetType == Boolean.class || targetType == boolean.class) { - if (value instanceof Boolean) { - return value; - } - return Boolean.parseBoolean(strValue) || "1".equals(strValue) || - "是".equals(strValue) || "true".equalsIgnoreCase(strValue); - } - - // Date类型 - if (targetType == Date.class) { - if (value instanceof Date) { - return value; - } - SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); - return sdf.parse(strValue); - } - - // 其他类型 - return value; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelUtilsExample.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelUtilsExample.java deleted file mode 100644 index c5c946f0..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/ExcelUtilsExample.java +++ /dev/null @@ -1,429 +0,0 @@ -package org.xyzh.common.utils.excel; - -import org.xyzh.common.utils.validation.ValidationParam; -import org.xyzh.common.utils.validation.method.ValidateMethodType; - -import java.io.File; -import java.util.*; - -/** - * @description Excel工具使用示例 - * @filename ExcelUtilsExample.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ExcelUtilsExample { - - /** - * 示例实体类:用户信息 - */ - public static class UserInfo { - private String name; - private Integer age; - private String phone; - private String email; - private String idCard; - private Date joinDate; - private Boolean active; - - // Getters and Setters - public String getName() { return name; } - public void setName(String name) { this.name = name; } - - public Integer getAge() { return age; } - public void setAge(Integer age) { this.age = age; } - - public String getPhone() { return phone; } - public void setPhone(String phone) { this.phone = phone; } - - public String getEmail() { return email; } - public void setEmail(String email) { this.email = email; } - - public String getIdCard() { return idCard; } - public void setIdCard(String idCard) { this.idCard = idCard; } - - public Date getJoinDate() { return joinDate; } - public void setJoinDate(Date joinDate) { this.joinDate = joinDate; } - - public Boolean getActive() { return active; } - public void setActive(Boolean active) { this.active = active; } - - @Override - public String toString() { - return "UserInfo{" + - "name='" + name + '\'' + - ", age=" + age + - ", phone='" + phone + '\'' + - ", email='" + email + '\'' + - ", idCard='" + idCard + '\'' + - ", joinDate=" + joinDate + - ", active=" + active + - '}'; - } - } - - /** - * 示例1:基本使用 - */ - public static void example1_BasicUsage() { - System.out.println("========== 示例1: 基本使用 =========="); - - // 1. 定义列映射关系 - List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnName("姓名") - .fieldName("name") - .fieldType(String.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnName("年龄") - .fieldName("age") - .fieldType(Integer.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnName("手机号") - .fieldName("phone") - .fieldType(String.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnName("邮箱") - .fieldName("email") - .fieldType(String.class) - .validations(Arrays.asList( - ValidationParam.builder() - .fieldName("email") - .fieldLabel("邮箱") - .required() - .validateMethod(ValidateMethodType.EMAIL) - .build() - )) - .build(), - - ExcelColumnMapping.builder() - .columnName("入职日期") - .fieldName("joinDate") - .fieldType(Date.class) - .dateFormat("yyyy-MM-dd") - .build(), - - ExcelColumnMapping.builder() - .columnName("是否在职") - .fieldName("active") - .fieldType(Boolean.class) - .defaultValue("true") - .build() - ); - - // 2. 读取Excel - File file = new File("users.xlsx"); - ExcelReadResult result = ExcelReaderUtils.readExcel( - file, - UserInfo.class, - columnMappings - ); - - // 3. 处理结果 - if (result.isSuccess()) { - System.out.println("读取成功!"); - System.out.println("总行数: " + result.getTotalRows()); - System.out.println("成功行数: " + result.getSuccessRows()); - - for (Object obj : result.getDataList()) { - UserInfo user = (UserInfo) obj; - System.out.println(user); - } - } else { - System.out.println("读取失败: " + result.getErrorMessage()); - } - } - - /** - * 示例2:带数据校验 - */ - public static void example2_WithValidation() { - System.out.println("\n========== 示例2: 带数据校验 =========="); - - // 定义列映射关系(带校验) - List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnName("姓名") - .fieldName("name") - .fieldType(String.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("name") - .fieldLabel("姓名") - .required() - .minLength(2) - .maxLength(20) - .validateMethod(ValidateMethodType.CHINESE) - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("年龄") - .fieldName("age") - .fieldType(Integer.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("age") - .fieldLabel("年龄") - .required() - .customValidator(value -> { - Integer age = (Integer) value; - return age >= 18 && age <= 65; - }) - .customErrorMessage("年龄必须在18-65岁之间") - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("手机号") - .fieldName("phone") - .fieldType(String.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("phone") - .fieldLabel("手机号") - .required() - .validateMethod(ValidateMethodType.PHONE) - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("邮箱") - .fieldName("email") - .fieldType(String.class) - .addValidation( - ValidationParam.builder() - .fieldName("email") - .fieldLabel("邮箱") - .required(false) - .validateMethod(ValidateMethodType.EMAIL) - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("身份证号") - .fieldName("idCard") - .fieldType(String.class) - .addValidation( - ValidationParam.builder() - .fieldName("idCard") - .fieldLabel("身份证号") - .required(false) - .validateMethod(ValidateMethodType.ID_CARD) - .build() - ) - .build() - ); - - // 读取配置 - Map options = new HashMap<>(); - options.put("continueOnError", true); // 遇到错误继续读取 - - File file = new File("users.xlsx"); - ExcelReadResult result = ExcelReaderUtils.readExcel( - file, - UserInfo.class, - columnMappings, - options - ); - - // 处理结果 - System.out.println("读取完成!"); - System.out.println("总行数: " + result.getTotalRows()); - System.out.println("成功行数: " + result.getSuccessRows()); - System.out.println("失败行数: " + result.getErrorRowsCount()); - - // 显示错误信息 - if (result.hasErrors()) { - System.out.println("\n错误信息:"); - result.getErrorRows().forEach((rowNum, error) -> { - System.out.println("第" + rowNum + "行: " + error); - }); - } - } - - /** - * 示例3:使用列索引 - */ - public static void example3_UseColumnIndex() { - System.out.println("\n========== 示例3: 使用列索引 =========="); - - // 使用列索引而非列名 - List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnIndex(0) // 第1列 - .fieldName("name") - .fieldType(String.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnIndex(1) // 第2列 - .fieldName("age") - .fieldType(Integer.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnIndex(2) // 第3列 - .fieldName("phone") - .fieldType(String.class) - .required() - .build() - ); - - File file = new File("users.xlsx"); - ExcelReadResult result = ExcelReaderUtils.readExcel( - file, - UserInfo.class, - columnMappings - ); - - System.out.println("成功读取: " + result.getSuccessRows() + " 行"); - } - - /** - * 示例4:自定义配置 - */ - public static void example4_CustomConfig() { - System.out.println("\n========== 示例4: 自定义配置 =========="); - - List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnName("姓名") - .fieldName("name") - .fieldType(String.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnName("年龄") - .fieldName("age") - .fieldType(Integer.class) - .required() - .build() - ); - - // 自定义配置 - Map options = new HashMap<>(); - options.put("sheetName", "员工信息"); // 指定Sheet名称 - options.put("headerRowIndex", 0); // 表头在第1行 - options.put("dataStartRowIndex", 1); // 数据从第2行开始 - options.put("skipEmptyRow", true); // 跳过空行 - options.put("maxRows", 1000); // 最多读取1000行 - options.put("continueOnError", true); // 遇到错误继续 - - File file = new File("users.xlsx"); - ExcelReadResult result = ExcelReaderUtils.readExcel( - file, - UserInfo.class, - columnMappings, - options - ); - - System.out.println("读取结果: " + result); - } - - /** - * 示例5:在Controller中使用 - */ - public static void example5_InController() { - System.out.println("\n========== 示例5: 在Controller中使用(代码示例)=========="); - System.out.println(""" - @PostMapping("/import") - public ResultDomain importUsers(@RequestParam("file") MultipartFile file) { - try { - // 1. 定义列映射关系 - List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnName("姓名") - .fieldName("name") - .fieldType(String.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("name") - .fieldLabel("姓名") - .required() - .validateMethod(ValidateMethodType.CHINESE) - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("手机号") - .fieldName("phone") - .fieldType(String.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("phone") - .fieldLabel("手机号") - .required() - .validateMethod(ValidateMethodType.PHONE) - .build() - ) - .build() - ); - - // 2. 读取Excel - ExcelReadResult result = ExcelReaderUtils.readExcel( - file.getInputStream(), - file.getOriginalFilename(), - UserInfo.class, - columnMappings - ); - - // 3. 处理结果 - if (result.hasErrors()) { - StringBuilder errorMsg = new StringBuilder(); - errorMsg.append("导入失败,共").append(result.getErrorRowsCount()).append("行数据有误:\\n"); - result.getErrorRows().forEach((rowNum, error) -> { - errorMsg.append("第").append(rowNum).append("行: ").append(error).append("\\n"); - }); - return ResultDomain.fail(errorMsg.toString()); - } - - // 4. 保存数据 - List users = new ArrayList<>(); - for (Object obj : result.getDataList()) { - users.add((UserInfo) obj); - } - userService.batchSave(users); - - return ResultDomain.success("导入成功,共导入" + result.getSuccessRows() + "条数据"); - - } catch (Exception e) { - return ResultDomain.fail("导入失败: " + e.getMessage()); - } - } - """); - } - - public static void main(String[] args) { - // 运行示例 - // example1_BasicUsage(); - // example2_WithValidation(); - // example3_UseColumnIndex(); - // example4_CustomConfig(); - example5_InController(); - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/README.md b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/README.md deleted file mode 100644 index 6095dd91..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/excel/README.md +++ /dev/null @@ -1,542 +0,0 @@ -# Excel读取工具使用说明 - -## 概述 - -这是一个功能强大的Excel读取工具,通过配置 **Excel列对象** 来定义Excel列与Java对象字段的映射关系,支持自动构建对象并集成数据校验功能。 - -## 核心组件 - -### 1. ExcelColumnMapping - Excel列映射配置 -定义Excel列与对象字段的映射关系: -- **columnName** - Excel列名(表头名称) -- **columnIndex** - Excel列索引(从0开始,优先级高于列名) -- **fieldName** - 对象字段名 -- **fieldType** - 字段类型 -- **required** - 是否必填 -- **defaultValue** - 默认值 -- **dateFormat** - 日期格式 -- **validationParams** - 校验参数列表 - -### 2. ExcelReaderUtils - Excel读取工具类 -提供静态方法读取Excel: -- `readExcel(File, Class, List)` - 从文件读取 -- `readExcel(File, Class, List, Map)` - 从文件读取(带配置) -- `readExcel(InputStream, fileName, Class, List)` - 从输入流读取 -- `readExcel(InputStream, fileName, Class, List, Map)` - 从输入流读取(带配置) - -### 3. ExcelReadResult - 读取结果 -包含读取结果的详细信息: -- 成功数据列表 -- 错误行信息(行号 -> 错误消息) -- 统计信息(总行数、成功数、失败数) - -## 基本使用 - -### 1. 定义实体类 - -```java -public class UserInfo { - private String name; - private Integer age; - private String phone; - private String email; - private Date joinDate; - private Boolean active; - - // Getters and Setters... -} -``` - -### 2. 定义列映射关系 - -```java -List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnName("姓名") // Excel列名 - .fieldName("name") // 对象字段名 - .fieldType(String.class) // 字段类型 - .required() // 必填 - .build(), - - ExcelColumnMapping.builder() - .columnName("年龄") - .fieldName("age") - .fieldType(Integer.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnName("手机号") - .fieldName("phone") - .fieldType(String.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnName("邮箱") - .fieldName("email") - .fieldType(String.class) - .build(), - - ExcelColumnMapping.builder() - .columnName("入职日期") - .fieldName("joinDate") - .fieldType(Date.class) - .dateFormat("yyyy-MM-dd") - .build(), - - ExcelColumnMapping.builder() - .columnName("是否在职") - .fieldName("active") - .fieldType(Boolean.class) - .defaultValue("true") - .build() -); -``` - -### 3. 读取Excel - -```java -// 读取文件 -File file = new File("users.xlsx"); -ExcelReadResult result = ExcelReaderUtils.readExcel( - file, - UserInfo.class, - columnMappings -); - -// 处理结果 -if (result.isSuccess()) { - for (Object obj : result.getDataList()) { - UserInfo user = (UserInfo) obj; - System.out.println(user); - } - System.out.println("成功读取: " + result.getSuccessRows() + " 行"); -} -``` - -### 4. 带数据校验的读取 - -```java -// 定义列映射关系(带校验) -List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnName("姓名") - .fieldName("name") - .fieldType(String.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("name") - .fieldLabel("姓名") - .required() - .minLength(2) - .maxLength(20) - .validateMethod(ValidateMethodType.CHINESE) - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("年龄") - .fieldName("age") - .fieldType(Integer.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("age") - .fieldLabel("年龄") - .required() - .customValidator(value -> { - Integer age = (Integer) value; - return age >= 18 && age <= 65; - }) - .customErrorMessage("年龄必须在18-65岁之间") - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("手机号") - .fieldName("phone") - .fieldType(String.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("phone") - .fieldLabel("手机号") - .required() - .validateMethod(ValidateMethodType.PHONE) - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("邮箱") - .fieldName("email") - .fieldType(String.class) - .addValidation( - ValidationParam.builder() - .fieldName("email") - .fieldLabel("邮箱") - .required(false) - .validateMethod(ValidateMethodType.EMAIL) - .build() - ) - .build() -); - -// 配置选项 -Map options = new HashMap<>(); -options.put("continueOnError", true); // 遇到错误继续读取 - -// 读取Excel -File file = new File("users.xlsx"); -ExcelReadResult result = ExcelReaderUtils.readExcel( - file, - UserInfo.class, - columnMappings, - options -); - -// 处理结果 -System.out.println("总行数: " + result.getTotalRows()); -System.out.println("成功: " + result.getSuccessRows()); -System.out.println("失败: " + result.getErrorRowsCount()); - -// 显示错误 -if (result.hasErrors()) { - result.getErrorRows().forEach((rowNum, error) -> { - System.out.println("第" + rowNum + "行: " + error); - }); -} -``` - -### 5. 使用列索引而非列名 - -```java -// 使用列索引(从0开始) -List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnIndex(0) // 第1列 - .fieldName("name") - .fieldType(String.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnIndex(1) // 第2列 - .fieldName("age") - .fieldType(Integer.class) - .required() - .build(), - - ExcelColumnMapping.builder() - .columnIndex(2) // 第3列 - .fieldName("phone") - .fieldType(String.class) - .required() - .build() -); - -File file = new File("users.xlsx"); -ExcelReadResult result = ExcelReaderUtils.readExcel( - file, - UserInfo.class, - columnMappings -); -``` - -### 6. 自定义配置选项 - -以下是旧版本的校验代码,现在已经整合到ExcelColumnMapping中: - -```java -// 旧版本(已弃用) -List validationParams = Arrays.asList( - ValidationParam.builder() - .fieldName("name") - .fieldLabel("姓名") - .required() - .minLength(2) - .maxLength(20) - .validateMethod(ValidateMethodType.CHINESE) - .build(), - - ValidationParam.builder() - .fieldName("phone") - .fieldLabel("手机号") - .required() - .validateMethod(ValidateMethodType.PHONE) - .build(), - - ValidationParam.builder() - .fieldName("email") - .fieldLabel("邮箱") - .required(false) - .validateMethod(ValidateMethodType.EMAIL) - .build(), - - ValidationParam.builder() - .fieldName("age") - .fieldLabel("年龄") - .required() - .customValidator(value -> { - Integer age = (Integer) value; - return age >= 18 && age <= 65; - }) - .customErrorMessage("年龄必须在18-65岁之间") - .build() -); - -// 创建配置 -ExcelReaderConfig config = new ExcelReaderConfig<>(UserInfo.class) - .setValidationParams(validationParams) - .setContinueOnError(true); // 遇到错误继续读取 - -// 读取 -ExcelReader reader = ExcelReader.create(config); -ExcelReadResult result = reader.read(file); - -// 处理结果 -System.out.println("总行数: " + result.getTotalRows()); -System.out.println("成功: " + result.getSuccessRows()); -System.out.println("失败: " + result.getErrorRowsCount()); - -// 显示错误 -if (result.hasErrors()) { - result.getErrorRows().forEach((rowNum, error) -> { - System.out.println("第" + rowNum + "行: " + error); - }); -} -``` - -```java -List columnMappings = Arrays.asList( - // 列映射配置... -); - -// 自定义配置选项 -Map options = new HashMap<>(); -options.put("sheetName", "员工信息"); // 指定Sheet名称 -options.put("headerRowIndex", 0); // 表头在第1行 -options.put("dataStartRowIndex", 1); // 数据从第2行开始 -options.put("skipEmptyRow", true); // 跳过空行 -options.put("maxRows", 1000); // 最多读取1000行 -options.put("continueOnError", true); // 遇到错误继续 - -File file = new File("users.xlsx"); -ExcelReadResult result = ExcelReaderUtils.readExcel( - file, - UserInfo.class, - columnMappings, - options -); -``` - -## 在Controller中使用 - -```java -@PostMapping("/import") -public ResultDomain importUsers(@RequestParam("file") MultipartFile file) { - try { - // 1. 定义列映射关系(带校验) - List columnMappings = Arrays.asList( - ExcelColumnMapping.builder() - .columnName("姓名") - .fieldName("name") - .fieldType(String.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("name") - .fieldLabel("姓名") - .required() - .validateMethod(ValidateMethodType.CHINESE) - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("手机号") - .fieldName("phone") - .fieldType(String.class) - .required() - .addValidation( - ValidationParam.builder() - .fieldName("phone") - .fieldLabel("手机号") - .required() - .validateMethod(ValidateMethodType.PHONE) - .build() - ) - .build(), - - ExcelColumnMapping.builder() - .columnName("邮箱") - .fieldName("email") - .fieldType(String.class) - .addValidation( - ValidationParam.builder() - .fieldName("email") - .fieldLabel("邮箱") - .validateMethod(ValidateMethodType.EMAIL) - .build() - ) - .build() - ); - - // 2. 读取Excel - ExcelReadResult result = ExcelReaderUtils.readExcel( - file.getInputStream(), - file.getOriginalFilename(), - UserInfo.class, - columnMappings - ); - - // 3. 处理结果 - if (result.hasErrors()) { - StringBuilder errorMsg = new StringBuilder(); - errorMsg.append("导入失败,共").append(result.getErrorRowsCount()).append("行数据有误:\n"); - result.getErrorRows().forEach((rowNum, error) -> { - errorMsg.append("第").append(rowNum).append("行: ").append(error).append("\n"); - }); - return ResultDomain.fail(errorMsg.toString()); - } - - // 4. 保存数据 - List users = new ArrayList<>(); - for (Object obj : result.getDataList()) { - users.add((UserInfo) obj); - } - userService.batchSave(users); - - return ResultDomain.success("导入成功,共导入" + result.getSuccessRows() + "条数据"); - - } catch (Exception e) { - return ResultDomain.fail("导入失败: " + e.getMessage()); - } -} -``` - -## 支持的数据类型 - -- **String** - 字符串 -- **Integer/int** - 整数 -- **Long/long** - 长整数 -- **Double/double** - 双精度浮点数 -- **Float/float** - 单精度浮点数 -- **Boolean/Boolean** - 布尔值(支持:true/false、1/0、是/否) -- **Date** - 日期(需指定dateFormat) - -## 配置选项 - -### ExcelColumnMapping Builder方法 - -| 方法 | 说明 | 必填 | -|------|------|------| -| columnName(String) | 设置Excel列名 | columnName和columnIndex至少一个 | -| columnIndex(int) | 设置Excel列索引(从0开始,优先级高于columnName) | columnName和columnIndex至少一个 | -| fieldName(String) | 设置对象字段名 | 是 | -| fieldType(Class) | 设置字段类型 | 否(默认String.class) | -| required() / required(Boolean) | 设置是否必填 | 否(默认false) | -| defaultValue(String) | 设置默认值 | 否 | -| dateFormat(String) | 设置日期格式 | 否(默认"yyyy-MM-dd") | -| addValidation(ValidationParam) | 添加校验参数 | 否 | -| validations(List) | 设置校验参数列表 | 否 | - -### Options配置项 - -传递给 `readExcel` 方法的 `Map options` 支持以下选项: - -| 键名 | 类型 | 说明 | 默认值 | -|------|------|------|--------| -| headerRowIndex | int | 表头所在行(从0开始) | 0 | -| dataStartRowIndex | int | 数据起始行(从0开始) | 1 | -| sheetIndex | int | Sheet索引(从0开始) | 0 | -| sheetName | String | Sheet名称(优先级高于sheetIndex) | null | -| skipEmptyRow | Boolean | 跳过空行 | true | -| maxRows | int | 最大读取行数(0=不限制) | 0 | -| continueOnError | Boolean | 遇到错误继续读取 | true | - -## 核心特性 - -1. **配置驱动**:通过ExcelColumnMapping配置Excel列与对象字段的映射关系 -2. **无需注解**:不需要在实体类上添加注解,更加灵活 -3. **数据校验**:集成ValidationUtils和ValidateMethodType进行专业数据校验 -4. **灵活配置**:支持多种配置选项(Sheet选择、行范围、错误处理等) -5. **错误处理**:详细的错误信息和错误行记录 -6. **类型转换**:自动进行类型转换 -7. **空值处理**:支持默认值和空值校验 -8. **多Sheet支持**:可指定Sheet名称或索引 -9. **两种映射方式**:支持列名和列索引两种方式 - -## 注意事项 - -1. **实体类要求**:必须有无参构造函数 -2. **字段访问**:字段必须有setter方法或可访问(支持父类字段) -3. **列映射优先级**:columnIndex优先级高于columnName -4. **日期类型**:必须指定dateFormat -5. **布尔类型**:支持多种格式(true/false、1/0、是/否) -6. **错误处理**:根据continueOnError选项决定遇到错误时是否继续 -7. **文件格式**:支持.xls和.xlsx两种格式 -8. **类型转换**:自动转换支持String、Interge、Long、Double、Float、Boolean、Date - -## 依赖 - -```xml - - org.apache.poi - poi - 5.2.3 - - - - org.apache.poi - poi-ooxml - 5.2.3 - -``` - -## API说明 - -### ExcelReaderUtils 静态方法 - -```java -// 从文件读取(基本) -public static ExcelReadResult readExcel( - File file, - Class targetClass, - List columnMappings -) - -// 从文件读取(带配置) -public static ExcelReadResult readExcel( - File file, - Class targetClass, - List columnMappings, - Map options -) - -// 从输入流读取(基本) -public static ExcelReadResult readExcel( - InputStream inputStream, - String fileName, - Class targetClass, - List columnMappings -) - -// 从输入流读取(带配置) -public static ExcelReadResult readExcel( - InputStream inputStream, - String fileName, - Class targetClass, - List columnMappings, - Map options -) -``` - -## 完整示例 - -参考 `ExcelUtilsExample.java` 查看完整使用示例。 - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/id/IdUtil.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/id/IdUtil.java deleted file mode 100644 index 573d88ea..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/id/IdUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.xyzh.common.utils.id; - -import java.util.UUID; -import java.util.concurrent.atomic.AtomicLong; - -/** - * @description ID生成工具类 - * @filename IdUtil.java - * @author yslg - * @copyright xyzh - * @since 2025-12-17 - */ -public class IdUtil { - - private static final AtomicLong SEQUENCE = new AtomicLong(0); - - /** - * 生成流水号(UUID格式,无横线) - */ - public static String getOptsn() { - return "optsn"+UUID.randomUUID().toString().replaceAll("-", ""); - } - - /** - * 生成雪花ID(简化实现,使用时间戳+序列号) - */ - public static String getSnowflakeId() { - long timestamp = System.currentTimeMillis(); - long seq = SEQUENCE.incrementAndGet() % 10000; - return String.valueOf(timestamp) + String.format("%04d", seq); - } - - /** - * 生成UUID - */ - public static String generateUUID() { - return UUID.randomUUID().toString().replaceAll("-", ""); - } - - /** - * 生成ID - */ - public static String generateID() { - return UUID.randomUUID().toString().replaceAll("-", ""); - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/README.md b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/README.md deleted file mode 100644 index 63f9fc96..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/README.md +++ /dev/null @@ -1,380 +0,0 @@ -# 数据校验工具使用说明 - -## 概述 - -这是一个灵活、可扩展的Java数据校验工具,支持对对象和Map进行多种类型的校验。 - -## 核心组件 - -### 1. ValidationParam - 校验参数对象 -定义字段的校验规则,支持: -- 字段名称和中文标签 -- 是否必传 -- 字段类型校验 -- 字符串长度限制 -- 数字范围限制 -- 正则表达式校验 -- 自定义校验函数 -- 预定义的校验方法(ValidateMethod) - -### 2. ValidationResult - 校验结果对象 -保存校验结果,包含: -- 是否校验通过 -- 错误信息列表 -- 第一个错误信息 -- 错误数量统计 - -### 3. ValidationUtils - 校验工具类 -执行校验逻辑,提供: -- 校验Java对象 -- 校验Map对象 -- 快捷方法:`requiredString()`, `requiredNumber()`, `email()`, `phone()` - -### 4. ValidateMethod - 校验方法接口 -预定义的专业校验方法,已实现: -- **PasswordValidateMethod** - 密码校验 -- **IdCardValidateMethod** - 身份证号校验 -- **PhoneValidateMethod** - 手机号码校验 -- **EmailValidateMethod** - 邮箱地址校验 -- **UrlValidateMethod** - URL链接校验 -- **BankCardValidateMethod** - 银行卡号校验 -- **ChineseValidateMethod** - 中文字符校验 - -### 5. ValidateMethodType - 校验方法类型枚举 ⭐推荐使用 -枚举类型指向预定义的校验方法,使用更简洁: -- **PASSWORD** - 密码校验(6-20位,字母+数字) -- **STRONG_PASSWORD** - 强密码校验(8-20位,大小写+数字+特殊字符) -- **ID_CARD** - 身份证号校验 -- **PHONE** - 手机号码校验(中国大陆) -- **PHONE_LOOSE** - 手机号码校验(支持大陆/香港/台湾) -- **EMAIL** - 邮箱地址校验 -- **URL** - URL链接校验 -- **HTTPS_URL** - HTTPS链接校验 -- **BANK_CARD** - 银行卡号校验 -- **CHINESE** - 中文字符校验(纯中文) -- **CHINESE_WITH_PUNCTUATION** - 中文字符校验(允许标点) - -## 基本使用示例 - -### 1. 使用枚举类型校验(⭐推荐) - -```java -List params = Arrays.asList( - ValidationParam.builder() - .fieldName("password") - .fieldLabel("密码") - .required() - .validateMethod(ValidateMethodType.PASSWORD) // 使用枚举 - .build(), - - ValidationParam.builder() - .fieldName("email") - .fieldLabel("邮箱") - .required() - .validateMethod(ValidateMethodType.EMAIL) // 使用枚举 - .build(), - - ValidationParam.builder() - .fieldName("phone") - .fieldLabel("手机号") - .required() - .validateMethod(ValidateMethodType.PHONE) // 使用枚举 - .build(), - - ValidationParam.builder() - .fieldName("idCard") - .fieldLabel("身份证号") - .required() - .validateMethod(ValidateMethodType.ID_CARD) // 使用枚举 - .build() -); - -ValidationResult result = ValidationUtils.validateMap(data, params); -if (!result.isValid()) { - System.out.println(result.getFirstError()); -} -``` - -### 2. 简单字段校验 - -```java -List params = Arrays.asList( - ValidationUtils.requiredString("username", "用户名", 3, 20), - ValidationUtils.email("email", "邮箱", true), - ValidationUtils.phone("phone", "手机号", false) -); - -// 校验对象 -ValidationResult result = ValidationUtils.validate(userObject, params); - -// 校验Map -ValidationResult result = ValidationUtils.validateMap(userMap, params); - -// 检查结果 -if (result.isValid()) { - // 校验通过 -} else { - // 获取错误信息 - String firstError = result.getFirstError(); - String allErrors = result.getAllErrors(); - List errors = result.getErrors(); -} -``` - -### 3. 使用ValidateMethod进行专业校验(兼容旧方式) - -```java -List params = Arrays.asList( - // 方式1:使用枚举(推荐) - ValidationParam.builder() - .fieldName("password") - .fieldLabel("密码") - .required() - .validateMethod(ValidateMethodType.STRONG_PASSWORD) // 使用预定义的强密码 - .build(), - - // 方式2:直接实例化(如需自定义参数) - ValidationParam.builder() - .fieldName("password2") - .fieldLabel("自定义密码") - .required() - .validateMethod(new PasswordValidateMethod(8, 20, true, true, true, true)) - .build(), - - // 身份证号校验 - ValidationParam.builder() - .fieldName("idCard") - .fieldLabel("身份证号") - .required() - .validateMethod(new IdCardValidateMethod()) - .build(), - - // 手机号校验 - ValidationParam.builder() - .fieldName("phone") - .fieldLabel("手机号") - .required() - .validateMethod(new PhoneValidateMethod()) - .build(), - - // 限制域名的邮箱校验 - ValidationParam.builder() - .fieldName("email") - .fieldLabel("邮箱") - .required() - .validateMethod(new EmailValidateMethod(new String[]{"company.com"})) - .build() -); - -ValidationResult result = ValidationUtils.validateMap(data, params); -``` - -### 4. 自定义校验 - -```java -ValidationParam param = ValidationParam.builder() - .fieldName("age") - .fieldLabel("年龄") - .required() - .customValidator(value -> { - Integer age = (Integer) value; - return age >= 18 && age <= 60; - }) - .customErrorMessage("年龄必须在18-60岁之间") - .build(); -``` - -### 5. 复合校验 - -```java -List params = Arrays.asList( - ValidationParam.builder() - .fieldName("username") - .fieldLabel("用户名") - .required() - .fieldType(String.class) - .minLength(3) - .maxLength(20) - .pattern("^[a-zA-Z0-9_]+$") - .patternDesc("只能包含字母、数字和下划线") - .build(), - - ValidationParam.builder() - .fieldName("password") - .fieldLabel("密码") - .required() - .minLength(6) - .validateMethod(new PasswordValidateMethod()) - .build() -); -``` - -## 预定义校验方法详解 - -### PasswordValidateMethod - 密码校验 - -```java -// 默认规则:6-20位,必须包含字母和数字 -new PasswordValidateMethod() - -// 自定义规则 -new PasswordValidateMethod( - 8, // 最小长度 - 20, // 最大长度 - true, // 需要大写字母 - true, // 需要小写字母 - true, // 需要数字 - true // 需要特殊字符 -) -``` - -### IdCardValidateMethod - 身份证号校验 - -```java -// 支持15位和18位身份证号 -// 自动校验:格式、省份代码、出生日期、校验码 -new IdCardValidateMethod() -``` - -### PhoneValidateMethod - 手机号码校验 - -```java -// 严格模式:仅中国大陆手机号 -new PhoneValidateMethod() - -// 宽松模式:支持大陆、香港、台湾 -new PhoneValidateMethod(false) -``` - -### EmailValidateMethod - 邮箱地址校验 - -```java -// 允许所有域名 -new EmailValidateMethod() - -// 限制特定域名 -new EmailValidateMethod(new String[]{"company.com", "example.com"}) -``` - -### UrlValidateMethod - URL链接校验 - -```java -// 允许HTTP和HTTPS -new UrlValidateMethod() - -// 仅允许HTTPS -new UrlValidateMethod(true) -``` - -### BankCardValidateMethod - 银行卡号校验 - -```java -// 使用Luhn算法校验银行卡号 -new BankCardValidateMethod() -``` - -### ChineseValidateMethod - 中文字符校验 - -```java -// 仅纯中文字符 -new ChineseValidateMethod() - -// 允许中文标点符号 -new ChineseValidateMethod(true) -``` - -## 在Controller中使用 - -```java -@PostMapping("/register") -public ResultDomain register(@RequestBody Map params) { - // 定义校验规则(使用枚举,更简洁) - List validationParams = Arrays.asList( - ValidationParam.builder() - .fieldName("username") - .fieldLabel("用户名") - .required() - .minLength(3) - .maxLength(20) - .build(), - - ValidationParam.builder() - .fieldName("password") - .fieldLabel("密码") - .required() - .validateMethod(ValidateMethodType.PASSWORD) // 使用枚举! - .build(), - - ValidationParam.builder() - .fieldName("email") - .fieldLabel("邮箱") - .required() - .validateMethod(ValidateMethodType.EMAIL) // 使用枚举! - .build(), - - ValidationParam.builder() - .fieldName("phone") - .fieldLabel("手机号") - .required() - .validateMethod(ValidateMethodType.PHONE) // 使用枚举! - .build() - ); - - // 执行校验 - ValidationResult validationResult = ValidationUtils.validateMap(params, validationParams); - - if (!validationResult.isValid()) { - ResultDomain result = new ResultDomain<>(); - result.fail(validationResult.getFirstError()); - return result; - } - - // 校验通过,继续业务逻辑 - // ... -} -``` - -## 自定义ValidateMethod - -如需添加新的校验方法,只需实现`ValidateMethod`接口: - -```java -public class CustomValidateMethod implements ValidateMethod { - - @Override - public Boolean validate(Object value) { - // 实现校验逻辑 - return true; - } - - @Override - public String getErrorMessage() { - return "自定义错误信息"; - } - - @Override - public String getName() { - return "自定义校验"; - } -} -``` - -## 优势 - -1. **简洁性**:使用枚举类型,无需每次new对象 ⭐ -2. **灵活性**:支持多种校验方式组合使用 -3. **可扩展性**:易于添加新的校验方法 -4. **可读性**:Builder模式让代码清晰易懂 -5. **可复用性**:预定义的校验方法可在项目中重复使用 -6. **专业性**:内置多种常用的专业校验算法(身份证、银行卡等) -7. **类型安全**:枚举类型提供编译时类型检查 - -## 注意事项 - -1. **推荐使用枚举类型**:`ValidateMethodType` 比直接 `new` 对象更简洁 -2. 校验顺序:必填 -> 类型 -> 长度/范围 -> 正则 -> 自定义 -> ValidateMethodType -> ValidateMethod -3. ValidateMethod和customValidator可以同时使用,都会执行 -4. 当值为null且非必填时,会跳过后续所有校验 -5. 错误信息会累积,可以获取所有错误或只获取第一个错误 -6. 枚举方式和实例方式可以并存,但推荐统一使用枚举方式 - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationParam.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationParam.java deleted file mode 100644 index 2af31176..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationParam.java +++ /dev/null @@ -1,276 +0,0 @@ -package org.xyzh.common.utils.validation; - -import org.xyzh.common.utils.validation.method.ValidateMethod; -import org.xyzh.common.utils.validation.method.ValidateMethodType; - -import java.util.function.Predicate; - -/** - * @description 校验参数对象,定义字段的校验规则 - * @filename ValidationParam.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ValidationParam { - - /** - * @description 字段名称 - */ - private String fieldName; - - /** - * @description 字段中文名称(用于错误提示) - */ - private String fieldLabel; - - /** - * @description 是否必传 - */ - private Boolean required; - - /** - * @description 字段类型 - */ - private Class fieldType; - - /** - * @description 最小长度(字符串) - */ - private Integer minLength; - - /** - * @description 最大长度(字符串) - */ - private Integer maxLength; - - /** - * @description 最小值(数字) - */ - private Number minValue; - - /** - * @description 最大值(数字) - */ - private Number maxValue; - - /** - * @description 正则表达式 - */ - private String pattern; - - /** - * @description 正则表达式描述(用于错误提示) - */ - private String patternDesc; - - /** - * @description 自定义校验函数 - */ - private Predicate customValidator; - - /** - * @description 自定义校验失败消息 - */ - private String customErrorMessage; - - /** - * @description 是否允许为空字符串(默认不允许) - */ - private Boolean allowEmpty = false; - - /** - * @description 校验方法(使用预定义的校验方法) - */ - private ValidateMethod validateMethod; - - /** - * @description 校验方法类型枚举 - */ - private ValidateMethodType validateMethodType; - - /** - * @description 校验方法配置参数(用于需要自定义参数的校验方法) - */ - private Object[] methodParams; - - // 私有构造函数,使用Builder模式 - private ValidationParam() { - } - - public String getFieldName() { - return fieldName; - } - - public String getFieldLabel() { - return fieldLabel; - } - - public Boolean isRequired() { - return required; - } - - public Class getFieldType() { - return fieldType; - } - - public Integer getMinLength() { - return minLength; - } - - public Integer getMaxLength() { - return maxLength; - } - - public Number getMinValue() { - return minValue; - } - - public Number getMaxValue() { - return maxValue; - } - - public String getPattern() { - return pattern; - } - - public String getPatternDesc() { - return patternDesc; - } - - public Predicate getCustomValidator() { - return customValidator; - } - - public String getCustomErrorMessage() { - return customErrorMessage; - } - - public Boolean isAllowEmpty() { - return allowEmpty; - } - - public ValidateMethod getValidateMethod() { - return validateMethod; - } - - public ValidateMethodType getValidateMethodType() { - return validateMethodType; - } - - public Object[] getMethodParams() { - return methodParams; - } - - /** - * @description Builder类用于构建ValidationParam对象 - */ - public static class Builder { - private ValidationParam param = new ValidationParam(); - - public Builder fieldName(String fieldName) { - param.fieldName = fieldName; - return this; - } - - public Builder fieldLabel(String fieldLabel) { - param.fieldLabel = fieldLabel; - return this; - } - - public Builder required(Boolean required) { - param.required = required; - return this; - } - - public Builder required() { - param.required = true; - return this; - } - - public Builder fieldType(Class fieldType) { - param.fieldType = fieldType; - return this; - } - - public Builder minLength(Integer minLength) { - param.minLength = minLength; - return this; - } - - public Builder maxLength(Integer maxLength) { - param.maxLength = maxLength; - return this; - } - - public Builder minValue(Number minValue) { - param.minValue = minValue; - return this; - } - - public Builder maxValue(Number maxValue) { - param.maxValue = maxValue; - return this; - } - - public Builder pattern(String pattern) { - param.pattern = pattern; - return this; - } - - public Builder patternDesc(String patternDesc) { - param.patternDesc = patternDesc; - return this; - } - - public Builder customValidator(Predicate customValidator) { - param.customValidator = customValidator; - return this; - } - - public Builder customErrorMessage(String customErrorMessage) { - param.customErrorMessage = customErrorMessage; - return this; - } - - public Builder allowEmpty(Boolean allowEmpty) { - param.allowEmpty = allowEmpty; - return this; - } - - public Builder validateMethod(ValidateMethod validateMethod) { - param.validateMethod = validateMethod; - return this; - } - - public Builder validateMethod(ValidateMethodType methodType) { - param.validateMethodType = methodType; - return this; - } - - public Builder validateMethod(ValidateMethodType methodType, Object... params) { - param.validateMethodType = methodType; - param.methodParams = params; - return this; - } - - public ValidationParam build() { - if (param.fieldName == null || param.fieldName.isEmpty()) { - throw new IllegalArgumentException("fieldName不能为空"); - } - if (param.fieldLabel == null || param.fieldLabel.isEmpty()) { - param.fieldLabel = param.fieldName; - } - return param; - } - } - - /** - * @description 创建Builder对象 - * @return Builder - */ - public static Builder builder() { - return new Builder(); - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationResult.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationResult.java deleted file mode 100644 index 37e0e5ab..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationResult.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.xyzh.common.utils.validation; - -import java.util.ArrayList; -import java.util.List; - -/** - * @description 校验结果类 - * @filename ValidationResult.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ValidationResult { - - /** - * @description 是否校验通过 - */ - private Boolean valid; - - /** - * @description 错误信息列表 - */ - private List errors; - - /** - * @description 第一个错误信息 - */ - private String firstError; - - public ValidationResult() { - this.valid = true; - this.errors = new ArrayList<>(); - } - - public Boolean isValid() { - return valid; - } - - public void setValid(Boolean valid) { - this.valid = valid; - } - - public List getErrors() { - return errors; - } - - public String getFirstError() { - return firstError; - } - - /** - * @description 添加错误信息 - * @param error 错误信息 - */ - public void addError(String error) { - this.valid = false; - this.errors.add(error); - if (this.firstError == null) { - this.firstError = error; - } - } - - /** - * @description 获取所有错误信息的字符串 - * @return 错误信息字符串 - */ - public String getAllErrors() { - return String.join("; ", errors); - } - - /** - * @description 是否有错误 - * @return Boolean - */ - public Boolean hasErrors() { - return !valid; - } - - /** - * @description 获取错误数量 - * @return 错误数量 - */ - public int getErrorCount() { - return errors.size(); - } - - @Override - public String toString() { - return "ValidationResult{" + - "valid=" + valid + - ", errorCount=" + errors.size() + - ", errors=" + errors + - '}'; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationUtils.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationUtils.java deleted file mode 100644 index 24329840..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/ValidationUtils.java +++ /dev/null @@ -1,413 +0,0 @@ -package org.xyzh.common.utils.validation; - -import org.xyzh.common.utils.validation.method.FieldCompareValidateMethod; -import org.xyzh.common.utils.validation.method.InSetValidateMethod; -import org.xyzh.common.utils.validation.method.MinFieldsValidateMethod; -import org.xyzh.common.utils.validation.method.ObjectValidateMethod; -import org.xyzh.common.utils.validation.method.ValidateMethod; - -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.regex.Pattern; - -/** - * @description 校验工具类 - * @filename ValidationUtils.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ValidationUtils { - - /** - * @description 校验对象 - * @param obj 待校验的对象 - * @param validationParams 校验参数列表 - * @return ValidationResult 校验结果 - */ - public static ValidationResult validate(Object obj, List validationParams) { - ValidationResult result = new ValidationResult(); - - if (obj == null) { - result.addError("待校验对象不能为null"); - return result; - } - - if (validationParams == null || validationParams.isEmpty()) { - return result; - } - - for (ValidationParam param : validationParams) { - try { - Object fieldValue = getFieldValue(obj, param.getFieldName()); - validateField(param, fieldValue, obj, result); - } catch (Exception e) { - result.addError(param.getFieldLabel() + "字段获取失败: " + e.getMessage()); - } - } - - return result; - } - - /** - * @description 校验Map对象 - * @param map 待校验的Map - * @param validationParams 校验参数列表 - * @return ValidationResult 校验结果 - */ - public static ValidationResult validateMap(Map map, List validationParams) { - ValidationResult result = new ValidationResult(); - - if (map == null) { - result.addError("待校验Map不能为null"); - return result; - } - - if (validationParams == null || validationParams.isEmpty()) { - return result; - } - - for (ValidationParam param : validationParams) { - Object fieldValue = map.get(param.getFieldName()); - validateField(param, fieldValue, map, result); - } - - return result; - } - - /** - * @description 校验单个字段 - * @param param 校验参数 - * @param fieldValue 字段值 - * @param obj 原始对象 - * @param result 校验结果 - */ - private static void validateField(ValidationParam param, Object fieldValue, Object obj, ValidationResult result) { - String fieldLabel = param.getFieldLabel(); - - // 1. 必填校验 - if (param.isRequired()) { - if (fieldValue == null) { - result.addError(fieldLabel + "不能为空"); - return; - } - if (fieldValue instanceof String) { - String strValue = (String) fieldValue; - if (!param.isAllowEmpty() && strValue.trim().isEmpty()) { - result.addError(fieldLabel + "不能为空字符串"); - return; - } - } - } - - // 如果值为null且非必填,跳过后续校验 - if (fieldValue == null) { - return; - } - - // 2. 类型校验 - if (param.getFieldType() != null) { - if (!param.getFieldType().isAssignableFrom(fieldValue.getClass())) { - result.addError(fieldLabel + "类型错误,期望类型: " + param.getFieldType().getSimpleName() + - ", 实际类型: " + fieldValue.getClass().getSimpleName()); - return; - } - } - - // 3. 字符串长度校验 - if (fieldValue instanceof String) { - String strValue = (String) fieldValue; - if (param.getMinLength() != null && strValue.length() < param.getMinLength()) { - result.addError(fieldLabel + "长度不能少于" + param.getMinLength() + "个字符"); - } - if (param.getMaxLength() != null && strValue.length() > param.getMaxLength()) { - result.addError(fieldLabel + "长度不能超过" + param.getMaxLength() + "个字符"); - } - } - - // 4. 数字范围校验 - if (fieldValue instanceof Number) { - double numValue = ((Number) fieldValue).doubleValue(); - if (param.getMinValue() != null && numValue < param.getMinValue().doubleValue()) { - result.addError(fieldLabel + "不能小于" + param.getMinValue()); - } - if (param.getMaxValue() != null && numValue > param.getMaxValue().doubleValue()) { - result.addError(fieldLabel + "不能大于" + param.getMaxValue()); - } - } - - // 5. 正则表达式校验 - if (param.getPattern() != null && fieldValue instanceof String) { - String strValue = (String) fieldValue; - if (!Pattern.matches(param.getPattern(), strValue)) { - String errorMsg = fieldLabel + "格式不正确"; - if (param.getPatternDesc() != null) { - errorMsg += "," + param.getPatternDesc(); - } - result.addError(errorMsg); - } - } - - // 6. 自定义校验 - if (param.getCustomValidator() != null) { - try { - if (!param.getCustomValidator().test(fieldValue)) { - String errorMsg = param.getCustomErrorMessage(); - if (errorMsg == null || errorMsg.isEmpty()) { - errorMsg = fieldLabel + "校验失败"; - } - result.addError(errorMsg); - } - } catch (Exception e) { - result.addError(fieldLabel + "自定义校验异常: " + e.getMessage()); - } - } - - // 7. 使用ValidateMethod校验(枚举类型) - if (param.getValidateMethodType() != null) { - try { - ValidateMethod method = param.getValidateMethodType().createInstance(); - if (!method.validate(fieldValue)) { - String errorMsg = method.getErrorMessage(); - if (errorMsg != null && !errorMsg.isEmpty()) { - result.addError(errorMsg); - } else { - result.addError(fieldLabel + "校验失败"); - } - } - } catch (Exception e) { - result.addError(fieldLabel + "校验异常: " + e.getMessage()); - } - } - - // 8. 使用ValidateMethod校验(直接传入实例) - if (param.getValidateMethod() != null) { - try { - Object validateTarget = (param.getValidateMethod() instanceof ObjectValidateMethod) ? obj : fieldValue; - if (!param.getValidateMethod().validate(validateTarget)) { - String errorMsg = param.getValidateMethod().getErrorMessage(); - if (errorMsg != null && !errorMsg.isEmpty()) { - result.addError(errorMsg); - } else { - result.addError(fieldLabel + "校验失败"); - } - } - } catch (Exception e) { - result.addError(fieldLabel + "校验异常: " + e.getMessage()); - } - } - } - - /** - * @description 获取对象字段值(支持getter方法、直接访问和嵌套路径) - * @param obj 对象 - * @param fieldName 字段名,支持嵌套路径如"pageParam.page" - * @return 字段值 - * @throws Exception 异常 - */ - private static Object getFieldValue(Object obj, String fieldName) throws Exception { - if (obj == null) { - return null; - } - - // 支持嵌套路径,如"pageParam.page" - if (fieldName.contains(".")) { - String[] parts = fieldName.split("\\.", 2); - Object nestedObj = getFieldValue(obj, parts[0]); - if (nestedObj == null) { - return null; - } - return getFieldValue(nestedObj, parts[1]); - } - - if (obj instanceof Map) { - return ((Map) obj).get(fieldName); - } - - Class clazz = obj.getClass(); - - // 首先尝试getter方法 - try { - String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); - return clazz.getMethod(getterName).invoke(obj); - } catch (NoSuchMethodException e) { - // getter方法不存在,尝试直接访问字段 - try { - Field field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - return field.get(obj); - } catch (NoSuchFieldException ex) { - // 尝试父类 - Class superClass = clazz.getSuperclass(); - if (superClass != null) { - Field field = superClass.getDeclaredField(fieldName); - field.setAccessible(true); - return field.get(obj); - } - throw ex; - } - } - } - - /** - * @description 快速创建必填字符串校验参数 - * @param fieldName 字段名 - * @param fieldLabel 字段标签 - * @return ValidationParam - */ - public static ValidationParam requiredString(String fieldName, String fieldLabel) { - return ValidationParam.builder() - .fieldName(fieldName) - .fieldLabel(fieldLabel) - .required() - .fieldType(String.class) - .build(); - } - - /** - * @description 快速创建必填字符串校验参数(带长度限制) - * @param fieldName 字段名 - * @param fieldLabel 字段标签 - * @param minLength 最小长度 - * @param maxLength 最大长度 - * @return ValidationParam - */ - public static ValidationParam requiredString(String fieldName, String fieldLabel, int minLength, int maxLength) { - return ValidationParam.builder() - .fieldName(fieldName) - .fieldLabel(fieldLabel) - .required() - .fieldType(String.class) - .minLength(minLength) - .maxLength(maxLength) - .build(); - } - - /** - * @description 快速创建必填数字校验参数 - * @param fieldName 字段名 - * @param fieldLabel 字段标签 - * @param minValue 最小值 - * @param maxValue 最大值 - * @return ValidationParam - */ - public static ValidationParam requiredNumber(String fieldName, String fieldLabel, Number minValue, Number maxValue) { - return ValidationParam.builder() - .fieldName(fieldName) - .fieldLabel(fieldLabel) - .required() - .minValue(minValue) - .maxValue(maxValue) - .build(); - } - - /** - * @description 快速创建邮箱校验参数 - * @param fieldName 字段名 - * @param fieldLabel 字段标签 - * @param required 是否必填 - * @return ValidationParam - */ - public static ValidationParam email(String fieldName, String fieldLabel, Boolean required) { - return ValidationParam.builder() - .fieldName(fieldName) - .fieldLabel(fieldLabel) - .required(required) - .fieldType(String.class) - .pattern("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$") - .patternDesc("请输入有效的邮箱地址") - .build(); - } - - /** - * @description 快速创建手机号校验参数 - * @param fieldName 字段名 - * @param fieldLabel 字段标签 - * @param required 是否必填 - * @return ValidationParam - */ - public static ValidationParam phone(String fieldName, String fieldLabel, Boolean required) { - return ValidationParam.builder() - .fieldName(fieldName) - .fieldLabel(fieldLabel) - .required(required) - .fieldType(String.class) - .pattern("^1[3-9]\\d{9}$") - .patternDesc("请输入有效的手机号码") - .build(); - } - - /** - * @description 创建"至少填一个"校验参数 - * @param fieldNames 字段名列表 - * @param fieldLabels 字段标签列表 - * @return ValidationParam - */ - public static ValidationParam atLeastOne(List fieldNames, List fieldLabels) { - return minFields(fieldNames, fieldLabels, 1); - } - - /** - * @description 创建"至少填几个"校验参数 - * @param fieldNames 字段名列表 - * @param fieldLabels 字段标签列表 - * @param minCount 至少填写的数量 - * @return ValidationParam - */ - public static ValidationParam minFields(List fieldNames, List fieldLabels, int minCount) { - return ValidationParam.builder() - .fieldName("_minFields") - .fieldLabel(String.join("、", fieldLabels)) - .validateMethod(new MinFieldsValidateMethod(fieldNames, fieldLabels, minCount)) - .build(); - } - - /** - * @description 创建N选1校验参数(值必须是集合中的一个) - * @param fieldName 字段名 - * @param fieldLabel 字段标签 - * @param required 是否必填 - * @param allowedValues 允许的值集合 - * @return ValidationParam - */ - public static ValidationParam inSet(String fieldName, String fieldLabel, Boolean required, Collection allowedValues) { - return ValidationParam.builder() - .fieldName(fieldName) - .fieldLabel(fieldLabel) - .required(required) - .validateMethod(new InSetValidateMethod(fieldLabel, allowedValues)) - .build(); - } - - /** - * @description 创建字段比较校验参数(比较对象中的两个字段) - * @param field1Name 第一个字段名称 - * @param field2Name 第二个字段名称 - * @param fieldLabel 字段标签 - * @param compareFunction 比较函数:(field1Value, field2Value) -> Boolean,返回true表示通过 - * @param errorMessage 自定义错误消息 - * @return ValidationParam - */ - public static ValidationParam fieldCompare(String field1Name, - String field2Name, - String fieldLabel, - BiFunction compareFunction, - String errorMessage) { - return ValidationParam.builder() - .fieldName(field1Name) - .fieldLabel(fieldLabel) - .required(false) - .validateMethod(new FieldCompareValidateMethod( - field1Name, - field2Name, - fieldLabel, - compareFunction, - errorMessage - )) - .build(); - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/AtLeastOneValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/AtLeastOneValidateMethod.java deleted file mode 100644 index e69de29b..00000000 diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/BankCardValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/BankCardValidateMethod.java deleted file mode 100644 index 5cff10f6..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/BankCardValidateMethod.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -/** - * @description 银行卡号校验方法(Luhn算法) - * @filename BankCardValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class BankCardValidateMethod implements ValidateMethod { - - @Override - public Boolean validate(Object value) { - if (value == null || !(value instanceof String)) { - return false; - } - - String cardNumber = ((String) value).replaceAll("\\s", ""); - - // 长度校验(银行卡号通常为16-19位) - if (cardNumber.length() < 16 || cardNumber.length() > 19) { - return false; - } - - // 数字校验 - if (!cardNumber.matches("^\\d+$")) { - return false; - } - - // Luhn算法校验 - return luhnCheck(cardNumber); - } - - /** - * @description Luhn算法校验(银行卡校验算法) - * @param cardNumber 银行卡号 - * @return Boolean 是否通过校验 - */ - private Boolean luhnCheck(String cardNumber) { - int sum = 0; - Boolean alternate = false; - - // 从右向左遍历 - for (int i = cardNumber.length() - 1; i >= 0; i--) { - int digit = Character.getNumericValue(cardNumber.charAt(i)); - - if (alternate) { - digit *= 2; - if (digit > 9) { - digit = digit - 9; - } - } - - sum += digit; - alternate = !alternate; - } - - return sum % 10 == 0; - } - - @Override - public String getErrorMessage() { - return "请输入有效的银行卡号"; - } - - @Override - public String getName() { - return "银行卡号校验"; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ChineseValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ChineseValidateMethod.java deleted file mode 100644 index 13bd89f5..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ChineseValidateMethod.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.util.regex.Pattern; - -/** - * @description 中文字符校验方法 - * @filename ChineseValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class ChineseValidateMethod implements ValidateMethod { - - // 中文字符正则(包括中文标点符号) - private static final Pattern CHINESE_PATTERN = Pattern.compile("^[\u4e00-\u9fa5]+$"); - - private final Boolean allowPunctuation; // 是否允许中文标点符号 - - public ChineseValidateMethod() { - this.allowPunctuation = false; - } - - public ChineseValidateMethod(Boolean allowPunctuation) { - this.allowPunctuation = allowPunctuation; - } - - @Override - public Boolean validate(Object value) { - if (value == null || !(value instanceof String)) { - return false; - } - - String str = (String) value; - - if (allowPunctuation) { - // 允许中文字符和中文标点符号 - return Pattern.matches("^[\u4e00-\u9fa5\\u3000-\\u303f]+$", str); - } else { - // 仅允许纯中文字符 - return CHINESE_PATTERN.matcher(str).matches(); - } - } - - @Override - public String getErrorMessage() { - return allowPunctuation ? "请输入中文字符" : "请输入纯中文字符(不含标点符号)"; - } - - @Override - public String getName() { - return "中文字符校验"; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/EmailValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/EmailValidateMethod.java deleted file mode 100644 index ef04d6db..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/EmailValidateMethod.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.util.regex.Pattern; - -/** - * @description 邮箱校验方法 - * @filename EmailValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class EmailValidateMethod implements ValidateMethod { - - // 邮箱正则表达式 - private static final Pattern EMAIL_PATTERN = Pattern.compile( - "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$" - ); - - private final String[] allowedDomains; // 允许的域名列表 - - /** - * @description 默认构造函数,允许所有域名 - */ - public EmailValidateMethod() { - this.allowedDomains = null; - } - - /** - * @description 限制域名的构造函数 - * @param allowedDomains 允许的域名列表,例如:["company.com", "example.com"] - */ - public EmailValidateMethod(String[] allowedDomains) { - this.allowedDomains = allowedDomains; - } - - @Override - public Boolean validate(Object value) { - if (value == null || !(value instanceof String)) { - return false; - } - - String email = ((String) value).trim().toLowerCase(); - - // 基本格式校验 - if (!EMAIL_PATTERN.matcher(email).matches()) { - return false; - } - - // 域名限制校验 - if (allowedDomains != null && allowedDomains.length > 0) { - Boolean domainMatched = false; - for (String domain : allowedDomains) { - if (email.endsWith("@" + domain.toLowerCase())) { - domainMatched = true; - break; - } - } - return domainMatched; - } - - return true; - } - - @Override - public String getErrorMessage() { - if (allowedDomains != null && allowedDomains.length > 0) { - return "请输入有效的邮箱地址(仅支持: " + String.join(", ", allowedDomains) + ")"; - } - return "请输入有效的邮箱地址"; - } - - @Override - public String getName() { - return "邮箱校验"; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/FieldCompareValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/FieldCompareValidateMethod.java deleted file mode 100644 index 9b78d2f5..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/FieldCompareValidateMethod.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.lang.reflect.Field; -import java.util.function.BiFunction; - -/** - * @description 字段比较校验方法,用于比较对象中的两个字段 - * @filename FieldCompareValidateMethod.java - * @author Claude Code - * @copyright xyzh - * @since 2025-12-26 - */ -public class FieldCompareValidateMethod implements ObjectValidateMethod { - - /** - * 第一个字段名称 - */ - private final String field1Name; - - /** - * 第二个字段名称 - */ - private final String field2Name; - - /** - * 字段标签(用于错误消息) - */ - private final String fieldLabel; - - /** - * 比较函数:(field1Value, field2Value) -> Boolean - * 返回 true 表示校验通过,false 表示校验失败 - */ - private final BiFunction compareFunction; - - /** - * 自定义错误消息 - */ - private final String customErrorMessage; - - /** - * 构造函数 - * - * @param field1Name 第一个字段名称 - * @param field2Name 第二个字段名称 - * @param fieldLabel 字段标签 - * @param compareFunction 比较函数 - * @param customErrorMessage 自定义错误消息 - */ - public FieldCompareValidateMethod(String field1Name, - String field2Name, - String fieldLabel, - BiFunction compareFunction, - String customErrorMessage) { - this.field1Name = field1Name; - this.field2Name = field2Name; - this.fieldLabel = fieldLabel; - this.compareFunction = compareFunction; - this.customErrorMessage = customErrorMessage; - } - - @Override - public Boolean validate(Object targetObject) { - if (targetObject == null) { - return true; - } - - try { - // 获取第一个字段的值 - Object field1Value = getFieldValue(targetObject, field1Name); - - // 获取第二个字段的值 - Object field2Value = getFieldValue(targetObject, field2Name); - - // 如果任意字段为null,跳过校验 - if (field1Value == null || field2Value == null) { - return true; - } - - // 执行比较函数 - return compareFunction.apply(field1Value, field2Value); - - } catch (Exception e) { - throw new RuntimeException("字段比较校验失败: " + e.getMessage(), e); - } - } - - @Override - public String getErrorMessage() { - if (customErrorMessage != null && !customErrorMessage.trim().isEmpty()) { - return customErrorMessage; - } - return fieldLabel + "校验失败"; - } - - @Override - public String getName() { - return "字段比较校验"; - } - - /** - * 获取字段值(支持嵌套字段) - * - * @param obj 对象 - * @param fieldName 字段名称(支持 "field" 或 "nested.field") - * @return 字段值 - */ - private Object getFieldValue(Object obj, String fieldName) throws Exception { - if (fieldName == null || fieldName.trim().isEmpty()) { - return null; - } - - // 支持嵌套字段访问(如 "user.name") - String[] fieldParts = fieldName.split("\\."); - Object currentObj = obj; - - for (String part : fieldParts) { - if (currentObj == null) { - return null; - } - - // 获取字段 - Field field = findField(currentObj.getClass(), part); - if (field == null) { - throw new NoSuchFieldException("字段不存在: " + part); - } - - // 设置可访问 - field.setAccessible(true); - - // 获取字段值 - currentObj = field.get(currentObj); - } - - return currentObj; - } - - /** - * 查找字段(包括父类) - * - * @param clazz 类 - * @param fieldName 字段名称 - * @return 字段 - */ - private Field findField(Class clazz, String fieldName) { - Class currentClass = clazz; - while (currentClass != null) { - try { - return currentClass.getDeclaredField(fieldName); - } catch (NoSuchFieldException e) { - currentClass = currentClass.getSuperclass(); - } - } - return null; - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/IdCardValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/IdCardValidateMethod.java deleted file mode 100644 index 164bf9ad..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/IdCardValidateMethod.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * @description 身份证号码校验方法(支持15位和18位身份证) - * @filename IdCardValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class IdCardValidateMethod implements ValidateMethod { - - // 加权因子 - private static final int[] WEIGHT = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}; - - // 校验码对应值 - private static final char[] VALIDATE_CODE = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}; - - // 省份代码 - private static final Map PROVINCE_CODES = new HashMap<>(); - - static { - PROVINCE_CODES.put("11", "北京"); - PROVINCE_CODES.put("12", "天津"); - PROVINCE_CODES.put("13", "河北"); - PROVINCE_CODES.put("14", "山西"); - PROVINCE_CODES.put("15", "内蒙古"); - PROVINCE_CODES.put("21", "辽宁"); - PROVINCE_CODES.put("22", "吉林"); - PROVINCE_CODES.put("23", "黑龙江"); - PROVINCE_CODES.put("31", "上海"); - PROVINCE_CODES.put("32", "江苏"); - PROVINCE_CODES.put("33", "浙江"); - PROVINCE_CODES.put("34", "安徽"); - PROVINCE_CODES.put("35", "福建"); - PROVINCE_CODES.put("36", "江西"); - PROVINCE_CODES.put("37", "山东"); - PROVINCE_CODES.put("41", "河南"); - PROVINCE_CODES.put("42", "湖北"); - PROVINCE_CODES.put("43", "湖南"); - PROVINCE_CODES.put("44", "广东"); - PROVINCE_CODES.put("45", "广西"); - PROVINCE_CODES.put("46", "海南"); - PROVINCE_CODES.put("50", "重庆"); - PROVINCE_CODES.put("51", "四川"); - PROVINCE_CODES.put("52", "贵州"); - PROVINCE_CODES.put("53", "云南"); - PROVINCE_CODES.put("54", "西藏"); - PROVINCE_CODES.put("61", "陕西"); - PROVINCE_CODES.put("62", "甘肃"); - PROVINCE_CODES.put("63", "青海"); - PROVINCE_CODES.put("64", "宁夏"); - PROVINCE_CODES.put("65", "新疆"); - PROVINCE_CODES.put("71", "台湾"); - PROVINCE_CODES.put("81", "香港"); - PROVINCE_CODES.put("82", "澳门"); - } - - @Override - public Boolean validate(Object value) { - if (value == null || !(value instanceof String)) { - return false; - } - - String idCard = ((String) value).toUpperCase(); - - // 长度校验 - if (idCard.length() != 15 && idCard.length() != 18) { - return false; - } - - // 格式校验 - if (idCard.length() == 15) { - return validate15IdCard(idCard); - } else { - return validate18IdCard(idCard); - } - } - - /** - * @description 校验15位身份证 - */ - private Boolean validate15IdCard(String idCard) { - // 15位身份证格式:省(2位)市(2位)县(2位)年(2位)月(2位)日(2位)顺序号(3位) - if (!Pattern.matches("^\\d{15}$", idCard)) { - return false; - } - - // 省份代码校验 - String provinceCode = idCard.substring(0, 2); - if (!PROVINCE_CODES.containsKey(provinceCode)) { - return false; - } - - // 出生日期校验 - String year = "19" + idCard.substring(6, 8); - String month = idCard.substring(8, 10); - String day = idCard.substring(10, 12); - - return validateDate(year, month, day); - } - - /** - * @description 校验18位身份证 - */ - private Boolean validate18IdCard(String idCard) { - // 18位身份证格式:省(2位)市(2位)县(2位)年(4位)月(2位)日(2位)顺序号(3位)校验码(1位) - if (!Pattern.matches("^\\d{17}[0-9Xx]$", idCard)) { - return false; - } - - // 省份代码校验 - String provinceCode = idCard.substring(0, 2); - if (!PROVINCE_CODES.containsKey(provinceCode)) { - return false; - } - - // 出生日期校验 - String year = idCard.substring(6, 10); - String month = idCard.substring(10, 12); - String day = idCard.substring(12, 14); - - if (!validateDate(year, month, day)) { - return false; - } - - // 校验码校验 - return validateCheckCode(idCard); - } - - /** - * @description 校验日期是否合法 - */ - private Boolean validateDate(String year, String month, String day) { - try { - int y = Integer.parseInt(year); - int m = Integer.parseInt(month); - int d = Integer.parseInt(day); - - // 年份范围:1900-当前年份 - int currentYear = java.time.Year.now().getValue(); - if (y < 1900 || y > currentYear) { - return false; - } - - // 月份范围:1-12 - if (m < 1 || m > 12) { - return false; - } - - // 日期范围 - int[] daysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - - // 闰年2月29天 - if (isLeapYear(y)) { - daysInMonth[1] = 29; - } - - return d >= 1 && d <= daysInMonth[m - 1]; - } catch (NumberFormatException e) { - return false; - } - } - - /** - * @description 判断是否为闰年 - */ - private Boolean isLeapYear(int year) { - return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); - } - - /** - * @description 校验18位身份证的校验码 - */ - private Boolean validateCheckCode(String idCard) { - int sum = 0; - for (int i = 0; i < 17; i++) { - sum += (idCard.charAt(i) - '0') * WEIGHT[i]; - } - - char checkCode = VALIDATE_CODE[sum % 11]; - return checkCode == idCard.charAt(17); - } - - @Override - public String getErrorMessage() { - return "请输入有效的身份证号码(15位或18位)"; - } - - @Override - public String getName() { - return "身份证号码校验"; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/InSetValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/InSetValidateMethod.java deleted file mode 100644 index 883c52d3..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/InSetValidateMethod.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.util.Collection; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * @description N选1校验方法,值必须是指定集合中的一个 - * @filename InSetValidateMethod.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -public class InSetValidateMethod implements ValidateMethod { - - private final Set allowedValues; - private final String errorMessage; - - /** - * @description 构造函数 - * @param fieldLabel 字段标签 - * @param allowedValues 允许的值集合 - */ - public InSetValidateMethod(String fieldLabel, Collection allowedValues) { - this.allowedValues = allowedValues.stream().map(v -> (Object) v).collect(Collectors.toSet()); - this.errorMessage = fieldLabel + "必须是以下值之一: " + formatValues(allowedValues); - } - - /** - * @description 构造函数(自定义错误信息) - * @param fieldLabel 字段标签 - * @param allowedValues 允许的值集合 - * @param customErrorMessage 自定义错误信息 - */ - public InSetValidateMethod(String fieldLabel, Collection allowedValues, String customErrorMessage) { - this.allowedValues = allowedValues.stream().map(v -> (Object) v).collect(Collectors.toSet()); - this.errorMessage = customErrorMessage; - } - - @Override - public Boolean validate(Object value) { - if (value == null) { - return false; - } - return allowedValues.contains(value); - } - - @Override - public String getErrorMessage() { - return errorMessage; - } - - @Override - public String getName() { - return "N选1校验"; - } - - /** - * @description 格式化允许值列表 - * @param values 值集合 - * @return 格式化后的字符串 - */ - private String formatValues(Collection values) { - return values.stream() - .map(v -> v instanceof String ? "\"" + v + "\"" : String.valueOf(v)) - .collect(Collectors.joining(", ", "[", "]")); - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/MinFieldsValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/MinFieldsValidateMethod.java deleted file mode 100644 index 3b1483ad..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/MinFieldsValidateMethod.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; - -/** - * @description 至少填几个字段校验方法 - * @filename MinFieldsValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-12-18 - */ -public class MinFieldsValidateMethod implements ObjectValidateMethod { - - - private final List fieldNames; - private final int minCount; - private final String errorMessage; - - public MinFieldsValidateMethod(List fieldNames, List fieldLabels) { - this(fieldNames, fieldLabels, 1); - } - - public MinFieldsValidateMethod(List fieldNames, List fieldLabels, int minCount) { - this.fieldNames = fieldNames; - this.minCount = minCount; - this.errorMessage = String.join("、", fieldLabels) + "至少填写" + minCount + "项"; - } - - @Override - public Boolean validate(Object obj) { - if (obj == null || fieldNames == null || fieldNames.isEmpty()) { - return false; - } - - int count = 0; - for (String fieldName : fieldNames) { - try { - Object fieldValue = getFieldValue(obj, fieldName); - if (fieldValue != null) { - if (fieldValue instanceof String) { - if (!((String) fieldValue).trim().isEmpty()) { - count++; - } - } else { - count++; - } - } - } catch (Exception e) { - // 字段不存在,忽略 - } - } - return count >= minCount; - } - - private Object getFieldValue(Object obj, String fieldName) throws Exception { - if (obj instanceof Map) { - return ((Map) obj).get(fieldName); - } - - Class clazz = obj.getClass(); - - // 尝试getter方法 - try { - String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); - Method getter = clazz.getMethod(getterName); - return getter.invoke(obj); - } catch (NoSuchMethodException e) { - // 尝试直接访问字段 - try { - Field field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - return field.get(obj); - } catch (NoSuchFieldException ex) { - // 尝试父类 - Class superClass = clazz.getSuperclass(); - if (superClass != null) { - Field field = superClass.getDeclaredField(fieldName); - field.setAccessible(true); - return field.get(obj); - } - throw ex; - } - } - } - - @Override - public String getErrorMessage() { - return errorMessage; - } - - @Override - public String getName() { - return "至少填" + minCount + "个校验"; - } -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ObjectValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ObjectValidateMethod.java deleted file mode 100644 index 695d5785..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ObjectValidateMethod.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -/** - * @description 对象级校验方法接口,表示对整个对象进行校验 - * @filename ObjectValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-12-18 - */ -public interface ObjectValidateMethod extends ValidateMethod { -} diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/PasswordValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/PasswordValidateMethod.java deleted file mode 100644 index ad206e71..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/PasswordValidateMethod.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.util.regex.Pattern; - -/** - * @description 密码校验方法 - * @filename PasswordValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class PasswordValidateMethod implements ValidateMethod { - - private final int minLength; - private final int maxLength; - private final Boolean requireUpperCase; - private final Boolean requireLowerCase; - private final Boolean requireDigit; - private final Boolean requireSpecialChar; - - /** - * @description 默认密码规则:6-20位,必须包含字母和数字 - */ - public PasswordValidateMethod() { - this(6, 20, false, false, true, false); - } - - /** - * @description 自定义密码规则 - * @param minLength 最小长度 - * @param maxLength 最大长度 - * @param requireUpperCase 是否需要大写字母 - * @param requireLowerCase 是否需要小写字母 - * @param requireDigit 是否需要数字 - * @param requireSpecialChar 是否需要特殊字符 - */ - public PasswordValidateMethod(int minLength, int maxLength, - Boolean requireUpperCase, Boolean requireLowerCase, - Boolean requireDigit, Boolean requireSpecialChar) { - this.minLength = minLength; - this.maxLength = maxLength; - this.requireUpperCase = requireUpperCase; - this.requireLowerCase = requireLowerCase; - this.requireDigit = requireDigit; - this.requireSpecialChar = requireSpecialChar; - } - - @Override - public Boolean validate(Object value) { - if (value == null || !(value instanceof String)) { - return false; - } - - String password = (String) value; - - // 长度校验 - if (password.length() < minLength || password.length() > maxLength) { - return false; - } - - // 大写字母校验 - if (requireUpperCase && !Pattern.compile("[A-Z]").matcher(password).find()) { - return false; - } - - // 小写字母校验 - if (requireLowerCase && !Pattern.compile("[a-z]").matcher(password).find()) { - return false; - } - - // 数字校验 - if (requireDigit && !Pattern.compile("[0-9]").matcher(password).find()) { - return false; - } - - // 特殊字符校验 - if (requireSpecialChar && !Pattern.compile("[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>/?]").matcher(password).find()) { - return false; - } - - return true; - } - - @Override - public String getErrorMessage() { - StringBuilder msg = new StringBuilder("密码必须是"); - msg.append(minLength).append("-").append(maxLength).append("位"); - - if (requireUpperCase || requireLowerCase || requireDigit || requireSpecialChar) { - msg.append(",且包含"); - Boolean first = true; - - if (requireUpperCase) { - msg.append("大写字母"); - first = false; - } - if (requireLowerCase) { - if (!first) msg.append("、"); - msg.append("小写字母"); - first = false; - } - if (requireDigit) { - if (!first) msg.append("、"); - msg.append("数字"); - first = false; - } - if (requireSpecialChar) { - if (!first) msg.append("、"); - msg.append("特殊字符"); - } - } - - return msg.toString(); - } - - @Override - public String getName() { - return "密码校验"; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/PhoneValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/PhoneValidateMethod.java deleted file mode 100644 index dfc8efc0..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/PhoneValidateMethod.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.util.regex.Pattern; - -/** - * @description 手机号码校验方法 - * @filename PhoneValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class PhoneValidateMethod implements ValidateMethod { - - // 中国大陆手机号正则 - private static final Pattern CHINA_PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$"); - - // 香港手机号正则 - private static final Pattern HK_PHONE_PATTERN = Pattern.compile("^[5-9]\\d{7}$"); - - // 台湾手机号正则 - private static final Pattern TW_PHONE_PATTERN = Pattern.compile("^09\\d{8}$"); - - private final Boolean strictMode; // 严格模式,只验证中国大陆手机号 - - public PhoneValidateMethod() { - this.strictMode = true; - } - - public PhoneValidateMethod(Boolean strictMode) { - this.strictMode = strictMode; - } - - @Override - public Boolean validate(Object value) { - if (value == null || !(value instanceof String)) { - return false; - } - - String phone = (String) value; - - // 去除空格和横线 - phone = phone.replaceAll("[\\s-]", ""); - - if (strictMode) { - // 严格模式:只验证中国大陆手机号 - return CHINA_PHONE_PATTERN.matcher(phone).matches(); - } else { - // 宽松模式:支持大陆、香港、台湾手机号 - return CHINA_PHONE_PATTERN.matcher(phone).matches() - || HK_PHONE_PATTERN.matcher(phone).matches() - || TW_PHONE_PATTERN.matcher(phone).matches(); - } - } - - @Override - public String getErrorMessage() { - return strictMode ? "请输入有效的手机号码" : "请输入有效的手机号码(支持大陆、香港、台湾)"; - } - - @Override - public String getName() { - return "手机号码校验"; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/UrlValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/UrlValidateMethod.java deleted file mode 100644 index 104d695d..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/UrlValidateMethod.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.util.regex.Pattern; - -/** - * @description URL校验方法 - * @filename UrlValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public class UrlValidateMethod implements ValidateMethod { - - // URL正则表达式 - private static final Pattern URL_PATTERN = Pattern.compile( - "^(https?|ftp)://[a-zA-Z0-9+&@#/%?=~_|!:,.;-]*[a-zA-Z0-9+&@#/%=~_|-]$" - ); - - private final Boolean requireHttps; // 是否要求HTTPS - - public UrlValidateMethod() { - this.requireHttps = false; - } - - public UrlValidateMethod(Boolean requireHttps) { - this.requireHttps = requireHttps; - } - - @Override - public Boolean validate(Object value) { - if (value == null || !(value instanceof String)) { - return false; - } - - String url = ((String) value).trim(); - - // 基本格式校验 - if (!URL_PATTERN.matcher(url).matches()) { - return false; - } - - // HTTPS校验 - if (requireHttps && !url.startsWith("https://")) { - return false; - } - - return true; - } - - @Override - public String getErrorMessage() { - return requireHttps ? "请输入有效的HTTPS链接" : "请输入有效的URL"; - } - - @Override - public String getName() { - return "URL校验"; - } -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ValidateMethod.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ValidateMethod.java deleted file mode 100644 index 877a0fd6..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ValidateMethod.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -/** - * @description 校验方法接口,定义不同类型的校验方式 - * @filename ValidateMethod.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public interface ValidateMethod { - - /** - * @description 校验方法 - * @param value 待校验的值 - * @return Boolean 是否校验通过 - */ - Boolean validate(Object value); - - /** - * @description 获取校验失败的错误提示信息 - * @return String 错误提示信息 - */ - String getErrorMessage(); - - /** - * @description 获取校验方法的名称 - * @return String 校验方法名称 - */ - String getName(); -} - diff --git a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ValidateMethodType.java b/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ValidateMethodType.java deleted file mode 100644 index 9c204aee..00000000 --- a/urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/validation/method/ValidateMethodType.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.xyzh.common.utils.validation.method; - -import java.util.function.Supplier; - -/** - * @description 校验方法类型枚举 - * @filename ValidateMethodType.java - * @author yslg - * @copyright yslg - * @since 2025-11-02 - */ -public enum ValidateMethodType { - - /** - * 密码校验(默认:6-20位,必须包含字母和数字) - */ - PASSWORD("密码校验", PasswordValidateMethod.class, PasswordValidateMethod::new), - - /** - * 强密码校验(8-20位,必须包含大小写字母、数字和特殊字符) - */ - STRONG_PASSWORD("强密码校验", PasswordValidateMethod.class, - () -> new PasswordValidateMethod(8, 20, true, true, true, true)), - - /** - * 身份证号校验(支持15位和18位) - */ - ID_CARD("身份证号校验", IdCardValidateMethod.class, IdCardValidateMethod::new), - - /** - * 手机号码校验(中国大陆) - */ - PHONE("手机号码校验", PhoneValidateMethod.class, PhoneValidateMethod::new), - - /** - * 手机号码校验(宽松模式,支持大陆、香港、台湾) - */ - PHONE_LOOSE("手机号码校验(宽松)", PhoneValidateMethod.class, - () -> new PhoneValidateMethod(false)), - - /** - * 邮箱地址校验 - */ - EMAIL("邮箱地址校验", EmailValidateMethod.class, EmailValidateMethod::new), - - /** - * URL链接校验 - */ - URL("URL链接校验", UrlValidateMethod.class, UrlValidateMethod::new), - - /** - * HTTPS链接校验 - */ - HTTPS_URL("HTTPS链接校验", UrlValidateMethod.class, - () -> new UrlValidateMethod(true)), - - /** - * 银行卡号校验 - */ - BANK_CARD("银行卡号校验", BankCardValidateMethod.class, BankCardValidateMethod::new), - - /** - * 中文字符校验(纯中文) - */ - CHINESE("中文字符校验", ChineseValidateMethod.class, ChineseValidateMethod::new), - - /** - * 中文字符校验(允许标点符号) - */ - CHINESE_WITH_PUNCTUATION("中文字符校验(含标点)", ChineseValidateMethod.class, - () -> new ChineseValidateMethod(true)); - - /** - * 校验方法名称 - */ - private final String name; - - /** - * 校验方法实现类 - */ - private final Class methodClass; - - /** - * 校验方法实例提供者 - */ - private final Supplier methodSupplier; - - ValidateMethodType(String name, Class methodClass, - Supplier methodSupplier) { - this.name = name; - this.methodClass = methodClass; - this.methodSupplier = methodSupplier; - } - - /** - * @description 获取校验方法名称 - * @return String - */ - public String getName() { - return name; - } - - /** - * @description 获取校验方法实现类 - * @return Class - */ - public Class getMethodClass() { - return methodClass; - } - - /** - * @description 创建校验方法实例 - * @return ValidateMethod - */ - public ValidateMethod createInstance() { - return methodSupplier.get(); - } - - /** - * @description 根据名称获取枚举 - * @param name 名称 - * @return ValidateMethodType - */ - public static ValidateMethodType fromName(String name) { - for (ValidateMethodType type : values()) { - if (type.getName().equals(name)) { - return type; - } - } - return null; - } -} - diff --git a/urbanLifelineServ/common/common-wechat/pom.xml b/urbanLifelineServ/common/common-wechat/pom.xml deleted file mode 100644 index d389d4d8..00000000 --- a/urbanLifelineServ/common/common-wechat/pom.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - 4.0.0 - - org.xyzh - common - 1.0.0 - - - org.xyzh.common - common-wechat - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - org.xyzh.apis - api-system - - - - org.xyzh.common - common-core - - - - org.apache.dubbo - dubbo-spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-web - - - - com.alibaba.fastjson2 - fastjson2 - - - - org.projectlombok - lombok - provided - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatKefuConfig.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatKefuConfig.java deleted file mode 100644 index aebc21fb..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatKefuConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.xyzh.common.wechat.config; - -import lombok.Data; - -/** - * @description 微信客服配置 - * @filename WeChatConfig.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -public class WeChatKefuConfig { - - private String corpId; - - private String secret; - - private String token; - - private String encodingAesKey; - - private String openKfid; - - private String welcomeTemplate; - - private String accessToken; - - private Long accessTokenExpireTime; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatKefuInit.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatKefuInit.java deleted file mode 100644 index 8ad88eb0..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatKefuInit.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.xyzh.common.wechat.config; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.xyzh.api.system.service.SysConfigService; -import org.xyzh.common.core.domain.ResultDomain; - -import jakarta.annotation.PostConstruct; - -/** - * @description 微信初始化配置,从系统配置中加载微信客服参数 - * @filename WeChatInit.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Component -public class WeChatKefuInit { - - private static final Logger logger = LoggerFactory.getLogger(WeChatKefuInit.class); - - @DubboReference(version = "1.0.0", group = "system", check = false, retries = 0) - private SysConfigService sysConfigService; - - private static WeChatKefuConfig weChatConfig; - - @PostConstruct - public void init() { - logger.info("初始化微信客服配置..."); - weChatConfig = new WeChatKefuConfig(); - loadConfig(); - } - - public void loadConfig() { - try { - weChatConfig.setCorpId(getConfigValue("wechat.kefu.corpId")); - weChatConfig.setSecret(getConfigValue("wechat.kefu.secret")); - weChatConfig.setToken(getConfigValue("wechat.kefu.token")); - weChatConfig.setEncodingAesKey(getConfigValue("wechat.kefu.encodingAesKey")); - weChatConfig.setOpenKfid(getConfigValue("wechat.kefu.openKfid")); - weChatConfig.setWelcomeTemplate(getConfigValue("wechat.kefu.welcomeTemplate")); - logger.info("微信客服配置加载完成: corpId={}, openKfid={}", weChatConfig.getCorpId(), weChatConfig.getOpenKfid()); - } catch (Exception e) { - logger.error("加载微信客服配置失败", e); - } - } - - private String getConfigValue(String key) { - if (sysConfigService == null) { - logger.warn("SysConfigService 未注入,跳过配置加载: {}", key); - return null; - } - ResultDomain result = sysConfigService.getConfigValueByKey(key); - if (result != null && result.getSuccess()) { - return result.getData(); - } - return null; - } - - public static WeChatKefuConfig getConfig() { - return weChatConfig; - } - - public void refreshConfig() { - loadConfig(); - } -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatMiniProgramConfig.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatMiniProgramConfig.java deleted file mode 100644 index 7f78b080..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/config/WeChatMiniProgramConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.xyzh.common.wechat.config; - -import lombok.Data; - -/** - * 微信小程序配置 - * @author cascade - * @since 2026-01-09 - */ -@Data -public class WeChatMiniProgramConfig { - - /** 小程序AppID */ - private String appId; - - /** 小程序AppSecret */ - private String appSecret; - - /** 当前access_token */ - private String accessToken; - - /** access_token过期时间(毫秒时间戳) */ - private Long accessTokenExpireTime; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/handler/DefaultKefuCallbackHandler.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/handler/DefaultKefuCallbackHandler.java deleted file mode 100644 index ab4344cb..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/handler/DefaultKefuCallbackHandler.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.xyzh.common.wechat.handler; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xyzh.common.wechat.pojo.kefu.KefuCallback; - -/** - * @description 客服回调默认处理器 - * @filename DefaultKefuCallbackHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -public class DefaultKefuCallbackHandler implements KefuCallbackHandler { - - private static final Logger logger = LoggerFactory.getLogger(DefaultKefuCallbackHandler.class); - - @Override - public void onEnterSession(KefuCallback callback) { - logger.info("用户进入会话: externalUserid={}, openKfid={}, welcomeCode={}", - callback.getExternalUserid(), callback.getOpenKfid(), callback.getWelcomeCode()); - } - - @Override - public void onMsgSendFail(KefuCallback callback) { - logger.warn("消息发送失败: failMsgid={}, failType={}", - callback.getFailMsgid(), callback.getFailType()); - } - - @Override - public void onUserRecallMsg(KefuCallback callback) { - logger.info("用户撤回消息: msgid={}", callback.getMsgid()); - } - - @Override - public void onServicerStatusChange(KefuCallback callback) { - logger.info("接待人员状态变更: openKfid={}", callback.getOpenKfid()); - } - - @Override - public void onSessionStatusChange(KefuCallback callback) { - logger.info("会话状态变更: openKfid={}, externalUserid={}", - callback.getOpenKfid(), callback.getExternalUserid()); - } - - @Override - public void onTextMessage(KefuCallback callback) { - logger.info("收到文本消息: externalUserid={}, content={}", - callback.getExternalUserid(), callback.getContent()); - } - - @Override - public void onImageMessage(KefuCallback callback) { - logger.info("收到图片消息: externalUserid={}, mediaId={}", - callback.getExternalUserid(), callback.getMediaId()); - } - - @Override - public void onVoiceMessage(KefuCallback callback) { - logger.info("收到语音消息: externalUserid={}, mediaId={}", - callback.getExternalUserid(), callback.getMediaId()); - } - - @Override - public void onVideoMessage(KefuCallback callback) { - logger.info("收到视频消息: externalUserid={}, mediaId={}", - callback.getExternalUserid(), callback.getMediaId()); - } - - @Override - public void onFileMessage(KefuCallback callback) { - logger.info("收到文件消息: externalUserid={}, mediaId={}", - callback.getExternalUserid(), callback.getMediaId()); - } - - @Override - public void onLocationMessage(KefuCallback callback) { - logger.info("收到位置消息: externalUserid={}", callback.getExternalUserid()); - } - - @Override - public void onLinkMessage(KefuCallback callback) { - logger.info("收到链接消息: externalUserid={}", callback.getExternalUserid()); - } - - @Override - public void onBusinessCardMessage(KefuCallback callback) { - logger.info("收到名片消息: externalUserid={}", callback.getExternalUserid()); - } - - @Override - public void onMiniprogramMessage(KefuCallback callback) { - logger.info("收到小程序消息: externalUserid={}", callback.getExternalUserid()); - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/handler/KefuCallbackHandler.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/handler/KefuCallbackHandler.java deleted file mode 100644 index 4b6d9c97..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/handler/KefuCallbackHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.xyzh.common.wechat.handler; - -import org.xyzh.common.wechat.pojo.kefu.KefuCallback; - -/** - * @description 客服回调处理接口 - * @filename KefuCallbackHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -public interface KefuCallbackHandler { - - void onEnterSession(KefuCallback callback); - - void onMsgSendFail(KefuCallback callback); - - void onUserRecallMsg(KefuCallback callback); - - void onServicerStatusChange(KefuCallback callback); - - void onSessionStatusChange(KefuCallback callback); - - void onTextMessage(KefuCallback callback); - - void onImageMessage(KefuCallback callback); - - void onVoiceMessage(KefuCallback callback); - - void onVideoMessage(KefuCallback callback); - - void onFileMessage(KefuCallback callback); - - void onLocationMessage(KefuCallback callback); - - void onLinkMessage(KefuCallback callback); - - void onBusinessCardMessage(KefuCallback callback); - - void onMiniprogramMessage(KefuCallback callback); - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/account/KefuAccountHandler.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/account/KefuAccountHandler.java deleted file mode 100644 index 53f06bcc..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/account/KefuAccountHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.common.wechat.kefu.account; - -/** - * @description 客服账号管理 Handler 接口 - * 业务模块可实现此接口处理账号变更事件 - * @filename KefuAccountHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -public interface KefuAccountHandler { - - /** - * 客服账号添加成功 - */ - default void onAccountAdded(String openKfid, String name) {} - - /** - * 客服账号删除成功 - */ - default void onAccountDeleted(String openKfid) {} - - /** - * 客服账号修改成功 - */ - default void onAccountUpdated(String openKfid, String name) {} - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/account/KefuAccountService.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/account/KefuAccountService.java deleted file mode 100644 index e17bcb9f..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/account/KefuAccountService.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.xyzh.common.wechat.kefu.account; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Lazy; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; -import org.xyzh.common.wechat.kefu.core.KefuAccessTokenManager; -import org.xyzh.common.wechat.pojo.kefu.KefuAccount; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; - -/** - * @description 客服账号管理服务 - * - 添加客服账号 - * - 删除客服账号 - * - 修改客服账号 - * - 获取客服账号列表 - * - 获取客服账号链接 - * @filename KefuAccountService.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Lazy -@Service -public class KefuAccountService { - - private static final Logger logger = LoggerFactory.getLogger(KefuAccountService.class); - private static final String BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin"; - - private final RestTemplate restTemplate = new RestTemplate(); - private final KefuAccessTokenManager tokenManager; - private KefuAccountHandler handler; - - public KefuAccountService(KefuAccessTokenManager tokenManager) { - this.tokenManager = tokenManager; - } - - public void setHandler(KefuAccountHandler handler) { - this.handler = handler; - } - - /** - * 添加客服账号 - */ - public String addAccount(String name, String mediaId) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/account/add?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - body.put("name", name); - if (mediaId != null) { - body.put("media_id", mediaId); - } - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - if (result.getIntValue("errcode") == 0) { - String openKfid = result.getString("open_kfid"); - logger.info("添加客服账号成功: name={}, openKfid={}", name, openKfid); - if (handler != null) { - handler.onAccountAdded(openKfid, name); - } - return openKfid; - } - - logger.error("添加客服账号失败: {}", response); - return null; - } - - /** - * 删除客服账号 - */ - public boolean deleteAccount(String openKfid) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/account/del?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - body.put("open_kfid", openKfid); - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - boolean success = result.getIntValue("errcode") == 0; - if (success) { - logger.info("删除客服账号成功: openKfid={}", openKfid); - if (handler != null) { - handler.onAccountDeleted(openKfid); - } - } else { - logger.error("删除客服账号失败: {}", response); - } - return success; - } - - /** - * 修改客服账号 - */ - public boolean updateAccount(String openKfid, String name, String mediaId) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/account/update?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - body.put("open_kfid", openKfid); - if (name != null) { - body.put("name", name); - } - if (mediaId != null) { - body.put("media_id", mediaId); - } - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - boolean success = result.getIntValue("errcode") == 0; - if (success) { - logger.info("修改客服账号成功: openKfid={}", openKfid); - if (handler != null) { - handler.onAccountUpdated(openKfid, name); - } - } else { - logger.error("修改客服账号失败: {}", response); - } - return success; - } - - /** - * 获取客服账号列表 - */ - public List getAccountList() { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/account/list?access_token=" + accessToken; - - String response = restTemplate.getForObject(url, String.class); - JSONObject result = JSON.parseObject(response); - - if (result.getIntValue("errcode") == 0) { - return result.getList("account_list", KefuAccount.class); - } - - logger.error("获取客服账号列表失败: {}", response); - return null; - } - - /** - * 获取客服账号链接 - */ - public String getAccountLink(String openKfid, String scene) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/add_contact_way?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - body.put("open_kfid", openKfid); - if (scene != null) { - body.put("scene", scene); - } - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - if (result.getIntValue("errcode") == 0) { - return result.getString("url"); - } - - logger.error("获取客服账号链接失败: {}", response); - return null; - } - - private String postJson(String url, String json) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity entity = new HttpEntity<>(json, headers); - return restTemplate.postForObject(url, entity, String.class); - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/core/KefuAccessTokenManager.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/core/KefuAccessTokenManager.java deleted file mode 100644 index e1d41319..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/core/KefuAccessTokenManager.java +++ /dev/null @@ -1,123 +0,0 @@ -package org.xyzh.common.wechat.kefu.core; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; -import org.xyzh.api.system.service.SysConfigService; -import org.xyzh.common.core.domain.ResultDomain; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; - -/** - * @description 微信客服 AccessToken 管理器 - * 负责获取和刷新 access_token - * @filename KefuAccessTokenManager.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Lazy -@Component -public class KefuAccessTokenManager { - - private static final Logger logger = LoggerFactory.getLogger(KefuAccessTokenManager.class); - private static final String BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin"; - - private final RestTemplate restTemplate = new RestTemplate(); - - @Lazy - @DubboReference(version = "1.0.0", group = "system", check = false, retries = 0) - private SysConfigService sysConfigService; - - private String corpId; - private String secret; - private String accessToken; - private Long accessTokenExpireTime; - private volatile boolean configLoaded = false; - - /** - * 懒加载配置 - */ - private void ensureConfigLoaded() { - if (!configLoaded) { - synchronized (this) { - if (!configLoaded) { - loadConfig(); - configLoaded = true; - } - } - } - } - - public void loadConfig() { - corpId = getConfigValue("wechat.kefu.corpId"); - secret = getConfigValue("wechat.kefu.secret"); - logger.info("微信客服配置加载完成: corpId={}", corpId); - } - - private String getConfigValue(String key) { - if (sysConfigService == null) { - logger.warn("SysConfigService 未注入,跳过配置加载: {}", key); - return null; - } - ResultDomain result = sysConfigService.getConfigValueByKey(key); - if (result != null && result.getSuccess()) { - return result.getData(); - } - return null; - } - - /** - * 获取 access_token,如果过期自动刷新 - */ - public String getAccessToken() { - ensureConfigLoaded(); - if (accessToken != null && accessTokenExpireTime != null - && System.currentTimeMillis() < accessTokenExpireTime) { - return accessToken; - } - return refreshAccessToken(); - } - - /** - * 刷新 access_token - */ - public String refreshAccessToken() { - ensureConfigLoaded(); - if (corpId == null || secret == null) { - logger.error("微信配置不完整,无法获取access_token"); - return null; - } - - String url = BASE_URL + "/gettoken?corpid=" + corpId + "&corpsecret=" + secret; - - try { - String response = restTemplate.getForObject(url, String.class); - JSONObject result = JSON.parseObject(response); - - if (result.getIntValue("errcode") == 0) { - accessToken = result.getString("access_token"); - int expiresIn = result.getIntValue("expires_in"); - accessTokenExpireTime = System.currentTimeMillis() + (expiresIn - 200) * 1000L; - logger.info("获取access_token成功,有效期: {}秒", expiresIn); - return accessToken; - } else { - logger.error("获取access_token失败: {}", response); - return null; - } - } catch (Exception e) { - logger.error("获取access_token异常", e); - return null; - } - } - - public String getCorpId() { - ensureConfigLoaded(); - return corpId; - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/info/KefuInfoHandler.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/info/KefuInfoHandler.java deleted file mode 100644 index 173872ec..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/info/KefuInfoHandler.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.xyzh.common.wechat.kefu.info; - -import org.xyzh.common.wechat.pojo.kefu.KefuCustomer; - -/** - * @description 基础信息获取 Handler 接口 - * 业务模块可实现此接口处理客户信息获取事件 - * @filename KefuInfoHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -public interface KefuInfoHandler { - - /** - * 客户信息获取成功 - */ - default void onCustomerInfoFetched(KefuCustomer customer) {} - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/info/KefuInfoService.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/info/KefuInfoService.java deleted file mode 100644 index b7a344d1..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/info/KefuInfoService.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.xyzh.common.wechat.kefu.info; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Lazy; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; -import org.xyzh.common.wechat.kefu.core.KefuAccessTokenManager; -import org.xyzh.common.wechat.pojo.kefu.KefuCustomer; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; - -/** - * @description 其他基础信息获取服务 - * - 获取客户基础信息 - * - 获取企业状态信息 - * @filename KefuInfoService.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Lazy -@Service -public class KefuInfoService { - - private static final Logger logger = LoggerFactory.getLogger(KefuInfoService.class); - private static final String BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin"; - - private final RestTemplate restTemplate = new RestTemplate(); - private final KefuAccessTokenManager tokenManager; - private KefuInfoHandler handler; - - public KefuInfoService(KefuAccessTokenManager tokenManager) { - this.tokenManager = tokenManager; - } - - public void setHandler(KefuInfoHandler handler) { - this.handler = handler; - } - - /** - * 获取客户基础信息 - */ - public List getCustomerInfo(List externalUseridList) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/customer/batchget?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - body.put("external_userid_list", externalUseridList); - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - if (result.getIntValue("errcode") == 0) { - List customers = result.getList("customer_list", KefuCustomer.class); - if (handler != null && customers != null) { - for (KefuCustomer customer : customers) { - handler.onCustomerInfoFetched(customer); - } - } - return customers; - } - - logger.error("获取客户信息失败: {}", response); - return null; - } - - /** - * 获取企业状态信息 - */ - public JSONObject getCorpStatistic() { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/get_corp_statistic?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - // 可添加时间范围等参数 - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - if (result.getIntValue("errcode") == 0) { - return result.getJSONObject("statistic"); - } - - logger.error("获取企业状态信息失败: {}", response); - return null; - } - - private String postJson(String url, String json) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity entity = new HttpEntity<>(json, headers); - return restTemplate.postForObject(url, entity, String.class); - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/message/KefuMessageHandler.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/message/KefuMessageHandler.java deleted file mode 100644 index da5bc693..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/message/KefuMessageHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.xyzh.common.wechat.kefu.message; - -import org.xyzh.common.wechat.pojo.kefu.KefuSyncMsgResponse.KefuSyncMsg; - -/** - * @description 客服消息处理 Handler 接口 - * 业务模块实现此接口处理客服消息和事件 - * @filename KefuMessageHandler.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -public interface KefuMessageHandler { - - /** - * 用户进入会话事件 - * @param openKfid 客服账号ID - * @param externalUserid 用户ID - * @param scene 场景值 - * @param sceneParam 场景参数(可传递工单ID等) - * @param welcomeCode 欢迎语code - */ - void onEnterSession(String openKfid, String externalUserid, String scene, String sceneParam, String welcomeCode); - - /** - * 收到文本消息 - */ - void onTextMessage(String openKfid, String externalUserid, String msgid, String content, Long sendTime); - - /** - * 收到图片消息 - */ - void onImageMessage(String openKfid, String externalUserid, String msgid, String mediaId, Long sendTime); - - /** - * 会话状态变更 - */ - void onSessionStatusChange(String openKfid, String externalUserid, String changeType, - String oldServicerUserid, String newServicerUserid); - - /** - * 消息发送失败 - */ - void onMsgSendFail(String openKfid, String externalUserid, String failMsgid, String failType); - - /** - * 其他消息(语音、视频、文件等) - */ - default void onOtherMessage(KefuSyncMsg msg) {} - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/message/KefuMessageService.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/message/KefuMessageService.java deleted file mode 100644 index 02082f03..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/kefu/message/KefuMessageService.java +++ /dev/null @@ -1,225 +0,0 @@ -package org.xyzh.common.wechat.kefu.message; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Lazy; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; -import org.xyzh.common.wechat.kefu.core.KefuAccessTokenManager; -import org.xyzh.common.wechat.pojo.kefu.KefuSyncMsgResponse; -import org.xyzh.common.wechat.pojo.kefu.KefuSyncMsgResponse.KefuSyncMsg; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; - -/** - * @description 客服消息收发服务 - * - 接收消息和事件(同步消息) - * - 发送消息 - * - 发送客服欢迎语 - * - 撤回消息 - * @filename KefuMessageService.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Lazy -@Service -public class KefuMessageService { - - private static final Logger logger = LoggerFactory.getLogger(KefuMessageService.class); - private static final String BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin"; - - private final RestTemplate restTemplate = new RestTemplate(); - private final KefuAccessTokenManager tokenManager; - private KefuMessageHandler handler; - - public KefuMessageService(KefuAccessTokenManager tokenManager) { - this.tokenManager = tokenManager; - } - - public void setHandler(KefuMessageHandler handler) { - this.handler = handler; - } - - // ========================= 接收消息和事件 ========================= - - /** - * 同步消息(拉取新消息) - */ - public KefuSyncMsgResponse syncMessages(String cursor, String token, Integer limit) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/sync_msg?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - if (cursor != null && !cursor.isEmpty()) { - body.put("cursor", cursor); - } - if (token != null && !token.isEmpty()) { - body.put("token", token); - } - if (limit != null) { - body.put("limit", limit); - } - - String response = postJson(url, body.toJSONString()); - return JSON.parseObject(response, KefuSyncMsgResponse.class); - } - - /** - * 处理同步消息(模板方法) - */ - public void processMessages(KefuSyncMsgResponse response) { - if (response == null || !response.isSuccess()) { - logger.error("消息同步响应异常: {}", response != null ? response.getErrmsg() : "null"); - return; - } - - List msgList = response.getMsgList(); - if (msgList == null || msgList.isEmpty()) { - return; - } - - logger.info("开始处理 {} 条消息", msgList.size()); - - for (KefuSyncMsg msg : msgList) { - try { - processMessage(msg); - } catch (Exception e) { - logger.error("处理消息异常: msgid={}", msg.getMsgid(), e); - } - } - } - - protected void processMessage(KefuSyncMsg msg) { - if (handler == null) { - logger.warn("未设置消息处理器"); - return; - } - - String msgtype = msg.getMsgtype(); - - if ("event".equals(msgtype)) { - processEvent(msg); - } else if ("text".equals(msgtype)) { - String content = msg.getText() != null ? msg.getText().getContent() : ""; - handler.onTextMessage(msg.getOpenKfid(), msg.getExternalUserid(), msg.getMsgid(), content, msg.getSendTime()); - } else if ("image".equals(msgtype)) { - String mediaId = msg.getImage() != null ? msg.getImage().getMediaId() : ""; - handler.onImageMessage(msg.getOpenKfid(), msg.getExternalUserid(), msg.getMsgid(), mediaId, msg.getSendTime()); - } else { - handler.onOtherMessage(msg); - } - } - - protected void processEvent(KefuSyncMsg msg) { - if (msg.getEvent() == null || handler == null) { - return; - } - - String eventType = msg.getEvent().getEventType(); - String openKfid = msg.getEvent().getOpenKfid(); - String externalUserid = msg.getEvent().getExternalUserid(); - - switch (eventType) { - case "enter_session": - handler.onEnterSession(openKfid, externalUserid, msg.getEvent().getScene(), - msg.getEvent().getSceneParam(), msg.getEvent().getWelcomeCode()); - break; - case "msg_send_fail": - handler.onMsgSendFail(openKfid, externalUserid, msg.getEvent().getFailMsgid(), msg.getEvent().getFailType()); - break; - case "session_status_change": - handler.onSessionStatusChange(openKfid, externalUserid, msg.getEvent().getChangeType(), - msg.getEvent().getOldServicerUserid(), msg.getEvent().getNewServicerUserid()); - break; - default: - logger.debug("未处理的事件类型: {}", eventType); - break; - } - } - - // ========================= 发送消息 ========================= - - /** - * 发送文本消息 - */ - public String sendTextMessage(String touser, String openKfid, String content) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/send_msg?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - body.put("touser", touser); - body.put("open_kfid", openKfid); - body.put("msgtype", "text"); - - JSONObject text = new JSONObject(); - text.put("content", content); - body.put("text", text); - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - if (result.getIntValue("errcode") == 0) { - return result.getString("msgid"); - } - - logger.error("发送消息失败: {}", response); - return null; - } - - /** - * 发送客服欢迎语 - */ - public String sendWelcomeMessage(String code, String content) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/send_msg_on_event?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - body.put("code", code); - body.put("msgtype", "text"); - - JSONObject text = new JSONObject(); - text.put("content", content); - body.put("text", text); - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - if (result.getIntValue("errcode") == 0) { - return result.getString("msgid"); - } - - logger.error("发送欢迎语失败: {}", response); - return null; - } - - /** - * 撤回消息 - */ - public boolean recallMessage(String msgid) { - String accessToken = tokenManager.getAccessToken(); - String url = BASE_URL + "/kf/recall_msg?access_token=" + accessToken; - - JSONObject body = new JSONObject(); - body.put("msgid", msgid); - - String response = postJson(url, body.toJSONString()); - JSONObject result = JSON.parseObject(response); - - return result.getIntValue("errcode") == 0; - } - - private String postJson(String url, String json) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity entity = new HttpEntity<>(json, headers); - return restTemplate.postForObject(url, entity, String.class); - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/WeChatPhoneResult.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/WeChatPhoneResult.java deleted file mode 100644 index 648e4a35..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/WeChatPhoneResult.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.xyzh.common.wechat.pojo; - -import com.alibaba.fastjson2.annotation.JSONField; - -import lombok.Data; - -/** - * 微信小程序获取手机号接口返回结果 - * @author cascade - * @since 2026-01-09 - */ -@Data -public class WeChatPhoneResult { - - /** 错误码 */ - private Integer errcode; - - /** 错误信息 */ - private String errmsg; - - /** 手机号信息 */ - @JSONField(name = "phone_info") - private PhoneInfo phoneInfo; - - /** - * 手机号信息 - */ - @Data - public static class PhoneInfo { - /** 用户绑定的手机号(国外手机号会有区号) */ - private String phoneNumber; - - /** 没有区号的手机号 */ - private String purePhoneNumber; - - /** 区号 */ - private String countryCode; - - /** 数据水印 */ - private Watermark watermark; - } - - /** - * 数据水印 - */ - @Data - public static class Watermark { - /** 小程序appid */ - private String appid; - - /** 时间戳 */ - private Long timestamp; - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/WeChatSessionResult.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/WeChatSessionResult.java deleted file mode 100644 index ce9e20c0..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/WeChatSessionResult.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.common.wechat.pojo; - -import lombok.Data; - -/** - * 微信小程序 code2Session 接口返回结果 - * @author cascade - * @since 2026-01-09 - */ -@Data -public class WeChatSessionResult { - - /** 用户唯一标识 */ - private String openid; - - /** 会话密钥 */ - private String sessionKey; - - /** 用户在开放平台的唯一标识符(需要绑定开放平台) */ - private String unionid; - - /** 错误码 */ - private Integer errcode; - - /** 错误信息 */ - private String errmsg; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/AccessTokenResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/AccessTokenResponse.java deleted file mode 100644 index 221e41e3..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/AccessTokenResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description access_token响应 - * @filename AccessTokenResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class AccessTokenResponse extends WeChatResponse { - - private String accessToken; - - private Integer expiresIn; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccount.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccount.java deleted file mode 100644 index 572207cb..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccount.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; -import java.util.List; - -/** - * @description 客服账号 - * @filename KefuAccount.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -public class KefuAccount { - - private String openKfid; - - private String name; - - private String avatar; - - private String managePrivilege; - - private List receptionistIdList; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccountAddResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccountAddResponse.java deleted file mode 100644 index 092c7e79..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccountAddResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description 添加客服账号响应 - * @filename KefuAccountAddResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class KefuAccountAddResponse extends WeChatResponse { - - private String openKfid; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccountListResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccountListResponse.java deleted file mode 100644 index af6abf19..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuAccountListResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import java.util.List; - -/** - * @description 客服账号列表响应 - * @filename KefuAccountListResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class KefuAccountListResponse extends WeChatResponse { - - private List accountList; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCallback.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCallback.java deleted file mode 100644 index b21dde44..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCallback.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; - -/** - * @description 客服回调消息 - * @filename KefuCallback.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -public class KefuCallback { - - private String toUserName; - - private String createTime; - - private String msgType; - - private String event; - - private String token; - - private String openKfid; - - private String externalUserid; - - private String scene; - - private String sceneParam; - - private String welcomeCode; - - private String failMsgid; - - private String failType; - - private String msgid; - - private String content; - - private String picUrl; - - private String mediaId; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCustomer.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCustomer.java deleted file mode 100644 index da7a74d5..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCustomer.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; - -/** - * @description 客服客户信息 - * @filename KefuCustomer.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -public class KefuCustomer { - - private String externalUserid; - - private String nickname; - - private String avatar; - - private Integer gender; - - private String unionid; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCustomerResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCustomerResponse.java deleted file mode 100644 index de8aa70c..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuCustomerResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import java.util.List; - -/** - * @description 获取客户信息响应 - * @filename KefuCustomerResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class KefuCustomerResponse extends WeChatResponse { - - private List customerList; - - private String invalidExternalUserid; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuEvent.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuEvent.java deleted file mode 100644 index 1eb2b5b4..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuEvent.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; - -/** - * @description 客服事件 - * @filename KefuEvent.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -public class KefuEvent { - - private String token; - - private String openKfid; - - private String externalUserid; - - private String scene; - - private String sceneParam; - - private String welcomeCode; - - private Long wechatChannels; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuLinkResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuLinkResponse.java deleted file mode 100644 index 641bb189..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuLinkResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description 获取客服链接响应 - * @filename KefuLinkResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class KefuLinkResponse extends WeChatResponse { - - private String url; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuMessage.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuMessage.java deleted file mode 100644 index eb2b8e1f..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; - -/** - * @description 客服消息 - * @filename KefuMessage.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -public class KefuMessage { - - private String touser; - - private String openKfid; - - private String msgid; - - private String msgtype; - - private TextContent text; - - private ImageContent image; - - private LinkContent link; - - private MiniprogramContent miniprogram; - - @Data - public static class TextContent { - private String content; - } - - @Data - public static class ImageContent { - private String mediaId; - } - - @Data - public static class LinkContent { - private String title; - private String desc; - private String url; - private String thumbMediaId; - } - - @Data - public static class MiniprogramContent { - private String appid; - private String pagepath; - private String title; - private String thumbMediaId; - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuSendMsgResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuSendMsgResponse.java deleted file mode 100644 index 3f19a498..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuSendMsgResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description 发送消息响应 - * @filename KefuSendMsgResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class KefuSendMsgResponse extends WeChatResponse { - - private String msgid; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuSyncMsgResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuSyncMsgResponse.java deleted file mode 100644 index cf06e699..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/KefuSyncMsgResponse.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import java.util.List; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description 同步消息响应 - * @filename KefuSyncMsgResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class KefuSyncMsgResponse extends WeChatResponse { - - private String nextCursor; - - private Integer hasMore; - - private List msgList; - - @Data - public static class KefuSyncMsg { - - private String msgid; - - private String openKfid; - - private String externalUserid; - - private Long sendTime; - - private Integer origin; - - private String servicerUserid; - - private String msgtype; - - private TextContent text; - - private ImageContent image; - - private VoiceContent voice; - - private VideoContent video; - - private FileContent file; - - private LocationContent location; - - private LinkContent link; - - private BusinessCardContent businessCard; - - private MiniprogramContent miniprogram; - - private EventContent event; - - } - - @Data - public static class TextContent { - private String content; - private String menuId; - } - - @Data - public static class ImageContent { - private String mediaId; - } - - @Data - public static class VoiceContent { - private String mediaId; - } - - @Data - public static class VideoContent { - private String mediaId; - } - - @Data - public static class FileContent { - private String mediaId; - } - - @Data - public static class LocationContent { - private String latitude; - private String longitude; - private String name; - private String address; - } - - @Data - public static class LinkContent { - private String title; - private String desc; - private String url; - private String picUrl; - } - - @Data - public static class BusinessCardContent { - private String userid; - } - - @Data - public static class MiniprogramContent { - private String title; - private String appid; - private String pagepath; - private String thumbMediaId; - } - - @Data - public static class EventContent { - private String eventType; - private String openKfid; - private String externalUserid; - private String scene; - private String sceneParam; - private String welcomeCode; - private String wechatChannels; - private String failMsgid; - private String failType; - private String servicerUserid; - private Integer status; - private String changeType; - private String oldServicerUserid; - private String newServicerUserid; - private String msgCode; - private String recallMsgid; - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/MediaUploadResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/MediaUploadResponse.java deleted file mode 100644 index 43d49cca..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/MediaUploadResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @description 素材上传响应 - * @filename MediaUploadResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class MediaUploadResponse extends WeChatResponse { - - private String type; - - private String mediaId; - - private Long createdAt; - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/WeChatResponse.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/WeChatResponse.java deleted file mode 100644 index fd66e222..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/pojo/kefu/WeChatResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.xyzh.common.wechat.pojo.kefu; - -import lombok.Data; - -/** - * @description 微信API通用响应 - * @filename WeChatResponse.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Data -public class WeChatResponse { - - private Integer errcode; - - private String errmsg; - - public boolean isSuccess() { - return errcode == null || errcode == 0; - } - -} diff --git a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/service/WeChatMiniProgramService.java b/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/service/WeChatMiniProgramService.java deleted file mode 100644 index 89a4a9c5..00000000 --- a/urbanLifelineServ/common/common-wechat/src/main/java/org/xyzh/common/wechat/service/WeChatMiniProgramService.java +++ /dev/null @@ -1,303 +0,0 @@ -package org.xyzh.common.wechat.service; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Base64; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.xyzh.api.system.service.SysConfigService; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.wechat.config.WeChatMiniProgramConfig; -import org.xyzh.common.wechat.pojo.WeChatPhoneResult; -import org.xyzh.common.wechat.pojo.WeChatSessionResult; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; - -/** - * 微信小程序服务 - * @author cascade - * @since 2026-01-09 - */ -@Lazy -@Service -public class WeChatMiniProgramService { - - private static final Logger logger = LoggerFactory.getLogger(WeChatMiniProgramService.class); - - /** 微信小程序配置缓存 */ - private volatile WeChatMiniProgramConfig config; - - /** code2Session接口地址 */ - private static final String CODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; - - /** 获取access_token接口地址 */ - private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token"; - - /** 获取手机号接口地址(新版API) */ - private static final String GET_PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber"; - - @Lazy - @DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0) - private SysConfigService sysConfigService; - - /** - * 获取微信小程序配置 - */ - public WeChatMiniProgramConfig getConfig() { - if (config == null) { - loadConfig(); - } - return config; - } - - /** - * 从系统配置加载微信小程序配置 - */ - private synchronized void loadConfig() { - if (config != null) { - return; - } - - config = new WeChatMiniProgramConfig(); - - try { - // 从系统配置获取小程序AppID - String appIdResult = sysConfigService.getStringConfig("wechat.miniprogram.appid"); - if (appIdResult != null && !appIdResult.trim().isEmpty()) { - config.setAppId(appIdResult); - } - - // 从系统配置获取小程序AppSecret - String appSecretResult = sysConfigService.getStringConfig("wechat.miniprogram.appsecret"); - if (appSecretResult != null && !appSecretResult.trim().isEmpty()) { - config.setAppSecret(appSecretResult); - } - - logger.info("微信小程序配置加载成功, appId: {}", config.getAppId()); - } catch (Exception e) { - logger.error("加载微信小程序配置失败", e); - } - } - - /** - * 刷新配置 - */ - public void refreshConfig() { - config = null; - loadConfig(); - } - - /** - * 通过code获取session信息(openid和session_key) - * @param code wx.login返回的code - * @return session信息 - */ - public ResultDomain code2Session(String code) { - WeChatMiniProgramConfig cfg = getConfig(); - if (cfg == null || cfg.getAppId() == null || cfg.getAppSecret() == null) { - return ResultDomain.failure("微信小程序配置未初始化"); - } - - try { - String url = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", - CODE2SESSION_URL, cfg.getAppId(), cfg.getAppSecret(), code); - - String response = httpGet(url); - logger.debug("code2Session响应: {}", response); - - WeChatSessionResult result = JSON.parseObject(response, WeChatSessionResult.class); - - if (result.getErrcode() != null && result.getErrcode() != 0) { - logger.error("code2Session失败: {} - {}", result.getErrcode(), result.getErrmsg()); - return ResultDomain.failure("获取session失败: " + result.getErrmsg()); - } - - return ResultDomain.success("获取session成功", result); - } catch (Exception e) { - logger.error("code2Session异常", e); - return ResultDomain.failure("获取session异常: " + e.getMessage()); - } - } - - /** - * 获取access_token - * @return access_token - */ - public String getAccessToken() { - WeChatMiniProgramConfig cfg = getConfig(); - if (cfg == null) { - return null; - } - - // 检查缓存的token是否有效 - if (cfg.getAccessToken() != null && cfg.getAccessTokenExpireTime() != null - && System.currentTimeMillis() < cfg.getAccessTokenExpireTime()) { - return cfg.getAccessToken(); - } - - // 重新获取token - try { - String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s", - ACCESS_TOKEN_URL, cfg.getAppId(), cfg.getAppSecret()); - - String response = httpGet(url); - JSONObject json = JSON.parseObject(response); - - if (json.containsKey("access_token")) { - String accessToken = json.getString("access_token"); - int expiresIn = json.getIntValue("expires_in"); - - cfg.setAccessToken(accessToken); - // 提前5分钟过期 - cfg.setAccessTokenExpireTime(System.currentTimeMillis() + (expiresIn - 300) * 1000L); - - logger.info("获取access_token成功, 有效期: {}秒", expiresIn); - return accessToken; - } else { - logger.error("获取access_token失败: {}", response); - return null; - } - } catch (Exception e) { - logger.error("获取access_token异常", e); - return null; - } - } - - /** - * 通过phoneCode获取手机号(新版API,推荐使用) - * @param phoneCode getPhoneNumber返回的code - * @return 手机号信息 - */ - public ResultDomain getPhoneNumber(String phoneCode) { - String accessToken = getAccessToken(); - if (accessToken == null) { - return ResultDomain.failure("获取access_token失败"); - } - - try { - String url = GET_PHONE_URL + "?access_token=" + accessToken; - - JSONObject requestBody = new JSONObject(); - requestBody.put("code", phoneCode); - - String response = httpPost(url, requestBody.toJSONString()); - logger.debug("getPhoneNumber响应: {}", response); - - WeChatPhoneResult result = JSON.parseObject(response, WeChatPhoneResult.class); - - if (result.getErrcode() != null && result.getErrcode() != 0) { - logger.error("getPhoneNumber失败: {} - {}", result.getErrcode(), result.getErrmsg()); - return ResultDomain.failure("获取手机号失败: " + result.getErrmsg()); - } - - return ResultDomain.success("获取手机号成功", result); - } catch (Exception e) { - logger.error("getPhoneNumber异常", e); - return ResultDomain.failure("获取手机号异常: " + e.getMessage()); - } - } - - /** - * 通过encryptedData和iv解密手机号(旧版API) - * @param sessionKey 会话密钥 - * @param encryptedData 加密数据 - * @param iv 解密向量 - * @return 解密后的手机号 - */ - public ResultDomain decryptPhoneNumber(String sessionKey, String encryptedData, String iv) { - try { - byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey); - byte[] encryptedDataBytes = Base64.getDecoder().decode(encryptedData); - byte[] ivBytes = Base64.getDecoder().decode(iv); - - SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES"); - IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); - - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); - - byte[] decryptedBytes = cipher.doFinal(encryptedDataBytes); - String decryptedData = new String(decryptedBytes, StandardCharsets.UTF_8); - - logger.debug("解密数据: {}", decryptedData); - - JSONObject json = JSON.parseObject(decryptedData); - String phoneNumber = json.getString("phoneNumber"); - - if (phoneNumber == null || phoneNumber.isEmpty()) { - phoneNumber = json.getString("purePhoneNumber"); - } - - return ResultDomain.success("解密成功", phoneNumber); - } catch (Exception e) { - logger.error("解密手机号失败", e); - return ResultDomain.failure("解密手机号失败: " + e.getMessage()); - } - } - - /** - * HTTP GET请求 - */ - private String httpGet(String urlStr) throws Exception { - URL url = new URL(urlStr); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("GET"); - conn.setConnectTimeout(5000); - conn.setReadTimeout(5000); - - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) { - StringBuilder response = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - response.append(line); - } - return response.toString(); - } finally { - conn.disconnect(); - } - } - - /** - * HTTP POST请求 - */ - private String httpPost(String urlStr, String body) throws Exception { - URL url = new URL(urlStr); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - conn.setConnectTimeout(5000); - conn.setReadTimeout(5000); - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "application/json"); - - try (OutputStream os = conn.getOutputStream()) { - os.write(body.getBytes(StandardCharsets.UTF_8)); - } - - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) { - StringBuilder response = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - response.append(line); - } - return response.toString(); - } finally { - conn.disconnect(); - } - } - -} diff --git a/urbanLifelineServ/common/pom.xml b/urbanLifelineServ/common/pom.xml deleted file mode 100644 index 55eafe1b..00000000 --- a/urbanLifelineServ/common/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - common - 1.0.0 - pom - - common-dto - common-core - common-auth - common-redis - common-utils - common-jdbc - common-all - common-exception - common-wechat - - - - 21 - 21 - - - - - - org.xyzh.common - common-all - ${urban-lifeline.version} - - - org.xyzh.common - common-auth - ${urban-lifeline.version} - - - org.xyzh.common - common-core - ${urban-lifeline.version} - - - org.xyzh.common - common-dto - ${urban-lifeline.version} - - - org.xyzh.common - common-redis - ${urban-lifeline.version} - - - org.xyzh.common - common-utils - ${urban-lifeline.version} - - - org.xyzh.common - common-exception - ${urban-lifeline.version} - - - org.xyzh.common - common-jdbc - ${urban-lifeline.version} - - - org.xyzh.common - common-wechat - ${urban-lifeline.version} - - - - - - - jakarta.servlet - jakarta.servlet-api - provided - - - - - org.springframework - spring-web - provided - - - org.springframework - spring-webmvc - provided - - - \ No newline at end of file diff --git a/urbanLifelineServ/crontab/pom.xml b/urbanLifelineServ/crontab/pom.xml deleted file mode 100644 index 936d2978..00000000 --- a/urbanLifelineServ/crontab/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - crontab - 1.0.0 - - - 21 - 21 - - - - crontab - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/crontab/src/main/java/org/xyzh/crontab/CrontabApp.java b/urbanLifelineServ/crontab/src/main/java/org/xyzh/crontab/CrontabApp.java deleted file mode 100644 index 122cebcd..00000000 --- a/urbanLifelineServ/crontab/src/main/java/org/xyzh/crontab/CrontabApp.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.xyzh.crontab; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@ComponentScan(basePackages = { - "org.xyzh.crontab", // 当前crontab模块 - "org.xyzh.common" // 公共模块 -}) -public class CrontabApp { - private static final Logger logger = LoggerFactory.getLogger(CrontabApp.class); - - public static void main(String[] args) { - logger.info("======================== CrontabApp 启动中 ========================="); - SpringApplication.run(CrontabApp.class, args); - logger.info("======================== CrontabApp 启动成功 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/crontab/src/main/resources/application.yml b/urbanLifelineServ/crontab/src/main/resources/application.yml deleted file mode 100644 index 464ea2e0..00000000 --- a/urbanLifelineServ/crontab/src/main/resources/application.yml +++ /dev/null @@ -1,35 +0,0 @@ -# ================== Crontab 定时任务服务配置 ================== -server: - port: 8086 - -spring: - application: - name: crontab-service - -# ================== Auth ================== -auth: - enabled: false # 定时任务服务不需要认证 - whitelist: - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - /favicon.ico - - /error - - /actuator/health - - /actuator/info - -# ================== SpringDoc ================== -springdoc: - group-configs: - - group: 'default' - display-name: '定时任务服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-crontab - qos-enable: false - scan: - base-packages: org.xyzh.crontab.service.impl diff --git a/urbanLifelineServ/crontab/src/main/resources/log4j2.xml b/urbanLifelineServ/crontab/src/main/resources/log4j2.xml deleted file mode 100644 index 678b02fe..00000000 --- a/urbanLifelineServ/crontab/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/dify/会话总结.yml b/urbanLifelineServ/dify/会话总结.yml deleted file mode 100644 index d3b472d0..00000000 --- a/urbanLifelineServ/dify/会话总结.yml +++ /dev/null @@ -1,268 +0,0 @@ -app: - description: '' - icon: 🤖 - icon_background: '#FFEAD5' - mode: workflow - name: 会话总结 - use_icon_as_answer_icon: false -dependencies: -- current_identifier: null - type: marketplace - value: - marketplace_plugin_unique_identifier: langgenius/siliconflow:0.0.38@4795747d4fca05fee9daf34b1bcc110ffbbfcd9112f5f9e914f90b8b5dd549e5 - version: null -kind: app -version: 0.5.0 -workflow: - conversation_variables: [] - environment_variables: [] - features: - file_upload: - allowed_file_extensions: - - .JPG - - .JPEG - - .PNG - - .GIF - - .WEBP - - .SVG - allowed_file_types: - - image - allowed_file_upload_methods: - - local_file - - remote_url - enabled: false - fileUploadConfig: - audio_file_size_limit: 50 - batch_count_limit: 5 - file_size_limit: 500 - image_file_batch_limit: 10 - image_file_size_limit: 10 - single_chunk_attachment_limit: 10 - video_file_size_limit: 100 - workflow_file_upload_limit: 10 - image: - enabled: false - number_limits: 3 - transfer_methods: - - local_file - - remote_url - number_limits: 3 - opening_statement: '' - retriever_resource: - enabled: true - sensitive_word_avoidance: - enabled: false - speech_to_text: - enabled: false - suggested_questions: [] - suggested_questions_after_answer: - enabled: false - text_to_speech: - enabled: false - language: '' - voice: '' - graph: - edges: - - data: - isInIteration: false - isInLoop: false - sourceType: start - targetType: code - id: 1767170626348-source-1767170986690-target - source: '1767170626348' - sourceHandle: source - target: '1767170986690' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInLoop: false - sourceType: code - targetType: llm - id: 1767170986690-source-1767170825066-target - source: '1767170986690' - sourceHandle: source - target: '1767170825066' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInIteration: false - isInLoop: false - sourceType: llm - targetType: end - id: 1767170825066-source-1767173247791-target - source: '1767170825066' - sourceHandle: source - target: '1767173247791' - targetHandle: target - type: custom - zIndex: 0 - nodes: - - data: - selected: false - title: 用户输入 - type: start - variables: - - default: '' - hint: '' - label: 聊天室对话数据 - max_length: 99999 - options: [] - placeholder: '' - required: true - type: paragraph - variable: chatMessages - height: 109 - id: '1767170626348' - position: - x: -40 - y: 267 - positionAbsolute: - x: -40 - y: 267 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - context: - enabled: true - variable_selector: - - '1767170986690' - - result - model: - completion_params: - temperature: 0.7 - mode: chat - name: Qwen/Qwen2.5-VL-72B-Instruct - provider: langgenius/siliconflow/siliconflow - prompt_template: - - id: fd7bffa7-97b7-4a7e-a47f-04dfbd15eca6 - role: system - text: '# 角色定义 - - 你是一个专业的聊天室总结助手,严格按照要求输出指定格式的JSON内容,不输出任何多余文字、注释、换行。 - - 聊天室角色说明:guest=用户、ai=智能助手、agent=人工客服,聊天消息已按send_time时间正序排列。 - - - # 输出规则(必须严格遵守,违反则任务失败) - - 1. 必须输出标准JSON字符串,仅包含 {"question":"","needs":[""],"answer":""} 三个字段,无其他字段、无多余内容; - - 2. question:提炼用户(guest)的核心问题,无业务问题则填"用户无明确业务问题,仅进行友好问候"; - - 3. needs:提取用户的核心诉求,格式为数组,无诉求则填空数组[],仅保留业务相关诉求,过滤问候语; - - 4. answer:整理有效解答(优先ai/agent回复),无有效解答则填"暂无有效解答,需用户补充更具体的问题或背景信息"; - - 5. JSON中禁止出现换行、多余空格,content中的特殊字符/引号自动转义,确保JSON语法合规。 - - - # 输出格式(唯一合法格式,必须原样输出) - - {"question":"用户提出的问题描述", "needs":["客户诉求1","客户诉求2"],"answer":"解决方案"} - - - # 聊天上下文(完整带角色,已排序) - - {{#context#}}' - selected: false - structured_output: - schema: - additionalProperties: false - properties: - answer: - type: string - needs: - items: - type: string - type: array - question: - type: string - required: - - question - - needs - - answer - type: object - structured_output_enabled: false - title: LLM - type: llm - vision: - enabled: false - height: 88 - id: '1767170825066' - position: - x: 886 - y: 294 - positionAbsolute: - x: 886 - y: 294 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - code: "import json\n\ndef main(chatMessages: str):\n # 核心:JSON字符串 转 Python对象/对象数组\n\ - \ obj_array = json.loads(chatMessages)\n # 返回转换后的对象数组,key自定义为你后续要用的名称(示例用result)\n\ - \ # {\"senderType\":\"ai\\guest\\staff\",\"content\":\"xxx\",\"send_time\"\ - :\"xxx\"}\n obj_array_sorted = sorted(obj_array, key=lambda x: x[\"send_time\"\ - ])\n return {\n \"result\": obj_array_sorted\n }" - code_language: python3 - outputs: - result: - children: null - type: array[object] - selected: false - title: jsonstring转对象数组 - type: code - variables: - - value_selector: - - '1767170626348' - - chatMessages - value_type: string - variable: chatMessages - height: 52 - id: '1767170986690' - position: - x: 301 - y: 308 - positionAbsolute: - x: 301 - y: 308 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - outputs: - - value_selector: - - '1767170825066' - - text - value_type: string - variable: text - selected: false - title: 输出 - type: end - height: 88 - id: '1767173247791' - position: - x: 1192 - y: 294 - positionAbsolute: - x: 1192 - y: 294 - selected: true - sourcePosition: right - targetPosition: left - type: custom - width: 242 - viewport: - x: -661 - y: 93.5 - zoom: 1 - rag_pipeline_variables: [] diff --git a/urbanLifelineServ/dify/动态知识库检索.yml b/urbanLifelineServ/dify/动态知识库检索.yml deleted file mode 100644 index d5a30458..00000000 --- a/urbanLifelineServ/dify/动态知识库检索.yml +++ /dev/null @@ -1,368 +0,0 @@ -app: - description: 根据用户指定的知识库进行检索,返回相似片段结构化数据。 - icon: 🤖 - icon_background: '#FFEAD5' - mode: workflow - name: 动态知识库检索 - use_icon_as_answer_icon: false -dependencies: [] -kind: app -version: 0.5.0 -workflow: - conversation_variables: [] - environment_variables: [] - features: - file_upload: - allowed_file_extensions: - - .JPG - - .JPEG - - .PNG - - .GIF - - .WEBP - - .SVG - allowed_file_types: - - image - allowed_file_upload_methods: - - local_file - - remote_url - enabled: false - fileUploadConfig: - audio_file_size_limit: 50 - batch_count_limit: 5 - file_size_limit: 15 - image_file_batch_limit: 10 - image_file_size_limit: 10 - single_chunk_attachment_limit: 10 - video_file_size_limit: 100 - workflow_file_upload_limit: 10 - image: - enabled: false - number_limits: 3 - transfer_methods: - - local_file - - remote_url - number_limits: 3 - opening_statement: '' - retriever_resource: - enabled: true - sensitive_word_avoidance: - enabled: false - speech_to_text: - enabled: false - suggested_questions: [] - suggested_questions_after_answer: - enabled: false - text_to_speech: - enabled: false - language: '' - voice: '' - graph: - edges: - - data: - isInIteration: false - isInLoop: false - sourceType: code - targetType: iteration - id: 1747125551298-source-1747125586388-target - selected: false - source: '1747125551298' - sourceHandle: source - target: '1747125586388' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInIteration: true - isInLoop: false - iteration_id: '1747125586388' - sourceType: iteration-start - targetType: http-request - id: 1747125586388start-source-1747125795256-target - source: 1747125586388start - sourceHandle: source - target: '1747125795256' - targetHandle: target - type: custom - zIndex: 1002 - - data: - isInIteration: false - isInLoop: false - sourceType: iteration - targetType: code - id: 1747125586388-source-1747125859504-target - source: '1747125586388' - sourceHandle: source - target: '1747125859504' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInIteration: false - isInLoop: false - sourceType: code - targetType: end - id: 1747125859504-source-1747125871123-target - source: '1747125859504' - sourceHandle: source - target: '1747125871123' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInLoop: false - sourceType: start - targetType: code - id: 1747125462435-source-1747125551298-target - source: '1747125462435' - sourceHandle: source - target: '1747125551298' - targetHandle: target - type: custom - zIndex: 0 - nodes: - - data: - desc: '' - selected: false - title: 开始 - type: start - variables: - - label: 知识库集(多个Id使用英文逗号隔开) - max_length: 256 - options: [] - required: true - type: text-input - variable: dataset_ids - - label: 用户问题 - max_length: 256 - options: [] - required: true - type: text-input - variable: query - - default: '' - hint: '' - label: dataset_apikey - max_length: 100 - options: [] - placeholder: '' - required: true - type: text-input - variable: dataset_apikey - height: 161 - id: '1747125462435' - position: - x: 80 - y: 282 - positionAbsolute: - x: 80 - y: 282 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - code: "\nimport json\ndef main(dataset_ids:str):\n return {\n \"\ - result\": json.loads(dataset_ids)\n }\n" - code_language: python3 - desc: '' - outputs: - result: - children: null - type: array[string] - selected: false - title: 知识库集 - type: code - variables: - - value_selector: - - '1747125462435' - - dataset_ids - value_type: string - variable: dataset_ids - height: 52 - id: '1747125551298' - position: - x: 682 - y: 282 - positionAbsolute: - x: 682 - y: 282 - selected: true - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - desc: '' - error_handle_mode: terminated - height: 231 - is_parallel: true - iterator_selector: - - '1747125551298' - - result - output_selector: - - '1747125795256' - - body - output_type: array[string] - parallel_nums: 10 - selected: false - start_node_id: 1747125586388start - title: 迭代 - type: iteration - width: 388 - height: 231 - id: '1747125586388' - position: - x: 988 - y: 282 - positionAbsolute: - x: 988 - y: 282 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 388 - zIndex: 1 - - data: - desc: '' - isInIteration: true - selected: false - title: '' - type: iteration-start - draggable: false - height: 48 - id: 1747125586388start - parentId: '1747125586388' - position: - x: 24 - y: 68 - positionAbsolute: - x: 1012 - y: 350 - selectable: false - sourcePosition: right - targetPosition: left - type: custom-iteration-start - width: 44 - zIndex: 1002 - - data: - authorization: - config: null - type: no-auth - body: - data: - - id: key-value-274 - key: '' - type: text - value: '{ - - "query": {{#1747125462435.query#}} - - }' - type: json - desc: '' - headers: 'Authorization:Bearer {{#1747125462435.dataset_apikey#}} - - Content-Type:application/json' - isInIteration: true - isInLoop: false - iteration_id: '1747125586388' - method: post - params: '' - retry_config: - max_retries: 3 - retry_enabled: false - retry_interval: 100 - selected: false - ssl_verify: true - timeout: - max_connect_timeout: 0 - max_read_timeout: 0 - max_write_timeout: 0 - title: HTTP 请求 - type: http-request - url: http://nginx:80/v1/datasets/{{#1747125586388.item#}}/retrieve - variables: [] - height: 111 - id: '1747125795256' - parentId: '1747125586388' - position: - x: 120.421417167448 - y: 54 - positionAbsolute: - x: 1108.421417167448 - y: 336 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - zIndex: 1002 - - data: - code: "\nfunction main({arg1}) {\n const result = [];\n \n // 判断arg1是否为空\n\ - \ if (!arg1 || arg1.length === 0) {\n return {\n result:\ - \ JSON.stringify([]) // 返回空数组的JSON字符串\n };\n }\n \n //\ - \ 遍历arg1中的每个元素\n for (const str of arg1) {\n try {\n \ - \ // 解析JSON\n const parsed = JSON.parse(str);\n \ - \ // 检查是否有records属性且不为空数组\n if (parsed.records && Array.isArray(parsed.records)\ - \ && parsed.records.length > 0) {\n result.push(...parsed.records)\n\ - \ }\n } catch (e) {\n // 如果JSON解析失败,跳过这个元素\n\ - \ console.error('Failed to parse JSON:', e);\n }\n \ - \ }\n \n // 将结果数组转换为JSON字符串返回\n return {\n result: JSON.stringify(result)\n\ - \ }\n}\n" - code_language: javascript - desc: '' - outputs: - result: - children: null - type: string - selected: false - title: 知识库检索结果整理 - type: code - variables: - - value_selector: - - '1747125586388' - - output - variable: arg1 - height: 52 - id: '1747125859504' - position: - x: 1436 - y: 282 - positionAbsolute: - x: 1436 - y: 282 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - desc: '' - outputs: - - value_selector: - - '1747125859504' - - result - value_type: string - variable: output - selected: false - title: 结束 - type: end - height: 88 - id: '1747125871123' - position: - x: 1739 - y: 282 - positionAbsolute: - x: 1739 - y: 282 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - viewport: - x: -33.22404773079188 - y: -134.2994836345366 - zoom: 0.8705505632961247 - rag_pipeline_variables: [] diff --git a/urbanLifelineServ/dify/泰豪小电.yml b/urbanLifelineServ/dify/泰豪小电.yml deleted file mode 100644 index 6d65dd4a..00000000 --- a/urbanLifelineServ/dify/泰豪小电.yml +++ /dev/null @@ -1,559 +0,0 @@ -app: - description: '' - icon: 🤖 - icon_background: '#FFEAD5' - mode: advanced-chat - name: 泰豪小电 - use_icon_as_answer_icon: false -dependencies: -- current_identifier: null - type: marketplace - value: - marketplace_plugin_unique_identifier: langgenius/siliconflow:0.0.38@4795747d4fca05fee9daf34b1bcc110ffbbfcd9112f5f9e914f90b8b5dd549e5 - version: null -kind: app -version: 0.5.0 -workflow: - conversation_variables: - - description: 设备代码 - id: 8a1c2cb7-376c-424a-914a-52e4155d9398 - name: device_code - selector: - - conversation - - device_code - value: '' - value_type: string - - description: 知识库访问apiKey - id: 9e385516-ad32-4ab5-ac90-1fa7c5126d06 - name: dataset_apikey - selector: - - conversation - - dataset_apikey - value: '' - value_type: string - - description: 知识库id集合,json序列化 - id: a9aaff15-cf7a-4054-a607-8ce319005703 - name: datasets - selector: - - conversation - - datasets - value: '' - value_type: string - environment_variables: [] - features: - file_upload: - allowed_file_extensions: - - .JPG - - .JPEG - - .PNG - - .GIF - - .WEBP - - .SVG - allowed_file_types: - - image - allowed_file_upload_methods: - - local_file - - remote_url - enabled: false - fileUploadConfig: - audio_file_size_limit: 50 - batch_count_limit: 5 - file_size_limit: 500 - image_file_batch_limit: 10 - image_file_size_limit: 10 - single_chunk_attachment_limit: 10 - video_file_size_limit: 100 - workflow_file_upload_limit: 10 - image: - enabled: false - number_limits: 3 - transfer_methods: - - local_file - - remote_url - number_limits: 3 - opening_statement: '' - retriever_resource: - enabled: true - sensitive_word_avoidance: - enabled: false - speech_to_text: - enabled: false - suggested_questions: [] - suggested_questions_after_answer: - enabled: false - text_to_speech: - enabled: false - language: '' - voice: '' - graph: - edges: - - data: - isInIteration: false - isInLoop: false - sourceType: start - targetType: if-else - id: 1766469212796-source-1766998282613-target - selected: false - source: '1766469212796' - sourceHandle: source - target: '1766998282613' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInIteration: false - isInLoop: false - sourceType: start - targetType: if-else - id: 1766469212796-source-1766998308433-target - selected: false - source: '1766469212796' - sourceHandle: source - target: '1766998308433' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInIteration: false - isInLoop: false - sourceType: if-else - targetType: assigner - id: 1766998282613-true-1766998338007-target - selected: false - source: '1766998282613' - sourceHandle: 'true' - target: '1766998338007' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInIteration: false - isInLoop: false - sourceType: if-else - targetType: assigner - id: 1766998308433-true-1766998352957-target - selected: false - source: '1766998308433' - sourceHandle: 'true' - target: '1766998352957' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInIteration: false - isInLoop: false - sourceType: assigner - targetType: tool - id: 1766998338007-source-1766998463133-target - selected: false - source: '1766998338007' - sourceHandle: source - target: '1766998463133' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInLoop: false - sourceType: assigner - targetType: tool - id: 1766998352957-source-1766998463133-target - selected: false - source: '1766998352957' - sourceHandle: source - target: '1766998463133' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInLoop: false - sourceType: if-else - targetType: tool - id: 1766998282613-false-1766998463133-target - selected: false - source: '1766998282613' - sourceHandle: 'false' - target: '1766998463133' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInLoop: false - sourceType: if-else - targetType: tool - id: 1766998308433-false-1766998463133-target - selected: false - source: '1766998308433' - sourceHandle: 'false' - target: '1766998463133' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInLoop: false - sourceType: tool - targetType: llm - id: 1766998463133-source-1766998751026-target - source: '1766998463133' - sourceHandle: source - target: '1766998751026' - targetHandle: target - type: custom - zIndex: 0 - - data: - isInLoop: false - sourceType: llm - targetType: answer - id: 1766998751026-source-answer-target - source: '1766998751026' - sourceHandle: source - target: answer - targetHandle: target - type: custom - zIndex: 0 - nodes: - - data: - selected: false - title: 用户输入 - type: start - variables: - - default: '' - hint: '' - label: 知识库id集合,json序列化 - max_length: 4096 - options: [] - placeholder: '' - required: true - type: paragraph - variable: datasets - - default: '' - hint: '' - label: 知识库访问apiKey - max_length: 100 - options: [] - placeholder: '' - required: true - type: text-input - variable: dataset_apikey - height: 135 - id: '1766469212796' - position: - x: 0 - y: 33 - positionAbsolute: - x: 0 - y: 33 - selected: true - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - answer: '{{#1766998751026.text#}}' - selected: false - title: 直接回复 - type: answer - variables: [] - height: 103 - id: answer - position: - x: 1770 - y: 87 - positionAbsolute: - x: 1770 - y: 87 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - cases: - - case_id: 'true' - conditions: - - comparison_operator: empty - id: 8edef3b0-823d-481c-a4eb-254a0bd42535 - value: '' - varType: string - variable_selector: - - conversation - - datasets - id: 'true' - logical_operator: and - selected: false - title: datasets初始化 - type: if-else - height: 124 - id: '1766998282613' - position: - x: 362 - y: 16 - positionAbsolute: - x: 362 - y: 16 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - cases: - - case_id: 'true' - conditions: - - comparison_operator: empty - id: 2976abfb-0b2d-43ec-bb02-f547892e39de - value: '' - varType: string - variable_selector: - - conversation - - dataset_apikey - id: 'true' - logical_operator: and - selected: false - title: 条件分支 2 - type: if-else - height: 124 - id: '1766998308433' - position: - x: 362 - y: 220 - positionAbsolute: - x: 362 - y: 220 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - items: - - input_type: variable - operation: over-write - value: - - '1766469212796' - - datasets - variable_selector: - - conversation - - datasets - write_mode: over-write - selected: false - title: 变量赋值 - type: assigner - version: '2' - height: 84 - id: '1766998338007' - position: - x: 724 - y: 0 - positionAbsolute: - x: 724 - y: 0 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - items: - - input_type: variable - operation: over-write - value: - - '1766469212796' - - dataset_apikey - variable_selector: - - conversation - - dataset_apikey - write_mode: over-write - selected: false - title: 变量赋值 2 - type: assigner - version: '2' - height: 84 - id: '1766998352957' - position: - x: 724 - y: 185 - positionAbsolute: - x: 724 - y: 185 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - is_team_authorization: true - paramSchemas: - - auto_generate: null - default: null - form: llm - human_description: - en_US: '' - ja_JP: '' - pt_BR: '' - zh_Hans: '' - label: - en_US: 知识库集(多个Id使用英文逗号隔开) - ja_JP: 知识库集(多个Id使用英文逗号隔开) - pt_BR: 知识库集(多个Id使用英文逗号隔开) - zh_Hans: 知识库集(多个Id使用英文逗号隔开) - llm_description: '' - max: null - min: null - name: dataset_ids - options: [] - placeholder: - en_US: '' - ja_JP: '' - pt_BR: '' - zh_Hans: '' - precision: null - required: true - scope: null - template: null - type: string - - auto_generate: null - default: null - form: llm - human_description: - en_US: '' - ja_JP: '' - pt_BR: '' - zh_Hans: '' - label: - en_US: 用户问题 - ja_JP: 用户问题 - pt_BR: 用户问题 - zh_Hans: 用户问题 - llm_description: '' - max: null - min: null - name: query - options: [] - placeholder: - en_US: '' - ja_JP: '' - pt_BR: '' - zh_Hans: '' - precision: null - required: true - scope: null - template: null - type: string - - auto_generate: null - default: '' - form: llm - human_description: - en_US: '' - ja_JP: '' - pt_BR: '' - zh_Hans: '' - label: - en_US: dataset_apikey - ja_JP: dataset_apikey - pt_BR: dataset_apikey - zh_Hans: dataset_apikey - llm_description: '' - max: null - min: null - name: dataset_apikey - options: [] - placeholder: - en_US: '' - ja_JP: '' - pt_BR: '' - zh_Hans: '' - precision: null - required: true - scope: null - template: null - type: string - params: - dataset_apikey: '' - dataset_ids: '' - query: '' - plugin_id: null - plugin_unique_identifier: null - provider_icon: - background: '#FFEAD5' - content: 🤖 - provider_id: 5d6141ab-e1ad-401f-a8b6-da6ce4dd682f - provider_name: 动态知识库检索 - provider_type: workflow - selected: false - title: 动态知识库检索 - tool_configurations: {} - tool_description: 根据用户指定的知识库进行检索,返回相似片段结构化数据。 - tool_label: 动态知识库检索 - tool_name: dynamic_dataset - tool_node_version: '2' - tool_parameters: - dataset_apikey: - type: mixed - value: '{{#conversation.dataset_apikey#}}' - dataset_ids: - type: mixed - value: '{{#conversation.datasets#}}' - query: - type: mixed - value: '{{#sys.query#}}' - type: tool - height: 52 - id: '1766998463133' - position: - x: 1086 - y: 113 - positionAbsolute: - x: 1086 - y: 113 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - - data: - context: - enabled: true - variable_selector: - - '1766998463133' - - text - model: - completion_params: - temperature: 0.7 - mode: chat - name: Pro/moonshotai/Kimi-K2-Instruct - provider: langgenius/siliconflow/siliconflow - prompt_config: - jinja2_variables: - - value_selector: - - '1766998463133' - - text - variable: text - prompt_template: - - edition_type: jinja2 - id: 1ee839fc-fff4-41b5-bbe3-b778b428cef4 - jinja2_text: 根据知识库内容{{ text }}回答用户问题 - role: system - text: '' - selected: false - title: LLM - type: llm - vision: - enabled: false - height: 88 - id: '1766998751026' - position: - x: 1428 - y: 95 - positionAbsolute: - x: 1428 - y: 95 - selected: false - sourcePosition: right - targetPosition: left - type: custom - width: 242 - viewport: - x: -671.7 - y: 334.55 - zoom: 0.7 - rag_pipeline_variables: [] diff --git a/urbanLifelineServ/file/pom.xml b/urbanLifelineServ/file/pom.xml deleted file mode 100644 index 2c30c6c9..00000000 --- a/urbanLifelineServ/file/pom.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - file - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - - org.xyzh.common - common-all - - - org.xyzh.apis - api-file - - - org.xyzh.apis - api-system - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - org.springframework.boot - spring-boot-starter-log4j2 - - - - - org.springframework.boot - spring-boot-starter-actuator - - - - - org.apache.dubbo - dubbo-spring-boot-starter - - - - - org.apache.dubbo - dubbo-nacos-spring-boot-starter - - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - - - io.minio - minio - - - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - - - - - com.baomidou - mybatis-plus-boot-starter - - - org.mybatis - mybatis-spring - - - - - - - org.mybatis - mybatis-spring - - - - - org.springframework.boot - spring-boot-starter-security - - - - - org.springframework.boot - spring-boot-starter-data-redis - - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/urbanLifelineServ/file/src/main/java/org/xyzh/file/FileApp.java b/urbanLifelineServ/file/src/main/java/org/xyzh/file/FileApp.java deleted file mode 100644 index 6634831e..00000000 --- a/urbanLifelineServ/file/src/main/java/org/xyzh/file/FileApp.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.file; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -/** - * FileApp 服务启动类 - * - * @author yslg - */ -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@ComponentScan(basePackages = { - "org.xyzh.file", // 当前system模块 - "org.xyzh.common" // 公共模块 -}) -public class FileApp { - private static final Logger logger = LoggerFactory.getLogger(FileApp.class); - public static void main(String[] args) { - logger.info("======================== FileApp 启动中 ========================="); - SpringApplication.run(FileApp.class, args); - logger.info("======================== FileApp 启动成功 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/file/src/main/java/org/xyzh/file/config/MinioConfig.java b/urbanLifelineServ/file/src/main/java/org/xyzh/file/config/MinioConfig.java deleted file mode 100644 index 5e9499aa..00000000 --- a/urbanLifelineServ/file/src/main/java/org/xyzh/file/config/MinioConfig.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.xyzh.file.config; - -import io.minio.MinioClient; -import lombok.Data; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.xyzh.api.system.service.SysConfigService; - -import org.apache.dubbo.config.annotation.DubboReference; -import jakarta.annotation.PostConstruct; - -/** - * @description MinIO 配置类,从数据库读取配置信息 - * @filename MinioConfig.java - * @author yslg - * @copyright yslg - * @since 2025-12-09 - */ -@Data -@Component -public class MinioConfig { - - private static final Logger logger = LoggerFactory.getLogger(MinioConfig.class); - - @DubboReference(version = "1.0.0", group = "system", timeout = 3000, retries = 0) - private SysConfigService sysConfigService; - - // MinIO 配置项的键名 - private static final String MINIO_ENDPOINT_KEY = "minio.endpoint"; - private static final String MINIO_ACCESS_KEY = "minio.accessKey"; - private static final String MINIO_SECRET_KEY = "minio.secretKey"; - private static final String MINIO_BUCKET_NAME_KEY = "minio.bucketName"; - private static final String MINIO_PUBLIC_URL_KEY = "minio.publicUrl"; - - // 默认值 - private static final String DEFAULT_ENDPOINT = "http://localhost:9000"; - private static final String DEFAULT_ACCESS_KEY = "minioadmin"; - private static final String DEFAULT_SECRET_KEY = "minioadmin123"; - private static final String DEFAULT_BUCKET_NAME = "urban-lifeline"; - private static final String DEFAULT_PUBLIC_URL = "http://localhost:9000"; - - // 配置属性 - private String endpoint; - private String accessKey; - private String secretKey; - private String bucketName; - private String publicUrl; - - private MinioClient minioClient; - - @PostConstruct - public void init() { - loadConfig(); - initClient(); - } - - /** - * 从数据库加载MinIO配置 - */ - private void loadConfig() { - try { - endpoint = sysConfigService.getStringConfig(MINIO_ENDPOINT_KEY); - accessKey = sysConfigService.getStringConfig(MINIO_ACCESS_KEY); - secretKey = sysConfigService.getStringConfig(MINIO_SECRET_KEY); - bucketName = sysConfigService.getStringConfig(MINIO_BUCKET_NAME_KEY); - publicUrl = sysConfigService.getStringConfig(MINIO_PUBLIC_URL_KEY); - - // 使用默认值如果配置不存在 - if (endpoint == null || endpoint.trim().isEmpty()) { - endpoint = DEFAULT_ENDPOINT; - logger.warn("未找到MinIO endpoint配置,使用默认值: {}", DEFAULT_ENDPOINT); - } - if (accessKey == null || accessKey.trim().isEmpty()) { - accessKey = DEFAULT_ACCESS_KEY; - logger.warn("未找到MinIO accessKey配置,使用默认值"); - } - if (secretKey == null || secretKey.trim().isEmpty()) { - secretKey = DEFAULT_SECRET_KEY; - logger.warn("未找到MinIO secretKey配置,使用默认值"); - } - if (bucketName == null || bucketName.trim().isEmpty()) { - bucketName = DEFAULT_BUCKET_NAME; - logger.warn("未找到MinIO bucketName配置,使用默认值: {}", DEFAULT_BUCKET_NAME); - } - if (publicUrl == null || publicUrl.trim().isEmpty()) { - publicUrl = endpoint; // 默认使用endpoint作为公网访问地址 - logger.warn("未找到MinIO publicUrl配置,使用endpoint作为默认值: {}", endpoint); - } - - logger.info("MinIO配置加载完成 - endpoint: {}, bucketName: {}", endpoint, bucketName); - - } catch (Exception e) { - logger.error("加载MinIO配置失败,使用默认配置", e); - endpoint = DEFAULT_ENDPOINT; - accessKey = DEFAULT_ACCESS_KEY; - secretKey = DEFAULT_SECRET_KEY; - bucketName = DEFAULT_BUCKET_NAME; - publicUrl = DEFAULT_PUBLIC_URL; - } - } - - /** - * 初始化MinIO客户端 - */ - private void initClient() { - try { - minioClient = MinioClient.builder() - .endpoint(endpoint) - .credentials(accessKey, secretKey) - .build(); - - logger.info("MinIO客户端初始化成功"); - } catch (Exception e) { - logger.error("MinIO客户端初始化失败", e); - throw new RuntimeException("MinIO客户端初始化失败", e); - } - } - - /** - * 重新加载配置 - */ - public void reloadConfig() { - logger.info("重新加载MinIO配置"); - loadConfig(); - initClient(); - } - - /** - * 获取MinIO客户端 - */ - public MinioClient getMinioClient() { - return minioClient; - } - - /** - * 构建文件的公网访问URL - * @param objectName 对象名称 - * @return 完整的文件访问URL - */ - public String buildFileUrl(String objectName) { - return publicUrl + "/" + bucketName + "/" + objectName; - } -} diff --git a/urbanLifelineServ/file/src/main/java/org/xyzh/file/controller/FileController.java b/urbanLifelineServ/file/src/main/java/org/xyzh/file/controller/FileController.java deleted file mode 100644 index a526f9ac..00000000 --- a/urbanLifelineServ/file/src/main/java/org/xyzh/file/controller/FileController.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.xyzh.file.controller; - -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; -import org.xyzh.api.file.dto.TbSysFileDTO; -import org.xyzh.api.file.service.FileService; -import org.xyzh.common.core.domain.ResultDomain; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; - -/** - * @description 文件管理控制器 - * @filename FileController.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Tag(name = "文件管理") -@RestController -@RequestMapping("/file") -public class FileController { - - @Autowired - private FileService fileService; - - // ========================= 文件上传 ========================= - - @Operation(summary = "上传文件") - @PostMapping("/upload") - public ResultDomain uploadFile( - @RequestParam("file") MultipartFile file, - @RequestParam(value = "module", required = false) String module, - @RequestParam(value = "businessId", required = false) String businessId, - @RequestParam(value = "fileName", required = false) String fileName) { - try { - // 如果前端传递了 fileName,使用它;否则使用 MultipartFile 的原始文件名 - String actualFileName = (fileName != null && !fileName.isEmpty()) ? fileName : file.getOriginalFilename(); - return fileService.uploadFileBytes(file.getBytes(), actualFileName, file.getContentType(), module, businessId); - } catch (Exception e) { - return ResultDomain.failure("文件上传失败: " + e.getMessage()); - } - } - - @Operation(summary = "批量上传文件") - @PostMapping("/upload/batch") - public ResultDomain batchUploadFiles( - @RequestParam("files") MultipartFile[] files, - @RequestParam(value = "module", required = false) String module, - @RequestParam(value = "businessId", required = false) String businessId, - @RequestParam(value = "uploader", required = false) String uploader) { - return fileService.batchUploadFiles(files, module, businessId, uploader); - } - - @Operation(summary = "上传临时文件") - @PostMapping("/upload/temp") - public ResultDomain saveTempFile( - @RequestParam("file") MultipartFile file, - @RequestParam(value = "module", required = false) String module, - @RequestParam(value = "businessId", required = false) String businessId) { - return fileService.saveTempFile(file, module, businessId); - } - - @Operation(summary = "上传新版本文件") - @PostMapping("/upload/version") - public ResultDomain uploadFileVersion( - @RequestParam("file") MultipartFile file, - @RequestParam(value = "module", required = false) String module, - @RequestParam(value = "businessId", required = false) String businessId, - @RequestParam("fileRootId") String fileRootId) { - return fileService.uploadFileVersion(file, module, businessId, fileRootId); - } - - // ========================= 文件查询 ========================= - - @Operation(summary = "获取文件信息") - @GetMapping("/{fileId}") - public ResultDomain getFileById(@PathVariable("fileId") String fileId) { - return fileService.getFileById(fileId); - } - - // ========================= 文件下载 ========================= - - @Operation(summary = "下载文件") - @GetMapping("/download/{fileId}") - public ResponseEntity downloadFile(@PathVariable("fileId") String fileId) { - ResultDomain result = fileService.downloadFile(fileId); - if (!result.getSuccess() || result.getData() == null) { - return ResponseEntity.notFound().build(); - } - - ResultDomain fileInfo = fileService.getFileById(fileId); - String filename = fileInfo.getData() != null ? fileInfo.getData().getName() : "download"; - String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8).replace("+", "%20"); - - return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFilename + "\"; filename*=UTF-8''" + encodedFilename) - .contentType(MediaType.APPLICATION_OCTET_STREAM) - .body(result.getData()); - } - - // ========================= 文件删除 ========================= - - @Operation(summary = "删除文件") - @DeleteMapping("/{fileId}") - public ResultDomain deleteFile(@PathVariable("fileId") String fileId) { - return fileService.deleteFile(fileId); - } - - @Operation(summary = "批量删除文件") - @DeleteMapping("/batch") - public ResultDomain batchDeleteFiles(@RequestParam("fileIds") String[] fileIds) { - return fileService.batchDeleteFiles(fileIds); - } - -} diff --git a/urbanLifelineServ/file/src/main/java/org/xyzh/file/mapper/FileMapper.java b/urbanLifelineServ/file/src/main/java/org/xyzh/file/mapper/FileMapper.java deleted file mode 100644 index 8ad585a8..00000000 --- a/urbanLifelineServ/file/src/main/java/org/xyzh/file/mapper/FileMapper.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.xyzh.file.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; -import org.apache.ibatis.annotations.Update; -import org.xyzh.api.file.dto.TbSysFileDTO; - -/** - * @description 文件Mapper接口 - * @filename FileMapper.java - * @author yslg - * @copyright yslg - * @since 2025-12-09 - */ -@Mapper -public interface FileMapper extends BaseMapper { - - /** - * 根据文件ID查询文件信息(自定义方法替代selectById) - * @param fileId 文件ID - * @return 文件信息 - */ - @Select("SELECT * FROM file.tb_sys_file WHERE file_id = #{fileId} AND deleted = false") - TbSysFileDTO selectByFileId(@Param("fileId") String fileId); - - /** - * 插入文件记录(自定义方法) - * @param fileDTO 文件DTO - * @return 影响行数 - */ - int insertFile(TbSysFileDTO fileDTO); - - /** - * 根据文件ID更新文件信息(自定义方法替代updateById) - * @param fileDTO 文件DTO - * @return 影响行数 - */ - int updateByFileId(TbSysFileDTO fileDTO); - - /** - * 根据文件ID逻辑删除文件(自定义方法) - * @param fileId 文件ID - * @param updater 更新者 - * @return 影响行数 - */ - @Update("UPDATE file.tb_sys_file SET deleted = true, delete_time = CURRENT_TIMESTAMP, updater = #{updater} WHERE file_id = #{fileId}") - int deleteByFileId(@Param("fileId") String fileId, @Param("updater") String updater); - - /** - * 根据模块和业务ID查询文件列表 - * @param module 模块 - * @param businessId 业务ID - * @return 文件列表 - */ - @Select("SELECT * FROM file.tb_sys_file WHERE module = #{module} AND business_id = #{businessId} AND deleted = false ORDER BY create_time DESC") - List selectByModuleAndBusinessId(@Param("module") String module, @Param("businessId") String businessId); - - /** - * 根据上传者查询文件列表 - * @param uploader 上传者用户ID - * @return 文件列表 - */ - @Select("SELECT * FROM file.tb_sys_file WHERE uploader = #{uploader} AND deleted = false ORDER BY create_time DESC") - List selectByUploader(@Param("uploader") String uploader); - - /** - * 根据MD5查询文件(用于防重复上传) - * @param md5Hash MD5哈希值 - * @return 文件信息 - */ - @Select("SELECT * FROM file.tb_sys_file WHERE md5_hash = #{md5Hash} AND deleted = false LIMIT 1") - TbSysFileDTO selectByMd5Hash(@Param("md5Hash") String md5Hash); - - /** - * 根据MinIO对象名称查询文件 - * @param bucketName 存储桶名称 - * @param objectName 对象名称 - * @return 文件信息 - */ - @Select("SELECT * FROM file.tb_sys_file WHERE bucket_name = #{bucketName} AND object_name = #{objectName} AND deleted = false") - TbSysFileDTO selectByMinioObject(@Param("bucketName") String bucketName, @Param("objectName") String objectName); - - /** - * @description 根据文件根ID查询最大版本号 - * @param fileRootId 文件根ID - * @return Integer 最大版本号 - * @author yslg - * @since 2025-12-18 - */ - @Select("SELECT MAX(version) FROM file.tb_sys_file WHERE file_root_id = #{fileRootId} AND deleted = false") - Integer selectMaxVersionByFileRootId(@Param("fileRootId") String fileRootId); -} diff --git a/urbanLifelineServ/file/src/main/java/org/xyzh/file/service/impl/FileServiceImpl.java b/urbanLifelineServ/file/src/main/java/org/xyzh/file/service/impl/FileServiceImpl.java deleted file mode 100644 index 0bec0c52..00000000 --- a/urbanLifelineServ/file/src/main/java/org/xyzh/file/service/impl/FileServiceImpl.java +++ /dev/null @@ -1,436 +0,0 @@ -package org.xyzh.file.service.impl; - -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -// import org.springframework.beans.BeanUtils; // 不再需要BeanUtils -import org.springframework.util.DigestUtils; -import org.springframework.web.multipart.MultipartFile; -import org.xyzh.api.file.dto.TbSysFileDTO; -import org.xyzh.api.file.service.FileService; -import org.xyzh.common.auth.utils.LoginUtil; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.file.config.MinioConfig; -import org.xyzh.file.mapper.FileMapper; -import org.xyzh.file.util.MinioUtil; - -import java.io.InputStream; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * @description 文件服务实现类 - * @filename FileServiceImpl.java - * @author yslg - * @copyright yslg - * @since 2025-12-09 - */ -@DubboService( - version = "1.0.0", - group = "file", - timeout = 3000, - retries = 0 -) -public class FileServiceImpl implements FileService { - - private static final Logger logger = LoggerFactory.getLogger(FileServiceImpl.class); - - @Autowired - private MinioConfig minioConfig; - - @Autowired - private MinioUtil minioUtil; - - @Autowired - private FileMapper fileMapper; - - @Override - public ResultDomain uploadFile(MultipartFile file, String module, String businessId) { - try { - if (file == null || file.isEmpty()) { - return ResultDomain.failure("文件不能为空"); - } - return uploadFileBytesWithUser(file.getBytes(), file.getOriginalFilename(), file.getContentType(), module, businessId, getCurrentUserId()); - } catch (Exception e) { - logger.error("文件上传失败", e); - return ResultDomain.failure("文件上传失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain batchUploadFiles(MultipartFile[] files, String module, String businessId, String uploader) { - try { - if (files == null || files.length == 0) { - return ResultDomain.failure("文件列表不能为空"); - } - - List uploadedFiles = new ArrayList<>(); - - for (MultipartFile file : files) { - ResultDomain result = uploadFile(file, module, businessId); - if (result.getSuccess()) { - TbSysFileDTO fileDTO = result.getData(); - fileDTO.setUploader(uploader); - uploadedFiles.add(fileDTO); - } else { - // 如果有文件上传失败,记录日志但继续处理其他文件 - logger.warn("文件上传失败: {}, 原因: {}", file.getOriginalFilename(), result.getMessage()); - } - } - - if (uploadedFiles.isEmpty()) { - return ResultDomain.failure("所有文件上传失败"); - } - - // 返回上传成功的文件列表(这里简化处理,实际可能需要返回详细结果) - TbSysFileDTO resultDTO = new TbSysFileDTO(); - // 可以在这里设置批量上传的汇总信息 - - logger.info("批量文件上传完成,成功: {}, 总数: {}", uploadedFiles.size(), files.length); - return ResultDomain.success("批量文件上传成功", resultDTO); - - } catch (Exception e) { - logger.error("批量文件上传失败", e); - return ResultDomain.failure("批量文件上传失败: " + e.getMessage()); - } - } - - /** - * @description 软删除文件(只标记数据库记录为已删除,不删除minio文件) - * @param fileId 文件ID - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-12-18 - */ - @Override - public ResultDomain deleteFile(String fileId) { - try { - // 从数据库获取文件信息 - TbSysFileDTO sysFile = fileMapper.selectByFileId(fileId); - if (sysFile == null) { - return ResultDomain.failure("文件不存在"); - } - - // 删除MinIO中的文件 - // minioUtil.deleteFile(sysFile.getBucketName(), sysFile.getObjectName()); - - // 逻辑删除数据库记录 - int result = fileMapper.deleteByFileId(fileId, "system"); - - if (result > 0) { - logger.info("文件软删除成功: {}", fileId); - return ResultDomain.success("文件删除成功", true); - } else { - return ResultDomain.failure("文件删除失败"); - } - - } catch (Exception e) { - logger.error("文件删除失败: {}", fileId, e); - return ResultDomain.failure("文件删除失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain batchDeleteFiles(String[] fileIds) { - try { - if (fileIds == null || fileIds.length == 0) { - return ResultDomain.failure("文件ID列表不能为空"); - } - - int successCount = 0; - for (String fileId : fileIds) { - ResultDomain result = deleteFile(fileId); - if (result.getSuccess()) { - successCount++; - } - } - - TbSysFileDTO resultDTO = new TbSysFileDTO(); - // 可以在这里设置批量删除的结果统计 - - logger.info("批量文件删除完成,成功: {}, 总数: {}", successCount, fileIds.length); - return ResultDomain.success("批量文件删除完成", resultDTO); - - } catch (Exception e) { - logger.error("批量文件删除失败", e); - return ResultDomain.failure("批量文件删除失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain downloadFile(String fileId) { - try { - // 从数据库获取文件信息 - TbSysFileDTO sysFile = fileMapper.selectByFileId(fileId); - if (sysFile == null) { - return ResultDomain.failure("文件不存在"); - } - - // 从MinIO下载文件 - InputStream inputStream = minioUtil.downloadFile(sysFile.getBucketName(), sysFile.getObjectName()); - if (inputStream == null) { - return ResultDomain.failure("文件下载失败"); - } - - // 将输入流转换为字节数组 - byte[] data = inputStream.readAllBytes(); - inputStream.close(); - - logger.info("文件下载成功: {}", fileId); - return ResultDomain.success("文件下载成功", data); - - } catch (Exception e) { - logger.error("文件下载失败: {}", fileId, e); - return ResultDomain.failure("文件下载失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain getFileById(String fileId) { - try { - TbSysFileDTO sysFile = fileMapper.selectByFileId(fileId); - if (sysFile == null) { - return ResultDomain.failure("文件不存在"); - } - - return ResultDomain.success("获取文件信息成功", sysFile); - - } catch (Exception e) { - logger.error("查询文件失败: {}", fileId, e); - return ResultDomain.failure("查询文件失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain saveTempFile(MultipartFile file, String module, String businessId) { - try { - // 临时文件上传逻辑与普通上传相同,但可以添加特殊标识 - ResultDomain result = uploadFile(file, module, businessId); - if (result.getSuccess()) { - TbSysFileDTO fileDTO = result.getData(); - fileDTO.setStatus("TEMP"); // 标记为临时文件 - - // 更新数据库中的状态 - fileMapper.updateByFileId(fileDTO); - } - - return result; - - } catch (Exception e) { - logger.error("临时文件保存失败", e); - return ResultDomain.failure("临时文件保存失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain uploadFileVersion(MultipartFile file, String module, String businessId, String fileRootId) { - try { - if (file == null || file.isEmpty()) { - return ResultDomain.failure("文件不能为空"); - } - if (fileRootId == null || fileRootId.isEmpty()) { - return ResultDomain.failure("文件根ID不能为空"); - } - return uploadFileBytesVersionWithUser(file.getBytes(), file.getOriginalFilename(), file.getContentType(), module, businessId, fileRootId, getCurrentUserId()); - } catch (Exception e) { - logger.error("新版本文件上传失败", e); - return ResultDomain.failure("文件上传失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain uploadFileBytes(byte[] fileBytes, String fileName, String contentType, String module, String businessId) { - return uploadFileBytesWithUser(fileBytes, fileName, contentType, module, businessId, getCurrentUserId()); - } - - @Override - public ResultDomain uploadFileBytesWithUser(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String uploaderUserId) { - try { - if (fileBytes == null || fileBytes.length == 0) { - return ResultDomain.failure("文件不能为空"); - } - - String extension = getFileExtension(fileName); - long size = fileBytes.length; - String objectName = generateObjectName(fileName, module); - String md5Hash = calculateMD5(fileBytes); - - String bucketName = minioConfig.getBucketName(); - java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(fileBytes); - boolean uploadSuccess = minioUtil.uploadFile(bucketName, objectName, inputStream, size, contentType); - - if (!uploadSuccess) { - return ResultDomain.failure("文件上传到MinIO失败"); - } - - TbSysFileDTO fileDTO = new TbSysFileDTO(); - String fileId = UUID.randomUUID().toString().replace("-", ""); - fileDTO.setOptsn(UUID.randomUUID().toString()); - fileDTO.setFileId(fileId); - fileDTO.setName(fileName); - fileDTO.setPath(objectName); - fileDTO.setUrl(null); - fileDTO.setSize(size); - fileDTO.setMimeType(contentType); - fileDTO.setExtension(extension); - fileDTO.setMd5Hash(md5Hash); - fileDTO.setModule(module); - fileDTO.setBusinessId(businessId); - fileDTO.setStorageType("MINIO"); - fileDTO.setObjectName(objectName); - fileDTO.setBucketName(bucketName); - fileDTO.setVersion(1); - fileDTO.setFileRootId(fileId); - fileDTO.setCreator(uploaderUserId); - fileDTO.setUploader(uploaderUserId); - fileDTO.setCreateTime(new java.util.Date()); - - int result = fileMapper.insertFile(fileDTO); - if (result <= 0) { - minioUtil.deleteFile(bucketName, objectName); - return ResultDomain.failure("文件信息保存失败"); - } - - logger.info("字节数组文件上传成功: {}, uploader: {}", fileName, uploaderUserId); - return ResultDomain.success("文件上传成功", fileDTO); - - } catch (Exception e) { - logger.error("字节数组文件上传失败", e); - return ResultDomain.failure("文件上传失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain uploadFileBytesVersion(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String fileRootId) { - return uploadFileBytesVersionWithUser(fileBytes, fileName, contentType, module, businessId, fileRootId, getCurrentUserId()); - } - - @Override - public ResultDomain uploadFileBytesVersionWithUser(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String fileRootId, String uploaderUserId) { - try { - if (fileBytes == null || fileBytes.length == 0) { - return ResultDomain.failure("文件不能为空"); - } - if (fileRootId == null || fileRootId.isEmpty()) { - return ResultDomain.failure("文件根ID不能为空"); - } - - // 1. 获取当前最大版本号 - Integer maxVersion = fileMapper.selectMaxVersionByFileRootId(fileRootId); - int newVersion = (maxVersion != null ? maxVersion : 0) + 1; - - // 2. 生成文件信息 - String extension = getFileExtension(fileName); - long size = fileBytes.length; - - // 3. 生成唯一的对象名称 - String objectName = generateObjectName(fileName, module); - - // 4. 计算文件MD5 - String md5Hash = calculateMD5(fileBytes); - - // 5. 上传到MinIO - String bucketName = minioConfig.getBucketName(); - java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(fileBytes); - boolean uploadSuccess = minioUtil.uploadFile( - bucketName, - objectName, - inputStream, - size, - contentType - ); - - if (!uploadSuccess) { - return ResultDomain.failure("文件上传到MinIO失败"); - } - - // 6. 构建文件访问URL - String fileUrl = minioConfig.buildFileUrl(objectName); - - // 7. 保存到数据库(新版本记录) - TbSysFileDTO fileDTO = new TbSysFileDTO(); - fileDTO.setOptsn(UUID.randomUUID().toString()); - fileDTO.setFileId(UUID.randomUUID().toString()); - fileDTO.setFileRootId(fileRootId); - fileDTO.setVersion(newVersion); - fileDTO.setName(fileName); - fileDTO.setPath(objectName); - fileDTO.setSize(size); - fileDTO.setType(extension); - fileDTO.setStorageType("MINIO"); - fileDTO.setMimeType(contentType); - fileDTO.setUrl(fileUrl); - fileDTO.setStatus("NORMAL"); - fileDTO.setModule(module); - fileDTO.setBusinessId(businessId); - fileDTO.setObjectName(objectName); - fileDTO.setBucketName(bucketName); - fileDTO.setMd5Hash(md5Hash); - fileDTO.setExtension(extension); - fileDTO.setCreator(uploaderUserId); - fileDTO.setUploader(uploaderUserId); - fileDTO.setCreateTime(new java.util.Date()); - - int result = fileMapper.insertFile(fileDTO); - if (result <= 0) { - minioUtil.deleteFile(bucketName, objectName); - return ResultDomain.failure("文件信息保存失败"); - } - - logger.info("新版本文件上传成功(bytes): {}, version: {}, fileRootId: {}, uploader: {}", fileName, newVersion, fileRootId, uploaderUserId); - return ResultDomain.success("文件上传成功", fileDTO); - - } catch (Exception e) { - logger.error("新版本文件上传失败(bytes)", e); - return ResultDomain.failure("文件上传失败: " + e.getMessage()); - } - } - - /** - * 生成唯一的对象名称 - */ - private String generateObjectName(String originalFilename, String module) { - String extension = getFileExtension(originalFilename); - String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); - String uuid = UUID.randomUUID().toString().replace("-", ""); - - return String.format("%s/%s/%s%s", module, date, uuid, extension); - } - - /** - * 获取文件扩展名 - */ - private String getFileExtension(String filename) { - if (filename == null || !filename.contains(".")) { - return ""; - } - return filename.substring(filename.lastIndexOf(".")); - } - - /** - * 计算文件MD5值 - */ - private String calculateMD5(byte[] data) { - return DigestUtils.md5DigestAsHex(data); - } - - /** - * 获取当前登录用户ID(支持未登录场景) - */ - private String getCurrentUserId() { - try { - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (loginDomain != null && loginDomain.getUser() != null) { - return loginDomain.getUser().getUserId(); - } - } catch (Exception e) { - logger.debug("获取当前登录用户失败: {}", e.getMessage()); - } - return null; - } -} diff --git a/urbanLifelineServ/file/src/main/java/org/xyzh/file/util/MinioUtil.java b/urbanLifelineServ/file/src/main/java/org/xyzh/file/util/MinioUtil.java deleted file mode 100644 index 2edb2bbe..00000000 --- a/urbanLifelineServ/file/src/main/java/org/xyzh/file/util/MinioUtil.java +++ /dev/null @@ -1,222 +0,0 @@ -package org.xyzh.file.util; - -import io.minio.*; -import io.minio.http.Method; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.xyzh.file.config.MinioConfig; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.TimeUnit; - -/** - * @description MinIO 工具类 - * @filename MinioUtil.java - * @author yslg - * @copyright yslg - * @since 2025-12-09 - */ -@Component -public class MinioUtil { - - private static final Logger logger = LoggerFactory.getLogger(MinioUtil.class); - - @Autowired - private MinioConfig minioConfig; - - /** - * 检查存储桶是否存在,如果不存在则创建 - * @param bucketName 存储桶名称 - * @return true 成功,false 失败 - */ - public boolean createBucketIfNotExists(String bucketName) { - try { - MinioClient minioClient = minioConfig.getMinioClient(); - - // 检查存储桶是否存在 - boolean exists = minioClient.bucketExists(BucketExistsArgs.builder() - .bucket(bucketName) - .build()); - - if (!exists) { - // 创建存储桶 - minioClient.makeBucket(MakeBucketArgs.builder() - .bucket(bucketName) - .build()); - logger.info("成功创建存储桶: {}", bucketName); - } - - return true; - } catch (Exception e) { - logger.error("创建存储桶失败: {}", bucketName, e); - return false; - } - } - - /** - * 上传文件到MinIO - * @param bucketName 存储桶名称 - * @param objectName 对象名称 - * @param inputStream 文件输入流 - * @param size 文件大小 - * @param contentType 文件类型 - * @return true 成功,false 失败 - */ - public boolean uploadFile(String bucketName, String objectName, InputStream inputStream, long size, String contentType) { - try { - MinioClient minioClient = minioConfig.getMinioClient(); - - // 确保存储桶存在 - if (!createBucketIfNotExists(bucketName)) { - return false; - } - - // 上传文件 - minioClient.putObject(PutObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .stream(inputStream, size, -1) - .contentType(contentType) - .build()); - - logger.info("文件上传成功: {}/{}", bucketName, objectName); - return true; - - } catch (Exception e) { - logger.error("文件上传失败: {}/{}", bucketName, objectName, e); - return false; - } - } - - /** - * 上传字节数组到MinIO - * @param bucketName 存储桶名称 - * @param objectName 对象名称 - * @param data 字节数组 - * @param contentType 文件类型 - * @return true 成功,false 失败 - */ - public boolean uploadFile(String bucketName, String objectName, byte[] data, String contentType) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(data)) { - return uploadFile(bucketName, objectName, inputStream, data.length, contentType); - } catch (IOException e) { - logger.error("创建字节数组输入流失败", e); - return false; - } - } - - /** - * 下载文件 - * @param bucketName 存储桶名称 - * @param objectName 对象名称 - * @return 文件输入流,失败返回null - */ - public InputStream downloadFile(String bucketName, String objectName) { - try { - MinioClient minioClient = minioConfig.getMinioClient(); - - return minioClient.getObject(GetObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .build()); - - } catch (Exception e) { - logger.error("文件下载失败: {}/{}", bucketName, objectName, e); - return null; - } - } - - /** - * 删除文件 - * @param bucketName 存储桶名称 - * @param objectName 对象名称 - * @return true 成功,false 失败 - */ - public boolean deleteFile(String bucketName, String objectName) { - try { - MinioClient minioClient = minioConfig.getMinioClient(); - - minioClient.removeObject(RemoveObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .build()); - - logger.info("文件删除成功: {}/{}", bucketName, objectName); - return true; - - } catch (Exception e) { - logger.error("文件删除失败: {}/{}", bucketName, objectName, e); - return false; - } - } - - /** - * 获取文件的预签名URL(用于临时访问) - * @param bucketName 存储桶名称 - * @param objectName 对象名称 - * @param expiry 过期时间(秒) - * @return 预签名URL,失败返回null - */ - public String getPresignedUrl(String bucketName, String objectName, int expiry) { - try { - MinioClient minioClient = minioConfig.getMinioClient(); - - return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() - .method(Method.GET) - .bucket(bucketName) - .object(objectName) - .expiry(expiry, TimeUnit.SECONDS) - .build()); - - } catch (Exception e) { - logger.error("生成预签名URL失败: {}/{}", bucketName, objectName, e); - return null; - } - } - - /** - * 检查文件是否存在 - * @param bucketName 存储桶名称 - * @param objectName 对象名称 - * @return true 存在,false 不存在 - */ - public boolean fileExists(String bucketName, String objectName) { - try { - MinioClient minioClient = minioConfig.getMinioClient(); - - minioClient.statObject(StatObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .build()); - - return true; - } catch (Exception e) { - return false; - } - } - - /** - * 获取文件信息 - * @param bucketName 存储桶名称 - * @param objectName 对象名称 - * @return 文件信息,失败返回null - */ - public StatObjectResponse getFileInfo(String bucketName, String objectName) { - try { - MinioClient minioClient = minioConfig.getMinioClient(); - - return minioClient.statObject(StatObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .build()); - - } catch (Exception e) { - logger.error("获取文件信息失败: {}/{}", bucketName, objectName, e); - return null; - } - } -} diff --git a/urbanLifelineServ/file/src/main/resources/application.yml b/urbanLifelineServ/file/src/main/resources/application.yml deleted file mode 100644 index b93b3be9..00000000 --- a/urbanLifelineServ/file/src/main/resources/application.yml +++ /dev/null @@ -1,44 +0,0 @@ -# ================== File 文件服务配置 ================== -server: - port: 8084 - -spring: - application: - name: file-service - servlet: - multipart: - enabled: true - max-file-size: 500MB - max-request-size: 500MB - -# ================== Auth ================== -auth: - enabled: true - gateway-mode: true - whitelist: - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - /favicon.ico - - /error - - /actuator/health - - /actuator/info - - /file/download/** - -# ================== SpringDoc ================== -springdoc: - group-configs: - - group: 'default' - display-name: '文件服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-file - qos-enable: false - protocol: - payload: 110100480 - scan: - base-packages: org.xyzh.file.service.impl diff --git a/urbanLifelineServ/file/src/main/resources/bootstrap.yml b/urbanLifelineServ/file/src/main/resources/bootstrap.yml deleted file mode 100644 index 60998f2b..00000000 --- a/urbanLifelineServ/file/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,64 +0,0 @@ -# ================================================ -# Urban Lifeline - 通用 Bootstrap 配置 -# 所有微服务共享的基础配置 -# ================================================ - -# ================== Spring Cloud Nacos ================== -spring: - cloud: - nacos: - discovery: - server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} - namespace: ${NACOS_NAMESPACE:dev} - group: ${NACOS_GROUP:DEFAULT_GROUP} - - # ================== DataSource ================== - datasource: - url: ${DB_URL:jdbc:postgresql://127.0.0.1:5432/urban_lifeline} - username: ${DB_USERNAME:postgres} - password: ${DB_PASSWORD:postgres} - driver-class-name: org.postgresql.Driver - - # ================== Redis ================== - data: - redis: - host: ${REDIS_HOST:127.0.0.1} - port: ${REDIS_PORT:6379} - database: ${REDIS_DATABASE:0} - password: ${REDIS_PASSWORD:123456} - -# ================== Security AES ================== -security: - aes: - # AES-256 密钥(Base64编码,必须与所有服务保持一致) - # 警告:这是开发环境密钥,生产环境请使用密钥管理系统 - secret-key: ${AES_SECRET_KEY:MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=} - -# ================== Dubbo ================== -dubbo: - protocol: - name: dubbo - port: -1 - registry: - address: nacos://${NACOS_SERVER_ADDR:127.0.0.1:8848} - -# ================== MyBatis-Plus ================== -mybatis-plus: - mapper-locations: classpath:mapper/**/*.xml - type-aliases-package: org.xyzh.common.dto, org.xyzh.api - -# ================== SpringDoc 基础配置 ================== -springdoc: - api-docs: - enabled: true - path: /v3/api-docs - swagger-ui: - enabled: true - path: /swagger-ui.html - -# ================== Logging ================== -logging: - config: classpath:log4j2.xml - charset: - console: UTF-8 - file: UTF-8 diff --git a/urbanLifelineServ/file/src/main/resources/log4j2.xml b/urbanLifelineServ/file/src/main/resources/log4j2.xml deleted file mode 100644 index bc2c497d..00000000 --- a/urbanLifelineServ/file/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/file/src/main/resources/mapper/FileMapper.xml b/urbanLifelineServ/file/src/main/resources/mapper/FileMapper.xml deleted file mode 100644 index b60a4115..00000000 --- a/urbanLifelineServ/file/src/main/resources/mapper/FileMapper.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERT INTO file.tb_sys_file ( - - optsn, file_id, name, path, size - - , creator - , updater - , dept_path - , remark - , create_time - , update_time - , delete_time - , deleted - , type - , storage_type - , mime_type - , url - , status - , module - , business_id - , uploader - , object_name - , bucket_name - , md5_hash - , extension - , file_root_id - , version - ) VALUES ( - - #{optsn}, #{fileId}, #{name}, #{path}, #{size} - - , #{creator} - , #{updater} - , #{deptPath} - , #{remark} - , #{createTime} - , #{updateTime} - , #{deleteTime} - , #{deleted} - , #{type} - , #{storageType} - , #{mimeType} - , #{url} - , #{status} - , #{module} - , #{businessId} - , #{uploader} - , #{objectName} - , #{bucketName} - , #{md5Hash} - , #{extension} - , #{fileRootId} - , #{version} - ) - - - - - UPDATE file.tb_sys_file - - updater = #{updater}, - dept_path = #{deptPath}, - remark = #{remark}, - update_time = CURRENT_TIMESTAMP, - name = #{name}, - path = #{path}, - size = #{size}, - type = #{type}, - storage_type = #{storageType}, - mime_type = #{mimeType}, - url = #{url}, - status = #{status}, - module = #{module}, - business_id = #{businessId}, - uploader = #{uploader}, - object_name = #{objectName}, - bucket_name = #{bucketName}, - md5_hash = #{md5Hash}, - extension = #{extension} - - WHERE file_id = #{fileId} AND ( deleted IS NULL OR deleted = false) - - - diff --git a/urbanLifelineServ/gateway/Dockerfile.dev b/urbanLifelineServ/gateway/Dockerfile.dev deleted file mode 100644 index 03221418..00000000 --- a/urbanLifelineServ/gateway/Dockerfile.dev +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.9-eclipse-temurin-21-alpine - -WORKDIR /app - -# 复制 pom.xml 和源代码 -COPY pom.xml ./ -COPY src ./src - -# 暴露端口 -EXPOSE 8080 - -# 使用 spring-boot-devtools 支持热重载 -CMD ["mvn", "spring-boot:run", "-Dspring-boot.run.jvmArguments=-Dspring.devtools.restart.enabled=true"] diff --git a/urbanLifelineServ/gateway/pom.xml b/urbanLifelineServ/gateway/pom.xml deleted file mode 100644 index 0c8c2ed5..00000000 --- a/urbanLifelineServ/gateway/pom.xml +++ /dev/null @@ -1,319 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - gateway - ${urban-lifeline.version} - - - 21 - 21 - - - - - - - - org.springframework.boot - spring-boot-starter-web - ${spring-boot.version} - test - - - * - * - - - - - - org.springframework.boot - spring-boot-starter-security - ${spring-boot.version} - test - - - * - * - - - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - ${springdoc.version} - test - - - * - * - - - - - - org.springframework.boot - spring-boot-starter-tomcat - ${spring-boot.version} - test - - - * - * - - - - - org.apache.tomcat.embed - tomcat-embed-core - 10.1.48 - test - - - org.apache.tomcat.embed - tomcat-embed-el - 10.1.48 - test - - - org.apache.tomcat.embed - tomcat-embed-websocket - 10.1.48 - test - - - - org.springframework - spring-webmvc - ${spring-framework.version} - test - - - - - - - - org.springframework.cloud - spring-cloud-starter-gateway - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - - - org.springframework.boot - spring-boot-starter-logging - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-config - - - org.springframework.boot - spring-boot-starter-logging - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - - - org.springframework.cloud - spring-cloud-starter-loadbalancer - - - - - org.xyzh.common - common-auth - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - org.apache.tomcat.embed - tomcat-embed-core - - - - - - - org.xyzh.common - common-redis - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - org.apache.tomcat.embed - tomcat-embed-core - - - - - - - - - - org.xyzh.common - common-core - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - org.apache.tomcat.embed - tomcat-embed-core - - - - - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - org.springframework.boot - spring-boot-starter-webflux - - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - - com.alibaba.fastjson2 - fastjson2 - - - - - org.projectlombok - lombok - true - - - - - org.springframework.security - spring-security-config - - - org.springframework.security - spring-security-web - - - - - jakarta.servlet - jakarta.servlet-api - provided - - - - - org.springframework - spring-webmvc - provided - - - - - ${project.artifactId} - - - org.springframework.boot - spring-boot-maven-plugin - - org.xyzh.gateway.GatewayApplication - - - - - diff --git a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/GatewayApplication.java b/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/GatewayApplication.java deleted file mode 100644 index 742221fe..00000000 --- a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/GatewayApplication.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.xyzh.gateway; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.FilterType; - -/** - * @description Gateway 网关启动类 - * @author yslg - * @since 2025-12-02 - */ -@SpringBootApplication(exclude = { - DataSourceAutoConfiguration.class // Gateway 不需要数据源 -}) -@EnableDiscoveryClient -@ComponentScan( - basePackages = { - "org.xyzh.gateway", // 当前 gateway 模块 - "org.xyzh.common" // 公共模块(包括 common-auth) - }, - excludeFilters = { - // 使用正则表达式排除 Spring MVC 相关配置,避免加载 WebMvcConfigurer 类 - @ComponentScan.Filter(type = FilterType.REGEX, pattern = { - "org\\.xyzh\\.common\\.auth\\.config\\.SecurityConfig", - "org\\.xyzh\\.common\\.auth\\.config\\.WebMvcConfig", - "org\\.xyzh\\.common\\.auth\\.config\\.GatewayAuthConfig", - "org\\.xyzh\\.common\\.utils\\.config\\.FastJsonConfiguration" - }) - } -) -public class GatewayApplication { - public static void main(String[] args) { - SpringApplication.run(GatewayApplication.class, args); - System.out.println("========================================"); - System.out.println(" Gateway 网关服务启动成功!"); - System.out.println("========================================"); - } -} diff --git a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/GatewayRouteConfig.java b/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/GatewayRouteConfig.java deleted file mode 100644 index 6054b36d..00000000 --- a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/GatewayRouteConfig.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.xyzh.gateway.config; - -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @description Gateway 动态路由配置(Java 代码方式) - * @author yslg - * @since 2025-12-02 - * - * 这是路由配置的第二种方式,与 application.yml 中的配置二选一或配合使用 - * 优点:灵活性更高,可以动态添加/修改路由,支持更复杂的路由逻辑 - */ -@Configuration -public class GatewayRouteConfig { - - /** - * 通过代码方式配置路由(示例,可根据需要启用) - */ - // @Bean - public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { - return builder.routes() - // 认证服务路由 - .route("auth-service", r -> r - .path("/auth/**") - .filters(f -> f - .stripPrefix(1) - .addRequestHeader("X-Gateway", "gateway-service") - ) - .uri("lb://auth-service") - ) - - // 系统服务路由 - .route("system-service", r -> r - .path("/system/**") - .filters(f -> f - .stripPrefix(1) - .addRequestHeader("X-Gateway", "gateway-service") - ) - .uri("lb://system-service") - ) - - // 日志服务路由 - .route("log-service", r -> r - .path("/log/**") - .filters(f -> f - .stripPrefix(1) - .addRequestHeader("X-Gateway", "gateway-service") - ) - .uri("lb://log-service") - ) - - // 文件服务路由 - .route("file-service", r -> r - .path("/file/**") - .filters(f -> f - .stripPrefix(1) - .addRequestHeader("X-Gateway", "gateway-service") - ) - .uri("lb://file-service") - ) - - // WebSocket 路由示例 - .route("websocket-route", r -> r - .path("/ws/**") - .uri("lb:ws://system-service") - ) - - .build(); - } - - /** - * 动态路由刷新端点(如需要) - * 可以配合 Nacos 配置中心实现动态路由更新 - */ -} diff --git a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/GatewaySecurityConfig.java b/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/GatewaySecurityConfig.java deleted file mode 100644 index 2e168d07..00000000 --- a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/GatewaySecurityConfig.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.xyzh.gateway.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.web.server.SecurityWebFilterChain; - -/** - * Gateway WebFlux Security 配置 - * 完全禁用Spring Security的默认行为,由AuthGlobalFilter处理认证 - * - * @author yslg - * @since 2025-12-11 - */ -@Configuration -@EnableWebFluxSecurity -public class GatewaySecurityConfig { - - @Bean - public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - return http - .csrf(ServerHttpSecurity.CsrfSpec::disable) - .formLogin(ServerHttpSecurity.FormLoginSpec::disable) - .httpBasic(ServerHttpSecurity.HttpBasicSpec::disable) - .logout(ServerHttpSecurity.LogoutSpec::disable) - .authorizeExchange(exchange -> exchange - .anyExchange().permitAll() // 允许所有请求,由AuthGlobalFilter处理认证 - ) - .build(); - } -} diff --git a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/RateLimiterConfig.java b/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/RateLimiterConfig.java deleted file mode 100644 index 639d15a1..00000000 --- a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/config/RateLimiterConfig.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.xyzh.gateway.config; - -import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import reactor.core.publisher.Mono; - -/** - * @description 限流配置 - 基于 Redis 的令牌桶算法 - * @author yslg - * @since 2025-12-02 - */ -@Configuration -public class RateLimiterConfig { - - /** - * 基于 IP 地址的限流 - */ - @Bean - public KeyResolver ipKeyResolver() { - return exchange -> { - String ip = exchange.getRequest().getRemoteAddress() != null - ? exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() - : "unknown"; - return Mono.just(ip); - }; - } - - /** - * 基于用户 ID 的限流(从请求头获取) - */ - // @Bean - public KeyResolver userKeyResolver() { - return exchange -> { - String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id"); - return Mono.just(userId != null ? userId : "anonymous"); - }; - } - - /** - * 基于 API 路径的限流 - */ - // @Bean - public KeyResolver apiKeyResolver() { - return exchange -> Mono.just(exchange.getRequest().getPath().value()); - } -} diff --git a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/controller/GatewayDiagnosticController.java b/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/controller/GatewayDiagnosticController.java deleted file mode 100644 index 698388e8..00000000 --- a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/controller/GatewayDiagnosticController.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.xyzh.gateway.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.gateway.route.Route; -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Flux; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Gateway诊断控制器 - 用于检查路由配置 - * - * @author yslg - * @since 2025-12-11 - */ -@RestController -@RequestMapping("/gateway-diagnostic") -public class GatewayDiagnosticController { - - @Autowired - private RouteLocator routeLocator; - - /** - * 获取所有路由信息 - * 访问: http://localhost:8180/gateway-diagnostic/routes - */ - @GetMapping("/routes") - public Flux> getRoutes() { - return routeLocator.getRoutes() - .map(route -> { - Map routeInfo = new HashMap<>(); - routeInfo.put("id", route.getId()); - routeInfo.put("uri", route.getUri().toString()); - routeInfo.put("order", route.getOrder()); - routeInfo.put("predicates", route.getPredicate().toString()); - routeInfo.put("filters", route.getFilters().toString()); - return routeInfo; - }); - } - - /** - * 健康检查 - * 访问: http://localhost:8180/gateway-diagnostic/health - */ - @GetMapping("/health") - public Map health() { - Map health = new HashMap<>(); - health.put("status", "UP"); - health.put("message", "Gateway is running"); - health.put("timestamp", System.currentTimeMillis()); - return health; - } -} diff --git a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/filter/AuthGlobalFilter.java b/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/filter/AuthGlobalFilter.java deleted file mode 100644 index 03606474..00000000 --- a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/filter/AuthGlobalFilter.java +++ /dev/null @@ -1,182 +0,0 @@ -package org.xyzh.gateway.filter; - -import com.alibaba.fastjson2.JSON; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.stereotype.Component; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.StringUtils; -import org.springframework.web.server.ServerWebExchange; -import org.xyzh.common.auth.config.AuthProperties; -import org.xyzh.common.auth.contants.AuthContants; -import org.xyzh.common.auth.token.TokenParser; -import org.xyzh.common.core.domain.ResultDomain; -import reactor.core.publisher.Mono; - -import java.nio.charset.StandardCharsets; -import java.util.List; - -/** - * @description Gateway 全局认证过滤器 - 用于验证 JWT Token - * @author yslg - * @since 2025-12-02 - */ -@Component -public class AuthGlobalFilter implements GlobalFilter, Ordered { - private static final Logger log = LoggerFactory.getLogger(AuthGlobalFilter.class); - - @Autowired - private TokenParser tokenParser; - - @Autowired - private AuthProperties authProperties; - - private final AntPathMatcher pathMatcher = new AntPathMatcher(); - - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - ServerHttpRequest request = exchange.getRequest(); - String path = request.getURI().getPath(); - - log.debug("Gateway 请求路径: {}", path); - - // 1. 检查认证功能是否启用 - if (!authProperties.isEnabled()) { - log.debug("认证功能未启用,直接放行"); - return chain.filter(exchange); - } - - // 2. 检查是否在白名单中 - if (isWhitelisted(path)) { - log.debug("路径在白名单中,跳过认证: {}", path); - return chain.filter(exchange); - } - - // 3. 提取 Token - String token = extractToken(request); - if (!StringUtils.hasText(token)) { - log.warn("请求缺少 Token: {}", path); - return unauthorizedResponse(exchange, "未提供认证令牌,请先登录"); - } - - try { - // 4. 验证 Token - if (tokenParser.isTokenExpired(token)) { - log.warn("Token 已过期: {}", path); - return unauthorizedResponse(exchange, "认证令牌已过期,请重新登录"); - } - - // 5. 获取用户信息 - String userId = tokenParser.getUserIdFromToken(token); - if (!StringUtils.hasText(userId)) { - log.warn("Token 中未找到用户ID: {}", path); - return unauthorizedResponse(exchange, "认证令牌无效"); - } - - // 6. 验证 Token 有效性 - if (!tokenParser.validateToken(token, userId)) { - log.warn("Token 验证失败: userId={}, path={}", userId, path); - return unauthorizedResponse(exchange, "认证令牌验证失败"); - } - - // 7. 将用户信息添加到请求头中,传递给下游服务 - ServerHttpRequest mutatedRequest = request.mutate() - .header(AuthContants.USER_ID_ATTRIBUTE, userId) - .header(AuthContants.TOKEN_ATTRIBUTE, token) - .build(); - - log.debug("Token 验证成功: userId={}, path={}", userId, path); - - // 8. 继续执行过滤器链 - return chain.filter(exchange.mutate().request(mutatedRequest).build()); - - } catch (Exception e) { - log.error("Token 解析或验证异常: path={}, error={}", path, e.getMessage(), e); - return unauthorizedResponse(exchange, "认证令牌解析失败: " + e.getMessage()); - } - } - - /** - * 检查路径是否在白名单中 - */ - private boolean isWhitelisted(String path) { - // 1. 检查认证相关接口 - if (authProperties.getAuthPaths() != null) { - for (String pattern : authProperties.getAuthPaths()) { - if (pattern != null && pathMatcher.match(pattern, path)) { - return true; - } - } - } - - // 2. 检查通用白名单 - if (authProperties.getWhitelist() != null) { - for (String pattern : authProperties.getWhitelist()) { - if (pattern != null && pathMatcher.match(pattern, path)) { - return true; - } - } - } - - return false; - } - - /** - * 从请求头或URL参数中提取 Token - */ - private String extractToken(ServerHttpRequest request) { - // 1. 优先从请求头获取 - List headers = request.getHeaders().get(authProperties.getTokenHeader()); - if (headers != null && !headers.isEmpty()) { - String header = headers.get(0); - if (StringUtils.hasText(header)) { - // 支持 Bearer 前缀 - String prefix = authProperties.getTokenPrefix(); - if (StringUtils.hasText(prefix) && header.startsWith(prefix)) { - return header.substring(prefix.length()).trim(); - } - // 也支持直接传递 Token(不带前缀) - return header.trim(); - } - } - - // 2. 从URL参数获取(用于WebSocket连接) - String tokenParam = request.getQueryParams().getFirst("token"); - if (StringUtils.hasText(tokenParam)) { - log.debug("从URL参数获取Token"); - return tokenParam.trim(); - } - - return null; - } - - /** - * 返回未授权响应 - */ - private Mono unauthorizedResponse(ServerWebExchange exchange, String message) { - ServerHttpResponse response = exchange.getResponse(); - response.setStatusCode(HttpStatus.UNAUTHORIZED); - response.getHeaders().setContentType(MediaType.APPLICATION_JSON); - - ResultDomain result = ResultDomain.failure(HttpStatus.UNAUTHORIZED.value(), message); - String json = JSON.toJSONString(result); - DataBuffer buffer = response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8)); - - return response.writeWith(Mono.just(buffer)); - } - - @Override - public int getOrder() { - // 优先级设置为最高,确保在其他过滤器之前执行 - return Ordered.HIGHEST_PRECEDENCE; - } -} diff --git a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/filter/LogGlobalFilter.java b/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/filter/LogGlobalFilter.java deleted file mode 100644 index 02e8e481..00000000 --- a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/filter/LogGlobalFilter.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.xyzh.gateway.filter; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; - -/** - * @description Gateway 全局日志过滤器 - 记录请求信息 - * @author yslg - * @since 2025-12-02 - */ -@Component -public class LogGlobalFilter implements GlobalFilter, Ordered { - private static final Logger log = LoggerFactory.getLogger(LogGlobalFilter.class); - - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - ServerHttpRequest request = exchange.getRequest(); - long startTime = System.currentTimeMillis(); - - String path = request.getURI().getPath(); - String method = request.getMethod().name(); - String remoteAddress = request.getRemoteAddress() != null - ? request.getRemoteAddress().getAddress().getHostAddress() - : "unknown"; - - log.info("==> Gateway 请求: {} {} | 来源: {}", method, path, remoteAddress); - - return chain.filter(exchange).then( - Mono.fromRunnable(() -> { - long endTime = System.currentTimeMillis(); - long duration = endTime - startTime; - int statusCode = exchange.getResponse().getStatusCode() != null - ? exchange.getResponse().getStatusCode().value() - : 0; - - log.info("<== Gateway 响应: {} {} | 状态: {} | 耗时: {}ms", - method, path, statusCode, duration); - }) - ); - } - - @Override - public int getOrder() { - // 优先级设置较低,在认证过滤器之后执行 - return Ordered.LOWEST_PRECEDENCE; - } -} diff --git a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/handler/GatewayExceptionHandler.java b/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/handler/GatewayExceptionHandler.java deleted file mode 100644 index a4f874ed..00000000 --- a/urbanLifelineServ/gateway/src/main/java/org/xyzh/gateway/handler/GatewayExceptionHandler.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.xyzh.gateway.handler; - -import com.alibaba.fastjson2.JSON; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; -import org.springframework.cloud.gateway.support.NotFoundException; -import org.springframework.core.annotation.Order; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ResponseStatusException; -import org.springframework.web.server.ServerWebExchange; -import org.xyzh.common.core.domain.ResultDomain; -import reactor.core.publisher.Mono; - -import java.nio.charset.StandardCharsets; - -/** - * @description Gateway 全局异常处理器 - * @author yslg - * @since 2025-12-02 - */ -@Component -@Order(-1) // 优先级设置为最高 -public class GatewayExceptionHandler implements ErrorWebExceptionHandler { - private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class); - - @Override - public Mono handle(ServerWebExchange exchange, Throwable ex) { - ServerHttpResponse response = exchange.getResponse(); - - if (response.isCommitted()) { - return Mono.error(ex); - } - - response.getHeaders().setContentType(MediaType.APPLICATION_JSON); - - ResultDomain result; - HttpStatus httpStatus; - - // 根据不同异常类型返回不同的错误信息 - if (ex instanceof NotFoundException) { - log.error("服务未找到: {}", ex.getMessage()); - httpStatus = HttpStatus.SERVICE_UNAVAILABLE; - result = ResultDomain.failure(httpStatus.value(), "服务暂时不可用: " + ex.getMessage()); - } else if (ex instanceof ResponseStatusException rse) { - log.error("响应状态异常: {}", rse.getMessage()); - httpStatus = (HttpStatus) rse.getStatusCode(); - result = ResultDomain.failure(httpStatus.value(), rse.getReason()); - } else if (ex instanceof IllegalStateException) { - log.error("非法状态异常: {}", ex.getMessage()); - httpStatus = HttpStatus.BAD_REQUEST; - result = ResultDomain.failure(httpStatus.value(), "请求参数错误: " + ex.getMessage()); - } else { - log.error("Gateway 内部错误", ex); - httpStatus = HttpStatus.INTERNAL_SERVER_ERROR; - result = ResultDomain.failure(httpStatus.value(), "网关内部错误,请稍后重试"); - } - - response.setStatusCode(httpStatus); - - String json = JSON.toJSONString(result); - DataBuffer buffer = response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8)); - - return response.writeWith(Mono.just(buffer)); - } -} diff --git a/urbanLifelineServ/gateway/src/main/resources/application.yml b/urbanLifelineServ/gateway/src/main/resources/application.yml deleted file mode 100644 index fbbcfe09..00000000 --- a/urbanLifelineServ/gateway/src/main/resources/application.yml +++ /dev/null @@ -1,171 +0,0 @@ -# ================== Gateway 服务配置 ================== -server: - port: 8080 - -spring: - application: - name: gateway-service - - # Gateway 必须使用 reactive 模式 - main: - web-application-type: reactive - - cloud: - nacos: - config: - enabled: false - - # Gateway 路由配置 - gateway: - discovery: - locator: - enabled: false - - routes: - # 认证服务 - - id: auth-service - uri: lb://auth-service - predicates: - - Path=/urban-lifeline/auth/** - filters: - - StripPrefix=1 - - name: RequestRateLimiter - args: - redis-rate-limiter.replenishRate: 100 - redis-rate-limiter.burstCapacity: 200 - - # 系统服务 - - id: system-service - uri: lb://system-service - predicates: - - Path=/urban-lifeline/system/** - filters: - - StripPrefix=1 - - # 日志服务 - - id: log-service - uri: lb://log-service - predicates: - - Path=/urban-lifeline/log/** - filters: - - StripPrefix=1 - - # 文件服务 - - id: file-service - uri: lb://file-service - predicates: - - Path=/urban-lifeline/file/** - filters: - - StripPrefix=1 - - # 消息服务 - - id: message-service - uri: lb://message-service - predicates: - - Path=/urban-lifeline/message/** - filters: - - StripPrefix=1 - - # 招投标服务 - - id: bidding-service - uri: lb://bidding-service - predicates: - - Path=/urban-lifeline/bidding/** - filters: - - StripPrefix=1 - - # 平台服务 - - id: platform-service - uri: lb://platform-service - predicates: - - Path=/urban-lifeline/platform/** - filters: - - StripPrefix=1 - - # 工单服务 WebSocket - - id: workcase-websocket - uri: lb:ws://workcase-service - predicates: - - Path=/urban-lifeline/workcase/ws/** - filters: - - StripPrefix=1 - - # 工单服务 - - id: workcase-service - uri: lb://workcase-service - predicates: - - Path=/urban-lifeline/workcase/** - filters: - - StripPrefix=1 - - # 定时任务服务 - - id: crontab-service - uri: lb://crontab-service - predicates: - - Path=/urban-lifeline/crontab/** - filters: - - StripPrefix=1 - - # AI 服务 - - id: ai-service - uri: lb://ai-service - predicates: - - Path=/urban-lifeline/ai/** - filters: - - StripPrefix=1 - - # 全局跨域配置 - globalcors: - cors-configurations: - '[/**]': - allowedOriginPatterns: "*" - allowedMethods: [GET, POST, PUT, DELETE, OPTIONS] - allowedHeaders: "*" - allowCredentials: true - maxAge: 3600 - - # Redis 连接池配置(Gateway 限流用) - data: - redis: - timeout: 5000ms - lettuce: - pool: - max-active: 20 - max-wait: -1ms - max-idle: 10 - min-idle: 5 - -# ================== Gateway 认证配置 ================== -auth: - enabled: true - token-header: Authorization - token-prefix: "Bearer " - login-path: /urban-lifeline/auth/login - logout-path: /urban-lifeline/auth/logout - captcha-path: /urban-lifeline/auth/captcha - refresh-path: /urban-lifeline/auth/refresh - whitelist: - - /actuator/** - - /v3/api-docs/** - - /swagger-ui/** - - /swagger-resources/** - - /webjars/** - - /doc.html - - /favicon.ico - - /error - - /urban-lifeline/*/v3/api-docs/** - - /urban-lifeline/*/swagger-ui/** - - /urban-lifeline/file/download/** - - /urban-lifeline/ai/chat/** - - /urban-lifeline/system/guest/identify - - /urban-lifeline/workcase/meeting/*/entry - -# ================== Actuator ================== -management: - endpoints: - web: - exposure: - include: health,info,gateway - endpoint: - health: - show-details: always diff --git a/urbanLifelineServ/gateway/src/main/resources/log4j2.xml b/urbanLifelineServ/gateway/src/main/resources/log4j2.xml deleted file mode 100644 index a0eeacbf..00000000 --- a/urbanLifelineServ/gateway/src/main/resources/log4j2.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - logs - gateway - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/message/pom.xml b/urbanLifelineServ/message/pom.xml deleted file mode 100644 index ce08ff47..00000000 --- a/urbanLifelineServ/message/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - message - 1.0.0 - - - 21 - 21 - - - - - org.xyzh.common - common-all - - - org.xyzh.apis - api-system - - - org.xyzh.apis - api-message - - - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - - - - - message - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/message/src/main/java/org/xyzh/message/MessageApp.java b/urbanLifelineServ/message/src/main/java/org/xyzh/message/MessageApp.java deleted file mode 100644 index 700beed6..00000000 --- a/urbanLifelineServ/message/src/main/java/org/xyzh/message/MessageApp.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.xyzh.message; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@ComponentScan(basePackages = { - "org.xyzh.message", // 当前message模块 - "org.xyzh.common" // 公共模块 -}) -public class MessageApp { - private static final Logger logger = LoggerFactory.getLogger(MessageApp.class); - - public static void main(String[] args) { - logger.info("======================== MessageApp 启动中 ========================="); - SpringApplication.run(MessageApp.class, args); - logger.info("======================== MessageApp 启动成功 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/DynamicConfigLoader.java b/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/DynamicConfigLoader.java deleted file mode 100644 index 7aae33a3..00000000 --- a/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/DynamicConfigLoader.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.xyzh.message.config; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; -import org.springframework.mail.javamail.JavaMailSenderImpl; -import org.springframework.util.StringUtils; -import org.xyzh.api.system.service.SysConfigService; - -import java.util.Properties; - -/** - * @description 动态配置加载器 - 从数据库加载邮件和短信配置 - * @filename DynamicConfigLoader.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -@Configuration -@Order(100) // 确保在其他组件初始化之后再加载配置 -public class DynamicConfigLoader implements ApplicationRunner { - - private static final Logger logger = LoggerFactory.getLogger(DynamicConfigLoader.class); - - @DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false, retries = 0) - private SysConfigService sysConfigService; - - @Autowired(required = false) - private JavaMailSenderImpl mailSender; - - @Autowired(required = false) - private EmailConfigProperties emailConfigProperties; - - @Autowired(required = false) - private SmsConfigProperties smsConfigProperties; - - @Override - public void run(ApplicationArguments args) throws Exception { - logger.info("=== 开始加载动态配置 ==="); - - try { - // 加载邮件配置 - if (emailConfigProperties != null) { - loadEmailConfig(); - } else { - logger.warn("EmailConfigProperties未注入,跳过邮件配置加载"); - } - - // 加载短信配置 - if (smsConfigProperties != null) { - loadSmsConfig(); - } else { - logger.warn("SmsConfigProperties未注入,跳过短信配置加载"); - } - - logger.info("=== 动态配置加载完成 ==="); - } catch (Exception e) { - logger.error("动态配置加载失败", e); - } - } - - /** - * 加载邮件配置 - */ - private void loadEmailConfig() { - try { - if (sysConfigService == null) { - logger.warn("SysConfigService未注入,无法加载邮件配置"); - return; - } - - String host = sysConfigService.getStringConfig("email.host"); - String port = sysConfigService.getStringConfig("email.port"); - String username = sysConfigService.getStringConfig("email.username"); - String password = sysConfigService.getStringConfig("email.password"); - String fromName = sysConfigService.getStringConfig("email.fromName"); - String sslEnable = sysConfigService.getStringConfig("email.ssl.enable"); - String timeout = sysConfigService.getStringConfig("email.timeout"); - - // 更新配置属性 - emailConfigProperties.setHost(host); - emailConfigProperties.setPort(StringUtils.hasText(port) ? Integer.valueOf(port) : 587); - emailConfigProperties.setUsername(username); - emailConfigProperties.setPassword(password); - emailConfigProperties.setFromName(fromName); - emailConfigProperties.setSslEnable("true".equalsIgnoreCase(sslEnable)); - emailConfigProperties.setTimeout(StringUtils.hasText(timeout) ? Integer.valueOf(timeout) : 30000); - - // 如果邮箱配置完整,则配置JavaMailSender - if (mailSender != null && StringUtils.hasText(host) && StringUtils.hasText(username) && StringUtils.hasText(password)) { - mailSender.setHost(host); - mailSender.setPort(emailConfigProperties.getPort()); - mailSender.setUsername(username); - mailSender.setPassword(password); - - // 设置邮件属性 - Properties props = mailSender.getJavaMailProperties(); - props.put("mail.smtp.auth", "true"); - props.put("mail.smtp.starttls.enable", emailConfigProperties.getSslEnable() ? "true" : "false"); - props.put("mail.smtp.starttls.required", emailConfigProperties.getSslEnable() ? "true" : "false"); - props.put("mail.smtp.timeout", emailConfigProperties.getTimeout()); - props.put("mail.smtp.connectiontimeout", emailConfigProperties.getTimeout()); - - logger.info("邮件配置加载成功: host={}, port={}, username={}", host, emailConfigProperties.getPort(), username); - } else { - logger.warn("邮件配置不完整,将使用默认配置或模拟模式"); - } - - } catch (Exception e) { - logger.error("加载邮件配置失败", e); - } - } - - /** - * 加载短信配置 - */ - private void loadSmsConfig() { - try { - if (sysConfigService == null) { - logger.warn("SysConfigService未注入,无法加载短信配置"); - return; - } - - String provider = sysConfigService.getStringConfig("sms.provider"); - String accessKeyId = sysConfigService.getStringConfig("sms.accessKeyId"); - String accessKeySecret = sysConfigService.getStringConfig("sms.accessKeySecret"); - String signName = sysConfigService.getStringConfig("sms.signName"); - String templateCodeLogin = sysConfigService.getStringConfig("sms.templateCode.login"); - String templateCodeRegister = sysConfigService.getStringConfig("sms.templateCode.register"); - String timeout = sysConfigService.getStringConfig("sms.timeout"); - - // 更新配置属性 - smsConfigProperties.setProvider(StringUtils.hasText(provider) ? provider : "aliyun"); - smsConfigProperties.setAccessKeyId(accessKeyId); - smsConfigProperties.setAccessKeySecret(accessKeySecret); - smsConfigProperties.setSignName(StringUtils.hasText(signName) ? signName : "校园新闻"); - smsConfigProperties.setTemplateCodeLogin(templateCodeLogin); - smsConfigProperties.setTemplateCodeRegister(templateCodeRegister); - smsConfigProperties.setTimeout(StringUtils.hasText(timeout) ? Integer.valueOf(timeout) : 30000); - - if (StringUtils.hasText(accessKeyId) && StringUtils.hasText(accessKeySecret)) { - logger.info("短信配置加载成功: provider={}, signName={}", smsConfigProperties.getProvider(), smsConfigProperties.getSignName()); - } else { - logger.warn("短信配置不完整,将使用模拟模式"); - } - - } catch (Exception e) { - logger.error("加载短信配置失败", e); - } - } -} diff --git a/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/EmailConfigProperties.java b/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/EmailConfigProperties.java deleted file mode 100644 index d0203e64..00000000 --- a/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/EmailConfigProperties.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.xyzh.message.config; - -import org.springframework.stereotype.Component; - -/** - * @description 邮件配置属性 - * @filename EmailConfigProperties.java - * @author yslg - * @copyright xyzh - * @since 2025-11-26 - */ -@Component -public class EmailConfigProperties { - - /** SMTP服务器地址 */ - private String host; - - /** SMTP端口 */ - private Integer port; - - /** 发件人邮箱 */ - private String username; - - /** 邮箱授权码 */ - private String password; - - /** 发件人名称 */ - private String fromName; - - /** 是否启用SSL */ - private Boolean sslEnable; - - /** 连接超时时间(毫秒) */ - private Integer timeout; - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public Integer getPort() { - return port; - } - - public void setPort(Integer port) { - this.port = port; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getFromName() { - return fromName; - } - - public void setFromName(String fromName) { - this.fromName = fromName; - } - - public Boolean getSslEnable() { - return sslEnable; - } - - public void setSslEnable(Boolean sslEnable) { - this.sslEnable = sslEnable; - } - - public Integer getTimeout() { - return timeout; - } - - public void setTimeout(Integer timeout) { - this.timeout = timeout; - } -} diff --git a/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/MailSenderConfig.java b/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/MailSenderConfig.java deleted file mode 100644 index e91fe54a..00000000 --- a/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/MailSenderConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.xyzh.message.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.mail.javamail.JavaMailSenderImpl; - -import java.util.Properties; - -/** - * @description 邮件发送器配置 - 手动创建JavaMailSender bean - * @filename MailSenderConfig.java - * @author yslg - * @copyright xyzh - * @since 2025-12-05 - */ -@Configuration -public class MailSenderConfig { - - /** - * 创建JavaMailSender bean - * 初始值为默认配置,实际配置将在DynamicConfigLoader中从数据库加载 - */ - @Bean - public JavaMailSender javaMailSender() { - JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); - - // 设置默认配置(防止未配置时报错) - mailSender.setHost("smtp.example.com"); - mailSender.setPort(587); - mailSender.setUsername("default"); - mailSender.setPassword("default"); - - // 设置邮件属性 - Properties props = mailSender.getJavaMailProperties(); - props.put("mail.smtp.auth", "true"); - props.put("mail.smtp.starttls.enable", "true"); - props.put("mail.smtp.starttls.required", "false"); - props.put("mail.smtp.timeout", "30000"); - props.put("mail.smtp.connectiontimeout", "30000"); - - return mailSender; - } -} diff --git a/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/SmsConfigProperties.java b/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/SmsConfigProperties.java deleted file mode 100644 index b673088a..00000000 --- a/urbanLifelineServ/message/src/main/java/org/xyzh/message/config/SmsConfigProperties.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.xyzh.message.config; - -import org.springframework.stereotype.Component; - -/** - * @description 短信配置属性 - * @filename SmsConfigProperties.java - * @author yslg - * @copyright xyzh - * @since 2025-11-26 - */ -@Component -public class SmsConfigProperties { - - /** 短信服务商 */ - private String provider; - - /** AccessKey ID */ - private String accessKeyId; - - /** AccessKey Secret */ - private String accessKeySecret; - - /** 短信签名 */ - private String signName; - - /** 登录验证码模板 */ - private String templateCodeLogin; - - /** 注册验证码模板 */ - private String templateCodeRegister; - - /** 请求超时时间(毫秒) */ - private Integer timeout; - - public String getProvider() { - return provider; - } - - public void setProvider(String provider) { - this.provider = provider; - } - - public String getAccessKeyId() { - return accessKeyId; - } - - public void setAccessKeyId(String accessKeyId) { - this.accessKeyId = accessKeyId; - } - - public String getAccessKeySecret() { - return accessKeySecret; - } - - public void setAccessKeySecret(String accessKeySecret) { - this.accessKeySecret = accessKeySecret; - } - - public String getSignName() { - return signName; - } - - public void setSignName(String signName) { - this.signName = signName; - } - - public String getTemplateCodeLogin() { - return templateCodeLogin; - } - - public void setTemplateCodeLogin(String templateCodeLogin) { - this.templateCodeLogin = templateCodeLogin; - } - - public String getTemplateCodeRegister() { - return templateCodeRegister; - } - - public void setTemplateCodeRegister(String templateCodeRegister) { - this.templateCodeRegister = templateCodeRegister; - } - - public Integer getTimeout() { - return timeout; - } - - public void setTimeout(Integer timeout) { - this.timeout = timeout; - } -} diff --git a/urbanLifelineServ/message/src/main/java/org/xyzh/message/service/MessageServiceImpl.java b/urbanLifelineServ/message/src/main/java/org/xyzh/message/service/MessageServiceImpl.java deleted file mode 100644 index d56c786f..00000000 --- a/urbanLifelineServ/message/src/main/java/org/xyzh/message/service/MessageServiceImpl.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.xyzh.message.service; - -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.api.message.dto.TbMessageDTO; -import org.xyzh.api.message.service.MessageService; -import org.xyzh.api.message.vo.MessageVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.message.config.DynamicConfigLoader; -import org.xyzh.message.utils.EmailUtils; -import org.xyzh.message.utils.SmsUtils; - -@DubboService( - version = "1.0.0", - group = "message", - timeout = 3000, - retries = 0 -) -public class MessageServiceImpl implements MessageService{ - - private static final Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class); - - @Autowired - private EmailUtils emailUtils; - - @Autowired - private SmsUtils smsUtils; - - @Override - public ResultDomain sendSimpleEmail(String to, String subject, String content) { - boolean flag = emailUtils.sendSimpleEmail(to, subject, content); - if (flag){ - return ResultDomain.success("发生成功"); - }else{ - return ResultDomain.failure("发送失败"); - } - } - - @Override - public ResultDomain sendHtmlEmail(String to, String subject, String content) { - boolean flag = emailUtils.sendHtmlEmail(to, subject, content); - if (flag){ - return ResultDomain.success("发生成功"); - }else{ - return ResultDomain.failure("发送失败"); - } - } - - @Override - public ResultDomain sendEmailVerificationCode(String to, String code) { - boolean flag = emailUtils.sendVerificationCode(to, code); - if (flag){ - return ResultDomain.success("发生成功"); - }else{ - return ResultDomain.failure("发送失败"); - } - } - - @Override - public ResultDomain sendPhoneVerificationCode(String phone, String code) { - boolean flag = smsUtils.sendVerificationCode(phone, code); - if (flag){ - return ResultDomain.success("发生成功"); - }else{ - return ResultDomain.failure("发送失败"); - } - } - - - - @Override - public ResultDomain createMessage(MessageVO messageVO) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain deleteMessage(String messageId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain getMessageDetail(String messageId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain getMessageList(TbMessageDTO filter) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain getMessagePage(TbMessageDTO filter, PageParam pageParam) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain getMyMessageDetail(String messageId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain getMyMessageList(TbMessageDTO filter) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain getMyMessagePage(TbMessageDTO filter, PageParam pageParam) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain handleMessage(String messageId, String status) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain sendMessage(MessageVO messageVO) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain updateMessage(MessageVO messageVO) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ResultDomain withdrawMessage(String messageId) { - // TODO Auto-generated method stub - return null; - } - - - -} diff --git a/urbanLifelineServ/message/src/main/java/org/xyzh/message/utils/EmailUtils.java b/urbanLifelineServ/message/src/main/java/org/xyzh/message/utils/EmailUtils.java deleted file mode 100644 index 2a5da88b..00000000 --- a/urbanLifelineServ/message/src/main/java/org/xyzh/message/utils/EmailUtils.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.xyzh.message.utils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.mail.SimpleMailMessage; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.mail.javamail.MimeMessageHelper; -import org.springframework.stereotype.Component; -import org.xyzh.message.config.EmailConfigProperties; - -import jakarta.mail.MessagingException; -import jakarta.mail.internet.MimeMessage; - -/** - * @description 邮件发送工具类 - * @filename EmailUtils.java - * @author yslg - * @copyright xyzh - * @since 2025-11-03 - */ -@Component -@ConditionalOnBean(JavaMailSender.class) -public class EmailUtils { - - private static final Logger logger = LoggerFactory.getLogger(EmailUtils.class); - - @Autowired - private JavaMailSender mailSender; - - @Autowired - private EmailConfigProperties emailConfigProperties; - - /** - * 发送简单文本邮件 - * @param to 收件人邮箱 - * @param subject 邮件主题 - * @param content 邮件内容 - * @return 是否发送成功 - */ - public boolean sendSimpleEmail(String to, String subject, String content) { - try { - SimpleMailMessage message = new SimpleMailMessage(); - String from = emailConfigProperties.getUsername(); - message.setFrom(from); - message.setTo(to); - message.setSubject(subject); - message.setText(content); - - mailSender.send(message); - logger.info("简单邮件发送成功,收件人: {}", to); - return true; - } catch (Exception e) { - logger.error("简单邮件发送失败,收件人: {}, 错误: {}", to, e.getMessage(), e); - return false; - } - } - - /** - * 发送HTML格式邮件 - * @param to 收件人邮箱 - * @param subject 邮件主题 - * @param content HTML格式的邮件内容 - * @return 是否发送成功 - */ - public boolean sendHtmlEmail(String to, String subject, String content) { - try { - MimeMessage message = mailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); - - String from = emailConfigProperties.getUsername(); - helper.setFrom(from); - helper.setTo(to); - helper.setSubject(subject); - helper.setText(content, true); // true表示HTML格式 - - mailSender.send(message); - logger.info("HTML邮件发送成功,收件人: {}", to); - return true; - } catch (MessagingException e) { - logger.error("HTML邮件发送失败,收件人: {}, 错误: {}", to, e.getMessage(), e); - return false; - } - } - - /** - * 发送验证码邮件 - * @param to 收件人邮箱 - * @param code 验证码 - * @return 是否发送成功 - */ - public boolean sendVerificationCode(String to, String code) { - String subject = "【红色思政学习平台】邮箱验证码"; - String content = buildVerificationCodeHtml(code); - return sendHtmlEmail(to, subject, content); - } - - /** - * 构建验证码邮件的HTML内容 - * @param code 验证码 - * @return HTML内容 - */ - private String buildVerificationCodeHtml(String code) { - return "" + - "" + - "" + - "" + - "" + - "" + - "" + - "
" + - "
" + - "

红色思政学习平台

" + - "
" + - "
" + - "

尊敬的用户,您好!

" + - "

您正在进行邮箱验证,您的验证码为:

" + - "
" + - "
" + code + "
" + - "
" + - "
" + - "

• 验证码有效期为10分钟,请尽快完成验证

" + - "

• 如果这不是您的操作,请忽略此邮件

" + - "

• 为了保护您的账号安全,请勿将验证码告知他人

" + - "
" + - "
" + - "
" + - "

此邮件由系统自动发送,请勿回复

" + - "

Copyright © 红色思政智能体平台

" + - "
" + - "
" + - "" + - ""; - } - - /** - * 生成6位数字验证码 - * @return 验证码 - */ - public static String generateVerificationCode() { - return String.valueOf((int)((Math.random() * 9 + 1) * 100000)); - } -} - diff --git a/urbanLifelineServ/message/src/main/java/org/xyzh/message/utils/SmsUtils.java b/urbanLifelineServ/message/src/main/java/org/xyzh/message/utils/SmsUtils.java deleted file mode 100644 index f0a4260a..00000000 --- a/urbanLifelineServ/message/src/main/java/org/xyzh/message/utils/SmsUtils.java +++ /dev/null @@ -1,260 +0,0 @@ -package org.xyzh.message.utils; - -import com.aliyun.dysmsapi20170525.Client; -import com.aliyun.dysmsapi20170525.models.SendSmsRequest; -import com.aliyun.dysmsapi20170525.models.SendSmsResponse; -import com.aliyun.teaopenapi.models.Config; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -import org.xyzh.message.config.SmsConfigProperties; - -/** - * @description 短信发送工具类 - 支持多种短信服务商 - * @filename SmsUtils.java - * @author yslg - * @copyright xyzh - * @since 2025-11-03 - */ -@Component -@ConditionalOnBean(SmsConfigProperties.class) -public class SmsUtils { - - private static final Logger logger = LoggerFactory.getLogger(SmsUtils.class); - - @Autowired - private SmsConfigProperties smsConfigProperties; - - /** - * 发送短信验证码 - * @param phone 手机号 - * @param code 验证码 - * @return 是否发送成功 - */ - public boolean sendVerificationCode(String phone, String code) { - // 如果未启用短信服务,使用模拟模式 - String accessKeyId = smsConfigProperties.getAccessKeyId(); - String accessKeySecret = smsConfigProperties.getAccessKeySecret(); - - if (!StringUtils.hasText(accessKeyId) || !StringUtils.hasText(accessKeySecret)) { - logger.warn("短信服务未配置或未启用,使用模拟模式"); - logger.info("【模拟发送】短信验证码,手机号: {}, 验证码: {}", phone, code); - return true; - } - - // 根据配置的服务商选择发送方式 - String provider = smsConfigProperties.getProvider(); - if (provider == null) provider = "aliyun"; - - switch (provider.toLowerCase()) { - case "aliyun": - return sendByAliyun(phone, code, smsConfigProperties.getTemplateCodeLogin()); - case "tencent": - logger.warn("腾讯云短信服务暂未实现,使用模拟模式"); - logger.info("【模拟发送】短信验证码,手机号: {}, 验证码: {}", phone, code); - return true; - default: - logger.error("未知的短信服务商: {}", provider); - return false; - } - } - - /** - * 使用阿里云发送短信验证码 - * @param phone 手机号 - * @param code 验证码 - * @param templateCode 短信模板CODE - * @return 是否发送成功 - */ - private boolean sendByAliyun(String phone, String code, String templateCode) { - try { - Client client = createAliyunClient(); - - SendSmsRequest request = new SendSmsRequest() - .setPhoneNumbers(phone) - .setSignName(smsConfigProperties.getSignName()) - .setTemplateCode(templateCode) - .setTemplateParam("{\"code\":\"" + code + "\"}"); - - SendSmsResponse response = client.sendSms(request); - - if ("OK".equals(response.getBody().getCode())) { - logger.info("阿里云短信发送成功,手机号: {}, BizId: {}", phone, response.getBody().getBizId()); - return true; - } else { - logger.error("阿里云短信发送失败,手机号: {}, Code: {}, Message: {}", - phone, response.getBody().getCode(), response.getBody().getMessage()); - return false; - } - } catch (Exception e) { - logger.error("阿里云短信发送异常,手机号: {}, 错误: {}", phone, e.getMessage(), e); - return false; - } - } - - /** - * 创建阿里云短信客户端 - * @return 短信客户端 - */ - private Client createAliyunClient() throws Exception { - Config config = new Config() - .setAccessKeyId(smsConfigProperties.getAccessKeyId()) - .setAccessKeySecret(smsConfigProperties.getAccessKeySecret()) - .setEndpoint("dysmsapi.aliyuncs.com"); - return new Client(config); - } - - /** - * 发送通用短信(支持自定义模板) - * @param phone 手机号 - * @param templateCode 模板CODE - * @param templateParam 模板参数(JSON格式) - * @return 是否发送成功 - */ - public boolean sendSms(String phone, String templateCode, String templateParam) { - // 如果未启用短信服务,使用模拟模式 - String accessKeyId = smsConfigProperties.getAccessKeyId(); - String accessKeySecret = smsConfigProperties.getAccessKeySecret(); - - if (!StringUtils.hasText(accessKeyId) || !StringUtils.hasText(accessKeySecret)) { - logger.warn("短信服务未配置或未启用,使用模拟模式"); - logger.info("【模拟发送】短信,手机号: {}, 模板: {}, 参数: {}", phone, templateCode, templateParam); - return true; - } - - // 根据配置的服务商选择发送方式 - String provider = smsConfigProperties.getProvider(); - if (provider == null) provider = "aliyun"; - - switch (provider.toLowerCase()) { - case "aliyun": - return sendSmsAliyun(phone, templateCode, templateParam); - case "tencent": - logger.warn("腾讯云短信服务暂未实现,使用模拟模式"); - logger.info("【模拟发送】短信,手机号: {}, 模板: {}, 参数: {}", phone, templateCode, templateParam); - return true; - default: - logger.error("未知的短信服务商: {}", provider); - return false; - } - } - - /** - * 使用阿里云发送通用短信 - */ - private boolean sendSmsAliyun(String phone, String templateCode, String templateParam) { - try { - Client client = createAliyunClient(); - - SendSmsRequest request = new SendSmsRequest() - .setPhoneNumbers(phone) - .setSignName(smsConfigProperties.getSignName()) - .setTemplateCode(templateCode) - .setTemplateParam(templateParam); - - SendSmsResponse response = client.sendSms(request); - - if ("OK".equals(response.getBody().getCode())) { - logger.info("阿里云短信发送成功,手机号: {}, BizId: {}", phone, response.getBody().getBizId()); - return true; - } else { - logger.error("阿里云短信发送失败,手机号: {}, Code: {}, Message: {}", - phone, response.getBody().getCode(), response.getBody().getMessage()); - return false; - } - } catch (Exception e) { - logger.error("阿里云短信发送异常,手机号: {}, 错误: {}", phone, e.getMessage(), e); - return false; - } - } - - /** - * 批量发送短信 - * @param phones 手机号列表,用逗号分隔 - * @param templateCode 模板CODE - * @param templateParam 模板参数(JSON格式) - * @return 是否发送成功 - */ - public boolean sendBatchSms(String phones, String templateCode, String templateParam) { - // 如果未启用短信服务,使用模拟模式 - String accessKeyId = smsConfigProperties.getAccessKeyId(); - String accessKeySecret = smsConfigProperties.getAccessKeySecret(); - - if (!StringUtils.hasText(accessKeyId) || !StringUtils.hasText(accessKeySecret)) { - logger.warn("短信服务未配置或未启用,使用模拟模式"); - logger.info("【模拟发送】批量短信,手机号: {}, 模板: {}, 参数: {}", phones, templateCode, templateParam); - return true; - } - - // 根据配置的服务商选择发送方式 - String provider = smsConfigProperties.getProvider(); - if (provider == null) provider = "aliyun"; - - switch (provider.toLowerCase()) { - case "aliyun": - return sendBatchSmsAliyun(phones, templateCode, templateParam); - case "tencent": - logger.warn("腾讯云短信服务暂未实现,使用模拟模式"); - logger.info("【模拟发送】批量短信,手机号: {}, 模板: {}, 参数: {}", phones, templateCode, templateParam); - return true; - default: - logger.error("未知的短信服务商: {}", provider); - return false; - } - } - - /** - * 使用阿里云批量发送短信 - */ - private boolean sendBatchSmsAliyun(String phones, String templateCode, String templateParam) { - try { - Client client = createAliyunClient(); - - SendSmsRequest request = new SendSmsRequest() - .setPhoneNumbers(phones) - .setSignName(smsConfigProperties.getSignName()) - .setTemplateCode(templateCode) - .setTemplateParam(templateParam); - - SendSmsResponse response = client.sendSms(request); - - if ("OK".equals(response.getBody().getCode())) { - logger.info("阿里云批量短信发送成功,手机号: {}, BizId: {}", phones, response.getBody().getBizId()); - return true; - } else { - logger.error("阿里云批量短信发送失败,手机号: {}, Code: {}, Message: {}", - phones, response.getBody().getCode(), response.getBody().getMessage()); - return false; - } - } catch (Exception e) { - logger.error("阿里云批量短信发送异常,手机号: {}, 错误: {}", phones, e.getMessage(), e); - return false; - } - } - - /** - * 生成6位数字验证码 - * @return 验证码 - */ - public static String generateVerificationCode() { - return String.valueOf((int)((Math.random() * 9 + 1) * 100000)); - } - - /** - * 验证手机号格式 - * @param phone 手机号 - * @return 是否有效 - */ - public static boolean isValidPhone(String phone) { - if (phone == null || phone.trim().isEmpty()) { - return false; - } - // 中国大陆手机号验证 - String regex = "^1[3-9]\\d{9}$"; - return phone.matches(regex); - } -} - diff --git a/urbanLifelineServ/message/src/main/resources/application.yml b/urbanLifelineServ/message/src/main/resources/application.yml deleted file mode 100644 index 1d2c6bc7..00000000 --- a/urbanLifelineServ/message/src/main/resources/application.yml +++ /dev/null @@ -1,36 +0,0 @@ -# ================== Message 消息服务配置 ================== -server: - port: 8085 - -spring: - application: - name: message-service - -# ================== Auth ================== -auth: - enabled: true - gateway-mode: true - whitelist: - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - /favicon.ico - - /error - - /actuator/health - - /actuator/info - -# ================== SpringDoc ================== -springdoc: - group-configs: - - group: 'default' - display-name: '消息服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-message - qos-enable: false - scan: - base-packages: org.xyzh.message.service.impl diff --git a/urbanLifelineServ/message/src/main/resources/log4j2.xml b/urbanLifelineServ/message/src/main/resources/log4j2.xml deleted file mode 100644 index 43a4cb6b..00000000 --- a/urbanLifelineServ/message/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/platform/pom.xml b/urbanLifelineServ/platform/pom.xml deleted file mode 100644 index 960d9721..00000000 --- a/urbanLifelineServ/platform/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - platform - 1.0.0 - - - 21 - 21 - - - - platform - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/platform/src/main/java/org/xyzh/platform/PlatformApp.java b/urbanLifelineServ/platform/src/main/java/org/xyzh/platform/PlatformApp.java deleted file mode 100644 index fae82f4b..00000000 --- a/urbanLifelineServ/platform/src/main/java/org/xyzh/platform/PlatformApp.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.xyzh.platform; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@ComponentScan(basePackages = { - "org.xyzh.platform", // 当前platform模块 - "org.xyzh.common" // 公共模块 -}) -public class PlatformApp { - private static final Logger logger = LoggerFactory.getLogger(PlatformApp.class); - - public static void main(String[] args) { - logger.info("======================== PlatformApp 启动中 ========================="); - SpringApplication.run(PlatformApp.class, args); - logger.info("======================== PlatformApp 启动成功 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/platform/src/main/resources/application.yml b/urbanLifelineServ/platform/src/main/resources/application.yml deleted file mode 100644 index 6bc62186..00000000 --- a/urbanLifelineServ/platform/src/main/resources/application.yml +++ /dev/null @@ -1,36 +0,0 @@ -# ================== Platform 平台服务配置 ================== -server: - port: 8089 - -spring: - application: - name: platform-service - -# ================== Auth ================== -auth: - enabled: true - gateway-mode: true - whitelist: - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - /favicon.ico - - /error - - /actuator/health - - /actuator/info - -# ================== SpringDoc ================== -springdoc: - group-configs: - - group: 'default' - display-name: '平台服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-platform - qos-enable: false - scan: - base-packages: org.xyzh.platform.service.impl diff --git a/urbanLifelineServ/platform/src/main/resources/log4j2.xml b/urbanLifelineServ/platform/src/main/resources/log4j2.xml deleted file mode 100644 index 9396f7ec..00000000 --- a/urbanLifelineServ/platform/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/pom.xml b/urbanLifelineServ/pom.xml deleted file mode 100644 index dceb275b..00000000 --- a/urbanLifelineServ/pom.xml +++ /dev/null @@ -1,559 +0,0 @@ - - - 4.0.0 - org.xyzh - urban-lifeline - 1.0.0 - pom - - - common - apis - gateway - system - auth - file - message - crontab - ai - bidding - platform - workcase - - - - 1.0.0 - 21 - 21 - 21 - UTF-8 - - 6.2.10 - 3.5.7 - 2025.0.0 - 2025.0.0.0-preview - - - 3.3.5 - 2023.0.3.3 - 1.9.8 - - 42.7.7 - 9.4.0 - 7.0.2 - - - 2.0.58 - 6.1.0 - - 1.18.40 - - - 0.11.5 - - - 2.23.1 - - 2.0.13 - - 3.5.16 - 3.0.5 - 3.5.14 - - 3.0.5 - - - 5.4.1 - - - 8.5.17 - - - 2.8.13 - - - - - - - org.springframework - spring-framework-bom - ${spring-framework.version} - pom - import - - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - org.springframework.boot - spring-boot-starter-web - ${spring-boot.version} - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - - - com.alibaba.cloud - spring-cloud-alibaba-dependencies - ${spring-cloud-alibaba.version} - pom - import - - - - - org.apache.dubbo - dubbo-bom - ${dubbo.version} - pom - import - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - ${nacos.version} - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-config - ${nacos.version} - - - - com.alibaba.csp - sentinel-spring-boot-starter - ${sentinel.version} - - - - - org.postgresql - postgresql - ${postgresql.version} - runtime - - - org.springframework.boot - spring-boot-starter-jdbc - ${spring-boot.version} - - - com.mysql - mysql-connector-j - ${mysql.version} - runtime - - - org.springframework.boot - spring-boot-starter-data-jdbc - ${spring-boot.version} - - - com.zaxxer - HikariCP - ${hikaricp.version} - - - org.mybatis - mybatis - ${mybatis.version} - provided - - - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - ${mybatis.spring.boot.version} - - - - com.baomidou - mybatis-plus-boot-starter - ${mybatis.plus.version} - - - - org.mybatis - mybatis-spring - - - - - - com.baomidou - mybatis-plus-annotation - ${mybatis.plus.version} - - - - org.mybatis - mybatis-spring - ${mybatis.spring.version} - - - - - com.alibaba.fastjson2 - fastjson2 - ${fastjson.version} - - - com.alibaba.fastjson2 - fastjson2-extension-spring6 - ${fastjson.version} - - - - - - - org.xyzh.apis - api-all - ${urban-lifeline.version} - - - org.xyzh.apis - api-auth - ${urban-lifeline.version} - - - org.xyzh.apis - api-file - ${urban-lifeline.version} - - - org.xyzh.apis - api-message - ${urban-lifeline.version} - - - org.xyzh.apis - api-system - ${urban-lifeline.version} - - - org.xyzh.apis - api-log - ${urban-lifeline.version} - - - org.xyzh.apis - api-ai - ${urban-lifeline.version} - - - org.xyzh.apis - api-workcase - ${urban-lifeline.version} - - - - - org.xyzh.common - common-all - ${urban-lifeline.version} - - - org.xyzh.common - common-core - ${urban-lifeline.version} - - - org.xyzh.common - common-auth - ${urban-lifeline.version} - - - org.xyzh.common - common-redis - ${urban-lifeline.version} - - - org.xyzh.common - common-utils - ${urban-lifeline.version} - - - org.xyzh.common - common-exception - ${urban-lifeline.version} - - - org.xyzh.common - common-jdbc - ${urban-lifeline.version} - - - org.xyzh.common - common-wechat - ${urban-lifeline.version} - - - - org.xyzh - system - ${urban-lifeline.version} - - - org.xyzh - file - ${urban-lifeline.version} - - - - - jakarta.servlet - jakarta.servlet-api - ${jakarta.servlet.version} - provided - - - - org.projectlombok - lombok - ${lombok.version} - provided - - - - - io.jsonwebtoken - jjwt-api - ${jjwt.version} - - - io.jsonwebtoken - jjwt-impl - ${jjwt.version} - - - io.jsonwebtoken - jjwt-jackson - ${jjwt.version} - - - - - org.springframework.boot - spring-boot-starter-log4j2 - ${spring-boot.version} - - - org.apache.logging.log4j - log4j-core - ${log4j2.version} - - - org.apache.logging.log4j - log4j-api - ${log4j2.version} - - - org.apache.logging.log4j - log4j-slf4j2-impl - ${log4j2.version} - - - - org.slf4j - slf4j-api - ${slf4j.version} - - - - com.lmax - disruptor - 3.4.4 - - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - ${springdoc.version} - - - - - org.apache.poi - poi - ${poi.version} - - - - org.apache.poi - poi-ooxml - ${poi.version} - - - - - io.minio - minio - ${minio.version} - - - - - - - org.springframework.cloud - spring-cloud-starter-bootstrap - - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - org.springframework.boot - spring-boot-starter-log4j2 - - - - - - org.apache.dubbo - dubbo-spring-boot-starter - - - org.springframework.boot - spring-boot-starter-logging - - - - - org.apache.dubbo - dubbo-nacos-spring-boot-starter - - - org.springframework.boot - spring-boot-starter-logging - - - ch.qos.logback - logback-classic - - - ch.qos.logback - logback-core - - - - - - - org.postgresql - postgresql - - - com.alibaba.fastjson2 - fastjson2 - - - - org.projectlombok - lombok - provided - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${java.version} - ${java.version} - ${project.build.sourceEncoding} - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${maven.compiler.source} - ${maven.compiler.target} - - - org.projectlombok - lombok - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - - - repackage - - - - - - - - - - - public - aliyun nexus - https://maven.aliyun.com/repository/public - - true - - - - - - - public - aliyun nexus - https://maven.aliyun.com/repository/public - - true - - - false - - - - \ No newline at end of file diff --git a/urbanLifelineServ/system/pom.xml b/urbanLifelineServ/system/pom.xml deleted file mode 100644 index 9e9f9305..00000000 --- a/urbanLifelineServ/system/pom.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - system - ${urban-lifeline.version} - jar - - - 21 - 21 - - - - - - org.xyzh.common - common-all - - - org.xyzh.common - common-wechat - - - org.xyzh.apis - api-system - - - org.xyzh.apis - api-auth - - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - ${mybatis.spring.boot.version} - - - - com.baomidou - mybatis-plus-boot-starter - ${mybatis.plus.version} - - - org.mybatis - mybatis-spring - - - - - - org.mybatis - mybatis-spring - ${mybatis.spring.version} - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - - - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - - - - - system - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/SystemApp.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/SystemApp.java deleted file mode 100644 index 555c9687..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/SystemApp.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xyzh.system; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -/** - * System 服务启动类 - * - * @author yslg - */ -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@ComponentScan(basePackages = { - "org.xyzh.system", // 当前system模块 - "org.xyzh.common" // 公共模块 -}) -public class SystemApp { - private static final Logger logger = LoggerFactory.getLogger(SystemApp.class); - public static void main(String[] args) { - logger.info("======================== SystemApp 启动中 ========================="); - SpringApplication.run(SystemApp.class, args); - logger.info("======================== SystemApp 启动成功 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/config/OpenApiConfig.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/config/OpenApiConfig.java deleted file mode 100644 index 4f2a103b..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/config/OpenApiConfig.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.xyzh.system.config; - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Contact; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.info.License; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import io.swagger.v3.oas.models.servers.Server; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.List; - -/** - * OpenAPI 配置类 - System 服务 - * 配置 Swagger/OpenAPI 文档,方便 Apifox 导入接口和对象进行测试 - * - * @author yslg - */ -@Configuration -public class OpenApiConfig { - - @Bean - public OpenAPI systemOpenAPI() { - return new OpenAPI() - .info(new Info() - .title("系统服务 API 文档") - .description(""" - 系统服务接口文档,包括用户管理、角色管理、权限管理、部门管理等功能。 - - ## 使用说明 - 1. 访问 Swagger UI: http://localhost:8082/urban-lifeline/system/swagger-ui.html - 2. 访问 OpenAPI JSON: http://localhost:8082/urban-lifeline/system/v3/api-docs - 3. 在 Apifox 中导入 OpenAPI JSON 进行接口测试 - """) - .version("1.0.0") - .contact(new Contact() - .name("yslg") - .email("3401275564@qq.com")) - .license(new License() - .name("Apache 2.0") - .url("https://www.apache.org/licenses/LICENSE-2.0.html"))) - .servers(List.of( - new Server().url("http://localhost:8082/urban-lifeline/system").description("本地开发环境") - )) - .addSecurityItem(new SecurityRequirement().addList("Bearer Authentication")) - .components(new Components() - .addSecuritySchemes("Bearer Authentication", - new SecurityScheme() - .type(SecurityScheme.Type.HTTP) - .scheme("bearer") - .bearerFormat("JWT") - .description("请输入JWT Token,格式:Bearer {token}"))); - } -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/DeptRoleController.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/DeptRoleController.java deleted file mode 100644 index 033deaee..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/DeptRoleController.java +++ /dev/null @@ -1,190 +0,0 @@ -package org.xyzh.system.controller; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.xyzh.api.system.service.DeptRoleService; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.api.system.vo.UserDeptRoleVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysDeptDTO; -import org.xyzh.common.dto.sys.TbSysRoleDTO; - -@RestController -@RequestMapping("/system/deptRole") -public class DeptRoleController { - - private static final Logger logger = LoggerFactory.getLogger(DeptRoleController.class); - - @Autowired - private DeptRoleService deptRoleService; - - // ================= 部门角色相关接口 ================= - /** - * @description 创建部门 - * @param deptDTO 部门DTO - * @return ResultDomain 创建结果 - * @author yslg - * @since 2025-11-10 - */ - @PostMapping("/dept") - @PreAuthorize("hasAuthority('system:dept:create')") - public ResultDomain createDept(@RequestBody TbSysDeptDTO deptDTO) { - return deptRoleService.insertDept(deptDTO); - } - - - /** - * @description 更新部门 - * @param deptDTO 部门DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-10 - */ - @PutMapping("/dept") - @PreAuthorize("hasAuthority('system:dept:edit')") - public ResultDomain updateDept(@RequestBody TbSysDeptDTO deptDTO) { - return deptRoleService.updateDept(deptDTO); - } - - /** - * @description 删除部门 - * @param deptDTO 部门DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-10 - */ - @DeleteMapping("/dept") - @PreAuthorize("hasAuthority('system:dept:delete')") - public ResultDomain deleteDept(@RequestBody TbSysDeptDTO deptDTO) { - return deptRoleService.deleteDept(deptDTO); - } - - /** - * @description 根据条件查询部门分页列表 - * @param PageRequest pageRequest 分页请求 - * @return ResultDomain 分页列表 - * @author yslg - * @since 2025-11-10 - */ - @GetMapping("/dept/page") - @PreAuthorize("hasAuthority('system:dept:view')") - public ResultDomain getDeptPage(@RequestBody PageRequest pageRequest) { - return deptRoleService.getDeptPage(pageRequest); - } - - /** - * @description 根据条件查询部门列表 - * @param filter 部门VO - * @return ResultDomain 部门列表 - * @author yslg - * @since 2025-11-10 - */ - @GetMapping("/dept/list") - @PreAuthorize("hasAuthority('system:dept:view')") - public ResultDomain getDeptList(@RequestBody UserDeptRoleVO filter) { - return deptRoleService.getDeptList(filter); - } - - // ================= 角色相关接口 ================= - /** - * @description 创建角色 - * @param roleDTO 角色DTO - * @return ResultDomain 创建结果 - * @author yslg - * @since 2025-11-10 - */ - @PostMapping("/role") - @PreAuthorize("hasAuthority('system:role:create')") - public ResultDomain createRole(@RequestBody TbSysRoleDTO roleDTO) { - return deptRoleService.insertRole(roleDTO); - } - - /** - * @description 更新角色 - * @param roleDTO 角色DTO - * @return ResultDomain 更新结果 - * @author yslg - * @since 2025-11-10 - */ - @PutMapping("/role") - @PreAuthorize("hasAuthority('system:role:edit')") - public ResultDomain updateRole(@RequestBody TbSysRoleDTO roleDTO) { - return deptRoleService.updateRole(roleDTO); - } - - /** - * @description 删除角色 - * @param roleDTO 角色DTO - * @return ResultDomain 删除结果 - * @author yslg - * @since 2025-11-10 - */ - @DeleteMapping("/role") - @PreAuthorize("hasAuthority('system:role:delete')") - public ResultDomain deleteRole(@RequestBody TbSysRoleDTO roleDTO) { - return deptRoleService.deleteRole(roleDTO); - } - - /** - * @description 根据条件查询角色分页列表 - * @param PageRequest pageRequest 分页请求 - * @return ResultDomain 分页列表 - * @author yslg - * @since 2025-11-10 - */ - @GetMapping("/role/page") - @PreAuthorize("hasAuthority('system:role:view')") - public ResultDomain getRolePage(@RequestBody PageRequest pageRequest) { - return deptRoleService.getRolePage(pageRequest); - } - - /** - * @description 根据条件查询角色列表 - * @param filter 角色VO - * @return ResultDomain 角色列表 - * @author yslg - * @since 2025-11-10 - */ - @GetMapping("/role/list") - @PreAuthorize("hasAuthority('system:role:view')") - public ResultDomain getRoleList(@RequestBody UserDeptRoleVO filter) { - return deptRoleService.getRoleList(filter); - } - - // ================== 角色权限相关接口 ================== - /** - * @description 给一个角色设置权限 - * @param - * @return 返回值描述 - * @author yslg - * @since 2025-11-11 - */ - @PostMapping("/rolePermission/bind") - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain getRolePermission(@RequestBody PermissionVO permissionVO) { - return deptRoleService.setRolePermission(permissionVO); - } - - /** - * @description 获取一个角色的权限列表 - * @param - * @return 返回值描述 - * @author yslg - * @since 2025-11-11 - */ - @PostMapping("/rolePermission/list") - @PreAuthorize("hasAuthority('system:permission:view')") - public ResultDomain getRolePermissionList(@RequestBody PermissionVO permissionVO) { - return deptRoleService.getRolePermissionList(permissionVO); - } -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/GuestController.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/GuestController.java deleted file mode 100644 index 026fdaac..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/GuestController.java +++ /dev/null @@ -1,387 +0,0 @@ -package org.xyzh.system.controller; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import com.alibaba.fastjson2.JSON; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springdoc.core.annotations.ParameterObject; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.xyzh.api.auth.service.AuthService; -import org.xyzh.api.system.service.GuestService; -import org.xyzh.api.system.service.ModulePermissionService; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.LoginParam; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbGuestDTO; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; -import org.xyzh.common.dto.sys.TbSysUserRoleDTO; -import org.xyzh.common.dto.sys.TbSysViewDTO; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.validation.ValidationUtils; -import org.xyzh.common.wechat.pojo.WeChatPhoneResult; -import org.xyzh.common.wechat.pojo.WeChatSessionResult; -import org.xyzh.common.wechat.service.WeChatMiniProgramService; -import org.xyzh.common.auth.utils.JwtTokenUtil; -import org.xyzh.common.redis.service.RedisService; - -import io.swagger.v3.oas.annotations.Operation; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; - -/** - * @description 来客控制器 - * @filename GuestController.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Validated -@RestController -@RequestMapping("/system/guest") -public class GuestController { - - private static final Logger logger = LoggerFactory.getLogger(GuestController.class); - - @Autowired - private GuestService guestService; - - @DubboReference(version = "1.0.0", group = "auth", timeout = 5000, check = false, retries = 0) - private AuthService authService; - - @Autowired - private ModulePermissionService modulePermissionService; - - @Autowired - private JwtTokenUtil jwtTokenUtil; - - @Autowired - private RedisService redisService; - - @Autowired - private WeChatMiniProgramService weChatMiniProgramService; - - - @PostMapping - public ResultDomain createGuest(@RequestBody TbGuestDTO guest) { - ValidationUtils.validate(guest, Arrays.asList( - ValidationUtils.requiredString("name", "姓名"), - ValidationUtils.atLeastOne( - Arrays.asList("phone", "email", "wechatId"), - Arrays.asList("电话", "邮箱", "微信ID") - ) - )); - return guestService.createGuest(guest); - } - - @PutMapping - public ResultDomain updateGuest(@RequestBody TbGuestDTO guest) { - ValidationUtils.validate(guest, Arrays.asList( - ValidationUtils.requiredString("name", "姓名"), - ValidationUtils.atLeastOne( - Arrays.asList("phone", "email", "wechatId"), - Arrays.asList("电话", "邮箱", "微信ID") - ) - )); - return guestService.updateGuest(guest); - } - - @DeleteMapping("/{userId}") - public ResultDomain deleteGuest(@PathVariable("userId") @NotNull String userId) { - return guestService.deleteGuest(userId); - } - - @GetMapping("/wechat/{wechatId}") - public ResultDomain selectGuestByWechat(@PathVariable("wechatId") @NotBlank String wechatId){ - return guestService.selectGuestByWechatId(wechatId); - } - - - @PostMapping("/list") - public ResultDomain listGuest(@RequestBody TbGuestDTO filter) { - return guestService.selectGuestList(filter); - } - - @PostMapping("/page") - public ResultDomain pageGuest(@RequestBody PageRequest pageRequest) { - return guestService.selectGuestPage(pageRequest); - } - - // ========================= 微信小程序用户识别登录 ========================= - - /** - * 模拟用户数据(用于测试,没有手机号校验appid时使用) - * 格式:手机号 -> [姓名, 微信ID, 角色] - */ - private static final java.util.Map MOCK_USERS = new java.util.HashMap() {{ - put("17857100375", new String[]{"超级管理员", "17857100375", "admin"}); - put("13870055185", new String[]{"魏瑶", "75719954", "engineer"}); - put("15170466624", new String[]{"刘杰", "liujie1370984851", "engineer"}); - put("15170037929", new String[]{"万家明", "WJM15170037929", "engineer"}); - put("19100185270", new String[]{"戴斌", "BaiBin0714", "guest"}); - put("15797790517", new String[]{"余其跃", "a540378218", "guest"}); - put("15879126468", new String[]{"李小华", "wxid_vgmmzfdcwx9021", "guest"}); - }}; - - @Operation(summary = "微信小程序用户识别登录") - @PostMapping("/identify") - public ResultDomain identifyUser(@RequestBody LoginParam loginParam, HttpServletRequest request) { - logger.info("微信小程序登录请求: wechatId={}, phone={}, mockMode={}", - loginParam.getWechatId(), - loginParam.getPhone(), - loginParam.getMockMode() != null ? loginParam.getMockMode() : false); - - // ========== 模拟模式:直接使用传入的手机号匹配用户 ========== - if (Boolean.TRUE.equals(loginParam.getMockMode()) && loginParam.getPhone() != null) { - String phone = loginParam.getPhone().trim(); - String[] mockUser = MOCK_USERS.get(phone); - - if (mockUser != null) { - // 设置模拟用户信息 - loginParam.setUsername(mockUser[0]); - loginParam.setWechatId(mockUser[1]); - logger.info("模拟登录: phone={}, name={}, wechatId={}, role={}", - phone, mockUser[0], mockUser[1], mockUser[2]); - } else { - return ResultDomain.failure("未找到该手机号对应的测试用户"); - } - } else { - // ========== 正常模式:通过微信API获取手机号 ========== - // 1. 处理微信登录code,获取openid - String openid = null; - String sessionKey = null; - if (loginParam.getCode() != null && !loginParam.getCode().trim().isEmpty()) { - ResultDomain sessionResult = weChatMiniProgramService.code2Session(loginParam.getCode()); - if (sessionResult.getSuccess() && sessionResult.getData() != null) { - openid = sessionResult.getData().getOpenid(); - sessionKey = sessionResult.getData().getSessionKey(); - logger.info("获取openid成功: {}", openid); - loginParam.setWechatId(openid); - } else { - logger.warn("获取openid失败: {}", sessionResult.getMessage()); - } - } - - // 2. 处理手机号授权 - String phoneNumber = null; - - // 方式1:使用phoneCode获取手机号(新版API,推荐) - if (loginParam.getPhoneCode() != null && !loginParam.getPhoneCode().trim().isEmpty()) { - ResultDomain phoneResult = weChatMiniProgramService.getPhoneNumber(loginParam.getPhoneCode()); - if (phoneResult.getSuccess() && phoneResult.getData() != null && phoneResult.getData().getPhoneInfo() != null) { - phoneNumber = phoneResult.getData().getPhoneInfo().getPurePhoneNumber(); - if (phoneNumber == null) { - phoneNumber = phoneResult.getData().getPhoneInfo().getPhoneNumber(); - } - logger.info("通过phoneCode获取手机号成功: {}", phoneNumber); - } else { - logger.warn("通过phoneCode获取手机号失败: {}", phoneResult.getMessage()); - } - } - - // 方式2:使用encryptedData和iv解密手机号(旧版API) - if (phoneNumber == null && sessionKey != null - && loginParam.getEncryptedData() != null && !loginParam.getEncryptedData().trim().isEmpty() - && loginParam.getIv() != null && !loginParam.getIv().trim().isEmpty()) { - ResultDomain decryptResult = weChatMiniProgramService.decryptPhoneNumber( - sessionKey, loginParam.getEncryptedData(), loginParam.getIv()); - if (decryptResult.getSuccess() && decryptResult.getData() != null) { - phoneNumber = decryptResult.getData(); - logger.info("通过解密获取手机号成功: {}", phoneNumber); - } else { - logger.warn("解密手机号失败: {}", decryptResult.getMessage()); - } - } - - // 设置手机号 - if (phoneNumber != null) { - loginParam.setPhone(phoneNumber); - } - } - - // 验证参数:必须有wechatId或phone - if ((loginParam.getWechatId() == null || loginParam.getWechatId().trim().isEmpty()) - && (loginParam.getPhone() == null || loginParam.getPhone().trim().isEmpty())) { - return ResultDomain.failure("微信ID或手机号不能为空"); - } - - // 设置登录类型为微信小程序 - loginParam.setLoginType("wechat_miniprogram"); - - // 从 request 中提取客户端 IP 并设置到 loginParam - loginParam.setClientIp(getClientIP(request)); - - // 3. 尝试通过AuthService登录(员工) - ResultDomain loginResult = authService.login(loginParam); - if (loginResult.getSuccess() && loginResult.getData() != null) { - // 登录成功,是系统员工 - logger.info("员工登录成功: userId={}", loginResult.getData().getUser().getUserId()); - return loginResult; - } - - // 4. 登录失败,查询/注册来客 - return handleGuestLogin(loginParam); - } - - /** - * 处理来客登录:查询或注册来客,构造LoginDomain - */ - private ResultDomain handleGuestLogin(LoginParam loginParam) { - TbGuestDTO guest = null; - - // 优先用wechatId查询 - if (loginParam.getWechatId() != null && !loginParam.getWechatId().trim().isEmpty()) { - ResultDomain guestResult = guestService.selectGuestByWechatId(loginParam.getWechatId()); - if (guestResult.getSuccess() && guestResult.getData() != null) { - guest = guestResult.getData(); - } - } - - // wechatId未找到,尝试用phone查询 - if (guest == null && loginParam.getPhone() != null && !loginParam.getPhone().trim().isEmpty()) { - TbGuestDTO filter = new TbGuestDTO(); - filter.setPhone(loginParam.getPhone()); - ResultDomain guestResult = guestService.selectGuestOne(filter); - if (guestResult.getSuccess() && guestResult.getData() != null) { - guest = guestResult.getData(); - // 如果来客存在但wechatId为空,更新wechatId - if (guest.getWechatId() == null && loginParam.getWechatId() != null) { - TbGuestDTO updateGuest = new TbGuestDTO(); - updateGuest.setUserId(guest.getUserId()); - updateGuest.setWechatId(loginParam.getWechatId()); - guestService.updateGuest(updateGuest); - guest.setWechatId(loginParam.getWechatId()); - } - } - } - - // 3. 来客不存在,创建新来客 - if (guest == null) { - TbGuestDTO newGuest = new TbGuestDTO(); - newGuest.setOptsn(IdUtil.getOptsn()); - newGuest.setUserId(IdUtil.generateID()); - newGuest.setWechatId(loginParam.getWechatId()); - newGuest.setPhone(loginParam.getPhone()); - newGuest.setName(loginParam.getUsername() != null ? loginParam.getUsername() : "来客"); - - ResultDomain createResult = guestService.createGuest(newGuest); - if (!createResult.getSuccess()) { - return ResultDomain.failure("创建来客失败: " + createResult.getMessage()); - } - guest = createResult.getData(); - } - - // 4. 构造来客的LoginDomain - return ResultDomain.success("来客登录成功", buildGuestLoginDomain(guest)); - } - - /** - * 从来客信息构造LoginDomain - */ - private LoginDomain buildGuestLoginDomain(TbGuestDTO guest) { - LoginDomain loginDomain = new LoginDomain(); - - // 构造TbSysUserDTO,status设为guest - TbSysUserDTO userDTO = new TbSysUserDTO(); - userDTO.setUserId(guest.getUserId()); - userDTO.setPhone(guest.getPhone()); - userDTO.setEmail(guest.getEmail()); - userDTO.setWechatId(guest.getWechatId()); - userDTO.setStatus("guest"); // 来客特殊状态 - loginDomain.setUser(userDTO); - - // 构造TbSysUserInfoDTO - TbSysUserInfoDTO userInfoDTO = new TbSysUserInfoDTO(); - userInfoDTO.setUserId(guest.getUserId()); - userInfoDTO.setUsername(guest.getName()); - loginDomain.setUserInfo(userInfoDTO); - - // 设置角色信息 - List userRoles = new ArrayList<>(); - TbSysUserRoleDTO userRole = new TbSysUserRoleDTO(); - userRole.setUserId(guest.getUserId()); - userRole.setRoleId("role_guest"); - userRole.setDeptId("dept_root"); - userRoles.add(userRole); - loginDomain.setUserRoles(userRoles); - - // 获取用户权限信息 - List userPermissions = new ArrayList<>(); - List userViews = new ArrayList<>(); - - ResultDomain permissionsResult = modulePermissionService.getUserPermissions(guest.getUserId()); - if (permissionsResult.getSuccess() && permissionsResult.getDataList() != null) { - for (PermissionVO permission : permissionsResult.getDataList()) { - if (permission.getPermissionId() != null) { - TbSysPermissionDTO permissionDTO = PermissionVO.toPermissionDTO(permission); - if (permissionDTO != null) { - userPermissions.add(permissionDTO); - } - } - if (permission.getViewId() != null) { - TbSysViewDTO viewDTO = PermissionVO.toViewDTO(permission); - if (viewDTO != null) { - userViews.add(viewDTO); - } - } - } - } - loginDomain.setUserPermissions(userPermissions); - loginDomain.setUserViews(userViews); - - loginDomain.setLoginType("wechat_miniprogram"); - - // 生成 JWT Token - String token = jwtTokenUtil.generateToken(loginDomain); - loginDomain.setToken(token); - - // 将登录信息存储到 Redis(24小时有效期) - String loginKey = "login:token:" + token; - redisService.set(loginKey, JSON.toJSONString(loginDomain), 24, TimeUnit.HOURS); - - // 存储用户登录状态 - String userLoginKey = "login:user:" + guest.getUserId(); - redisService.set(userLoginKey, token, 24, TimeUnit.HOURS); - - return loginDomain; - } - - /** - * 获取客户端IP地址 - */ - private String getClientIP(HttpServletRequest request) { - String ip = request.getHeader("X-Forwarded-For"); - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); - } - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); - } - if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); - } - if (ip != null && ip.contains(",")) { - ip = ip.split(",")[0].trim(); - } - return ip; - } -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/LogController.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/LogController.java deleted file mode 100644 index 98785db5..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/LogController.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.xyzh.system.controller; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.xyzh.api.system.dto.TbSysLogDTO; -import org.xyzh.api.system.service.LogService; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; - -/** - * @description 系统日志控制器 - * @filename LogController.java - * @author yslg - * @copyright yslg - * @since 2026-01-01 - */ -@RestController -@RequestMapping("/system/log") -public class LogController { - - private static final Logger logger = LoggerFactory.getLogger(LogController.class); - - @Autowired - private LogService logService; - - // ================= 系统日志相关接口 ================= - - /** - * 添加系统日志 - */ - @PostMapping - @PreAuthorize("hasAuthority('log:log:add')") - public ResultDomain addSysLog(@RequestBody TbSysLogDTO sysLog) { - return logService.addSysLog(sysLog); - } - - /** - * 统计日志数量 - */ - @PostMapping("/count") - @PreAuthorize("hasAuthority('log:log:view')") - public ResultDomain countSysLog(@RequestBody TbSysLogDTO filter) { - return logService.countSysLog(filter); - } - - /** - * 获取日志列表 - */ - @PostMapping("/list") - @PreAuthorize("hasAuthority('log:log:view')") - public ResultDomain getSysLogList(@RequestBody TbSysLogDTO filter) { - return logService.getSysLogList(filter); - } - - /** - * 分页查询日志 - */ - @PostMapping("/page") - @PreAuthorize("hasAuthority('log:log:view')") - public ResultDomain getSysLogPage(@RequestBody PageRequest pageRequest) { - return logService.getSysLogPage(pageRequest); - } -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/PermissionController.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/PermissionController.java deleted file mode 100644 index d106678d..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/PermissionController.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.xyzh.system.controller; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.xyzh.api.system.service.ModulePermissionService; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysModuleDTO; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; - - -@RestController -@RequestMapping("/system/permission") -public class PermissionController { - - private static final Logger logger = LoggerFactory.getLogger(PermissionController.class); - - @Autowired - private ModulePermissionService modulePermissionService; - - // ================= 模块相关接口 ================= - /** - * @description 创建模块 - * @param moduleDTO 模块DTO - * @return 创建结果 - * @author yslg - * @since 2025-11-10 - */ - @PostMapping("/module") - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain createModule(@RequestBody TbSysModuleDTO moduleDTO) { - return modulePermissionService.insertModule(moduleDTO); - } - - /** - * @description 更新模块 - * @param moduleDTO 模块DTO - * @return 更新结果 - * @author yslg - * @since 2025-11-10 - */ - @PutMapping("/moudule") - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain updateModule(@RequestBody TbSysModuleDTO moduleDTO) { - return modulePermissionService.updateModule(moduleDTO); - } - - /** - * @description 删除模块 - * @param moduleDTO 模块DTO - * @return 删除结果 - * @author yslg - * @since 2025-11-10 - */ - @DeleteMapping("/module") - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain deleteModule(@RequestBody TbSysModuleDTO moduleDTO) { - return modulePermissionService.deleteModule(moduleDTO); - } - - /** - * @description 获取模块分页数据 - * @param PageRequest pageRequest 分页请求参数 - * @return 返回值描述 - * @author yslg - * @since 2025-11-10 - */ - @PostMapping("/module/page") - @PreAuthorize("hasAuthority('system:permission:view')") - public ResultDomain getModulePage(@RequestBody PageRequest pageRequest) { - return modulePermissionService.getModulePage(pageRequest); - } - - /** - * @description 获取模块列表 - * @param filter 模块DTO - * @return 返回值描述 - * @author yslg - * @since 2025-11-10 - */ - @PostMapping("/module/list") - @PreAuthorize("hasAuthority('system:permission:view')") - public ResultDomain getModuleList(@RequestBody PermissionVO filter) { - return modulePermissionService.getModuleList(filter); - } - - // ================= 权限相关接口 ================= - /** - * @description 创建权限 - * @param permissionDTO 权限DTO - * @return ResultDomain 创建结果 - * @author yslg - * @since 2025-11-10 - */ - @PostMapping - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain createPermission(@RequestBody TbSysPermissionDTO permissionDTO) { - return modulePermissionService.insertPermission(permissionDTO); - } - - /** - * @description 更新权限 - * @param permissionDTO 权限DTO - * @return 更新结果 - * @author yslg - * @since 2025-11-10 - */ - @PutMapping - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain updatePermission(@RequestBody TbSysPermissionDTO permissionDTO) { - return modulePermissionService.updatePermission(permissionDTO); - } - - /** - * @description 删除权限 - * @param permissionDTO 权限DTO - * @return 删除结果 - * @author yslg - * @since 2025-11-10 - */ - @DeleteMapping - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain deletePermission(@RequestBody TbSysPermissionDTO permissionDTO) { - return modulePermissionService.deletePermission(permissionDTO); - } - - /** - * @description 获取权限分页数据 - * @param PageRequest pageRequest 分页请求参数 - * @return 分页数据 - * @author yslg - * @since 2025-11-10 - */ - @PostMapping("/page") - @PreAuthorize("hasAuthority('system:permission:view')") - public ResultDomain getModulePermissionPage(@RequestBody PageRequest pageRequest) { - return modulePermissionService.getModulePermissionPage(pageRequest); - } - - /** - * @description 获取权限列表 - * @param filter 权限VO - * @return 列表数据 - * @author yslg - * @since 2025-11-10 - */ - @PostMapping("/list") - @PreAuthorize("hasAuthority('system:permission:view')") - public ResultDomain getModulePermissionList(@RequestBody PermissionVO filter) { - return modulePermissionService.getModulePermissionList(filter); - } - - -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/SysConfigController.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/SysConfigController.java deleted file mode 100644 index d9bcc0b8..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/SysConfigController.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.xyzh.system.controller; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.xyzh.api.system.service.SysConfigService; -import org.xyzh.api.system.vo.SysConfigVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysConfigDTO; - - -@RestController -@RequestMapping("/system/config") -public class SysConfigController { - - private static final Logger logger = LoggerFactory.getLogger(SysConfigController.class); - - @Autowired - private SysConfigService sysConfigService; - - // ================= 系统配置相关接口 ================= - - @PostMapping - @PreAuthorize("hasAuthority('config:config:edit')") - public ResultDomain createConfig(@RequestBody TbSysConfigDTO configDTO) { - return sysConfigService.insertConfig(configDTO); - } - - @PutMapping - @PreAuthorize("hasAuthority('config:config:edit')") - public ResultDomain updateConfig(@RequestBody TbSysConfigDTO configDTO) { - return sysConfigService.updateConfig(configDTO); - } - - @DeleteMapping - @PreAuthorize("hasAuthority('config:config:edit')") - public ResultDomain deleteConfig(@RequestBody TbSysConfigDTO configDTO) { - return sysConfigService.deleteConfig(configDTO); - } - - @PostMapping("/page") - @PreAuthorize("hasAuthority('config:config:view')") - public ResultDomain getConfigPage(@RequestBody PageRequest pageRequest) { - return sysConfigService.getConfigPage(pageRequest); - } - - @PostMapping("/list") - @PreAuthorize("hasAuthority('config:config:view')") - public ResultDomain getConfigList(@RequestBody SysConfigVO filter) { - return sysConfigService.getConfigList(filter); - } - - - -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/UserController.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/UserController.java deleted file mode 100644 index 4a8b3c34..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/UserController.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.xyzh.system.controller; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.security.access.prepost.PreAuthorize; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; - -@RestController -@RequestMapping("/system/user") -public class UserController { - - private static final Logger logger = LoggerFactory.getLogger(UserController.class); - - @Autowired - private SysUserService sysUserService; - - // ================= 用户相关接口 ================= - - @PostMapping - @PreAuthorize("hasAuthority('system:user:create')") - public ResultDomain createUser(@RequestBody SysUserVO userVO) { - return sysUserService.insertUser(userVO); - } - - @PutMapping - @PreAuthorize("hasAuthority('system:user:edit')") - public ResultDomain updateUser(@RequestBody SysUserVO userVO) { - return sysUserService.updateUser(userVO); - } - - @DeleteMapping - @PreAuthorize("hasAuthority('system:user:delete')") - public ResultDomain deleteUser(@RequestBody TbSysUserDTO userDTO) { - return sysUserService.deleteUser(userDTO); - } - - @PostMapping("/page") - @PreAuthorize("hasAuthority('system:user:view')") - public ResultDomain getUserPage(@RequestBody PageRequest pageRequest) { - return sysUserService.getUserPage(pageRequest); - } - - @PostMapping("/list") - @PreAuthorize("hasAuthority('system:user:view')") - public ResultDomain getUserList(@RequestBody SysUserVO filter) { - return sysUserService.getUserList(filter); - } - - // ================= 用户信息相关接口 ================== - - @PutMapping("/info") - @PreAuthorize("hasAuthority('system:user:edit')") - public ResultDomain updateUserInfo(@RequestBody TbSysUserInfoDTO userInfoDTO) { - return sysUserService.updateUserInfo(userInfoDTO); - } - - @GetMapping("/info/{userId}") - @PreAuthorize("hasAuthority('system:user:view')") - public ResultDomain getUserInfo(@PathVariable("userId") String userId) { - return sysUserService.getUserInfo(userId); - } - - -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/ViewController.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/ViewController.java deleted file mode 100644 index 3fdf8dc6..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/controller/ViewController.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.xyzh.system.controller; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.xyzh.api.system.service.ViewService; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysViewDTO; - -@RestController -@RequestMapping("/system/view") -public class ViewController { - - private static final Logger logger = LoggerFactory.getLogger(ViewController.class); - - @Autowired - private ViewService viewService; - - // ================= 视图相关接口 ================= - @PostMapping - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain createView(@RequestBody TbSysViewDTO viewDTO) { - return viewService.insertView(viewDTO); - } - - @PutMapping - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain updateView(@RequestBody TbSysViewDTO viewDTO) { - return viewService.updateView(viewDTO); - } - - @DeleteMapping - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain deleteView(@RequestBody TbSysViewDTO viewDTO) { - return viewService.deleteView(viewDTO); - } - - @PostMapping("/page") - @PreAuthorize("hasAuthority('system:permission:view')") - public ResultDomain getViewPage(@RequestBody PageRequest pageRequest) { - return viewService.getViewPage(pageRequest); - } - - @PostMapping("/list") - @PreAuthorize("hasAuthority('system:permission:view')") - public ResultDomain getViewList(@RequestBody PermissionVO filter) { - return viewService.getViewList(filter); - } - - // ================= 视图权限相关接口 ================== - @PostMapping("/permission/bind") - @PreAuthorize("hasAuthority('system:permission:manage')") - public ResultDomain bindViewPermission(@RequestBody PermissionVO permissionVO) { - return viewService.setViewPermissions(permissionVO); - } - - @PostMapping("/permission/list") - @PreAuthorize("hasAuthority('system:permission:view')") - public ResultDomain getViewPermissions(@RequestBody PermissionVO permissionVO) { - return viewService.getViewPermissionList(permissionVO); - } -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/acl/TbSysAclMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/acl/TbSysAclMapper.java deleted file mode 100644 index c1c9446a..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/acl/TbSysAclMapper.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.xyzh.system.mapper.acl; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.AclVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysAclDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统访问控制列表Mapper接口 - * @filename TbSysAclMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysAclMapper extends BaseMapper { - - /** - * @description 插入系统访问控制列表 - * @param aclDTO 系统访问控制列表DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertAcl(TbSysAclDTO aclDTO); - - /** - * @description 更新系统访问控制列表 - * @param aclDTO 系统访问控制列表DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateAcl(TbSysAclDTO aclDTO); - - /** - * @description 删除系统访问控制列表 - * @param aclDTO 系统访问控制列表DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteAcl(TbSysAclDTO aclDTO); - - /** - * @description 根据访问控制列表ID查询系统访问控制列表 - * @param aclId 访问控制列表ID - * @return AclVO 访问控制列表VO - * @author yslg - * @since 2025-11-07 - */ - AclVO getAclById(String aclId); - - /** - * @description 根据对象ID查询系统访问控制列表 - * @param objectId 对象ID - * @return List 访问控制列表VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getAclByObjectId(String objectId); - - /** - * @description 根据条件查询系统访问控制列表 - * @param filter 系统访问控制列表DTO - * @return List 访问控制列表VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getAclByFilter(@Param("filter") TbSysAclDTO filter); - - /** - * @description 根据条件查询系统访问控制列表分页列表 - * @param filter 系统访问控制列表DTO - * @param pageParam 分页参数 - * @return List 访问控制列表VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getAclPageByFilter(@Param("filter") TbSysAclDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统访问控制列表数量 - * @param filter 系统访问控制列表DTO - * @return int 系统访问控制列表数量 - * @author yslg - * @since 2025-11-07 - */ - int getAclCount(TbSysAclDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/acl/TbSysAclPolicyMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/acl/TbSysAclPolicyMapper.java deleted file mode 100644 index 92e519d6..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/acl/TbSysAclPolicyMapper.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.system.mapper.acl; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.AclVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysAclPolicyDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统访问控制策略Mapper接口 - * @filename TbSysAclPolicyMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysAclPolicyMapper extends BaseMapper { - - /** - * @description 插入系统访问控制策略 - * @param aclPolicyDTO 系统访问控制策略DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertAclPolicy(TbSysAclPolicyDTO aclPolicyDTO); - - /** - * @description 更新系统访问控制策略 - * @param aclPolicyDTO 系统访问控制策略DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateAclPolicy(TbSysAclPolicyDTO aclPolicyDTO); - - /** - * @description 删除系统访问控制策略 - * @param aclPolicyDTO 系统访问控制策略DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteAclPolicy(TbSysAclPolicyDTO aclPolicyDTO); - - /** - * @description 根据策略ID查询系统访问控制策略 - * @param policyId 策略ID - * @return AclVO 访问控制列表VO - * @author yslg - * @since 2025-11-07 - */ - AclVO getAclPolicyById(String policyId); - - /** - * @description 根据条件查询系统访问控制策略列表 - * @param filter 系统访问控制策略DTO - * @return List 访问控制列表VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getAclPolicyByFilter(@Param("filter") TbSysAclPolicyDTO filter); - - /** - * @description 根据条件查询系统访问控制策略分页列表 - * @param filter 系统访问控制策略DTO - * @param pageParam 分页参数 - * @return List 访问控制列表VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getAclPolicyPageByFilter(@Param("filter") TbSysAclPolicyDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统访问控制策略数量 - * @param filter 系统访问控制策略DTO - * @return int 系统访问控制策略数量 - * @author yslg - * @since 2025-11-07 - */ - int getAclPolicyCount(TbSysAclPolicyDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/config/TbSysConfigMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/config/TbSysConfigMapper.java deleted file mode 100644 index 956327ca..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/config/TbSysConfigMapper.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.system.mapper.config; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.SysConfigVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysConfigDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统配置Mapper接口 - * @filename TbSysConfigMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysConfigMapper extends BaseMapper { - - /** - * @description 从key读取配置 - * @param - * @author yslg - * @since 2025-12-05 - */ - TbSysConfigDTO selectSysConfigByKey(@Param("configKey") String configKey); - - - /** - * @description 插入系统配置 - * @param configDTO 系统配置DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertConfig(TbSysConfigDTO configDTO); - - /** - * @description 更新系统配置 - * @param configDTO 系统配置DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateConfig(TbSysConfigDTO configDTO); - - /** - * @description 删除系统配置 - * @param configDTO 系统配置DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteConfig(TbSysConfigDTO configDTO); - - /** - * @description 根据条件查询系统配置列表 - * @param filter 系统配置DTO - * @return List 系统配置VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getConfigByFilter(@Param("filter") TbSysConfigDTO filter); - - /** - * @description 根据条件查询系统配置分页列表 - * @param filter 系统配置DTO - * @param pageParam 分页参数 - * @return List 系统配置VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getConfigPageByFilter(@Param("filter") TbSysConfigDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统配置数量 - * @param filter 系统配置DTO - * @return int 系统配置数量 - * @author yslg - * @since 2025-11-07 - */ - int getConfigCount(TbSysConfigDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/dept/TbSysDeptMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/dept/TbSysDeptMapper.java deleted file mode 100644 index 0397aaa3..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/dept/TbSysDeptMapper.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.xyzh.system.mapper.dept; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysDeptDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统部门Mapper接口 - * @filename TbSysDeptMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysDeptMapper extends BaseMapper { - - /** - * @description 插入系统部门 - * @param deptDTO 系统部门DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertDept(TbSysDeptDTO deptDTO); - - /** - * @description 更新系统部门 - * @param deptDTO 系统部门DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateDept(TbSysDeptDTO deptDTO); - - /** - * @description 删除系统部门 - * @param deptDTO 系统部门DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteDept(TbSysDeptDTO deptDTO); - - /** - * @description 根据条件查询系统部门列表 - * @param filter 系统部门DTO - * @return List 系统部门列表 - * @author yslg - * @since 2025-11-07 - */ - List getDeptByFilter(@Param("filter") TbSysDeptDTO filter); - - /** - * @description 根据条件查询系统部门分页列表 - * @param filter 系统部门DTO - * @param pageParam 分页参数 - * @return List 系统部门列表 - * @author yslg - * @since 2025-11-07 - */ - List getDeptPageByFilter(@Param("filter") TbSysDeptDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统部门数量 - * @param filter 系统部门DTO - * @return int 系统部门数量 - * @author yslg - * @since 2025-11-07 - */ - int getDeptCount(TbSysDeptDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/log/TbSysLogMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/log/TbSysLogMapper.java deleted file mode 100644 index 49a0b659..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/log/TbSysLogMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.xyzh.system.mapper.log; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.dto.TbSysLogDTO; -import org.xyzh.common.core.page.PageParam; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统日志Mapper接口 - * @filename TbSysLogMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysLogMapper extends BaseMapper { - - /** - * @description 插入系统日志 - * @param logDTO 系统日志DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertLog(TbSysLogDTO logDTO); - - /** - * @description 更新系统日志 - * @param logDTO 系统日志DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateLog(TbSysLogDTO logDTO); - - /** - * @description 删除系统日志 - * @param logDTO 系统日志DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteLog(TbSysLogDTO logDTO); - - /** - * @description 根据日志ID查询系统日志 - * @param logId 日志ID - * @return TbSysLogDTO 系统日志DTO - * @author yslg - * @since 2025-11-07 - */ - TbSysLogDTO getLogById(String logId); - - /** - * @description 根据条件查询系统日志列表 - * @param filter 系统日志DTO - * @return List 系统日志列表 - * @author yslg - * @since 2025-11-07 - */ - List getLogByFilter(@Param("filter") TbSysLogDTO filter); - - /** - * @description 根据条件查询系统日志分页列表 - * @param filter 系统日志DTO - * @param pageParam 分页参数 - * @return List 系统日志列表 - * @author yslg - * @since 2025-11-07 - */ - List getLogPageByFilter(@Param("filter") TbSysLogDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统日志数量 - * @param filter 系统日志DTO - * @return int 系统日志数量 - * @author yslg - * @since 2025-11-07 - */ - int getLogCount(TbSysLogDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/log/TbSysLoginLogMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/log/TbSysLoginLogMapper.java deleted file mode 100644 index 117594b3..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/log/TbSysLoginLogMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.xyzh.system.mapper.log; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.dto.TbSysLoginLogDTO; -import org.xyzh.common.core.page.PageParam; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统登录日志Mapper接口 - * @filename TbSysLoginLogMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysLoginLogMapper extends BaseMapper { - - /** - * @description 插入系统登录日志 - * @param loginLogDTO 系统登录日志DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertLoginLog(TbSysLoginLogDTO loginLogDTO); - - /** - * @description 更新系统登录日志 - * @param loginLogDTO 系统登录日志DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateLoginLog(TbSysLoginLogDTO loginLogDTO); - - /** - * @description 删除系统登录日志 - * @param loginLogDTO 系统登录日志DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteLoginLog(TbSysLoginLogDTO loginLogDTO); - - /** - * @description 根据登录日志ID查询系统登录日志 - * @param loginLogId 登录日志ID - * @return TbSysLoginLogDTO 系统登录日志DTO - * @author yslg - * @since 2025-11-07 - */ - TbSysLoginLogDTO getLoginLogById(String loginLogId); - - /** - * @description 根据条件查询系统登录日志列表 - * @param filter 系统登录日志DTO - * @return List 系统登录日志列表 - * @author yslg - * @since 2025-11-07 - */ - List getLoginLogByFilter(@Param("filter") TbSysLoginLogDTO filter); - - /** - * @description 根据条件查询系统登录日志分页列表 - * @param filter 系统登录日志DTO - * @param pageParam 分页参数 - * @return List 系统登录日志列表 - * @author yslg - * @since 2025-11-07 - */ - List getLoginLogPageByFilter(@Param("filter") TbSysLoginLogDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统登录日志数量 - * @param filter 系统登录日志DTO - * @return int 系统登录日志数量 - * @author yslg - * @since 2025-11-07 - */ - int getLoginLogCount(TbSysLoginLogDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/module/TbSysModuleMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/module/TbSysModuleMapper.java deleted file mode 100644 index ee19fff6..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/module/TbSysModuleMapper.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.system.mapper.module; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysModuleDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统模块Mapper接口 - * @filename TbSysModuleMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysModuleMapper extends BaseMapper { - - /** - * @description 插入系统模块 - * @param moduleDTO 系统模块DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertModule(TbSysModuleDTO moduleDTO); - - /** - * @description 更新系统模块 - * @param moduleDTO 系统模块DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateModule(TbSysModuleDTO moduleDTO); - - /** - * @description 删除系统模块 - * @param moduleDTO 系统模块DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteModule(TbSysModuleDTO moduleDTO); - - /** - * @description 根据模块ID查询系统模块 - * @param moduleId 模块ID - * @return SysModuleVO 系统模块VO - * @author yslg - * @since 2025-11-07 - */ - PermissionVO getModuleById(String moduleId); - - /** - * @description 根据条件查询系统模块列表 - * @param filter 系统模块DTO - * @return List 系统模块VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getModuleByFilter(@Param("filter") TbSysModuleDTO filter); - - /** - * @description 根据条件查询系统模块分页列表 - * @param filter 系统模块DTO - * @param pageParam 分页参数 - * @return List 系统模块VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getModulePageByFilter(@Param("filter") TbSysModuleDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统模块数量 - * @param filter 系统模块DTO - * @return int 系统模块数量 - * @author yslg - * @since 2025-11-07 - */ - int getModuleCount(TbSysModuleDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/permission/TbSysPermissionMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/permission/TbSysPermissionMapper.java deleted file mode 100644 index 354843b0..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/permission/TbSysPermissionMapper.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.system.mapper.permission; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统权限Mapper接口 - * @filename TbSysPermissionMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysPermissionMapper extends BaseMapper { - - /** - * @description 插入系统权限 - * @param permissionDTO 系统权限DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertPermission(TbSysPermissionDTO permissionDTO); - - /** - * @description 更新系统权限 - * @param permissionDTO 系统权限DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updatePermission(TbSysPermissionDTO permissionDTO); - - /** - * @description 删除系统权限 - * @param permissionDTO 系统权限DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deletePermission(TbSysPermissionDTO permissionDTO); - - /** - * @description 根据权限ID查询系统权限 - * @param permissionId 权限ID - * @return PermissionVO 权限VO - * @author yslg - * @since 2025-11-07 - */ - PermissionVO getPermissionById(String permissionId); - - /** - * @description 根据条件查询系统权限列表 - * @param filter 系统权限DTO - * @return List 权限VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getPermissionByFilter(@Param("filter") TbSysPermissionDTO filter); - - /** - * @description 根据条件查询系统权限分页列表 - * @param filter 系统权限DTO - * @param pageParam 分页参数 - * @return List 权限VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getPermissionPageByFilter(@Param("filter") TbSysPermissionDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统权限数量 - * @param filter 系统权限DTO - * @return int 系统权限数量 - * @author yslg - * @since 2025-11-07 - */ - int getPermissionCount(TbSysPermissionDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/role/TbSysRoleMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/role/TbSysRoleMapper.java deleted file mode 100644 index 50464243..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/role/TbSysRoleMapper.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.xyzh.system.mapper.role; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysRoleDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统角色Mapper接口 - * @filename TbSysRoleMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysRoleMapper extends BaseMapper { - - /** - * @description 插入系统角色 - * @param roleDTO 系统角色DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertRole(TbSysRoleDTO roleDTO); - - /** - * @description 更新系统角色 - * @param roleDTO 系统角色DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateRole(TbSysRoleDTO roleDTO); - - /** - * @description 删除系统角色 - * @param roleDTO 系统角色DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteRole(TbSysRoleDTO roleDTO); - - /** - * @description 根据条件查询系统角色列表 - * @param filter 系统角色DTO - * @return List 系统角色VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getRoleByFilter(@Param("filter") TbSysRoleDTO filter); - - /** - * @description 根据条件查询系统角色分页列表 - * @param filter 系统角色DTO - * @param pageParam 分页参数 - * @return List 系统角色VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getRolePageByFilter(@Param("filter") TbSysRoleDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统角色数量 - * @param filter 系统角色DTO - * @return int 系统角色数量 - * @author yslg - * @since 2025-11-07 - */ - int getRoleCount(TbSysRoleDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/role/TbSysRolePermissionMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/role/TbSysRolePermissionMapper.java deleted file mode 100644 index 21acab9f..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/role/TbSysRolePermissionMapper.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.xyzh.system.mapper.role; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysRolePermissionDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统角色权限关系Mapper接口 - * @filename TbSysRolePermissionMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysRolePermissionMapper extends BaseMapper { - - /** - * @description 插入系统角色权限关系 - * @param rolePermissionDTO 系统角色权限关系DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertRolePermission(TbSysRolePermissionDTO rolePermissionDTO); - - /** - * @description 更新系统角色权限关系 - * @param rolePermissionDTO 系统角色权限关系DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateRolePermission(TbSysRolePermissionDTO rolePermissionDTO); - - /** - * @description 删除系统角色权限关系 - * @param rolePermissionDTO 系统角色权限关系DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteRolePermission(TbSysRolePermissionDTO rolePermissionDTO); - - /** - * @description 根据角色ID查询系统角色权限关系 - * @param roleId 角色ID - * @return List 权限VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getRolePermissionByRoleId(String roleId); - - /** - * @description 根据条件查询系统角色权限关系列表 - * @param filter 系统角色权限关系DTO - * @return List 权限VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getRolePermissionByFilter(@Param("filter") TbSysRolePermissionDTO filter); - - /** - * @description 根据条件查询系统角色权限关系分页列表 - * @param filter 系统角色权限关系DTO - * @param pageParam 分页参数 - * @return List 权限VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getRolePermissionPageByFilter(@Param("filter") TbSysRolePermissionDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统角色权限关系数量 - * @param filter 系统角色权限关系DTO - * @return int 系统角色权限关系数量 - * @author yslg - * @since 2025-11-07 - */ - int getRolePermissionCount(TbSysRolePermissionDTO filter); - - /** - * @description 根据用户ID一次性查询该用户所有权限(连表 user_role -> role_permission -> permission-> view_permission) - * @param userId 用户ID - * @return List 权限VO列表 - */ - List getPermissionsByUserId(@Param("userId") String userId); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbGuestMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbGuestMapper.java deleted file mode 100644 index 04c4dfeb..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbGuestMapper.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.xyzh.system.mapper.user; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.springframework.security.access.method.P; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbGuestDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 来客Mapper - * @filename TbGuestMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Mapper -public interface TbGuestMapper extends BaseMapper{ - - /** - * @description 插入来客 - * @param guest 来客信息 - * @author yslg - * @since 2025-12-18 - */ - int insertGuest(TbGuestDTO guest); - - /** - * @description 更新来客 - * @param guest 来客信息 - * @author yslg - * @since 2025-12-18 - */ - int updateGuest(TbGuestDTO guest); - - /** - * @description 删除来客 - * @param userId 来客ID - * @author yslg - * @since 2025-12-18 - */ - int deleteGuest(String userId); - - /** - * @description 查询单个来客 - * @param guest 来客信息 - * @author yslg - * @since 2025-12-18 - */ - TbGuestDTO selectGuestOne(TbGuestDTO guest); - - /** - * @description 根据微信id查询来客 - * @param wechatId - * @author yslg - * @since 2025-12-18 - */ - TbGuestDTO selectGuestByWechatId(String wechatId); - - /** - * @description 查询来客列表 - * @param guest 来客信息 - * @author yslg - * @since 2025-12-18 - */ - List selectGuestList(@Param("filter") TbGuestDTO filter); - - /** - * @description 查询来客分页列表 - * @param guest 来客信息 - * @param pageParam 分页参数 - * @author yslg - * @since 2025-12-18 - */ - List selectGuestPage(@Param("filter") TbGuestDTO guest, @Param("pageParam") PageParam pageParam); - - int countGuest(TbGuestDTO guest); -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserInfoMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserInfoMapper.java deleted file mode 100644 index 48b8a2f4..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserInfoMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.xyzh.system.mapper.user; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统用户信息Mapper接口 - * @filename TbSysUserInfoMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysUserInfoMapper extends BaseMapper { - - /** - * @description 插入系统用户信息 - * @param userInfoDTO 系统用户信息DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertUserInfo(TbSysUserInfoDTO userInfoDTO); - - /** - * @description 更新系统用户信息 - * @param userInfoDTO 系统用户信息DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateUserInfo(TbSysUserInfoDTO userInfoDTO); - - /** - * @description 删除系统用户信息 - * @param userInfoDTO 系统用户信息DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteUserInfo(TbSysUserInfoDTO userInfoDTO); - - /** - * @description 根据用户ID查询系统用户信息 - * @param userId 用户ID - * @return TbSysUserInfoDTO 系统用户信息DTO - * @author yslg - * @since 2025-11-07 - */ - TbSysUserInfoDTO getUserInfoById(String userId); - - /** - * @description 根据条件查询系统用户信息列表 - * @param filter 系统用户信息DTO - * @return List 系统用户信息列表 - * @author yslg - * @since 2025-11-07 - */ - List getUserInfoByFilter(@Param("filter") TbSysUserInfoDTO filter); - - /** - * @description 根据条件查询系统用户信息分页列表 - * @param filter 系统用户信息DTO - * @param pageParam 分页参数 - * @return List 系统用户信息列表 - * @author yslg - * @since 2025-11-07 - */ - List getUserInfoPageByFilter(@Param("filter") TbSysUserInfoDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统用户信息数量 - * @param filter 系统用户信息DTO - * @return int 系统用户信息数量 - * @author yslg - * @since 2025-11-07 - */ - int getUserInfoCount(TbSysUserInfoDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserMapper.java deleted file mode 100644 index 7afa76f6..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserMapper.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.system.mapper.user; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysUserDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统用户Mapper接口 - * @filename TbSysUserMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysUserMapper extends BaseMapper { - - - /** - * @description 插入系统用户 - * @param userDTO 系统用户DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertUser(TbSysUserDTO userDTO); - - /** - * @description 更新系统用户 - * @param userDTO 系统用户DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateUser(TbSysUserDTO userDTO); - - /** - * @description 删除系统用户 - * @param userDTO 系统用户DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteUser(TbSysUserDTO userDTO); - - /** - * @description 根据用户ID查询系统用户 - * @param userId 用户ID - * @return SysUserVO 系统用户VO - * @author yslg - * @since 2025-11-07 - */ - SysUserVO getUserById(String userId); - - /** - * @description 根据条件查询系统用户列表 - * @param filter 系统用户DTO - * @return List 系统用户VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getUserByFilter(@Param("filter") SysUserVO filter); - - /** - * @description 根据条件查询系统用户分页列表 - * @param filter 系统用户DTO - * @param pageParam 分页参数 - * @return List 系统用户VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getUserPageByFilter(@Param("filter") TbSysUserDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统用户数量 - * @param filter 系统用户DTO - * @return int 系统用户数量 - * @author yslg - * @since 2025-11-07 - */ - int getUserCount(TbSysUserDTO filter); -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserRoleMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserRoleMapper.java deleted file mode 100644 index 98b2c133..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/user/TbSysUserRoleMapper.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xyzh.system.mapper.user; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.UserDeptRoleVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysUserRoleDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统用户角色关系Mapper接口 - * @filename TbSysUserRoleMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysUserRoleMapper extends BaseMapper { - - /** - * @description 插入系统用户角色关系 - * @param userRoleDTO 系统用户角色关系DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertUserRole(TbSysUserRoleDTO userRoleDTO); - - /** - * @description 更新系统用户角色关系 - * @param userRoleDTO 系统用户角色关系DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateUserRole(TbSysUserRoleDTO userRoleDTO); - - /** - * @description 删除系统用户角色关系 - * @param userRoleDTO 系统用户角色关系DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteUserRole(TbSysUserRoleDTO userRoleDTO); - - /** - * @description 根据用户ID查询系统用户角色关系 - * @param userId 用户ID - * @return List 用户部门角色VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getUserRoleByUserId(String userId); - - /** - * @description 根据条件查询系统用户角色关系列表 - * @param filter 系统用户角色关系DTO - * @return List 用户部门角色VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getUserRoleByFilter(@Param("filter") TbSysUserRoleDTO filter); - - /** - * @description 根据条件查询系统用户角色关系分页列表 - * @param filter 系统用户角色关系DTO - * @param pageParam 分页参数 - * @return List 用户部门角色VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getUserRolePageByFilter(@Param("filter") TbSysUserRoleDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统用户角色关系数量 - * @param filter 系统用户角色关系DTO - * @return int 系统用户角色关系数量 - * @author yslg - * @since 2025-11-07 - */ - int getUserRoleCount(TbSysUserRoleDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/view/TbSysViewMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/view/TbSysViewMapper.java deleted file mode 100644 index d79ac471..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/view/TbSysViewMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.xyzh.system.mapper.view; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysViewDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统视图Mapper接口 - * @filename TbSysViewMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysViewMapper extends BaseMapper { - - /** - * @description 插入系统视图 - * @param viewDTO 系统视图DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertView(TbSysViewDTO viewDTO); - - /** - * @description 更新系统视图 - * @param viewDTO 系统视图DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateView(TbSysViewDTO viewDTO); - - /** - * @description 删除系统视图 - * @param viewDTO 系统视图DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteView(TbSysViewDTO viewDTO); - - /** - * @description 根据视图ID查询系统视图 - * @param viewId 视图ID - * @return TbSysViewDTO 系统视图DTO - * @author yslg - * @since 2025-11-07 - */ - TbSysViewDTO getViewById(String viewId); - - /** - * @description 根据条件查询系统视图列表 - * @param filter 系统视图DTO - * @return List 系统视图列表 - * @author yslg - * @since 2025-11-07 - */ - List getViewByFilter(@Param("filter") TbSysViewDTO filter); - - /** - * @description 根据条件查询系统视图分页列表 - * @param filter 系统视图DTO - * @param pageParam 分页参数 - * @return List 系统视图列表 - * @author yslg - * @since 2025-11-07 - */ - List getViewPageByFilter(@Param("filter") TbSysViewDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统视图数量 - * @param filter 系统视图DTO - * @return int 系统视图数量 - * @author yslg - * @since 2025-11-07 - */ - int getViewCount(TbSysViewDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/view/TbSysViewPermissionMapper.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/view/TbSysViewPermissionMapper.java deleted file mode 100644 index af21b701..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/mapper/view/TbSysViewPermissionMapper.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.xyzh.system.mapper.view; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.dto.sys.TbSysViewPermissionDTO; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @description 系统视图权限关系Mapper接口 - * @filename TbSysViewPermissionMapper.java - * @author yslg - * @copyright yslg - * @since 2025-11-07 - */ -@Mapper -public interface TbSysViewPermissionMapper extends BaseMapper { - - /** - * @description 插入系统视图权限关系 - * @param viewPermissionDTO 系统视图权限关系DTO - * @return int 插入结果 - * @author yslg - * @since 2025-11-07 - */ - int insertViewPermission(TbSysViewPermissionDTO viewPermissionDTO); - - /** - * @description 更新系统视图权限关系 - * @param viewPermissionDTO 系统视图权限关系DTO - * @return int 更新结果 - * @author yslg - * @since 2025-11-07 - */ - int updateViewPermission(TbSysViewPermissionDTO viewPermissionDTO); - - /** - * @description 删除系统视图权限关系 - * @param viewPermissionDTO 系统视图权限关系DTO - * @return int 删除结果 - * @author yslg - * @since 2025-11-07 - */ - int deleteViewPermission(TbSysViewPermissionDTO viewPermissionDTO); - - /** - * @description 根据视图ID查询系统视图权限关系 - * @param viewId 视图ID - * @param permissionId 权限ID - * @return PermissionVO 权限VO - * @author yslg - * @since 2025-11-07 - */ - PermissionVO getViewPermissionByViewId(String viewId, String permissionId); - - /** - * @description 根据条件查询系统视图权限关系列表 - * @param filter 系统视图权限关系DTO - * @return List 权限VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getViewPermissionByFilter(@Param("filter") TbSysViewPermissionDTO filter); - - /** - * @description 根据条件查询系统视图权限关系分页列表 - * @param filter 系统视图权限关系DTO - * @param pageParam 分页参数 - * @return List 权限VO列表 - * @author yslg - * @since 2025-11-07 - */ - List getViewPermissionPageByFilter(@Param("filter") TbSysViewPermissionDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * @description 根据条件查询系统视图权限关系数量 - * @param filter 系统视图权限关系DTO - * @return int 系统视图权限关系数量 - * @author yslg - * @since 2025-11-07 - */ - int getViewPermissionCount(TbSysViewPermissionDTO filter); -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/AclServiceImpl.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/AclServiceImpl.java deleted file mode 100644 index c7a7a7c9..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/AclServiceImpl.java +++ /dev/null @@ -1,281 +0,0 @@ -package org.xyzh.system.service.impl; - -import jakarta.annotation.Resource; -import java.util.Date; -import java.util.List; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xyzh.api.system.service.AclService; -import org.xyzh.api.system.vo.AclVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysAclDTO; -import org.xyzh.common.dto.sys.TbSysAclPolicyDTO; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.StringUtils; -import org.xyzh.system.mapper.acl.TbSysAclMapper; -import org.xyzh.system.mapper.acl.TbSysAclPolicyMapper; - -/** - * @description 访问控制列表服务实现类 - * @filename AclServiceImpl.java - * @author yslg - * @copyright yslg - * @since 2025-12-05 - */ -@DubboService( - version = "1.0.0", - group = "system", - timeout = 3000, - retries = 0 -) -public class AclServiceImpl implements AclService { - - private static final Logger logger = LoggerFactory.getLogger(AclServiceImpl.class); - private static final String MSG_ACL_PARAM_REQUIRED = "访问控制列表参数不能为空"; - private static final String MSG_ACL_ID_REQUIRED = "访问控制列表ID不能为空"; - private static final String MSG_POLICY_PARAM_REQUIRED = "访问控制策略参数不能为空"; - private static final String MSG_POLICY_ID_REQUIRED = "访问控制策略ID不能为空"; - private static final String MSG_PAGE_PARAM_REQUIRED = "分页参数不能为空"; - - @Resource - private TbSysAclMapper aclMapper; - - @Resource - private TbSysAclPolicyMapper aclPolicyMapper; - - // ================= ACL 管理 ================= - @Override - public ResultDomain insertAcl(TbSysAclDTO aclDTO) { - if (aclDTO == null) { - return ResultDomain.failure(MSG_ACL_PARAM_REQUIRED); - } - if (StringUtils.isBlank(aclDTO.getAclId())) { - aclDTO.setAclId(IdUtil.generateID()); - } - if (aclDTO.getCreateTime() == null) { - aclDTO.setCreateTime(new Date()); - } - if (aclDTO.getDeleted() == null) { - aclDTO.setDeleted(false); - } - if (aclDTO.getAllow() == null) { - aclDTO.setAllow(true); - } - if (aclDTO.getIncludeDescendants() == null) { - aclDTO.setIncludeDescendants(false); - } - - int rows = aclMapper.insertAcl(aclDTO); - if (rows > 0) { - logger.info("新增访问控制列表成功, aclId={}", aclDTO.getAclId()); - return ResultDomain.success("新增访问控制列表成功", aclDTO); - } - logger.warn("新增访问控制列表失败, aclId={}", aclDTO.getAclId()); - return ResultDomain.failure("新增访问控制列表失败"); - } - - @Override - public ResultDomain updateAcl(TbSysAclDTO aclDTO) { - if (aclDTO == null || StringUtils.isBlank(aclDTO.getAclId())) { - return ResultDomain.failure(MSG_ACL_ID_REQUIRED); - } - aclDTO.setUpdateTime(new Date()); - - int rows = aclMapper.updateAcl(aclDTO); - if (rows > 0) { - logger.info("更新访问控制列表成功, aclId={}", aclDTO.getAclId()); - return ResultDomain.success("更新访问控制列表成功", aclDTO); - } - logger.warn("更新访问控制列表失败, aclId={}", aclDTO.getAclId()); - return ResultDomain.failure("更新访问控制列表失败"); - } - - @Override - public ResultDomain deleteAcl(TbSysAclDTO aclDTO) { - if (aclDTO == null || StringUtils.isBlank(aclDTO.getAclId())) { - return ResultDomain.failure(MSG_ACL_ID_REQUIRED); - } - aclDTO.setDeleteTime(new Date()); - - int rows = aclMapper.deleteAcl(aclDTO); - if (rows > 0) { - logger.info("删除访问控制列表成功, aclId={}", aclDTO.getAclId()); - return ResultDomain.success("删除访问控制列表成功", true); - } - logger.warn("删除访问控制列表失败, aclId={}", aclDTO.getAclId()); - return ResultDomain.failure("删除访问控制列表失败"); - } - - @Override - public ResultDomain getAclPage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - - AclVO filter = pageRequest.getFilter(); - if (filter == null) { - filter = new AclVO(); - } - - // 转换为 DTO - TbSysAclDTO aclDTO = new TbSysAclDTO(); - aclDTO.setAclId(filter.getAclId()); - aclDTO.setObjectType(filter.getObjectType()); - aclDTO.setObjectId(filter.getObjectId()); - aclDTO.setPrincipalType(filter.getPrincipalType()); - aclDTO.setPrincipalId(filter.getPrincipalId()); - aclDTO.setPrincipalDeptId(filter.getPrincipalDeptId()); - - // 获取总数 - int total = aclMapper.getAclCount(aclDTO); - - // 分页查询 - PageParam pageParam = pageRequest.getPageParam(); - List list = aclMapper.getAclPageByFilter(aclDTO, pageParam); - - pageParam.setTotal(total); - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - - @Override - public ResultDomain getAclList(AclVO filter) { - if (filter == null) { - filter = new AclVO(); - } - - // 转换为 DTO - TbSysAclDTO aclDTO = new TbSysAclDTO(); - aclDTO.setAclId(filter.getAclId()); - aclDTO.setObjectType(filter.getObjectType()); - aclDTO.setObjectId(filter.getObjectId()); - aclDTO.setPrincipalType(filter.getPrincipalType()); - aclDTO.setPrincipalId(filter.getPrincipalId()); - aclDTO.setPrincipalDeptId(filter.getPrincipalDeptId()); - - List list = aclMapper.getAclByFilter(aclDTO); - return ResultDomain.success("查询成功", list); - } - - @Override - public ResultDomain getAclByObjectId(String objectId) { - if (StringUtils.isBlank(objectId)) { - return ResultDomain.failure("对象ID不能为空"); - } - - List list = aclMapper.getAclByObjectId(objectId); - return ResultDomain.success("查询成功", list); - } - - // ================= ACL Policy 管理 ================= - @Override - public ResultDomain insertAclPolicy(TbSysAclPolicyDTO aclPolicyDTO) { - if (aclPolicyDTO == null) { - return ResultDomain.failure(MSG_POLICY_PARAM_REQUIRED); - } - if (StringUtils.isBlank(aclPolicyDTO.getPolicyId())) { - aclPolicyDTO.setPolicyId(IdUtil.generateID()); - } - if (aclPolicyDTO.getCreateTime() == null) { - aclPolicyDTO.setCreateTime(new Date()); - } - if (aclPolicyDTO.getDeleted() == null) { - aclPolicyDTO.setDeleted(false); - } - if (aclPolicyDTO.getDefaultAllow() == null) { - aclPolicyDTO.setDefaultAllow(true); - } - if (aclPolicyDTO.getApplyToChildren() == null) { - aclPolicyDTO.setApplyToChildren(true); - } - - int rows = aclPolicyMapper.insertAclPolicy(aclPolicyDTO); - if (rows > 0) { - logger.info("新增访问控制策略成功, policyId={}", aclPolicyDTO.getPolicyId()); - return ResultDomain.success("新增访问控制策略成功", aclPolicyDTO); - } - logger.warn("新增访问控制策略失败, policyId={}", aclPolicyDTO.getPolicyId()); - return ResultDomain.failure("新增访问控制策略失败"); - } - - @Override - public ResultDomain updateAclPolicy(TbSysAclPolicyDTO aclPolicyDTO) { - if (aclPolicyDTO == null || StringUtils.isBlank(aclPolicyDTO.getPolicyId())) { - return ResultDomain.failure(MSG_POLICY_ID_REQUIRED); - } - aclPolicyDTO.setUpdateTime(new Date()); - - int rows = aclPolicyMapper.updateAclPolicy(aclPolicyDTO); - if (rows > 0) { - logger.info("更新访问控制策略成功, policyId={}", aclPolicyDTO.getPolicyId()); - return ResultDomain.success("更新访问控制策略成功", aclPolicyDTO); - } - logger.warn("更新访问控制策略失败, policyId={}", aclPolicyDTO.getPolicyId()); - return ResultDomain.failure("更新访问控制策略失败"); - } - - @Override - public ResultDomain deleteAclPolicy(TbSysAclPolicyDTO aclPolicyDTO) { - if (aclPolicyDTO == null || StringUtils.isBlank(aclPolicyDTO.getPolicyId())) { - return ResultDomain.failure(MSG_POLICY_ID_REQUIRED); - } - aclPolicyDTO.setDeleteTime(new Date()); - - int rows = aclPolicyMapper.deleteAclPolicy(aclPolicyDTO); - if (rows > 0) { - logger.info("删除访问控制策略成功, policyId={}", aclPolicyDTO.getPolicyId()); - return ResultDomain.success("删除访问控制策略成功", true); - } - logger.warn("删除访问控制策略失败, policyId={}", aclPolicyDTO.getPolicyId()); - return ResultDomain.failure("删除访问控制策略失败"); - } - - @Override - public ResultDomain getAclPolicyPage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - - AclVO filter = pageRequest.getFilter(); - if (filter == null) { - filter = new AclVO(); - } - - // 转换为 DTO - TbSysAclPolicyDTO aclPolicyDTO = new TbSysAclPolicyDTO(); - aclPolicyDTO.setPolicyId(filter.getPolicyId()); - aclPolicyDTO.setName(filter.getPolicyName()); - aclPolicyDTO.setObjectType(filter.getPolicyObjectType()); - - // 获取总数 - int total = aclPolicyMapper.getAclPolicyCount(aclPolicyDTO); - - // 分页查询 - PageParam pageParam = pageRequest.getPageParam(); - List list = aclPolicyMapper.getAclPolicyPageByFilter(aclPolicyDTO, pageParam); - - pageParam.setTotal(total); - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - - @Override - public ResultDomain getAclPolicyList(AclVO filter) { - if (filter == null) { - filter = new AclVO(); - } - - // 转换为 DTO - TbSysAclPolicyDTO aclPolicyDTO = new TbSysAclPolicyDTO(); - aclPolicyDTO.setPolicyId(filter.getPolicyId()); - aclPolicyDTO.setName(filter.getPolicyName()); - aclPolicyDTO.setObjectType(filter.getPolicyObjectType()); - - List list = aclPolicyMapper.getAclPolicyByFilter(aclPolicyDTO); - return ResultDomain.success("查询成功", list); - } -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/DeptRoleServiceImpl.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/DeptRoleServiceImpl.java deleted file mode 100644 index a572f195..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/DeptRoleServiceImpl.java +++ /dev/null @@ -1,335 +0,0 @@ -package org.xyzh.system.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import jakarta.annotation.Resource; -import java.util.Date; -import java.util.Collections; -import java.util.List; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xyzh.api.system.service.DeptRoleService; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.api.system.vo.UserDeptRoleVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; - -import org.xyzh.common.dto.sys.TbSysDeptDTO; -import org.xyzh.common.dto.sys.TbSysDeptRoleDTO; -import org.xyzh.common.dto.sys.TbSysRoleDTO; -import org.xyzh.common.dto.sys.TbSysRolePermissionDTO; -import org.xyzh.common.dto.sys.TbSysUserRoleDTO; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.StringUtils; -import org.xyzh.system.mapper.dept.TbSysDeptMapper; -import org.xyzh.system.mapper.role.TbSysRoleMapper; -import org.xyzh.system.mapper.role.TbSysRolePermissionMapper; -import org.xyzh.system.mapper.user.TbSysUserRoleMapper; - -/** - * @description 部门角色服务实现类 - * @filename DeptRoleServiceImpl.java - */ -@DubboService( - version = "1.0.0", - group = "system", - timeout = 3000, - retries = 0 -) -public class DeptRoleServiceImpl implements DeptRoleService { - - private static final Logger logger = LoggerFactory.getLogger(DeptRoleServiceImpl.class); - private static final String MSG_DEPT_PARAM_REQUIRED = "部门参数不能为空"; - private static final String MSG_ROLE_PARAM_REQUIRED = "角色参数不能为空"; - private static final String MSG_DEPT_ID_REQUIRED = "部门ID不能为空"; - private static final String MSG_ROLE_ID_REQUIRED = "角色ID不能为空"; - private static final String MSG_DEPT_ROLE_ID_REQUIRED = "部门ID和角色ID不能为空"; - private static final String MSG_QUERY_PARAM_REQUIRED = "查询条件不能为空"; - private static final String MSG_PAGE_PARAM_REQUIRED = "分页参数不能为空"; - - @Resource - private TbSysDeptMapper deptMapper; - - @Resource - private TbSysRoleMapper roleMapper; - - @Resource - private TbSysUserRoleMapper userRoleMapper; - - @Resource - private TbSysRolePermissionMapper rolePermissionMapper; - - @Override - public ResultDomain insertDept(TbSysDeptDTO deptDTO) { - if (deptDTO == null) { - return ResultDomain.failure(MSG_DEPT_PARAM_REQUIRED); - } - if (StringUtils.isBlank(deptDTO.getDeptId())) { - deptDTO.setDeptId(IdUtil.generateID()); - } - if (deptDTO.getCreateTime() == null) { - deptDTO.setCreateTime(new Date()); - } - if (deptDTO.getDeleted() == null) { - deptDTO.setDeleted(false); - } - int rows = deptMapper.insertDept(deptDTO); - if (rows > 0) { - logger.info("新增部门成功, deptId={}", deptDTO.getDeptId()); - return ResultDomain.success("新增部门成功", deptDTO); - } - logger.warn("新增部门失败, deptId={}", deptDTO.getDeptId()); - return ResultDomain.failure("新增部门失败"); - } - - @Override - public ResultDomain updateDept(TbSysDeptDTO deptDTO) { - if (deptDTO == null || StringUtils.isBlank(deptDTO.getDeptId())) { - return ResultDomain.failure(MSG_DEPT_ID_REQUIRED); - } - deptDTO.setUpdateTime(new Date()); - int rows = deptMapper.updateDept(deptDTO); - if (rows > 0) { - logger.info("更新部门成功, deptId={}", deptDTO.getDeptId()); - return ResultDomain.success("更新部门成功", deptDTO); - } - logger.warn("更新部门失败, deptId={}", deptDTO.getDeptId()); - return ResultDomain.failure("更新部门失败"); - } - - @Override - public ResultDomain deleteDept(TbSysDeptDTO deptDTO) { - if (deptDTO == null || StringUtils.isBlank(deptDTO.getDeptId())) { - return ResultDomain.failure(MSG_DEPT_ID_REQUIRED); - } - int rows = deptMapper.deleteDept(deptDTO); - if (rows > 0) { - logger.info("删除部门成功, deptId={}", deptDTO.getDeptId()); - return ResultDomain.success("删除部门成功", Boolean.TRUE); - } - logger.warn("删除部门失败, deptId={}", deptDTO.getDeptId()); - return ResultDomain.failure("删除部门失败"); - } - - @Override - public ResultDomain getDept(UserDeptRoleVO filter) { - TbSysDeptDTO dto = UserDeptRoleVO.toDeptDTO(filter); - if (dto == null) { - return ResultDomain.failure(MSG_QUERY_PARAM_REQUIRED); - } - List permissionList = deptMapper.getDeptByFilter(dto); - if (permissionList == null || permissionList.isEmpty()) { - return ResultDomain.failure("未找到部门"); - } - UserDeptRoleVO dept = UserDeptRoleVO.fromPermission(permissionList.get(0)); - return ResultDomain.success("获取部门成功", dept); - } - - @Override - public ResultDomain getDeptList(UserDeptRoleVO filter) { - TbSysDeptDTO dto = UserDeptRoleVO.toDeptDTO(filter); - List permissionList = deptMapper.getDeptByFilter(dto); - List result = (permissionList == null || permissionList.isEmpty()) ? - java.util.Collections.emptyList() : - permissionList.stream().map(UserDeptRoleVO::fromPermission).filter(java.util.Objects::nonNull).toList(); - return ResultDomain.success("获取部门列表成功", result); - } - - @Override - public ResultDomain getDeptPage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - PageParam pageParam = pageRequest.getPageParam(); - TbSysDeptDTO filter = UserDeptRoleVO.toDeptDTO(pageRequest.getFilter()); - int total = deptMapper.getDeptCount(filter); - pageParam.setTotal(total); - pageParam.setTotalPages(pageParam.getPageSize() == 0 ? 0 : (int) Math.ceil((double) total / pageParam.getPageSize())); - List permissionList = deptMapper.getDeptPageByFilter(filter, pageParam); - List data = (permissionList == null || permissionList.isEmpty()) ? - java.util.Collections.emptyList() : - permissionList.stream().map(UserDeptRoleVO::fromPermission).filter(java.util.Objects::nonNull).toList(); - PageDomain pageDomain = new PageDomain<>(pageParam, data); - return ResultDomain.success("分页查询部门成功", pageDomain); - } - - @Override - public ResultDomain getDeptTree(UserDeptRoleVO filter) { - return getDeptList(filter); - } - - @Override - public ResultDomain insertRole(TbSysRoleDTO roleDTO) { - if (roleDTO == null) { - return ResultDomain.failure(MSG_ROLE_PARAM_REQUIRED); - } - if (StringUtils.isBlank(roleDTO.getRoleId())) { - roleDTO.setRoleId(IdUtil.generateID()); - } - if (roleDTO.getCreateTime() == null) { - roleDTO.setCreateTime(new Date()); - } - if (roleDTO.getDeleted() == null) { - roleDTO.setDeleted(false); - } - int rows = roleMapper.insertRole(roleDTO); - if (rows > 0) { - logger.info("新增角色成功, roleId={}", roleDTO.getRoleId()); - return ResultDomain.success("新增角色成功", roleDTO); - } - logger.warn("新增角色失败, roleId={}", roleDTO.getRoleId()); - return ResultDomain.failure("新增角色失败"); - } - - @Override - public ResultDomain updateRole(TbSysRoleDTO roleDTO) { - if (roleDTO == null || StringUtils.isBlank(roleDTO.getRoleId())) { - return ResultDomain.failure(MSG_ROLE_ID_REQUIRED); - } - roleDTO.setUpdateTime(new Date()); - int rows = roleMapper.updateRole(roleDTO); - if (rows > 0) { - logger.info("更新角色成功, roleId={}", roleDTO.getRoleId()); - return ResultDomain.success("更新角色成功", roleDTO); - } - logger.warn("更新角色失败, roleId={}", roleDTO.getRoleId()); - return ResultDomain.failure("更新角色失败"); - } - - @Override - public ResultDomain deleteRole(TbSysRoleDTO roleDTO) { - if (roleDTO == null || StringUtils.isBlank(roleDTO.getRoleId())) { - return ResultDomain.failure(MSG_ROLE_ID_REQUIRED); - } - int rows = roleMapper.deleteRole(roleDTO); - if (rows > 0) { - logger.info("删除角色成功, roleId={}", roleDTO.getRoleId()); - return ResultDomain.success("删除角色成功", Boolean.TRUE); - } - logger.warn("删除角色失败, roleId={}", roleDTO.getRoleId()); - return ResultDomain.failure("删除角色失败"); - } - - @Override - public ResultDomain getRole(UserDeptRoleVO filter) { - TbSysRoleDTO dto = UserDeptRoleVO.toRoleDTO(filter); - if (dto == null) { - return ResultDomain.failure(MSG_QUERY_PARAM_REQUIRED); - } - List permissionList = roleMapper.getRoleByFilter(dto); - if (permissionList == null || permissionList.isEmpty()) { - return ResultDomain.failure("未找到角色"); - } - UserDeptRoleVO role = UserDeptRoleVO.fromPermission(permissionList.get(0)); - return ResultDomain.success("获取角色成功", role); - } - - @Override - public ResultDomain getRoleList(UserDeptRoleVO filter) { - TbSysRoleDTO dto = UserDeptRoleVO.toRoleDTO(filter); - List permissionList = roleMapper.getRoleByFilter(dto); - List result = (permissionList == null || permissionList.isEmpty()) ? - java.util.Collections.emptyList() : - permissionList.stream().map(UserDeptRoleVO::fromPermission).filter(java.util.Objects::nonNull).toList(); - return ResultDomain.success("获取角色列表成功", result); - } - - @Override - public ResultDomain getRolePage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - PageParam pageParam = pageRequest.getPageParam(); - TbSysRoleDTO filter = UserDeptRoleVO.toRoleDTO(pageRequest.getFilter()); - int total = roleMapper.getRoleCount(filter); - pageParam.setTotal(total); - pageParam.setTotalPages(pageParam.getPageSize() == 0 ? 0 : (int) Math.ceil((double) total / pageParam.getPageSize())); - List permissionList = roleMapper.getRolePageByFilter(filter, pageParam); - List data = (permissionList == null || permissionList.isEmpty()) ? - java.util.Collections.emptyList() : - permissionList.stream().map(UserDeptRoleVO::fromPermission).filter(java.util.Objects::nonNull).toList(); - PageDomain pageDomain = new PageDomain<>(pageParam, data); - return ResultDomain.success("分页查询角色成功", pageDomain); - } - - @Override - public ResultDomain getRoleListByDeptId(String deptId) { - if (StringUtils.isBlank(deptId)) { - return ResultDomain.failure(MSG_DEPT_ID_REQUIRED); - } - TbSysRoleDTO filter = new TbSysRoleDTO(); - filter.setOwnerDeptId(deptId); - List permissionList = roleMapper.getRoleByFilter(filter); - List result = (permissionList == null || permissionList.isEmpty()) ? - java.util.Collections.emptyList() : - permissionList.stream().map(UserDeptRoleVO::fromPermission).filter(java.util.Objects::nonNull).toList(); - return ResultDomain.success("根据部门获取角色成功", result); - } - - @Override - public ResultDomain getRoleListByUserId(String userId) { - if (StringUtils.isBlank(userId)) { - return ResultDomain.failure("用户ID不能为空"); - } - TbSysUserRoleDTO filter = new TbSysUserRoleDTO(); - filter.setUserId(userId); - List roleList = userRoleMapper.getUserRoleByFilter(filter); - if (roleList == null) { - roleList = Collections.emptyList(); - } - return ResultDomain.success("根据用户获取角色成功", roleList); - } - - @Override - public ResultDomain setRolePermission(PermissionVO permissionVO) { - if (permissionVO == null || StringUtils.isBlank(permissionVO.getRoleId())) { - return ResultDomain.failure(MSG_ROLE_ID_REQUIRED); - } - rolePermissionMapper.delete(new QueryWrapper() - .eq("role_id", permissionVO.getRoleId())); - List permissionIds = permissionVO.getPermissionIdList(); - if (permissionIds != null && !permissionIds.isEmpty()) { - Date now = new Date(); - for (String permissionId : permissionIds) { - if (StringUtils.isBlank(permissionId)) { - continue; - } - TbSysRolePermissionDTO dto = new TbSysRolePermissionDTO(); - dto.setRoleId(permissionVO.getRoleId()); - dto.setPermissionId(permissionId); - dto.setCreateTime(now); - dto.setDeleted(false); - rolePermissionMapper.insertRolePermission(dto); - } - } - logger.info("角色权限设置成功, roleId={}, count={}", - permissionVO.getRoleId(), - permissionIds == null ? 0 : permissionIds.size()); - return ResultDomain.success("设置角色权限成功", permissionVO); - } - - @Override - public ResultDomain getRolePermissionList(PermissionVO permissionVO) { - TbSysRolePermissionDTO dto = new TbSysRolePermissionDTO(); - if (permissionVO != null) { - dto.setRoleId(permissionVO.getRoleId()); - if (permissionVO.getPermissionIdList() != null && !permissionVO.getPermissionIdList().isEmpty()) { - dto.setPermissionId(permissionVO.getPermissionIdList().get(0)); - } else { - dto.setPermissionId(permissionVO.getPermissionId()); - } - dto.setDeptPath(permissionVO.getDeptPath()); - dto.setDeleted(permissionVO.getDeleted()); - } - List list = rolePermissionMapper.getRolePermissionByFilter(dto); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取角色权限列表成功", list); - } - - - -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/GuestServiceImpl.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/GuestServiceImpl.java deleted file mode 100644 index 51de183d..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/GuestServiceImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.xyzh.system.service.impl; - -import java.util.List; - -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; -import org.xyzh.api.system.service.GuestService; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbGuestDTO; -import org.xyzh.common.dto.sys.TbSysUserRoleDTO; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.system.mapper.user.TbGuestMapper; -import org.xyzh.system.mapper.user.TbSysUserRoleMapper; - -import java.util.Date; - - -/** - * @description 来客服务接口实现 - * @filename GuestServiceImpl.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@DubboService( - version = "1.0.0", - group = "system", - timeout = 3000, - retries = 0 -) -public class GuestServiceImpl implements GuestService{ - private static final Logger logger = LoggerFactory.getLogger(GuestServiceImpl.class); - - @Autowired - private TbGuestMapper guestMapper; - - @Autowired - private TbSysUserRoleMapper userRoleMapper; - - @Override - @Transactional - public ResultDomain createGuest(TbGuestDTO guest) { - guestMapper.insertGuest(guest); - - // 绑定访客角色(role_guest) - TbSysUserRoleDTO userRole = new TbSysUserRoleDTO(); - userRole.setOptsn(IdUtil.getOptsn()); - userRole.setUserId(guest.getUserId()); - userRole.setRoleId("role_guest"); - userRole.setDeptId("dept_root"); - userRole.setCreateTime(new Date()); - userRoleMapper.insertUserRole(userRole); - - return ResultDomain.success("创建成功",guest); - } - - @Override - @Transactional - public ResultDomain updateGuest(TbGuestDTO guest) { - guestMapper.updateGuest(guest); - return ResultDomain.success("更新成功",guest); - } - - @Override - @Transactional - public ResultDomain deleteGuest(String userId) { - int rows = guestMapper.deleteGuest(userId); - if (rows > 0) { - return ResultDomain.success("删除成功"); - } - return ResultDomain.failure("删除失败,来客不存在"); - } - - @Override - public ResultDomain selectGuestList(TbGuestDTO guest) { - List list = guestMapper.selectGuestList(guest); - return ResultDomain.success("查询成功", list); - } - - @Override - public ResultDomain selectGuestOne(TbGuestDTO guest) { - TbGuestDTO selected = guestMapper.selectGuestOne(guest); - return ResultDomain.success("查询成功",selected); - } - - @Override - public ResultDomain selectGuestByWechatId(String wechatId){ - TbGuestDTO selected = guestMapper.selectGuestByWechatId(wechatId); - return ResultDomain.success("查询成功", selected); - } - - @Override - public ResultDomain selectGuestPage(PageRequest pageRequest) { - List guestList = guestMapper.selectGuestPage(pageRequest.getFilter(),pageRequest.getPageParam()); - int total = guestMapper.countGuest(pageRequest.getFilter()); - PageDomain pageDomain = new PageDomain<>(); - pageDomain.setPageParam(pageRequest.getPageParam()); - pageDomain.getPageParam().setTotal(total); - - pageDomain.setDataList(guestList); - return ResultDomain.success("查询成功",pageDomain); - } - -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/LogServiceImpl.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/LogServiceImpl.java deleted file mode 100644 index 0f0f4ea5..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/LogServiceImpl.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.xyzh.system.service.impl; - -import jakarta.annotation.Resource; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xyzh.api.system.dto.TbSysLogDTO; -import org.xyzh.api.system.service.LogService; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.StringUtils; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.system.mapper.log.TbSysLogMapper; - -import java.util.Collections; -import java.util.Date; -import java.util.List; - -/** - * @description 系统日志服务实现类 - * @filename LogServiceImpl.java - * @author yslg - * @copyright yslg - * @since 2026-01-01 - */ -@DubboService( - version = "1.0.0", - group = "system", - timeout = 3000, - retries = 0 -) -public class LogServiceImpl implements LogService { - - private static final Logger logger = LoggerFactory.getLogger(LogServiceImpl.class); - - private static final String MSG_LOG_PARAM_REQUIRED = "日志参数不能为空"; - private static final String MSG_FILTER_PARAM_REQUIRED = "查询条件不能为空"; - private static final String MSG_PAGE_PARAM_REQUIRED = "分页参数不能为空"; - - @Resource - private TbSysLogMapper sysLogMapper; - - @Override - public ResultDomain addSysLog(TbSysLogDTO sysLog) { - if (sysLog == null) { - return ResultDomain.failure(MSG_LOG_PARAM_REQUIRED); - } - - try { - // 设置默认值 - if (StringUtils.isBlank(sysLog.getLogId())) { - sysLog.setLogId(IdUtil.generateID()); - } - if (StringUtils.isBlank(sysLog.getOptsn())) { - sysLog.setOptsn(IdUtil.generateID()); - } - if (sysLog.getCreateTime() == null) { - sysLog.setCreateTime(new Date()); - } - if (sysLog.getDeleted() == null) { - sysLog.setDeleted(false); - } - - int rows = sysLogMapper.insertLog(sysLog); - if (rows > 0) { - logger.info("添加系统日志成功, logId={}", sysLog.getLogId()); - return ResultDomain.success("添加系统日志成功", sysLog); - } - logger.warn("添加系统日志失败, logId={}", sysLog.getLogId()); - return ResultDomain.failure("添加系统日志失败"); - } catch (Exception e) { - logger.error("添加系统日志异常", e); - return ResultDomain.failure("添加系统日志异常: " + e.getMessage()); - } - } - - @Override - public ResultDomain countSysLog(TbSysLogDTO filter) { - if (filter == null) { - return ResultDomain.failure(MSG_FILTER_PARAM_REQUIRED); - } - - try { - int count = sysLogMapper.getLogCount(filter); - return ResultDomain.success("统计日志数量成功", count); - } catch (Exception e) { - logger.error("统计日志数量异常", e); - return ResultDomain.failure("统计日志数量异常: " + e.getMessage()); - } - } - - @Override - public ResultDomain getSysLogList(TbSysLogDTO filter) { - try { - List list = sysLogMapper.getLogByFilter(filter); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取日志列表成功", list); - } catch (Exception e) { - logger.error("获取日志列表异常", e); - return ResultDomain.failure("获取日志列表异常: " + e.getMessage()); - } - } - - @Override - public ResultDomain getSysLogPage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - - try { - PageParam pageParam = pageRequest.getPageParam(); - TbSysLogDTO filter = pageRequest.getFilter(); - - // 查询总数 - int total = sysLogMapper.getLogCount(filter); - pageParam.setTotal(total); - pageParam.setTotalPages(pageParam.getPageSize() == 0 ? 0 : - (int) Math.ceil((double) total / pageParam.getPageSize())); - - // 查询分页数据 - List data = sysLogMapper.getLogPageByFilter(filter, pageParam); - if (data == null) { - data = Collections.emptyList(); - } - - PageDomain pageDomain = new PageDomain<>(pageParam, data); - return ResultDomain.success("分页查询日志成功", pageDomain); - } catch (Exception e) { - logger.error("分页查询日志异常", e); - return ResultDomain.failure("分页查询日志异常: " + e.getMessage()); - } - } -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/ModulePermissionServiceImpl.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/ModulePermissionServiceImpl.java deleted file mode 100644 index 4ef2dc19..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/ModulePermissionServiceImpl.java +++ /dev/null @@ -1,264 +0,0 @@ -package org.xyzh.system.service.impl; - -import org.apache.dubbo.config.annotation.DubboService; -import org.xyzh.api.system.service.ModulePermissionService; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysModuleDTO; -import org.xyzh.common.dto.sys.TbSysPermissionDTO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import jakarta.annotation.Resource; -import java.util.Date; -import java.util.Collections; -import java.util.List; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.StringUtils; -import org.xyzh.system.mapper.module.TbSysModuleMapper; -import org.xyzh.system.mapper.permission.TbSysPermissionMapper; -import org.xyzh.system.mapper.role.TbSysRolePermissionMapper; -import org.xyzh.system.mapper.user.TbSysUserRoleMapper; - -/** - * @description 模块权限服务实现类 - * @filename ModulePermissionServiceImpl.java - */ -@DubboService( - version = "1.0.0", - group = "system", - timeout = 3000, - retries = 0 -) -public class ModulePermissionServiceImpl implements ModulePermissionService { - - private static final Logger logger = LoggerFactory.getLogger(ModulePermissionServiceImpl.class); - - private static final String MSG_MODULE_PARAM_REQUIRED = "模块参数不能为空"; - private static final String MSG_PERMISSION_PARAM_REQUIRED = "权限参数不能为空"; - private static final String MSG_MODULE_ID_REQUIRED = "模块ID不能为空"; - private static final String MSG_PERMISSION_ID_REQUIRED = "权限ID不能为空"; - private static final String MSG_QUERY_PARAM_REQUIRED = "查询条件不能为空"; - private static final String MSG_PAGE_PARAM_REQUIRED = "分页参数不能为空"; - - @Resource - private TbSysModuleMapper moduleMapper; - - @Resource - private TbSysPermissionMapper permissionMapper; - - @Resource - private TbSysRolePermissionMapper rolePermissionMapper; - - @Resource - private TbSysUserRoleMapper userRoleMapper; - - @Override - public ResultDomain insertModule(TbSysModuleDTO moduleDTO) { - if (moduleDTO == null) { - return ResultDomain.failure(MSG_MODULE_PARAM_REQUIRED); - } - if (StringUtils.isBlank(moduleDTO.getModuleId())) { - moduleDTO.setModuleId(IdUtil.generateID()); - } - if (moduleDTO.getCreateTime() == null) { - moduleDTO.setCreateTime(new Date()); - } - if (moduleDTO.getDeleted() == null) { - moduleDTO.setDeleted(false); - } - int rows = moduleMapper.insertModule(moduleDTO); - if (rows > 0) { - logger.info("新增模块成功, moduleId={}", moduleDTO.getModuleId()); - return ResultDomain.success("新增模块成功", moduleDTO); - } - logger.warn("新增模块失败, moduleId={}", moduleDTO.getModuleId()); - return ResultDomain.failure("新增模块失败"); - } - - @Override - public ResultDomain updateModule(TbSysModuleDTO moduleDTO) { - if (moduleDTO == null || StringUtils.isBlank(moduleDTO.getModuleId())) { - return ResultDomain.failure(MSG_MODULE_ID_REQUIRED); - } - moduleDTO.setUpdateTime(new Date()); - int rows = moduleMapper.updateModule(moduleDTO); - if (rows > 0) { - logger.info("更新模块成功, moduleId={}", moduleDTO.getModuleId()); - return ResultDomain.success("更新模块成功", moduleDTO); - } - logger.warn("更新模块失败, moduleId={}", moduleDTO.getModuleId()); - return ResultDomain.failure("更新模块失败"); - } - - @Override - public ResultDomain deleteModule(TbSysModuleDTO moduleDTO) { - if (moduleDTO == null || StringUtils.isBlank(moduleDTO.getModuleId())) { - return ResultDomain.failure(MSG_MODULE_ID_REQUIRED); - } - int rows = moduleMapper.deleteModule(moduleDTO); - if (rows > 0) { - logger.info("删除模块成功, moduleId={}", moduleDTO.getModuleId()); - return ResultDomain.success("删除模块成功", Boolean.TRUE); - } - logger.warn("删除模块失败, moduleId={}", moduleDTO.getModuleId()); - return ResultDomain.failure("删除模块失败"); - } - - @Override - public ResultDomain getModulePage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - PageParam pageParam = pageRequest.getPageParam(); - TbSysModuleDTO filter = org.xyzh.api.system.vo.PermissionVO.toModuleDTO(pageRequest.getFilter()); - int total = moduleMapper.getModuleCount(filter); - pageParam.setTotal(total); - pageParam.setTotalPages(pageParam.getPageSize() == 0 ? 0 : (int) Math.ceil((double) total / pageParam.getPageSize())); - List list = moduleMapper.getModulePageByFilter(filter, pageParam); - PageDomain pageDomain = new PageDomain<>(pageParam, list == null ? Collections.emptyList() : list); - return ResultDomain.success("分页查询模块成功", pageDomain); - } - - @Override - public ResultDomain getModuleList(PermissionVO filter) { - TbSysModuleDTO dto = org.xyzh.api.system.vo.PermissionVO.toModuleDTO(filter); - List list = moduleMapper.getModuleByFilter(dto); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取模块列表成功", list); - } - - @Override - public ResultDomain insertPermission(TbSysPermissionDTO permissionDTO) { - if (permissionDTO == null) { - return ResultDomain.failure(MSG_PERMISSION_PARAM_REQUIRED); - } - if (StringUtils.isBlank(permissionDTO.getPermissionId())) { - permissionDTO.setPermissionId(IdUtil.generateID()); - } - if (permissionDTO.getCreateTime() == null) { - permissionDTO.setCreateTime(new Date()); - } - if (permissionDTO.getDeleted() == null) { - permissionDTO.setDeleted(false); - } - int rows = permissionMapper.insertPermission(permissionDTO); - if (rows > 0) { - logger.info("新增权限成功, permissionId={}", permissionDTO.getPermissionId()); - return ResultDomain.success("新增权限成功", permissionDTO); - } - logger.warn("新增权限失败, permissionId={}", permissionDTO.getPermissionId()); - return ResultDomain.failure("新增权限失败"); - } - - @Override - public ResultDomain updatePermission(TbSysPermissionDTO permissionDTO) { - if (permissionDTO == null || StringUtils.isBlank(permissionDTO.getPermissionId())) { - return ResultDomain.failure(MSG_PERMISSION_ID_REQUIRED); - } - permissionDTO.setUpdateTime(new Date()); - int rows = permissionMapper.updatePermission(permissionDTO); - if (rows > 0) { - logger.info("更新权限成功, permissionId={}", permissionDTO.getPermissionId()); - return ResultDomain.success("更新权限成功", permissionDTO); - } - logger.warn("更新权限失败, permissionId={}", permissionDTO.getPermissionId()); - return ResultDomain.failure("更新权限失败"); - } - - @Override - public ResultDomain deletePermission(TbSysPermissionDTO permissionDTO) { - if (permissionDTO == null || StringUtils.isBlank(permissionDTO.getPermissionId())) { - return ResultDomain.failure(MSG_PERMISSION_ID_REQUIRED); - } - int rows = permissionMapper.deletePermission(permissionDTO); - if (rows > 0) { - logger.info("删除权限成功, permissionId={}", permissionDTO.getPermissionId()); - return ResultDomain.success("删除权限成功", Boolean.TRUE); - } - logger.warn("删除权限失败, permissionId={}", permissionDTO.getPermissionId()); - return ResultDomain.failure("删除权限失败"); - } - - @Override - public ResultDomain getPermissionListByModuleId(String moduleId) { - if (StringUtils.isBlank(moduleId)) { - return ResultDomain.failure(MSG_MODULE_ID_REQUIRED); - } - TbSysPermissionDTO filter = new TbSysPermissionDTO(); - filter.setModuleId(moduleId); - List list = permissionMapper.getPermissionByFilter(filter); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("根据模块获取权限列表成功", list); - } - - @Override - public ResultDomain getModulePermission(PermissionVO filter) { - TbSysPermissionDTO dto = org.xyzh.api.system.vo.PermissionVO.toPermissionDTO(filter); - if (dto == null) { - return ResultDomain.failure(MSG_QUERY_PARAM_REQUIRED); - } - List list = permissionMapper.getPermissionByFilter(dto); - if (list == null || list.isEmpty()) { - return ResultDomain.failure("未找到模块权限"); - } - return ResultDomain.success("获取模块权限成功", list.get(0)); - } - - @Override - public ResultDomain getModulePermissionList(PermissionVO filter) { - TbSysPermissionDTO dto = org.xyzh.api.system.vo.PermissionVO.toPermissionDTO(filter); - List list = permissionMapper.getPermissionByFilter(dto); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取模块权限列表成功", list); - } - - @Override - public ResultDomain getModulePermissionPage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - PageParam pageParam = pageRequest.getPageParam(); - TbSysPermissionDTO filter = org.xyzh.api.system.vo.PermissionVO.toPermissionDTO(pageRequest.getFilter()); - int total = permissionMapper.getPermissionCount(filter); - pageParam.setTotal(total); - pageParam.setTotalPages(pageParam.getPageSize() == 0 ? 0 : (int) Math.ceil((double) total / pageParam.getPageSize())); - List list = permissionMapper.getPermissionPageByFilter(filter, pageParam); - PageDomain pageDomain = new PageDomain<>(pageParam, list == null ? Collections.emptyList() : list); - return ResultDomain.success("分页查询模块权限成功", pageDomain); - } - - @Override - public ResultDomain getModulePermissionListByRoleId(String roleId) { - if (StringUtils.isBlank(roleId)) { - return ResultDomain.failure("角色ID不能为空"); - } - List list = rolePermissionMapper.getRolePermissionByRoleId(roleId); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("根据角色获取权限列表成功", list); - } - - @Override - public ResultDomain getUserPermissions(String userId) { - if (StringUtils.isBlank(userId)) { - return ResultDomain.failure("用户ID不能为空"); - } - List list = rolePermissionMapper.getPermissionsByUserId(userId); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取用户权限成功", list); - } - -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/SysConfigServiceImpl.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/SysConfigServiceImpl.java deleted file mode 100644 index 4f871c9c..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/SysConfigServiceImpl.java +++ /dev/null @@ -1,394 +0,0 @@ -package org.xyzh.system.service.impl; - -import org.apache.dubbo.config.annotation.DubboService; -import org.xyzh.api.system.service.SysConfigService; -import org.xyzh.api.system.vo.SysConfigVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysConfigDTO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import jakarta.annotation.Resource; -import java.util.Date; -import java.util.Collections; -import java.util.List; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageDomain; - -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.StringUtils; -import org.xyzh.common.redis.service.RedisService; -import org.xyzh.api.system.constance.SysConfigRedisPrefix; -import org.xyzh.system.mapper.config.TbSysConfigMapper; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * @description 系统配置服务实现类 - * @filename SysConfigServiceImpl.java - */ -@DubboService( - version = "1.0.0", - group = "system", - timeout = 3000, - retries = 0 -) -public class SysConfigServiceImpl implements SysConfigService { - - private static final Logger logger = LoggerFactory.getLogger(SysConfigServiceImpl.class); - - private static final String MSG_CONFIG_PARAM_REQUIRED = "配置参数不能为空"; - private static final String MSG_CONFIG_ID_REQUIRED = "配置ID不能为空"; - private static final String MSG_QUERY_PARAM_REQUIRED = "查询条件不能为空"; - private static final String MSG_PAGE_PARAM_REQUIRED = "分页参数不能为空"; - - @Resource - private TbSysConfigMapper configMapper; - - @Resource - private RedisService redisService; - - /** 异步发送事件的线程池 */ - private final ExecutorService eventExecutor = Executors.newSingleThreadExecutor(r -> { - Thread t = new Thread(r, "sys-config-event"); - t.setDaemon(true); - return t; - }); - - /** - * 异步发布配置变更事件 - * @param group 配置分组 - */ - private void publishConfigChangeEvent(String group) { - if (StringUtils.isBlank(group)) { - return; - } - eventExecutor.execute(() -> { - try { - String channel = SysConfigRedisPrefix.getChannelByGroup(group); - if (channel != null) { - redisService.publish(channel, System.currentTimeMillis()); - logger.info("配置变更事件发布成功: channel={}", channel); - } - } catch (Exception e) { - logger.error("配置变更事件发布失败: group={}", group, e); - } - }); - } - - /** - * 根据key查询配置 - */ - private TbSysConfigDTO getConfigByKey(String key) { - if (key == null || key.isEmpty()) { - return null; - } - return configMapper.selectSysConfigByKey(key); - } - - public Object getSysConfig(String key) { - try { - TbSysConfigDTO config = getConfigByKey(key); - if (config == null) { - logger.warn("配置项不存在: {}", key); - return null; - } - - String configType = config.getConfigType(); - String configValue = config.getValue(); - - if (configValue == null || configValue.isEmpty()) { - return null; - } - - // 根据config_type返回对应的类型 - if (configType == null || "string".equalsIgnoreCase(configType)) { - return configValue; - } else if ("number".equalsIgnoreCase(configType) || "integer".equalsIgnoreCase(configType)) { - try { - // 尝试解析为Integer,如果失败则解析为Long - return Integer.parseInt(configValue); - } catch (NumberFormatException e) { - try { - return Long.parseLong(configValue); - } catch (NumberFormatException ex) { - logger.error("配置项 {} 的值无法转换为数字: {}", key, configValue); - return configValue; - } - } - } else if ("boolean".equalsIgnoreCase(configType)) { - String value = configValue.toLowerCase().trim(); - if ("true".equals(value) || "1".equals(value) || "yes".equals(value) || "on".equals(value)) { - return true; - } else if ("false".equals(value) || "0".equals(value) || "no".equals(value) || "off".equals(value)) { - return false; - } else { - logger.warn("配置项 {} 的值无法识别为Boolean: {}", key, value); - return configValue; - } - } else if ("double".equalsIgnoreCase(configType) || "float".equalsIgnoreCase(configType)) { - try { - return Double.parseDouble(configValue); - } catch (NumberFormatException e) { - logger.error("配置项 {} 的值无法转换为Double: {}", key, configValue); - return configValue; - } - } else { - // 未知类型,直接返回字符串 - return configValue; - } - } catch (Exception e) { - logger.error("获取配置失败: {}", key, e); - return null; - } - } - - @Override - public String getStringConfig(String key) { - try { - TbSysConfigDTO config = getConfigByKey(key); - if (config == null) { - logger.warn("配置项不存在: {}", key); - return null; - } - return config.getValue(); - } catch (Exception e) { - logger.error("获取字符串配置失败: {}", key, e); - return null; - } - } - - @Override - public Integer getIntConfig(String key) { - try { - TbSysConfigDTO config = getConfigByKey(key); - if (config == null) { - logger.warn("配置项不存在: {}", key); - return null; - } - - String value = config.getValue(); - if (value == null || value.isEmpty()) { - return null; - } - - return Integer.parseInt(value); - } catch (NumberFormatException e) { - logger.error("配置项 {} 的值无法转换为Integer: {}", key, e.getMessage()); - return null; - } catch (Exception e) { - logger.error("获取Integer配置失败: {}", key, e); - return null; - } - } - - @Override - public Boolean getBooleanConfig(String key) { - try { - TbSysConfigDTO config = getConfigByKey(key); - if (config == null) { - logger.warn("配置项不存在: {}", key); - return null; - } - - String value = config.getValue(); - if (value == null || value.isEmpty()) { - return null; - } - - // 支持多种布尔值表示:true/false, 1/0, yes/no, on/off - value = value.toLowerCase().trim(); - if ("true".equals(value) || "1".equals(value) || "yes".equals(value) || "on".equals(value)) { - return true; - } else if ("false".equals(value) || "0".equals(value) || "no".equals(value) || "off".equals(value)) { - return false; - } else { - logger.warn("配置项 {} 的值无法识别为Boolean: {}", key, value); - return null; - } - } catch (Exception e) { - logger.error("获取Boolean配置失败: {}", key, e); - return null; - } - } - - @Override - public Double getDoubleConfig(String key) { - try { - TbSysConfigDTO config = getConfigByKey(key); - if (config == null) { - logger.warn("配置项不存在: {}", key); - return null; - } - - String value = config.getValue(); - if (value == null || value.isEmpty()) { - return null; - } - - return Double.parseDouble(value); - } catch (NumberFormatException e) { - logger.error("配置项 {} 的值无法转换为Double: {}", key, e.getMessage()); - return null; - } catch (Exception e) { - logger.error("获取Double配置失败: {}", key, e); - return null; - } - } - - @Override - public Long getLongConfig(String key) { - try { - TbSysConfigDTO config = getConfigByKey(key); - if (config == null) { - logger.warn("配置项不存在: {}", key); - return null; - } - - String value = config.getValue(); - if (value == null || value.isEmpty()) { - return null; - } - - return Long.parseLong(value); - } catch (NumberFormatException e) { - logger.error("配置项 {} 的值无法转换为Long: {}", key, e.getMessage()); - return null; - } catch (Exception e) { - logger.error("获取Long配置失败: {}", key, e); - return null; - } - } - - @Override - public ResultDomain insertConfig(TbSysConfigDTO configDTO) { - if (configDTO == null) { - return ResultDomain.failure(MSG_CONFIG_PARAM_REQUIRED); - } - if (StringUtils.isBlank(configDTO.getConfigId())) { - configDTO.setConfigId(IdUtil.generateID()); - } - if (configDTO.getCreateTime() == null) { - configDTO.setCreateTime(new Date()); - } - if (configDTO.getDeleted() == null) { - configDTO.setDeleted(false); - } - int rows = configMapper.insertConfig(configDTO); - if (rows > 0) { - logger.info("新增配置成功, configId={}", configDTO.getConfigId()); - // 异步发布配置变更事件 - publishConfigChangeEvent(configDTO.getGroup()); - return ResultDomain.success("新增配置成功", configDTO); - } - logger.warn("新增配置失败, configId={}", configDTO.getConfigId()); - return ResultDomain.failure("新增配置失败"); - } - - @Override - public ResultDomain updateConfig(TbSysConfigDTO configDTO) { - if (configDTO == null || StringUtils.isBlank(configDTO.getConfigId())) { - return ResultDomain.failure(MSG_CONFIG_ID_REQUIRED); - } - configDTO.setUpdateTime(new Date()); - int rows = configMapper.updateConfig(configDTO); - if (rows > 0) { - logger.info("更新配置成功, configId={}", configDTO.getConfigId()); - // 异步发布配置变更事件 - publishConfigChangeEvent(configDTO.getGroup()); - return ResultDomain.success("更新配置成功", configDTO); - } - logger.warn("更新配置失败, configId={}", configDTO.getConfigId()); - return ResultDomain.failure("更新配置失败"); - } - - @Override - public ResultDomain deleteConfig(TbSysConfigDTO configDTO) { - if (configDTO == null || StringUtils.isBlank(configDTO.getConfigId())) { - return ResultDomain.failure(MSG_CONFIG_ID_REQUIRED); - } - int rows = configMapper.deleteConfig(configDTO); - if (rows > 0) { - logger.info("删除配置成功, configId={}", configDTO.getConfigId()); - // 异步发布配置变更事件 - publishConfigChangeEvent(configDTO.getGroup()); - return ResultDomain.success("删除配置成功", Boolean.TRUE); - } - logger.warn("删除配置失败, configId={}", configDTO.getConfigId()); - return ResultDomain.failure("删除配置失败"); - } - - @Override - public ResultDomain getConfig(SysConfigVO filter) { - TbSysConfigDTO dto = SysConfigVO.toDTO(filter); - if (dto == null) { - return ResultDomain.failure(MSG_QUERY_PARAM_REQUIRED); - } - List list = configMapper.getConfigByFilter(dto); - if (list == null || list.isEmpty()) { - return ResultDomain.failure("未找到配置"); - } - return ResultDomain.success("获取配置成功", list.get(0)); - } - - @Override - public ResultDomain getConfigList(SysConfigVO filter) { - TbSysConfigDTO dto = SysConfigVO.toDTO(filter); - List list = configMapper.getConfigByFilter(dto); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取配置列表成功", list); - } - - @Override - public ResultDomain getConfigPage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - PageParam pageParam = pageRequest.getPageParam(); - TbSysConfigDTO filter = SysConfigVO.toDTO(pageRequest.getFilter()); - int total = configMapper.getConfigCount(filter); - pageParam.setTotal(total); - pageParam.setTotalPages(pageParam.getPageSize() == 0 ? 0 : (int) Math.ceil((double) total / pageParam.getPageSize())); - List data = configMapper.getConfigPageByFilter(filter, pageParam); - if (data == null) { - data = Collections.emptyList(); - } - PageDomain pageDomain = new PageDomain<>(pageParam, data); - return ResultDomain.success("分页查询配置成功", pageDomain); - } - - @Override - public ResultDomain getConfigValueByKey(String key) { - if (StringUtils.isBlank(key)) { - return ResultDomain.failure("配置键不能为空"); - } - TbSysConfigDTO filter = new TbSysConfigDTO(); - filter.setKey(key); - List list = configMapper.getConfigByFilter(filter); - if (list == null || list.isEmpty()) { - return ResultDomain.failure("未找到配置"); - } - String value = list.get(0).getValue(); - return ResultDomain.success("获取配置值成功", value); - } - - @Override - public ResultDomain getConfigListByModuleId(String moduleId) { - if (StringUtils.isBlank(moduleId)) { - return ResultDomain.failure("模块ID不能为空"); - } - TbSysConfigDTO filter = new TbSysConfigDTO(); - filter.setModuleId(moduleId); - List list = configMapper.getConfigByFilter(filter); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("根据模块ID获取配置列表成功", list); - } - - -} - diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/SysUserServiceImpl.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/SysUserServiceImpl.java deleted file mode 100644 index 6b8de971..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/SysUserServiceImpl.java +++ /dev/null @@ -1,469 +0,0 @@ -package org.xyzh.system.service.impl; - -import org.apache.dubbo.config.annotation.DubboService; -import org.xyzh.api.system.service.SysUserService; -import org.xyzh.api.system.vo.SysUserVO; -import org.xyzh.api.system.vo.UserDeptRoleVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysUserDTO; -import org.xyzh.common.dto.sys.TbSysUserInfoDTO; -import org.xyzh.common.dto.sys.TbSysUserRoleDTO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import jakarta.annotation.Resource; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageDomain; - -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.NonUtils; -import org.xyzh.common.utils.StringUtils; -import org.xyzh.common.utils.crypto.AesEncryptUtil; -import org.xyzh.system.mapper.user.TbSysUserMapper; -import org.xyzh.system.mapper.user.TbSysUserInfoMapper; -import org.xyzh.system.mapper.user.TbSysUserRoleMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.transaction.annotation.Transactional; - -/** - * @description 用户服务实现类 - * @filename SysUserServiceImpl.java - */ -@DubboService( - version = "1.0.0", - group = "system", - timeout = 3000, - retries = 0 -) -public class SysUserServiceImpl implements SysUserService { - - private static final Logger logger = LoggerFactory.getLogger(SysUserServiceImpl.class); - - private static final String MSG_USER_PARAM_REQUIRED = "用户参数不能为空"; - private static final String MSG_USER_ID_REQUIRED = "用户ID不能为空"; - private static final String MSG_QUERY_PARAM_REQUIRED = "查询条件不能为空"; - private static final String MSG_PAGE_PARAM_REQUIRED = "分页参数不能为空"; - - @Resource - private TbSysUserMapper userMapper; - - @Resource - private TbSysUserInfoMapper userInfoMapper; - - @Resource - private TbSysUserRoleMapper userRoleMapper; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Autowired - private AesEncryptUtil aesEncryptUtil; - - @Transactional - @Override - public ResultDomain registerUser(SysUserVO userVO) { - try { - logger.info("开始注册用户:{}", userVO.getUsername()); - userVO.setPhone(aesEncryptUtil.decrypt(userVO.getPhone())); - // 检查用户是否已存在 - if (checkUserExists(userVO)) { - return ResultDomain.failure("用户已存在"); - } - - // 转换为 DTO - TbSysUserDTO dto = SysUserVO.toDTO(userVO); - - // 设置用户基本信息 - Date now = new Date(); - if (StringUtils.isBlank(dto.getUserId())) { - dto.setUserId(IdUtil.generateID()); - } - dto.setPhone(userVO.getPhone()); - dto.setCreateTime(now); - dto.setDeleted(false); - - // 加密密码 - if (StringUtils.isNotBlank(dto.getPassword())) { - dto.setPassword(passwordEncoder.encode(aesEncryptUtil.decrypt(dto.getPassword()))); - } - - // 插入用户主表 - int rows = userMapper.insertUser(dto); - if (rows <= 0) { - logger.warn("插入用户失败, userVO:", userVO.toString()); - return ResultDomain.failure("插入用户失败"); - } - - // 创建用户信息表 - TbSysUserInfoDTO userInfo = new TbSysUserInfoDTO(); - userInfo.setUserId(dto.getUserId()); - userInfo.setCreateTime(now); - userInfo.setAvatar("default"); - userInfoMapper.insertUserInfo(userInfo); - - // 分配默认角色(role_guest) - TbSysUserRoleDTO userRole = new TbSysUserRoleDTO(); - userRole.setUserId(dto.getUserId()); - userRole.setRoleId("role_guest"); - userRole.setCreateTime(now); - userRoleMapper.insertUserRole(userRole); - - return ResultDomain.success("注册用户成功", dto); - - } catch (Exception e) { - logger.error("注册用户失败:{}", userVO.getUsername(), e); - return ResultDomain.failure("注册用户失败:" + e.getMessage()); - } - } - - /** - * 检查用户是否已存在 - * @param userVO 用户信息 - * @return true-存在,false-不存在 - */ - private boolean checkUserExists(SysUserVO userVO) { - SysUserVO filter = new SysUserVO(); - - // 检查用户名是否存在 - if (StringUtils.isNotBlank(userVO.getUsername())) { - filter.setUsername(userVO.getUsername()); - List users = userMapper.getUserByFilter(filter); - if (users != null && !users.isEmpty()) { - logger.warn("用户名已存在: {}", userVO.getUsername()); - return true; - } - } - - // 检查手机号是否存在 - if (StringUtils.isNotBlank(userVO.getPhone())) { - filter = new SysUserVO(); - filter.setPhone(userVO.getPhone()); - List users = userMapper.getUserByFilter(filter); - if (users != null && !users.isEmpty()) { - logger.warn("手机号已存在: {}", userVO.getPhone()); - return true; - } - } - - // 检查邮箱是否存在 - if (StringUtils.isNotBlank(userVO.getEmail())) { - filter = new SysUserVO(); - filter.setEmail(userVO.getEmail()); - List users = userMapper.getUserByFilter(filter); - if (users != null && !users.isEmpty()) { - logger.warn("邮箱已存在: {}", userVO.getEmail()); - return true; - } - } - - return false; - } - - @Override - public ResultDomain insertUser(SysUserVO userVO) { - if (userVO == null) { - return ResultDomain.failure(MSG_USER_PARAM_REQUIRED); - } - - ResultDomain rows = registerUser(userVO); - TbSysUserDTO dto = rows.getData(); - - if (rows.getSuccess()) { - logger.info("新增用户成功, userId={}", dto.getUserId()); - return ResultDomain.success("新增用户成功", dto); - } - logger.warn("新增用户失败, userId={}", dto.getUserId()); - return ResultDomain.failure("新增用户失败"); - } - - @Override - public ResultDomain updateUser(SysUserVO userVO) { - if (userVO == null || StringUtils.isBlank(userVO.getUserId())) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - TbSysUserDTO dto = SysUserVO.toDTO(userVO); - dto.setUpdateTime(new Date()); - int rows = userMapper.updateUser(dto); - if (rows > 0) { - logger.info("更新用户成功, userId={}", dto.getUserId()); - return ResultDomain.success("更新用户成功", dto); - } - logger.warn("更新用户失败, userId={}", dto.getUserId()); - return ResultDomain.failure("更新用户失败"); - } - - @Override - public ResultDomain deleteUser(TbSysUserDTO userDTO) { - if (userDTO == null || StringUtils.isBlank(userDTO.getUserId())) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - int rows = userMapper.deleteUser(userDTO); - if (rows > 0) { - logger.info("删除用户成功, userId={}", userDTO.getUserId()); - return ResultDomain.success("删除用户成功", Boolean.TRUE); - } - logger.warn("删除用户失败, userId={}", userDTO.getUserId()); - return ResultDomain.failure("删除用户失败"); - } - - @Override - public ResultDomain getUser(SysUserVO filter) { - if (filter == null) { - return ResultDomain.failure(MSG_QUERY_PARAM_REQUIRED); - } - List list = userMapper.getUserByFilter(filter); - if (list == null || list.isEmpty()) { - return ResultDomain.failure("未找到用户"); - } - return ResultDomain.success("获取用户成功", list.get(0)); - } - - @Override - public ResultDomain getLoginUser(SysUserVO filter) { - // 登录查询语义与 getUser 相同(可根据用户名/手机号/邮箱/wechatId查询) - if(NonUtils.isNotNull(filter.getPhone())){ - // 确保 phoneHash 被正确设置 - filter.setPhone(filter.getPhone()); - logger.info("登录查询 - phone: {}, phoneHash: {}", filter.getPhone(), filter.getPhoneHash()); - } - if(NonUtils.isNotNull(filter.getWechatId())){ - logger.info("登录查询 - wechatId: {}", filter.getWechatId()); - } - List list = userMapper.getUserByFilter(filter); - logger.info("登录查询结果数量: {}", list != null ? list.size() : 0); - if (list == null || list.isEmpty()) { - return ResultDomain.failure("用户不存在"); - } - return ResultDomain.success("查询成功", list.get(0)); - } - - @Override - public ResultDomain getUserList(SysUserVO filter) { - List list = userMapper.getUserByFilter(filter); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取用户列表成功", list); - } - - @Override - public ResultDomain getUserPage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - PageParam pageParam = pageRequest.getPageParam(); - TbSysUserDTO filter = SysUserVO.toDTO(pageRequest.getFilter()); - int total = userMapper.getUserCount(filter); - pageParam.setTotal(total); - pageParam.setTotalPages(pageParam.getPageSize() == 0 ? 0 : (int) Math.ceil((double) total / pageParam.getPageSize())); - List data = userMapper.getUserPageByFilter(filter, pageParam); - if (data == null) { - data = Collections.emptyList(); - } - PageDomain pageDomain = new PageDomain<>(pageParam, data); - return ResultDomain.success("分页查询用户成功", pageDomain); - } - - @Override - public ResultDomain getUserByUsername(String username) { - if (StringUtils.isBlank(username)) { - return ResultDomain.failure("用户名不能为空"); - } - SysUserVO userVO = new SysUserVO(); - userVO.setUsername(username); - List list = userMapper.getUserByFilter(userVO); - if (list == null || list.isEmpty()) { - return ResultDomain.failure("未找到用户"); - } - return ResultDomain.success("根据用户名获取用户成功", list.get(0)); - } - - @Override - public ResultDomain updateUserPassword(String userId, String oldPassword, String newPassword) { - if (StringUtils.isBlank(userId)) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - if (StringUtils.isBlank(newPassword)) { - return ResultDomain.failure("新密码不能为空"); - } - TbSysUserDTO dto = new TbSysUserDTO(); - dto.setUserId(userId); - dto.setPassword(newPassword); - dto.setUpdateTime(new Date()); - int rows = userMapper.updateUser(dto); - if (rows > 0) { - logger.info("更新用户密码成功, userId={}", userId); - return ResultDomain.success("更新用户密码成功", Boolean.TRUE); - } - logger.warn("更新用户密码失败, userId={}", userId); - return ResultDomain.failure("更新用户密码失败"); - } - - @Override - public ResultDomain resetUserPassword(String userId) { - if (StringUtils.isBlank(userId)) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - String newPwd = IdUtil.generateID(); - if (newPwd.length() > 12) { - newPwd = newPwd.substring(0, 12); - } - TbSysUserDTO dto = new TbSysUserDTO(); - dto.setUserId(userId); - dto.setPassword(newPwd); - dto.setUpdateTime(new Date()); - int rows = userMapper.updateUser(dto); - if (rows > 0) { - logger.info("重置用户密码成功, userId={}", userId); - return ResultDomain.success("重置用户密码成功", newPwd); - } - logger.warn("重置用户密码失败, userId={}", userId); - return ResultDomain.failure("重置用户密码失败"); - } - - @Override - public ResultDomain updateUserStatus(String userId, String status) { - if (StringUtils.isBlank(userId)) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - TbSysUserDTO dto = new TbSysUserDTO(); - dto.setUserId(userId); - dto.setStatus(status); - dto.setUpdateTime(new Date()); - int rows = userMapper.updateUser(dto); - if (rows > 0) { - logger.info("更新用户状态成功, userId={}", userId); - return ResultDomain.success("更新用户状态成功", Boolean.TRUE); - } - logger.warn("更新用户状态失败, userId={}", userId); - return ResultDomain.failure("更新用户状态失败"); - } - - @Override - public ResultDomain updateUserInfo(TbSysUserInfoDTO userInfoDTO) { - if (userInfoDTO == null || StringUtils.isBlank(userInfoDTO.getUserId())) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - userInfoDTO.setUpdateTime(new Date()); - int rows = userInfoMapper.updateUserInfo(userInfoDTO); - if (rows > 0) { - logger.info("更新用户信息成功, userId={}", userInfoDTO.getUserId()); - return ResultDomain.success("更新用户信息成功", userInfoDTO); - } - logger.warn("更新用户信息失败, userId={}", userInfoDTO.getUserId()); - return ResultDomain.failure("更新用户信息失败"); - } - - @Override - public ResultDomain getUserInfo(String userId) { - if (StringUtils.isBlank(userId)) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - TbSysUserInfoDTO info = userInfoMapper.getUserInfoById(userId); - if (info == null) { - return ResultDomain.failure("未找到用户信息"); - } - SysUserVO vo = new SysUserVO(); - vo.setUserId(userId); - vo.setAvatar(info.getAvatar()); - vo.setGender(info.getGender()); - vo.setUsername(info.getUsername()); - vo.setLevel(info.getLevel()); - vo.setIdCard(info.getIdCard()); - vo.setAddress(info.getAddress()); - vo.setCreateTime(info.getCreateTime()); - vo.setUpdateTime(info.getUpdateTime()); - vo.setDeleteTime(info.getDeleteTime()); - vo.setDeleted(info.getDeleted()); - return ResultDomain.success("获取用户信息成功", vo); - } - - @Override - public ResultDomain addUserRole(TbSysUserRoleDTO userRoleDTO) { - if (userRoleDTO == null || StringUtils.isBlank(userRoleDTO.getUserId()) || StringUtils.isBlank(userRoleDTO.getRoleId())) { - return ResultDomain.failure("用户ID和角色ID不能为空"); - } - if (userRoleDTO.getCreateTime() == null) { - userRoleDTO.setCreateTime(new Date()); - } - if (userRoleDTO.getDeleted() == null) { - userRoleDTO.setDeleted(false); - } - int rows = userRoleMapper.insertUserRole(userRoleDTO); - if (rows > 0) { - logger.info("新增用户角色关联成功, userId={}, roleId={}", userRoleDTO.getUserId(), userRoleDTO.getRoleId()); - return ResultDomain.success("新增用户角色关联成功", userRoleDTO); - } - logger.warn("新增用户角色关联失败, userId={}, roleId={}", userRoleDTO.getUserId(), userRoleDTO.getRoleId()); - return ResultDomain.failure("新增用户角色关联失败"); - } - - @Override - public ResultDomain removeUserRole(TbSysUserRoleDTO userRoleDTO) { - if (userRoleDTO == null || StringUtils.isBlank(userRoleDTO.getUserId()) || StringUtils.isBlank(userRoleDTO.getRoleId())) { - return ResultDomain.failure("用户ID和角色ID不能为空"); - } - int rows = userRoleMapper.deleteUserRole(userRoleDTO); - if (rows > 0) { - logger.info("删除用户角色关联成功, userId={}, roleId={}", userRoleDTO.getUserId(), userRoleDTO.getRoleId()); - return ResultDomain.success("删除用户角色关联成功", Boolean.TRUE); - } - logger.warn("删除用户角色关联失败, userId={}, roleId={}", userRoleDTO.getUserId(), userRoleDTO.getRoleId()); - return ResultDomain.failure("删除用户角色关联失败"); - } - - @Override - public ResultDomain setUserRoles(String userId, String[] roleIds) { - if (StringUtils.isBlank(userId)) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - // 先删除现有的用户角色关系 - List exists = userRoleMapper.getUserRoleByUserId(userId); - if (exists != null) { - for (UserDeptRoleVO vo : exists) { - if (vo == null || StringUtils.isBlank(vo.getRoleId())) { - continue; - } - TbSysUserRoleDTO del = new TbSysUserRoleDTO(); - del.setUserId(userId); - del.setRoleId(vo.getRoleId()); - userRoleMapper.deleteUserRole(del); - } - } - // 批量插入新角色 - if (roleIds != null) { - Date now = new Date(); - for (String rid : roleIds) { - if (StringUtils.isBlank(rid)) { - continue; - } - TbSysUserRoleDTO add = new TbSysUserRoleDTO(); - add.setUserId(userId); - add.setRoleId(rid); - add.setCreateTime(now); - add.setDeleted(false); - userRoleMapper.insertUserRole(add); - } - } - logger.info("设置用户角色成功, userId={}, count={}", userId, roleIds == null ? 0 : roleIds.length); - return ResultDomain.success("设置用户角色成功", Boolean.TRUE); - } - - @Override - public ResultDomain getUserWithDeptRole(String userId) { - if (StringUtils.isBlank(userId)) { - return ResultDomain.failure(MSG_USER_ID_REQUIRED); - } - List list = userRoleMapper.getUserRoleByUserId(userId); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取用户部门角色成功", list); - } - - -} diff --git a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/ViewServiceImpl.java b/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/ViewServiceImpl.java deleted file mode 100644 index e137b653..00000000 --- a/urbanLifelineServ/system/src/main/java/org/xyzh/system/service/impl/ViewServiceImpl.java +++ /dev/null @@ -1,190 +0,0 @@ -package org.xyzh.system.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import jakarta.annotation.Resource; -import java.util.Date; -import java.util.Collections; -import java.util.List; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xyzh.api.system.service.ViewService; -import org.xyzh.api.system.vo.PermissionVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.dto.sys.TbSysViewDTO; -import org.xyzh.common.dto.sys.TbSysViewPermissionDTO; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.common.utils.StringUtils; -import org.xyzh.system.mapper.view.TbSysViewMapper; -import org.xyzh.system.mapper.view.TbSysViewPermissionMapper; - -/** - * @description 视图服务实现类 - * @filename ViewServiceImpl.java - */ -@DubboService( - version = "1.0.0", - group = "system", - timeout = 3000, - retries = 0 -) -public class ViewServiceImpl implements ViewService { - - private static final Logger logger = LoggerFactory.getLogger(ViewServiceImpl.class); - private static final String MSG_VIEW_ID_REQUIRED = "视图ID不能为空"; - private static final String MSG_QUERY_PARAM_REQUIRED = "查询条件不能为空"; - private static final String MSG_PAGE_PARAM_REQUIRED = "分页参数不能为空"; - - @Resource - private TbSysViewMapper viewMapper; - - @Resource - private TbSysViewPermissionMapper viewPermissionMapper; - - @Override - public ResultDomain insertView(TbSysViewDTO viewDTO) { - if (viewDTO == null) { - return ResultDomain.failure("视图参数不能为空"); - } - if (StringUtils.isBlank(viewDTO.getViewId())) { - viewDTO.setViewId(IdUtil.generateID()); - } - if (viewDTO.getCreateTime() == null) { - viewDTO.setCreateTime(new Date()); - } - if (viewDTO.getDeleted() == null) { - viewDTO.setDeleted(false); - } - int rows = viewMapper.insertView(viewDTO); - if (rows > 0) { - logger.info("新增视图成功, viewId={}", viewDTO.getViewId()); - return ResultDomain.success("新增视图成功", viewDTO); - } - logger.warn("新增视图失败, viewId={}", viewDTO.getViewId()); - return ResultDomain.failure("新增视图失败"); - } - - @Override - public ResultDomain updateView(TbSysViewDTO viewDTO) { - if (viewDTO == null || StringUtils.isBlank(viewDTO.getViewId())) { - return ResultDomain.failure(MSG_VIEW_ID_REQUIRED); - } - viewDTO.setUpdateTime(new Date()); - int rows = viewMapper.updateView(viewDTO); - if (rows > 0) { - logger.info("更新视图成功, viewId={}", viewDTO.getViewId()); - return ResultDomain.success("更新视图成功", viewDTO); - } - logger.warn("更新视图失败, viewId={}", viewDTO.getViewId()); - return ResultDomain.failure("更新视图失败"); - } - - @Override - public ResultDomain deleteView(TbSysViewDTO viewDTO) { - if (viewDTO == null || StringUtils.isBlank(viewDTO.getViewId())) { - return ResultDomain.failure(MSG_VIEW_ID_REQUIRED); - } - int rows = viewMapper.deleteView(viewDTO); - if (rows > 0) { - logger.info("删除视图成功, viewId={}", viewDTO.getViewId()); - return ResultDomain.success("删除视图成功", Boolean.TRUE); - } - logger.warn("删除视图失败, viewId={}", viewDTO.getViewId()); - return ResultDomain.failure("删除视图失败"); - } - - @Override - public ResultDomain getView(PermissionVO filter) { - TbSysViewDTO dto = PermissionVO.toViewDTO(filter); - if (dto == null) { - return ResultDomain.failure(MSG_QUERY_PARAM_REQUIRED); - } - List list = viewMapper.getViewByFilter(dto); - if (list == null || list.isEmpty()) { - return ResultDomain.failure("未找到视图"); - } - PermissionVO result = PermissionVO.fromViewDTO(list.get(0)); - return ResultDomain.success("获取视图成功", result); - } - - @Override - public ResultDomain getViewList(PermissionVO filter) { - TbSysViewDTO dto = PermissionVO.toViewDTO(filter); - List list = viewMapper.getViewByFilter(dto); - List result = PermissionVO.fromViewDTOList(list); - return ResultDomain.success("获取视图列表成功", result); - } - - @Override - public ResultDomain getViewPage(PageRequest pageRequest) { - if (pageRequest == null) { - return ResultDomain.failure(MSG_PAGE_PARAM_REQUIRED); - } - PageParam pageParam = pageRequest.getPageParam(); - TbSysViewDTO filter = PermissionVO.toViewDTO(pageRequest.getFilter()); - int total = viewMapper.getViewCount(filter); - pageParam.setTotal(total); - pageParam.setTotalPages(pageParam.getPageSize() == 0 ? 0 : (int) Math.ceil((double) total / pageParam.getPageSize())); - List list = viewMapper.getViewPageByFilter(filter, pageParam); - List data = PermissionVO.fromViewDTOList(list); - PageDomain pageDomain = new PageDomain<>(pageParam, data); - return ResultDomain.success("分页查询视图成功", pageDomain); - } - - @Override - public ResultDomain getViewTree(PermissionVO filter) { - return getViewList(filter); - } - - @Override - public ResultDomain setViewPermissions(PermissionVO permissionVO) { - if (permissionVO == null || StringUtils.isBlank(permissionVO.getViewId())) { - return ResultDomain.failure(MSG_VIEW_ID_REQUIRED); - } - viewPermissionMapper.delete(new QueryWrapper() - .eq("view_id", permissionVO.getViewId())); - List permissionIds = permissionVO.getPermissionIdList(); - if (permissionIds != null && !permissionIds.isEmpty()) { - Date now = new Date(); - for (String permissionId : permissionIds) { - if (StringUtils.isBlank(permissionId)) { - continue; - } - TbSysViewPermissionDTO dto = new TbSysViewPermissionDTO(); - dto.setViewId(permissionVO.getViewId()); - dto.setPermissionId(permissionId); - dto.setCreateTime(now); - dto.setDeleted(false); - viewPermissionMapper.insertViewPermission(dto); - } - } - logger.info("视图权限设置成功, viewId={}, count={}", - permissionVO.getViewId(), - permissionIds == null ? 0 : permissionIds.size()); - return ResultDomain.success("设置视图权限成功", permissionVO); - } - - @Override - public ResultDomain getViewPermissionList(PermissionVO permissionVO) { - TbSysViewPermissionDTO dto = new TbSysViewPermissionDTO(); - if (permissionVO != null) { - dto.setViewId(permissionVO.getViewId()); - if (permissionVO.getPermissionIdList() != null && !permissionVO.getPermissionIdList().isEmpty()) { - dto.setPermissionId(permissionVO.getPermissionIdList().get(0)); - } else { - dto.setPermissionId(permissionVO.getPermissionId()); - } - dto.setDeptPath(permissionVO.getDeptPath()); - dto.setDeleted(permissionVO.getDeleted()); - } - List list = viewPermissionMapper.getViewPermissionByFilter(dto); - if (list == null) { - list = Collections.emptyList(); - } - return ResultDomain.success("获取视图权限列表成功", list); - } - -} diff --git a/urbanLifelineServ/system/src/main/resources/application.yml b/urbanLifelineServ/system/src/main/resources/application.yml deleted file mode 100644 index f6a5ddf0..00000000 --- a/urbanLifelineServ/system/src/main/resources/application.yml +++ /dev/null @@ -1,44 +0,0 @@ -# ================== System 系统服务配置 ================== -server: - port: 8082 - -spring: - application: - name: system-service - -# ================== Auth ================== -auth: - enabled: true - gateway-mode: true - whitelist: - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - /favicon.ico - - /error - - /actuator/health - - /actuator/info - - /system/guest/identify - -# ================== SpringDoc ================== -springdoc: - swagger-ui: - try-it-out-enabled: true - show-common-extensions: true - show-extensions: true - filter: true - tags-sorter: alpha - operations-sorter: alpha - group-configs: - - group: 'default' - display-name: '系统服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-system - qos-enable: false - scan: - base-packages: org.xyzh.system.service.impl diff --git a/urbanLifelineServ/system/src/main/resources/bootstrap.yml b/urbanLifelineServ/system/src/main/resources/bootstrap.yml deleted file mode 100644 index 60998f2b..00000000 --- a/urbanLifelineServ/system/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,64 +0,0 @@ -# ================================================ -# Urban Lifeline - 通用 Bootstrap 配置 -# 所有微服务共享的基础配置 -# ================================================ - -# ================== Spring Cloud Nacos ================== -spring: - cloud: - nacos: - discovery: - server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} - namespace: ${NACOS_NAMESPACE:dev} - group: ${NACOS_GROUP:DEFAULT_GROUP} - - # ================== DataSource ================== - datasource: - url: ${DB_URL:jdbc:postgresql://127.0.0.1:5432/urban_lifeline} - username: ${DB_USERNAME:postgres} - password: ${DB_PASSWORD:postgres} - driver-class-name: org.postgresql.Driver - - # ================== Redis ================== - data: - redis: - host: ${REDIS_HOST:127.0.0.1} - port: ${REDIS_PORT:6379} - database: ${REDIS_DATABASE:0} - password: ${REDIS_PASSWORD:123456} - -# ================== Security AES ================== -security: - aes: - # AES-256 密钥(Base64编码,必须与所有服务保持一致) - # 警告:这是开发环境密钥,生产环境请使用密钥管理系统 - secret-key: ${AES_SECRET_KEY:MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=} - -# ================== Dubbo ================== -dubbo: - protocol: - name: dubbo - port: -1 - registry: - address: nacos://${NACOS_SERVER_ADDR:127.0.0.1:8848} - -# ================== MyBatis-Plus ================== -mybatis-plus: - mapper-locations: classpath:mapper/**/*.xml - type-aliases-package: org.xyzh.common.dto, org.xyzh.api - -# ================== SpringDoc 基础配置 ================== -springdoc: - api-docs: - enabled: true - path: /v3/api-docs - swagger-ui: - enabled: true - path: /swagger-ui.html - -# ================== Logging ================== -logging: - config: classpath:log4j2.xml - charset: - console: UTF-8 - file: UTF-8 diff --git a/urbanLifelineServ/system/src/main/resources/log4j2.xml b/urbanLifelineServ/system/src/main/resources/log4j2.xml deleted file mode 100644 index 81a36da0..00000000 --- a/urbanLifelineServ/system/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/acl/TbSysAclMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/acl/TbSysAclMapper.xml deleted file mode 100644 index b3600144..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/acl/TbSysAclMapper.xml +++ /dev/null @@ -1,285 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - acl_id, object_type, object_id, principal_type, principal_id, principal_dept_id, permission, allow, include_descendants, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_acl - - - acl_id, - object_type, - object_id, - principal_type, - principal_id, - principal_dept_id, - permission, - allow, - include_descendants, - optsn, - - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{aclId}, - #{objectType}, - #{objectId}, - #{principalType}, - #{principalId}, - #{principalDeptId}, - #{permission}, - #{allow}, - #{includeDescendants}, - #{optsn}, - - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_acl - - - object_type = #{objectType}, - - - updater = #{updater}, - - - principal_id = #{principalId}, - - - principal_dept_id = #{principalDeptId}, - - - permission = #{permission}, - - - allow = #{allow}, - - - include_descendants = #{includeDescendants}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE acl_id = #{aclId} - - AND deleted = #{deleted} - - - - - - DELETE FROM sys.tb_sys_acl - WHERE acl_id = #{aclId} - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/system/src/main/resources/mapper/acl/TbSysAclPolicyMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/acl/TbSysAclPolicyMapper.xml deleted file mode 100644 index 2712e3c1..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/acl/TbSysAclPolicyMapper.xml +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - policy_id, name, object_type, edit_hierarchy_rule, view_hierarchy_rule, default_permission, default_allow, apply_to_children, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_acl_policy - - - policy_id, - name, - object_type, - edit_hierarchy_rule, - view_hierarchy_rule, - default_permission, - default_allow, - apply_to_children, - optsn, - - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{policyId}, - #{name}, - #{objectType}, - #{editHierarchyRule}, - #{viewHierarchyRule}, - #{defaultPermission}, - #{defaultAllow}, - #{applyToChildren}, - #{optsn}, - - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_acl_policy - - - name = #{name}, - - - object_type = #{objectType}, - - - edit_hierarchy_rule = #{editHierarchyRule}, - - - view_hierarchy_rule = #{viewHierarchyRule}, - - - default_permission = #{defaultPermission}, - - - default_allow = #{defaultAllow}, - - - apply_to_children = #{applyToChildren}, - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE policy_id = #{policyId} - - AND deleted = #{deleted} - - - - - - DELETE FROM sys.tb_sys_acl_policy - WHERE policy_id = #{policyId} - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/config/TbSysConfigMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/config/TbSysConfigMapper.xml deleted file mode 100644 index cd938752..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/config/TbSysConfigMapper.xml +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - config_id, key, name, value, config_type, render_type, description, re, options, "group", module_id, order_num, status, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - - - - - INSERT INTO config.tb_sys_config - - - config_id, - key, - name, - value, - config_type, - render_type, - description, - "group", - module_id, - order_num, - optsn, - remark, - - re, - options, - status, - creator, - updater, - dept_path, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{configId}, - #{key}, - #{name}, - #{value}, - #{configType}, - #{renderType}, - #{description}, - #{group}, - #{moduleId}, - #{orderNum}, - #{optsn}, - #{remark}, - - #{re}, - #{options}, - #{status}, - #{creator}, - #{updater}, - #{deptPath}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE config.tb_sys_config - - key = #{key}, - name = #{name}, - value = #{value}, - config_type = #{configType}, - render_type = #{renderType}, - description = #{description}, - re = #{re}, - options = #{options}, - "group" = #{group}, - module_id = #{moduleId}, - order_num = #{orderNum}, - status = #{status}, - updater = #{updater}, - dept_path = #{deptPath}, - remark = #{remark}, - update_time = #{updateTime}, - delete_time = #{deleteTime}, - deleted = #{deleted}, - - WHERE config_id = #{configId} - - AND deleted = #{deleted} - - - - - - UPDATE config.tb_sys_config - SET deleted = true, - delete_time = NOW() - WHERE config_id = #{configId} - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/dept/TbSysDeptMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/dept/TbSysDeptMapper.xml deleted file mode 100644 index a6877a6d..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/dept/TbSysDeptMapper.xml +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - dept_id, name, parent_id, description, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_dept - - - dept_id, - name, - optsn, - - parent_id, - description, - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{deptId}, - #{name}, - #{optsn}, - - #{parentId}, - #{description}, - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_dept - - - name = #{name}, - - - parent_id = #{parentId}, - - - description = #{description}, - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE dept_id = #{deptId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_dept - SET deleted = true, - delete_time = NOW() - WHERE dept_id = #{deptId} - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/log/TbSysLogMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/log/TbSysLogMapper.xml deleted file mode 100644 index 6956ee96..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/log/TbSysLogMapper.xml +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - log_id, optsn, type, level, module, ip_address, ip_source, browser, os, message, - data, creator, creator_name, service, dept_path, updater, - create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_log - - log_id, - optsn, - type, - level, - module, - message, - service, - ip_address, - ip_source, - browser, - os, - data, - creator, - creator_name, - dept_path, - updater, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - #{logId}, - #{optsn}, - #{type}, - #{level}, - #{module}, - #{message}, - #{servce}, - #{ipAddress}, - #{ip_source}, - #{browser}, - #{os}, - #{data, typeHandler=org.xyzh.common.jdbc.handler.FastJson2TypeHandler}, - #{creator}, - #{creatorName}, - #{deptPath}, - #{updater}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_log - - type = #{type}, - level = #{level}, - module = #{module}, - ip_address = #{ipAddress}, - ip_source = #{ip_source}, - browser = #{browser}, - os = #{os}, - message = #{message}, - data = #{data, typeHandler=org.xyzh.common.jdbc.handler.FastJson2TypeHandler}, - service = #{servce}, - updater = #{updater}, - dept_path = #{deptPath}, - update_time = #{updateTime}, - delete_time = #{deleteTime}, - deleted = #{deleted}, - - WHERE log_id = #{logId} - - - - - UPDATE sys.tb_sys_log - SET deleted = true, - delete_time = NOW() - WHERE log_id = #{logId} - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/log/TbSysLoginLogMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/log/TbSysLoginLogMapper.xml deleted file mode 100644 index 384aced8..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/log/TbSysLoginLogMapper.xml +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - optsn, user_id, username, ip_address, ip_source, browser, os, password, - login_time, status, error_count, message, create_time - - - - - INSERT INTO sys.tb_sys_login_log - - optsn, - user_id, - username, - ip_address, - ip_source, - browser, - os, - password, - login_time, - status, - error_count, - message, - create_time, - - VALUES - - #{optsn}, - #{userId}, - #{username}, - #{ipAddress}, - #{ipSource}, - #{browser}, - #{os}, - #{password}, - #{loginTime}, - #{status}, - #{errorCount}, - #{message}, - #{createTime}, - - - - - - UPDATE sys.tb_sys_login_log - - user_id = #{userId}, - username = #{username}, - ip_address = #{ipAddress}, - ip_source = #{ipSource}, - browser = #{browser}, - os = #{os}, - password = #{password}, - login_time = #{loginTime}, - status = #{status}, - error_count = #{errorCount}, - message = #{message}, - - WHERE optsn = #{optsn} - - - - - DELETE FROM sys.tb_sys_login_log - WHERE optsn = #{optsn} - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/module/TbSysModuleMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/module/TbSysModuleMapper.xml deleted file mode 100644 index 59a0e317..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/module/TbSysModuleMapper.xml +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - module_id, name, description, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_module - - - module_id, - name, - optsn, - - description, - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{moduleId}, - #{name}, - #{optsn}, - - #{description}, - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_module - - - name = #{name}, - - - description = #{description}, - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE module_id = #{moduleId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_module - SET deleted = true, - delete_time = NOW() - WHERE module_id = #{moduleId} - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/permission/TbSysPermissionMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/permission/TbSysPermissionMapper.xml deleted file mode 100644 index 66b63f2e..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/permission/TbSysPermissionMapper.xml +++ /dev/null @@ -1,249 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - permission_id, name, code, description, module_id, status, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_permission - - - permission_id, - name, - code, - module_id, - optsn, - - description, - status, - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{permissionId}, - #{name}, - #{code}, - #{moduleId}, - #{optsn}, - - #{description}, - #{status}, - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_permission - - - name = #{name}, - - - code = #{code}, - - - description = #{description}, - - - module_id = #{moduleId}, - - - status = #{status}, - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE permission_id = #{permissionId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_permission - SET deleted = true, - delete_time = NOW() - WHERE permission_id = #{permissionId} - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/role/TbSysRoleMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/role/TbSysRoleMapper.xml deleted file mode 100644 index 9483f398..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/role/TbSysRoleMapper.xml +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - role_id, name, description, scope, owner_dept_id, status, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_role - - - role_id, - name, - optsn, - - description, - scope, - owner_dept_id, - status, - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{roleId}, - #{name}, - #{optsn}, - - #{description}, - #{scope}, - #{ownerDeptId}, - #{status}, - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_role - - - name = #{name}, - - - description = #{description}, - - - scope = #{scope}, - - - owner_dept_id = #{ownerDeptId}, - - - status = #{status}, - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE role_id = #{roleId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_role - SET deleted = true, - delete_time = NOW() - WHERE role_id = #{roleId} - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/role/TbSysRolePermissionMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/role/TbSysRolePermissionMapper.xml deleted file mode 100644 index c7124f05..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/role/TbSysRolePermissionMapper.xml +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - role_id, permission_id, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_role_permission - - - role_id, - permission_id, - optsn, - - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted - - VALUES - - - - #{item.roleId}, - #{item.permissionId}, - #{item.optsn}, - - #{item.creator}, - #{item.deptPath}, - #{item.remark}, - #{item.createTime}, - #{item.updateTime}, - #{item.deleteTime}, - #{item.deleted} - - - - - - - INSERT INTO sys.tb_sys_role_permission ( - role_id, permission_id, - optsn, creator, dept_path, remark, create_time - ) VALUES ( - #{roleId}, #{permissionId}, - #{optsn}, #{creator}, #{deptPath}, #{remark}, #{createTime} - ) - - - - - UPDATE sys.tb_sys_role_permission - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE role_id = #{roleId} AND permission_id = #{permissionId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_role_permission - SET deleted = true, - delete_time = NOW() - WHERE role_id = #{roleId} AND permission_id = #{permissionId} - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/user/TbGuestMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/user/TbGuestMapper.xml deleted file mode 100644 index b312b249..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/user/TbGuestMapper.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - - - - - - - - optsn, user_id, name, phone, email, wechat_id, create_time, update_time, delete_time, deleted - - - - INSERT INTO sys.tb_guest ( - optsn, user_id, name - , phone - , email - , wechat_id - , create_time - , deleted - ) VALUES ( - #{optsn}, #{userId}, #{name} - , #{phone} - , #{email} - , #{wechatId} - , #{createTime} - , #{deleted} - ) - - - - UPDATE sys.tb_guest - - name = #{name}, - phone = #{phone}, - email = #{email}, - wechat_id = #{wechatId}, - update_time = now() - - WHERE user_id = #{userId} AND deleted = false - - - - UPDATE sys.tb_guest - SET deleted = true, - delete_time = now() - WHERE user_id = #{userId} AND deleted = false - - - - - - - - - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserInfoMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserInfoMapper.xml deleted file mode 100644 index 034c11a0..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserInfoMapper.xml +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - user_id, avatar, gender, username, level, id_card, address, - optsn, creator, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_user_info - - - optsn, - user_id, - - avatar, - gender, - username, - level, - id_card, - address, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{optsn}, - #{userId}, - - #{avatar}, - #{gender}, - #{username}, - #{level}, - #{idCard}, - #{address}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_user_info - - - avatar = #{avatar}, - - - gender = #{gender}, - - - username = #{username}, - - - level = #{level}, - - - id_card = #{idCard}, - - - address = #{address}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE user_id = #{userId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_user_info - SET deleted = true, - delete_time = NOW() - WHERE user_id = #{userId} - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserMapper.xml deleted file mode 100644 index dca2594f..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserMapper.xml +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - user_id, password, email, phone, wechat_id, status, - optsn, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_user - - - optsn, - user_id, - password, - - email, - phone, phone_hash, - wechat_id, - create_time, - update_time, - delete_time, - deleted, - status, - - VALUES - - - #{optsn}, - #{userId}, - #{password}, - - #{email}, - #{phone, typeHandler=org.xyzh.common.jdbc.handler.EncryptedStringTypeHandler}, #{phoneHash}, - #{wechatId}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - #{status}, - - - - - - UPDATE sys.tb_sys_user - - - password = #{password}, - - - email = #{email}, - - - phone = #{phone, typeHandler=org.xyzh.common.jdbc.handler.EncryptedStringTypeHandler}, - phone_hash = #{phoneHash}, - - - wechat_id = #{wechatId}, - - - status = #{status}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE user_id = #{userId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_user - SET deleted = true, - delete_time = NOW() - WHERE user_id = #{userId} - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserRoleMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserRoleMapper.xml deleted file mode 100644 index ed136fbf..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/user/TbSysUserRoleMapper.xml +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - user_id, role_id, dept_id, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_user_role - - - user_id, - role_id, - dept_id, - optsn, - - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{userId}, - #{roleId}, - #{deptId}, - #{optsn}, - - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_user_role - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE user_id = #{userId} AND role_id = #{roleId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_user_role - SET deleted = true, - delete_time = NOW() - WHERE user_id = #{userId} AND role_id = #{roleId} - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/view/TbSysViewMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/view/TbSysViewMapper.xml deleted file mode 100644 index 5dbcba88..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/view/TbSysViewMapper.xml +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - view_id, name, parent_id, url, component, icon, type, view_type, iframe_url, service, layout, order_num, description, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_view - - - view_id, - name, - type, - layout, - order_num, - optsn, - - parent_id, - url, - component, - icon, - view_type, - iframe_url, - service, - description, - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{viewId}, - #{name}, - #{type}, - #{layout}, - #{orderNum}, - #{optsn}, - - #{parentId}, - #{url}, - #{component}, - #{icon}, - #{viewType}, - #{iframeUrl}, - #{service}, - #{description}, - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_view - - - name = #{name}, - - - parent_id = #{parentId}, - - - url = #{url}, - - - component = #{component}, - - - icon = #{icon}, - - - type = #{type}, - - - view_type = #{viewType}, - - - iframe_url = #{iframeUrl}, - - - service = #{service}, - - - layout = #{layout}, - - - order_num = #{orderNum}, - - - description = #{description}, - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE view_id = #{viewId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_view - SET deleted = true, - delete_time = NOW() - WHERE view_id = #{viewId} - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/system/src/main/resources/mapper/view/TbSysViewPermissionMapper.xml b/urbanLifelineServ/system/src/main/resources/mapper/view/TbSysViewPermissionMapper.xml deleted file mode 100644 index 22ca7a3a..00000000 --- a/urbanLifelineServ/system/src/main/resources/mapper/view/TbSysViewPermissionMapper.xml +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - view_id, permission_id, - optsn, creator, updater, dept_path, remark, create_time, update_time, delete_time, deleted - - - - - INSERT INTO sys.tb_sys_view_permission - - - view_id, - permission_id, - optsn, - - creator, - dept_path, - remark, - create_time, - update_time, - delete_time, - deleted, - - VALUES - - - #{viewId}, - #{permissionId}, - #{optsn}, - - #{creator}, - #{deptPath}, - #{remark}, - #{createTime}, - #{updateTime}, - #{deleteTime}, - #{deleted}, - - - - - - UPDATE sys.tb_sys_view_permission - - - updater = #{updater}, - - - dept_path = #{deptPath}, - - - remark = #{remark}, - - - update_time = #{updateTime}, - - - WHERE view_id = #{viewId} AND permission_id = #{permissionId} - - AND deleted = #{deleted} - - - - - - UPDATE sys.tb_sys_view_permission - SET deleted = true, - delete_time = NOW() - WHERE view_id = #{viewId} AND permission_id = #{permissionId} - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/Jitsi会议独立页面实现方案.md b/urbanLifelineServ/workcase/Jitsi会议独立页面实现方案.md deleted file mode 100644 index c02a5f3d..00000000 --- a/urbanLifelineServ/workcase/Jitsi会议独立页面实现方案.md +++ /dev/null @@ -1,530 +0,0 @@ -# Jitsi 会议独立页面实现方案 - -## 问题背景 - -1. **Web端问题**:ChatRoom 弹窗关闭按钮不应该触发 `endMeeting`,只有在 Jitsi iframe 中点击"结束会议"才应该结束会议 -2. **主持人问题**:主持人应该是数据库中的会议创建人,而不是第一个进入会议的人 -3. **小程序问题**:无法捕捉结束会议事件 - -## 解决方案 - -### 1. 后端修改(已完成) - -#### 1.1 新增路由配置 (`initDataPermission.sql`) - -```sql --- Jitsi视频会议独立页面(支持URL参数token认证,用于小程序和外部链接访问) -('VIEW-W003', 'view_workcase_jitsi_meeting', 'Jitsi视频会议', NULL, '/meeting/:meetingId', - 'public/Meeting/JitsiMeetingView.vue', 'Video', 1, - 'route', NULL, 'workcase', 'BlankLayout', 25, - 'Jitsi视频会议独立页面,支持token参数认证', 'system', now(), false); -``` - -#### 1.2 新增 API 接口 - -| 接口 | 方法 | 说明 | -|------|------|------| -| `/meeting/{meetingId}/entry?token=xxx` | GET | 会议入口(支持URL参数token认证) | -| `/meeting/{meetingId}/share-url` | GET | 生成会议分享URL | - -#### 1.3 Gateway 白名单 - -```yaml -whitelist: - - /urban-lifeline/workcase/meeting/*/entry -``` - -#### 1.4 主持人逻辑 - -主持人判断逻辑已正确实现:`userId.equals(meeting.getCreator())` - -### 2. 前端实现(需要在前端仓库实现) - -#### 2.1 创建 `JitsiMeetingView.vue` - -路径:`src/views/public/Meeting/JitsiMeetingView.vue` - -```vue - - - - - -``` - -#### 2.2 API 接口定义 - -```typescript -// src/api/meeting.ts -import request from '@/utils/request' - -// 获取会议入口信息(支持token参数) -export function getMeetingEntry(meetingId: string, token?: string) { - return request({ - url: `/workcase/meeting/${meetingId}/entry`, - method: 'get', - params: { token }, - // 不使用默认的Authorization header - headers: token ? { 'Authorization': `Bearer ${token}` } : {} - }) -} - -// 结束会议 -export function endMeeting(meetingId: string) { - return request({ - url: `/workcase/meeting/${meetingId}/end`, - method: 'post' - }) -} - -// 生成会议分享URL -export function generateMeetingShareUrl(meetingId: string, baseUrl?: string) { - return request({ - url: `/workcase/meeting/${meetingId}/share-url`, - method: 'get', - params: { baseUrl } - }) -} -``` - -#### 2.3 路由配置 - -```typescript -// src/router/workcase.ts -{ - path: '/meeting/:meetingId', - name: 'JitsiMeeting', - component: () => import('@/views/public/Meeting/JitsiMeetingView.vue'), - meta: { - layout: 'BlankLayout', - requiresAuth: false, // 允许通过URL token认证 - title: '视频会议' - } -} -``` - -#### 2.4 修改 ChatRoom 组件 - -在 ChatRoom 组件中,点击"进入会议"时: - -```typescript -// 进入会议 -const joinMeeting = async (meetingId: string) => { - // 生成会议入口URL - const response = await generateMeetingShareUrl(meetingId) - if (response.success) { - // 在新窗口打开会议页面 - window.open(response.data, '_blank', 'width=1200,height=800') - } -} -``` - -#### 2.5 Web 初始化逻辑修改 - -在 workcase 前端的初始化逻辑中,添加从 URL token 恢复登录状态的功能: - -```typescript -// src/utils/auth.ts -export async function initAuth() { - // 1. 检查 localStorage 中是否有登录信息 - const storedToken = localStorage.getItem('token') - if (storedToken) { - // 验证token是否有效 - const isValid = await validateToken(storedToken) - if (isValid) { - return true - } - } - - // 2. 检查 URL 参数中是否有 token - const urlParams = new URLSearchParams(window.location.search) - const urlToken = urlParams.get('token') - if (urlToken) { - try { - // 调用 refresh 接口验证 token 并获取用户信息 - const response = await refreshToken(urlToken) - if (response.success) { - // 保存登录信息到 localStorage - localStorage.setItem('token', response.data.token) - localStorage.setItem('loginDomain', JSON.stringify(response.data)) - return true - } - } catch (e) { - console.error('URL token 验证失败:', e) - } - } - - return false -} -``` - -### 3. 小程序端实现 - -小程序端直接给出会议链接,用户在手机浏览器中打开: - -```javascript -// 小程序中获取会议链接 -const getMeetingUrl = async (meetingId) => { - const token = wx.getStorageSync('token') - const baseUrl = 'https://your-domain.com/workcase' - - // 构建会议入口URL - const meetingUrl = `${baseUrl}/meeting/${meetingId}?token=${token}` - - // 复制到剪贴板或显示给用户 - wx.setClipboardData({ - data: meetingUrl, - success: () => { - wx.showToast({ - title: '会议链接已复制,请在浏览器中打开', - icon: 'none' - }) - } - }) -} -``` - -### 4. 关键流程 - -#### 4.1 Web 端进入会议流程 - -``` -用户点击"进入会议" - ↓ -调用 generateMeetingShareUrl 获取带token的URL - ↓ -window.open 打开 JitsiMeetingView.vue - ↓ -JitsiMeetingView 从URL获取token - ↓ -调用 /meeting/{id}/entry?token=xxx 获取会议信息 - ↓ -初始化 Jitsi External API - ↓ -监听 readyToClose/hangup 事件 - ↓ -主持人结束会议时调用 endMeeting API -``` - -#### 4.2 小程序端进入会议流程 - -``` -用户点击"进入会议" - ↓ -获取当前用户token - ↓ -构建会议URL: /meeting/{id}?token=xxx - ↓ -复制URL到剪贴板 - ↓ -用户在手机浏览器打开URL - ↓ -JitsiMeetingView 从URL获取token - ↓ -调用 /meeting/{id}/entry?token=xxx 获取会议信息 - ↓ -初始化 Jitsi External API -``` - -### 5. 注意事项 - -1. **主持人权限**:只有会议创建人(`meeting.creator`)才是主持人,JWT token 中的 `moderator` 字段会正确设置 - -2. **结束会议**:只有主持人点击"结束会议"或挂断时才会调用 `endMeeting` API - -3. **Token 安全**:URL 中的 token 应该有时效性,建议使用短期 token 或一次性 token - -4. **跨域问题**:确保 Jitsi 服务器配置了正确的 CORS 策略 - -5. **HTTPS**:生产环境必须使用 HTTPS,否则浏览器可能阻止摄像头/麦克风访问 diff --git a/urbanLifelineServ/workcase/pom.xml b/urbanLifelineServ/workcase/pom.xml deleted file mode 100644 index 42df991f..00000000 --- a/urbanLifelineServ/workcase/pom.xml +++ /dev/null @@ -1,166 +0,0 @@ - - - 4.0.0 - - org.xyzh - urban-lifeline - 1.0.0 - - - org.xyzh - workcase - 1.0.0 - jar - - 21 - 21 - - - - org.xyzh.apis - api-workcase - - - org.xyzh.apis - api-system - - - org.xyzh.apis - api-auth - - - org.xyzh.apis - api-file - - - - org.xyzh.common - common-redis - - - org.xyzh.common - common-auth - - - org.xyzh.common - common-utils - - - org.xyzh.common - common-exception - - - org.xyzh.common - common-jdbc - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - - - - org.springframework.boot - spring-boot-starter-log4j2 - - - org.apache.dubbo - dubbo-spring-boot-starter - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - - - org.springframework.boot - spring-boot-starter-logging - - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - - - com.alibaba.nacos - nacos-logback-adapter-12 - - - com.alibaba.nacos - logback-adapter - - - - - - com.baomidou - mybatis-plus-boot-starter - - - org.postgresql - postgresql - runtime - - - - - org.springframework.boot - spring-boot-starter-websocket - - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - - - - - com.google.zxing - core - 3.5.3 - - - com.google.zxing - javase - 3.5.3 - - - - - org.apache.httpcomponents.client5 - httpclient5 - - - - - org.jsoup - jsoup - 1.17.2 - - - - - workcase - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/WorkcaseApp.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/WorkcaseApp.java deleted file mode 100644 index 5f855af9..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/WorkcaseApp.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.xyzh.workcase; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDubbo // 启用 Dubbo 服务 -@ComponentScan(basePackages = { - "org.xyzh.workcase", // workcase - "org.xyzh.common" // 公共模块 -}) -public class WorkcaseApp { - private static final Logger logger = LoggerFactory.getLogger(WorkcaseApp.class); - - public static void main(String[] args) { - logger.info("======================== WorkcaseApp 启动中 ========================="); - SpringApplication.run(WorkcaseApp.class, args); - logger.info("======================== WorkcaseApp 启动成功 ========================="); - } -} \ No newline at end of file diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/AiInit.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/AiInit.java deleted file mode 100644 index 175e00d2..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/AiInit.java +++ /dev/null @@ -1,226 +0,0 @@ -package org.xyzh.workcase.config; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.CommandLineRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.xyzh.api.ai.dto.TbAgent; -import org.xyzh.api.ai.dto.TbKnowledge; -import org.xyzh.api.ai.service.AgentService; -import org.xyzh.api.ai.service.KnowledgeService; -import org.xyzh.api.system.service.SysConfigService; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.utils.id.IdUtil; - -/** - * @description 初始化客服系统必须的8个知识库,4个内部知识库,4个外部知识库,运行结束即销毁 - * @filename KnowledgeInit.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Configuration -public class AiInit { - private static final Logger logger = LoggerFactory.getLogger(AiInit.class); - - private static final String SERVICE_WORKCASE = "workcase"; - private static final String CATEGORY_INTERNAL = "internal"; - private static final String CATEGORY_EXTERNAL = "external"; - - @DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0) - private KnowledgeService knowledgeService; - - @DubboReference(version = "1.0.0", group = "system", timeout = 30000, retries = 0) - private SysConfigService sysConfigService; - - @DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0) - private AgentService agentService; - - @Bean - public CommandLineRunner knowledgeInitRunner() { - return args -> { - logger.info("开始初始化客服系统知识库..."); - - List knowledges = buildKnowledgeConfigs(); - int successCount = 0; - int skipCount = 0; - for(TbKnowledge knowledge : knowledges){ - if(!checkKnowledgeExists(knowledge.getKnowledgeId())){ - if(createKnowledge(knowledge)){ - successCount++; - } - }else{ - skipCount++; - } - } - - logger.info("客服系统知识库初始化完成: 成功创建{}个,跳过{}个", successCount, skipCount); - }; - } - - @Bean - public CommandLineRunner agentInitRunner(){ - return args -> { - String chatAgentApiKey = sysConfigService.getStringConfig("dify.workcase.agent.chat"); - logger.info("开始初始化客服系统智能体..."); - TbAgent agent = new TbAgent(); - agent.setIsOuter(true); - agent.setName("泰豪小电"); - ResultDomain listDomain = agentService.getAgentList(agent); - if (listDomain.getSuccess()&&!listDomain.getDataList().isEmpty()) { - logger.info("泰豪小电智能体已经存在"); - }else{ - agent.setApiKey(chatAgentApiKey); - agent.setIntroduce("您好,我是泰豪小电智能客服。请描述您的问题,我会尽力协助。"); - agent.setCategory("客服智能体"); - ResultDomain resultDomain = agentService.addAgent(agent); - if(resultDomain.getSuccess()){ - logger.info("泰豪小电智能体初始化成功"); - }else{ - logger.error("泰豪小电智能体初始化失败"+resultDomain.getMessage()); - } - } - - String summaryAgentApiKey = sysConfigService.getStringConfig("dify.workcase.workflow.summary"); - TbAgent summaryAgent = new TbAgent(); - summaryAgent.setIsOuter(true); - summaryAgent.setName("工单总结"); - ResultDomain listDomain2 = agentService.getAgentList(summaryAgent); - if (listDomain2.getSuccess()&&!listDomain2.getDataList().isEmpty()) { - logger.info("工单总结智能体已经存在"); - }else { - summaryAgent.setApiKey(summaryAgentApiKey); - summaryAgent.setIntroduce("工单总结工作流"); - summaryAgent.setCategory("工作流"); - ResultDomain resultDomain2 = agentService.addAgent(summaryAgent); - if(resultDomain2.getSuccess()){ - logger.info("泰豪小电智能体初始化成功"); - }else{ - logger.error("泰豪小电智能体初始化失败"+resultDomain2.getMessage()); - } - } - }; - } - - /** - * 构建8个知识库配置 - */ - private List buildKnowledgeConfigs() { - List knowledges = new ArrayList<>(); - // 从数据库获取知识库配置默认信息 - TbKnowledge baseKnowledge = new TbKnowledge(); - baseKnowledge.setDifyIndexingTechnique(sysConfigService.getStringConfig("dify.knowledge.indexing.tchnique")); - baseKnowledge.setEmbeddingModel(sysConfigService.getStringConfig("dify.knowledge.embedding.model")); - baseKnowledge.setEmbeddingModelProvider(sysConfigService.getStringConfig("dify.knowledge.embedding.model.provider")); - baseKnowledge.setRerankingEnable(sysConfigService.getBooleanConfig("dify.knowledge.reranking.enable")); - baseKnowledge.setRerankModel(sysConfigService.getStringConfig("dify.knowledge.rerank.model")); - baseKnowledge.setRerankModelProvider(sysConfigService.getStringConfig("dify.knowledge.rerank.model.provider")); - baseKnowledge.setRetrievalTopK(sysConfigService.getIntConfig("dify.knowledge.retrieval.top.k")); - baseKnowledge.setRetrievalScoreThreshold(sysConfigService.getDoubleConfig("dify.knowledge.retrieval.score.threshold")); - - - // 外部知识库 - TbKnowledge outerDevOperKnowledge = new TbKnowledge(); - outerDevOperKnowledge.setKnowledgeId("workcase_outer_device_operate"); - outerDevOperKnowledge.setTitle("设备操作指南"); - outerDevOperKnowledge.setAvatar("settings"); - outerDevOperKnowledge.setCategory(CATEGORY_EXTERNAL); - knowledges.add(outerDevOperKnowledge); - - TbKnowledge outerCommonErrorKnowledge = new TbKnowledge(); - outerCommonErrorKnowledge.setKnowledgeId("workcase_outer_common_error"); - outerCommonErrorKnowledge.setTitle("常见故障解决方案"); - outerCommonErrorKnowledge.setAvatar("question"); - outerCommonErrorKnowledge.setCategory(CATEGORY_EXTERNAL); - knowledges.add(outerCommonErrorKnowledge); - - TbKnowledge outerSanBaoKnowledge = new TbKnowledge(); - outerSanBaoKnowledge.setKnowledgeId("workcase_outer_sanbao"); - outerSanBaoKnowledge.setTitle("三包外服务政策"); - outerSanBaoKnowledge.setAvatar("document"); - outerSanBaoKnowledge.setCategory(CATEGORY_EXTERNAL); - knowledges.add(outerSanBaoKnowledge); - - TbKnowledge outerMountingsKnowledge = new TbKnowledge(); - outerMountingsKnowledge.setKnowledgeId("workcase_outer_mounting_chat"); - outerMountingsKnowledge.setTitle("配件咨询话术"); - outerMountingsKnowledge.setAvatar("chat"); - outerMountingsKnowledge.setCategory(CATEGORY_EXTERNAL); - knowledges.add(outerMountingsKnowledge); - - // 内部知识库 - TbKnowledge innerDevFixKnowledge = new TbKnowledge(); - innerDevFixKnowledge.setKnowledgeId("workcase_inner_device_fix"); - innerDevFixKnowledge.setTitle("技术维修手册"); - innerDevFixKnowledge.setAvatar("settings"); - innerDevFixKnowledge.setCategory(CATEGORY_INTERNAL); - knowledges.add(innerDevFixKnowledge); - - TbKnowledge innerProArgsKnowledge = new TbKnowledge(); - innerProArgsKnowledge.setKnowledgeId("workcase_inner_product_args_info"); - innerProArgsKnowledge.setTitle("产品参数明细"); - innerProArgsKnowledge.setAvatar("document"); - innerProArgsKnowledge.setCategory(CATEGORY_INTERNAL); - knowledges.add(innerProArgsKnowledge); - - TbKnowledge innerServExpKnowledge = new TbKnowledge(); - innerServExpKnowledge.setKnowledgeId("workcase_inner_service_exp"); - innerServExpKnowledge.setTitle("内部服务流程规范"); - innerServExpKnowledge.setAvatar("document"); - innerServExpKnowledge.setCategory(CATEGORY_INTERNAL); - knowledges.add(innerServExpKnowledge); - - TbKnowledge innerServChatKnowledge = new TbKnowledge(); - innerServChatKnowledge.setKnowledgeId("workcase_inner_service_chat"); - innerServChatKnowledge.setTitle("客户服务话术模板"); - innerServChatKnowledge.setAvatar("chat"); - innerServChatKnowledge.setCategory(CATEGORY_INTERNAL); - knowledges.add(innerServChatKnowledge); - - // 统一设置dify知识库相关参数,并设置service为workcase - for(TbKnowledge knowledge: knowledges){ - knowledge.setService(SERVICE_WORKCASE); - knowledge.setOptsn(IdUtil.getOptsn()); - // 从baseKnowledge同步知识库默认配置 - knowledge.setDifyIndexingTechnique(baseKnowledge.getDifyIndexingTechnique()); - knowledge.setEmbeddingModel(baseKnowledge.getEmbeddingModel()); - knowledge.setEmbeddingModelProvider(baseKnowledge.getEmbeddingModelProvider()); - knowledge.setRerankingEnable(baseKnowledge.getRerankingEnable()); - knowledge.setRerankModel(baseKnowledge.getRerankModel()); - knowledge.setRerankModelProvider(baseKnowledge.getRerankModelProvider()); - knowledge.setRetrievalTopK(baseKnowledge.getRetrievalTopK()); - knowledge.setRetrievalScoreThreshold(baseKnowledge.getRetrievalScoreThreshold()); - } - - return knowledges; - } - - private boolean checkKnowledgeExists(String knowledgeId){ - ResultDomain knowledge = knowledgeService.getKnowledgeById(knowledgeId); - if(knowledge.getSuccess() && knowledge.getData() != null){ - return true; - } - return false; - } - - /** - * 创建知识库 - */ - private boolean createKnowledge(TbKnowledge knowledge) { - - ResultDomain result = knowledgeService.createKnowledgeInternal(knowledge); - - if (result.getSuccess()) { - logger.info("创建知识库成功: {} [{}]", knowledge.getTitle(), knowledge.getCategory()); - return true; - } else { - logger.error("创建知识库失败: {} - {}", knowledge.getTitle(), result.getMessage()); - return false; - } - } -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/JitsiProperties.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/JitsiProperties.java deleted file mode 100644 index 5e92cbd6..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/JitsiProperties.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.xyzh.workcase.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -/** - * @description Jitsi Meet 配置属性类 - * @filename JitsiProperties.java - * @author claude - * @copyright xyzh - * @since 2025-12-27 - */ -@Configuration -@ConfigurationProperties(prefix = "jitsi") -public class JitsiProperties { - - /** - * 应用配置 - */ - private App app = new App(); - - /** - * 服务器配置 - */ - private Server server = new Server(); - - /** - * Token配置 - */ - private Token token = new Token(); - - public App getApp() { - return app; - } - - public void setApp(App app) { - this.app = app; - } - - public Server getServer() { - return server; - } - - public void setServer(Server server) { - this.server = server; - } - - public Token getToken() { - return token; - } - - public void setToken(Token token) { - this.token = token; - } - - /** - * 应用配置 - */ - public static class App { - /** - * 应用ID(必须与Docker配置中的JWT_APP_ID一致) - */ - private String id = "urbanLifeline"; - - /** - * JWT密钥(必须与Docker配置中的JWT_APP_SECRET一致) - */ - private String secret = "your-secret-key-change-in-production"; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getSecret() { - return secret; - } - - public void setSecret(String secret) { - this.secret = secret; - } - } - - /** - * 服务器配置 - */ - public static class Server { - /** - * Jitsi Meet服务器地址 - */ - private String url = "https://meet.jit.si"; - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - } - - /** - * Token配置 - */ - public static class Token { - /** - * JWT Token有效期(毫秒)- 默认2小时 - */ - private Long expiration = 7200000L; - - public Long getExpiration() { - return expiration; - } - - public void setExpiration(Long expiration) { - this.expiration = expiration; - } - } -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/RedisSubscriberConfig.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/RedisSubscriberConfig.java deleted file mode 100644 index adf114ba..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/RedisSubscriberConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.xyzh.workcase.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.listener.PatternTopic; -import org.springframework.data.redis.listener.RedisMessageListenerContainer; - -import org.xyzh.api.workcase.constant.WorkcaseConstant; -import org.xyzh.workcase.listener.ChatMessageListener; - -/** - * @description Redis Pub/Sub订阅配置 - * @filename RedisSubscriberConfig.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Configuration -public class RedisSubscriberConfig { - - @Autowired - private ChatMessageListener chatMessageListener; - - @Bean - public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) { - RedisMessageListenerContainer container = new RedisMessageListenerContainer(); - container.setConnectionFactory(connectionFactory); - - // 订阅聊天室消息频道,使用通配符匹配所有聊天室 - // 频道格式: chat:room:* - container.addMessageListener(chatMessageListener, - new PatternTopic(WorkcaseConstant.REDIS_CHAT_PREFIX + "*")); - - // 订阅聊天室列表更新频道 - container.addMessageListener(chatMessageListener, - new PatternTopic(WorkcaseConstant.REDIS_CHAT_LIST_UPDATE)); - - return container; - } -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/WebSocketAuthInterceptor.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/WebSocketAuthInterceptor.java deleted file mode 100644 index 54de0987..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/WebSocketAuthInterceptor.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.xyzh.workcase.config; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.server.HandshakeInterceptor; -import org.xyzh.common.auth.contants.AuthContants; - -import java.util.Map; - -/** - * WebSocket握手拦截器 - * 从网关传递的请求头中获取已验证的用户信息 - */ -@Component -public class WebSocketAuthInterceptor implements HandshakeInterceptor { - - private static final Logger log = LoggerFactory.getLogger(WebSocketAuthInterceptor.class); - - @Override - public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler wsHandler, Map attributes) throws Exception { - - log.info("WebSocket握手开始,URI: {}", request.getURI()); - - try { - // 从网关传递的请求头中获取用户ID(网关已完成token验证) - String userId = extractUserIdFromRequest(request); - - if (!StringUtils.hasText(userId)) { - log.warn("WebSocket握手失败:请求头中未找到用户ID,网关认证可能失败"); - return false; - } - - // 可选:也获取token,供后续使用 - String token = extractTokenFromRequest(request); - - // 将用户信息存储到WebSocket会话属性中,供后续使用 - attributes.put("userId", userId); - if (StringUtils.hasText(token)) { - attributes.put("token", token); - } - - log.info("WebSocket握手成功,userId: {}", userId); - return true; - - } catch (Exception e) { - log.error("WebSocket握手异常", e); - return false; - } - } - - @Override - public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler wsHandler, Exception exception) { - if (exception != null) { - log.error("WebSocket握手后发生异常", exception); - } - } - - /** - * 从网关传递的请求头中提取用户ID - */ - private String extractUserIdFromRequest(ServerHttpRequest request) { - if (request instanceof ServletServerHttpRequest) { - ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; - - // 从网关传递的请求头获取(标准微服务架构方式) - String userId = servletRequest.getHeaders().getFirst(AuthContants.USER_ID_ATTRIBUTE); - if (StringUtils.hasText(userId)) { - log.debug("从网关请求头获取用户ID: {}", userId); - return userId; - } - } - - log.warn("未能从请求头中获取用户ID"); - return null; - } - - /** - * 从请求头中提取token(可选) - */ - private String extractTokenFromRequest(ServerHttpRequest request) { - if (request instanceof ServletServerHttpRequest) { - ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; - - // 从网关传递的请求头获取 - String token = servletRequest.getHeaders().getFirst(AuthContants.TOKEN_ATTRIBUTE); - if (StringUtils.hasText(token)) { - return token; - } - - // 也支持从Authorization头获取 - String authHeader = servletRequest.getHeaders().getFirst("Authorization"); - if (StringUtils.hasText(authHeader)) { - if (authHeader.startsWith("Bearer ")) { - return authHeader.substring(7); - } - return authHeader; - } - } - - return null; - } -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/WebSocketConfig.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/WebSocketConfig.java deleted file mode 100644 index 3e61548e..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/config/WebSocketConfig.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.xyzh.workcase.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; - -/** - * WebSocket配置类 - * 用于聊天室实时消息推送 - */ -@Configuration -@EnableWebSocketMessageBroker -public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Autowired - private WebSocketAuthInterceptor webSocketAuthInterceptor; - - @Override - public void configureMessageBroker(MessageBrokerRegistry config) { - // 配置消息代理 - // 客户端订阅路径前缀:/topic(广播)、/queue(点对点) - config.enableSimpleBroker("/topic", "/queue"); - - // 客户端发送消息路径前缀 - config.setApplicationDestinationPrefixes("/app"); - - // 点对点消息前缀 - config.setUserDestinationPrefix("/user"); - } - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // 原生WebSocket端点(不使用SockJS) - registry.addEndpoint("/workcase/ws/chat") - .setAllowedOriginPatterns("*") - .addInterceptors(webSocketAuthInterceptor); - - // SockJS端点(用于不支持WebSocket的浏览器降级) - registry.addEndpoint("/workcase/ws/chat-sockjs") - .setAllowedOriginPatterns("*") - .addInterceptors(webSocketAuthInterceptor) - .withSockJS(); - } -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseChatController.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseChatController.java deleted file mode 100644 index e96aec9b..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseChatController.java +++ /dev/null @@ -1,587 +0,0 @@ -package org.xyzh.workcase.controller; - -import jakarta.servlet.http.HttpServletRequest; -import java.util.Map; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.xyzh.api.workcase.dto.TbChatRoomDTO; -import org.xyzh.api.workcase.dto.TbChatRoomMemberDTO; -import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO; -import org.xyzh.api.workcase.dto.TbCustomerServiceDTO; -import org.xyzh.api.workcase.dto.TbVideoMeetingDTO; -import org.xyzh.api.workcase.dto.TbWordCloudDTO; -import org.xyzh.api.workcase.dto.ChatRoomSummaryRequest; -import org.xyzh.api.workcase.dto.ChatRoomSummaryResponse; -import org.xyzh.api.workcase.service.AgentService; -import org.xyzh.api.workcase.service.ChatRoomService; -import org.xyzh.api.workcase.service.WorkcaseChatService; -import org.xyzh.api.workcase.vo.ChatMemberVO; -import org.xyzh.api.workcase.vo.ChatRoomMessageVO; -import org.xyzh.api.workcase.vo.ChatRoomVO; -import org.xyzh.api.workcase.vo.CustomerServiceVO; -import org.xyzh.api.workcase.vo.VideoMeetingVO; -import org.xyzh.common.auth.utils.JwtTokenUtil; -import org.xyzh.common.auth.utils.LoginUtil; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.validation.ValidationParam; -import org.xyzh.common.utils.validation.ValidationResult; -import org.xyzh.common.utils.validation.ValidationUtils; - -import io.swagger.v3.oas.annotations.Operation; - -import java.util.Arrays; -import java.util.Date; -import java.util.Map; - -import io.swagger.v3.oas.annotations.tags.Tag; - -/** - * @description 工单对话控制器 - * - AI对话管理(智能问答) - * - ChatRoom聊天室管理(实时IM) - * - 微信客服消息接收 - * - 词云管理 - * @filename WorkcaseChatController.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Tag(name = "工单对话") -@Validated -@RestController -@RequestMapping("/workcase/chat") -public class WorkcaseChatController { - - @Autowired - private WorkcaseChatService workcaseChatService; - - @Autowired - private ChatRoomService chatRoomService; - - @Autowired - private AgentService agentService; - - @Autowired - private JwtTokenUtil jwtTokenUtil; - - // ========================= ChatRoom聊天室管理(实时IM) ========================= - - @Operation(summary = "创建聊天室(转人工时调用)") - @PreAuthorize("hasAuthority('workcase:room:create')") - @PostMapping("/room") - public ResultDomain createChatRoom(@RequestBody TbChatRoomDTO chatRoom) { - ValidationResult vr = ValidationUtils.validate(chatRoom, Arrays.asList( - ValidationUtils.requiredString("guestId", "来客ID"), - ValidationUtils.requiredString("deviceCode", "设备代码") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - chatRoom.setCreator(chatRoom.getGuestId()); - try { - return chatRoomService.createChatRoom(chatRoom); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - @Operation(summary = "更新聊天室") - @PreAuthorize("hasAuthority('workcase:room:update')") - @PutMapping("/room") - public ResultDomain updateChatRoom(@RequestBody TbChatRoomDTO chatRoom) { - ValidationResult vr = ValidationUtils.validate(chatRoom, Arrays.asList( - ValidationUtils.requiredString("roomId", "聊天室ID") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return chatRoomService.updateChatRoom(chatRoom); - } - - @Operation(summary = "关闭聊天室") - @PreAuthorize("hasAuthority('workcase:room:close')") - @PostMapping("/room/{roomId}/close") - public ResultDomain closeChatRoom(@PathVariable(value = "roomId") String roomId, @RequestParam String closedBy) { - return chatRoomService.closeChatRoom(roomId, closedBy); - } - - /** - * 提交聊天室服务评分 - * @param roomId 聊天室ID - * @param commentLevel 评分(1-5星) - * @return 提交结果 - */ - @Operation(summary = "提交聊天室服务评分") - @PreAuthorize("hasAuthority('workcase:room:view')") - @PostMapping("/room/{roomId}/comment") - public ResultDomain submitComment( - @PathVariable("roomId") String roomId, - @RequestBody Map body) { - - Integer commentLevel = body.get("commentLevel"); - if (commentLevel == null || commentLevel < 1 || commentLevel > 5) { - return ResultDomain.failure("评分必须在1-5之间"); - } - - // 获取当前登录用户ID - String userId = LoginUtil.getCurrentUserId(); - - // 调用服务层提交评分 - return chatRoomService.submitCommentLevel(roomId, commentLevel, userId); - } - - @Operation(summary = "获取聊天室详情") - @PreAuthorize("hasAuthority('workcase:room:view')") - @GetMapping("/room/{roomId}") - public ResultDomain getChatRoomById(@PathVariable(value = "roomId") String roomId) { - return chatRoomService.getChatRoomById(roomId); - } - - @Operation(summary = "分页查询聊天室") - @PreAuthorize("hasAuthority('workcase:room:view')") - @PostMapping("/room/page") - public ResultDomain getChatRoomPage( - @RequestBody PageRequest pageRequest) { - ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList( - ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null), - ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - String userId = loginDomain.getUser().getUserId(); - if("guest".equals(loginDomain.getUser().getStatus())){ - pageRequest.getFilter().setGuestId(userId); - } - return chatRoomService.getChatRoomPage(pageRequest, userId); - } - - @Operation(summary = "统计聊天室数量") - @PreAuthorize("hasAuthority('workcase:room:view')") - @PostMapping("/room/count") - public ResultDomain countChatRooms(@RequestBody TbChatRoomDTO filter) { - return chatRoomService.countChatRooms(filter); - } - - // ========================= ChatRoom成员管理 ========================= - - @Operation(summary = "添加聊天室成员") - @PreAuthorize("hasAuthority('workcase:room:member')") - @PostMapping("/room/member") - public ResultDomain addChatRoomMember(@RequestBody TbChatRoomMemberDTO member) { - ValidationResult vr = ValidationUtils.validate(member, Arrays.asList( - ValidationUtils.requiredString("roomId", "聊天室ID"), - ValidationUtils.requiredString("userId", "用户ID") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return chatRoomService.addChatRoomMember(member); - } - - @Operation(summary = "移除聊天室成员") - @PreAuthorize("hasAuthority('workcase:room:member')") - @DeleteMapping("/room/member/{memberId}") - public ResultDomain removeChatRoomMember(@PathVariable(value = "memberId") String memberId) { - return chatRoomService.removeChatRoomMember(memberId); - } - - @Operation(summary = "获取聊天室成员列表") - @PreAuthorize("hasAuthority('workcase:room:member')") - @GetMapping("/room/{roomId}/members") - public ResultDomain getChatRoomMemberList(@PathVariable(value = "roomId") String roomId) { - return chatRoomService.getChatRoomMemberList(roomId); - } - - @Operation(summary = "获取当前用户在指定聊天室的未读消息数") - @PreAuthorize("hasAuthority('workcase:room:member')") - @GetMapping("/room/{roomId}/unread") - public ResultDomain getUnreadCount( - @PathVariable(value = "roomId") String roomId, - @RequestParam(value = "userId") String userId) { - return chatRoomService.getUnreadCount(roomId, userId); - } - - // ========================= ChatRoom消息管理 ========================= - - @Operation(summary = "发送聊天室消息") - @PreAuthorize("hasAuthority('workcase:room:message')") - @PostMapping("/room/message") - public ResultDomain sendMessage(@RequestBody TbChatRoomMessageDTO message) { - ValidationResult vr = ValidationUtils.validate(message, Arrays.asList( - ValidationUtils.requiredString("roomId", "聊天室ID"), - ValidationUtils.requiredString("senderId", "发送者ID"), - ValidationUtils.requiredString("content", "消息内容"), - ValidationUtils.requiredString("senderName", "发送者名称") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return chatRoomService.sendMessage(message); - } - - @Operation(summary = "分页查询聊天室消息") - @PreAuthorize("hasAuthority('workcase:room:message')") - @PostMapping("/room/message/page") - public ResultDomain getChatMessagePage(@RequestBody PageRequest pageRequest) { - ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList( - ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null), - ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return chatRoomService.getChatMessagePage(pageRequest); - } - - @Operation(summary = "删除聊天室消息") - @PreAuthorize("hasAuthority('workcase:room:message')") - @DeleteMapping("/room/message/{messageId}") - public ResultDomain deleteRoomMessage(@PathVariable(value = "messageId") String messageId) { - return chatRoomService.deleteMessage(messageId); - } - - @Operation(summary = "获取聊天室最新总结") - @PreAuthorize("hasAuthority('workcase:room:view')") - @GetMapping("/room/{roomId}/summary") - public ResultDomain getLatestSummary(@PathVariable(value = "roomId") String roomId) { - return agentService.getLatestSummary(roomId); - } - - @Operation(summary = "生成聊天室对话总结") - @PreAuthorize("hasAuthority('workcase:room:view')") - @PostMapping("/room/{roomId}/summary") - public ResultDomain summaryChatRoom( - @PathVariable(value = "roomId") String roomId, - @RequestBody(required = false) ChatRoomSummaryRequest request) { - // 如果请求体为空,创建一个默认的请求对象 - if (request == null) { - request = new ChatRoomSummaryRequest(); - } - - // 设置聊天室ID - request.setRoomId(roomId); - - // 调用服务层进行总结 - return agentService.summaryChatRoom(request); - } - - // ========================= 客服人员管理 ========================= - - @Operation(summary = "添加客服人员") - @PostMapping("/customer-service") - public ResultDomain addCustomerService(@RequestBody TbCustomerServiceDTO customerService) { - ValidationResult vr = ValidationUtils.validate(customerService, Arrays.asList( - ValidationUtils.requiredString("userId", "员工ID") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return chatRoomService.addCustomerService(customerService); - } - - @Operation(summary = "更新客服人员") - @PutMapping("/customer-service") - public ResultDomain updateCustomerService(@RequestBody TbCustomerServiceDTO customerService) { - ValidationResult vr = ValidationUtils.validate(customerService, Arrays.asList( - ValidationUtils.requiredString("userId", "员工ID") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return chatRoomService.updateCustomerService(customerService); - } - - @Operation(summary = "删除客服人员") - @DeleteMapping("/customer-service/{userId}") - public ResultDomain deleteCustomerService(@PathVariable(value = "userId") String userId) { - return chatRoomService.deleteCustomerService(userId); - } - - @Operation(summary = "分页查询客服人员") - @PostMapping("/customer-service/page") - public ResultDomain getCustomerServicePage(@RequestBody PageRequest pageRequest) { - ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList( - ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null), - ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return chatRoomService.getCustomerServicePage(pageRequest); - } - - @Operation(summary = "更新客服在线状态") - @PostMapping("/customer-service/{userId}/status/{status}") - public ResultDomain updateCustomerServiceStatus(@PathVariable(value = "userId") String userId, @PathVariable(value = "status") String status) { - return chatRoomService.updateCustomerServiceStatus(userId, status); - } - - @Operation(summary = "获取可接待客服列表") - @GetMapping("/customer-service/available") - public ResultDomain getAvailableCustomerServices() { - return chatRoomService.getAvailableCustomerServices(); - } - - @Operation(summary = "自动分配客服") - @PostMapping("/room/{roomId}/assign") - public ResultDomain assignCustomerService(@PathVariable(value = "roomId") String roomId) { - return chatRoomService.assignCustomerService(roomId); - } - - // ========================= 视频会议管理(Jitsi Meet) ========================= - - @Autowired - private org.xyzh.api.workcase.service.VideoMeetingService videoMeetingService; - - @Operation(summary = "创建视频会议") - @PreAuthorize("hasAuthority('meeting:create:own')") - @PostMapping("/meeting/create") - public ResultDomain createVideoMeeting( - @RequestBody TbVideoMeetingDTO meetingDTO) { - ValidationResult vr = ValidationUtils.validate(meetingDTO, Arrays.asList( - ValidationUtils.requiredString("roomId", "聊天室ID"), - ValidationUtils.requiredString("meetingName", "会议名称"), - // 校验开始时间不为空 - ValidationParam.builder() - .fieldName("startTime") - .fieldLabel("会议开始时间") - .required() - .build(), - // 校验结束时间不为空 - ValidationParam.builder() - .fieldName("endTime") - .fieldLabel("会议结束时间") - .required() - .build(), - // 校验开始时间小于结束时间(使用 fieldCompare 比较两个字段) - ValidationUtils.fieldCompare( - "startTime", - "endTime", - "会议时间", - (startTime, endTime) -> { - if (startTime instanceof Date && endTime instanceof Date) { - return ((Date) startTime).before((Date) endTime); - } - return true; - }, - "会议开始时间不能晚于结束时间" - ) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - - try { - return videoMeetingService.createMeeting(meetingDTO); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - @Operation(summary = "获取会议信息") - @PreAuthorize("hasAuthority('meeting:url:any')") - @GetMapping("/meeting/{meetingId}") - public ResultDomain getMeetingInfo( - @PathVariable(value = "meetingId") String meetingId) { - String userId = LoginUtil.getCurrentUserId(); - - try { - return videoMeetingService.getMeetingInfo(meetingId, userId); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - @Operation(summary = "加入会议(生成用户专属JWT)") - @PreAuthorize("hasAuthority('meeting:join:any')") - @PostMapping("/meeting/{meetingId}/join") - public ResultDomain joinMeeting( - @PathVariable(value = "meetingId") String meetingId) { - String userId = LoginUtil.getCurrentUserId(); - - // 验证加入权限 - ResultDomain accessCheck = videoMeetingService.validateMeetingAccess(meetingId, userId); - if (!accessCheck.getSuccess() || !accessCheck.getData()) { - return ResultDomain.failure("您无权加入此会议"); - } - - // 生成用户专属的iframe URL(包含JWT Token) - try { - return videoMeetingService.generateUserMeetingUrl(meetingId, userId); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - @Operation(summary = "开始会议") - @PreAuthorize("hasAuthority('meeting:create:own')") - @PostMapping("/meeting/{meetingId}/start") - public ResultDomain startMeeting(@PathVariable(value = "meetingId") String meetingId) { - try { - return videoMeetingService.startMeeting(meetingId); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - @Operation(summary = "结束会议") - @PreAuthorize("hasAuthority('meeting:create:own')") - @PostMapping("/meeting/{meetingId}/end") - public ResultDomain endMeeting( - @PathVariable(value = "meetingId") String meetingId) { - try { - return videoMeetingService.endMeeting(meetingId); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - @Operation(summary = "获取聊天室当前活跃会议") - @PreAuthorize("hasAuthority('meeting:url:any')") - @GetMapping("/meeting/room/{roomId}/active") - public ResultDomain getActiveMeetingByRoom( - @PathVariable(value = "roomId") String roomId) { - try { - return videoMeetingService.getActiveMeetingByRoom(roomId); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - @Operation(summary = "会议入口(支持URL参数token认证,用于小程序和外部链接)") - @GetMapping("/meeting/{meetingId}/entry") - public ResultDomain getMeetingEntry( - @PathVariable(value = "meetingId") String meetingId, - @RequestParam(value = "token", required = false) String token, - HttpServletRequest request) { - // 优先从URL参数获取token,其次从Header获取 - if (token == null || token.trim().isEmpty()) { - token = request.getHeader("Authorization"); - } - - try { - return videoMeetingService.getMeetingEntryByToken(meetingId, token); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - @Operation(summary = "生成会议入口URL(用于分享给小程序用户)") - @PreAuthorize("hasAuthority('meeting:url:any')") - @GetMapping("/meeting/{meetingId}/share-url") - public ResultDomain generateMeetingShareUrl( - @PathVariable(value = "meetingId") String meetingId, - @RequestParam(value = "baseUrl", defaultValue = "") String baseUrl, - HttpServletRequest request) { - // 如果没有提供baseUrl,则从请求中构建 - if (baseUrl == null || baseUrl.trim().isEmpty()) { - String scheme = request.getScheme(); - String serverName = request.getServerName(); - int serverPort = request.getServerPort(); - String contextPath = request.getContextPath(); - - if ((scheme.equals("http") && serverPort == 80) || - (scheme.equals("https") && serverPort == 443)) { - baseUrl = scheme + "://" + serverName + contextPath + "/workcase"; - } else { - baseUrl = scheme + "://" + serverName + ":" + serverPort + contextPath + "/workcase"; - } - } - - try { - return videoMeetingService.generateMeetingEntryUrl(meetingId, baseUrl); - } catch (Exception e) { - return ResultDomain.failure(e.getMessage()); - } - } - - // ========================= 微信客服消息回调 ========================= - - // @Operation(summary = "微信客服消息回调验证(GET)") - // @GetMapping("/kefu/callback") - // public String kefuCallbackVerify( - // @RequestParam("msg_signature") String msgSignature, - // @RequestParam("timestamp") String timestamp, - // @RequestParam("nonce") String nonce, - // @RequestParam("echostr") String echostr) { - // // TODO: 验证签名并返回 echostr - // // 实际应使用微信提供的加解密工具验证 - // return echostr; - // } - - // @Operation(summary = "微信客服消息回调(POST)") - // @PostMapping("/kefu/callback") - // public String kefuCallback( - // @RequestParam("msg_signature") String msgSignature, - // @RequestParam("timestamp") String timestamp, - // @RequestParam("nonce") String nonce, - // @RequestBody String xmlBody) { - // // TODO: 解密消息,调用同步接口拉取消息 - // // 收到回调后,应调用 kefuMessageService.syncMessages() 拉取新消息 - // // 然后通过 processMessages() 处理消息 - // return "success"; - // } - - // ========================= 词云管理 ========================= - - @Operation(summary = "添加词云") - @PostMapping("/wordcloud") - public ResultDomain addWordCloud(@RequestBody TbWordCloudDTO wordCloud) { - ValidationResult vr = ValidationUtils.validate(wordCloud, Arrays.asList( - ValidationUtils.requiredString("word", "词语"), - ValidationUtils.requiredString("category", "分类") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseChatService.addWordCloud(wordCloud); - } - - @Operation(summary = "更新词云") - @PutMapping("/wordcloud") - public ResultDomain updateWordCloud(@RequestBody TbWordCloudDTO wordCloud) { - ValidationResult vr = ValidationUtils.validate(wordCloud, Arrays.asList( - ValidationUtils.requiredString("wordCloudId", "词云ID") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseChatService.updateWordCloud(wordCloud); - } - - @Operation(summary = "查询词云列表") - @PostMapping("/wordcloud/list") - public ResultDomain getWordCloudList(@RequestBody TbWordCloudDTO filter) { - return workcaseChatService.getWordCloudList(filter); - } - - @Operation(summary = "分页查询词云") - @PostMapping("/wordcloud/page") - public ResultDomain getWordCloudPage(@RequestBody PageRequest pageRequest) { - ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList( - ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null), - ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseChatService.getWordCloudPage(pageRequest); - } - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseController.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseController.java deleted file mode 100644 index 00c6a79e..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseController.java +++ /dev/null @@ -1,327 +0,0 @@ -package org.xyzh.workcase.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.xyzh.api.workcase.dto.TbWorkcaseDTO; -import org.xyzh.api.workcase.dto.TbWorkcaseDeviceDTO; -import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO; -import org.xyzh.api.workcase.service.WorkcaseService; -import org.xyzh.api.workcase.vo.WorkcaseProcessVO; -import org.xyzh.common.auth.utils.LoginUtil; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.validation.ValidationParam; -import org.xyzh.common.utils.validation.ValidationResult; -import org.xyzh.common.utils.validation.ValidationUtils; - -import com.alibaba.fastjson2.JSONObject; -import io.swagger.v3.oas.annotations.Operation; - -import java.util.Arrays; -import java.util.Date; - -import io.swagger.v3.oas.annotations.tags.Tag; - -/** - * @description 工单管理控制器 - * @filename WorkcaseController.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Tag(name = "工单管理") -@RestController -@RequestMapping("/workcase") -public class WorkcaseController { - - @Autowired - private WorkcaseService workcaseService; - - // ========================= 工单管理 ========================= - - @Operation(summary = "创建工单") - @PreAuthorize("hasAuthority('workcase:ticket:create')") - @PostMapping - public ResultDomain createWorkcase(@RequestBody TbWorkcaseDTO workcase) { - ValidationResult vr = ValidationUtils.validate(workcase, Arrays.asList( - ValidationUtils.requiredString("deviceNamePlate", "设备名称牌图片"), - ValidationUtils.requiredString("deviceCode", "设备代码"), - ValidationUtils.requiredString("type", "问题类型"), - ValidationUtils.requiredString("userId", "用户ID"), - ValidationUtils.requiredString("username", "用户名称") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - try{ - workcaseService.createWorkcase(workcase); - return ResultDomain.success("创建工单成功", workcase); - } catch (Exception e) { - if(e.getMessage().contains("tb_workcase_room_id_key")){ - return ResultDomain.failure("您已有未完成的工单,请勿重复提交"); - } - return ResultDomain.failure("创建工单失败: " + e.getMessage()); - } - } - - @Operation(summary = "更新工单") - @PreAuthorize("hasAuthority('workcase:ticket:update')") - @PutMapping - public ResultDomain updateWorkcase(@RequestBody TbWorkcaseDTO workcase) { - ValidationResult vr = ValidationUtils.validate(workcase, Arrays.asList( - ValidationUtils.requiredString("workcaseId", "工单ID") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.updateWorkcase(workcase); - } - - @Operation(summary = "删除工单") - @PreAuthorize("hasAuthority('workcase:ticket:update')") - @DeleteMapping("/{workcaseId}") - public ResultDomain deleteWorkcase(@PathVariable(value = "workcaseId") String workcaseId) { - TbWorkcaseDTO workcase = new TbWorkcaseDTO(); - workcase.setWorkcaseId(workcaseId); - return workcaseService.deleteWorkcase(workcase); - } - - @Operation(summary = "撤销工单") - @PreAuthorize("hasAuthority('workcase:ticket:update')") - @PostMapping("/revoke/{workcaseId}") - public ResultDomain revokeWorkcase(@PathVariable(value = "workcaseId") String workcaseId) { - // 创建撤销处理过程 - TbWorkcaseProcessDTO process = new TbWorkcaseProcessDTO(); - process.setWorkcaseId(workcaseId); - process.setAction("repeal"); - process.setMessage("用户撤销工单"); - return workcaseService.createWorkcaseProcess(process); - } - - @Operation(summary = "获取工单详情") - @PreAuthorize("hasAuthority('workcase:ticket:view')") - @GetMapping("/{workcaseId}") - public ResultDomain getWorkcaseById(@PathVariable(value = "workcaseId") String workcaseId) { - return workcaseService.getWorkcaseById(workcaseId); - } - - @Operation(summary = "查询工单列表") - @PreAuthorize("hasAuthority('workcase:ticket:view')") - @PostMapping("/list") - public ResultDomain getWorkcaseList(@RequestBody TbWorkcaseDTO filter) { - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if ("guest".equals(loginDomain.getUser().getStatus())) { - filter.setUserId(loginDomain.getUser().getUserId()); - } - return workcaseService.getWorkcaseList(filter); - } - - @Operation(summary = "分页查询工单") - @PreAuthorize("hasAuthority('workcase:ticket:view')") - @PostMapping("/page") - public ResultDomain getWorkcasePage(@RequestBody PageRequest pageRequest) { - ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList( - ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null), - ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.getWorkcasePage(pageRequest); - } - - @Operation(summary = "查询工单问题统计") - @PreAuthorize("hasAuthority('workcase:ticket:view')") - @PostMapping("/category/count") - public ResultDomain countWorkcasesByType(@RequestBody TbWorkcaseDTO workcase) { - ValidationResult vr = ValidationUtils.validate(workcase, Arrays.asList( - ValidationParam.builder() - .fieldName("startTime") - .fieldLabel("统计开始时间") - .required() - .build(), - // 校验结束时间不为空 - ValidationParam.builder() - .fieldName("endTime") - .fieldLabel("统计结束时间") - .required() - .build(), - // 校验开始时间小于结束时间(使用 fieldCompare 比较两个字段) - ValidationUtils.fieldCompare( - "startTime", - "endTime", - "统计时间", - (startTime, endTime) -> { - if (startTime instanceof Date && endTime instanceof Date) { - return ((Date) startTime).before((Date) endTime); - } - return true; - }, - "统计开始时间不能晚于结束时间" - ) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.countWorkcasesByType(workcase); - } - - @Operation(summary = "统计工单数量") - @PreAuthorize("hasAuthority('workcase:ticket:view')") - @PostMapping("/count") - public ResultDomain countWorkcases(@RequestBody TbWorkcaseDTO workcase) { - return workcaseService.countWorkcases(workcase); - } - - // ========================= CRM同步接口 ========================= - - @Operation(summary = "同步工单到CRM") - @PostMapping("/sync/crm") - public ResultDomain syncWorkcaseToCrm(@RequestBody TbWorkcaseDTO workcase) { - ValidationResult vr = ValidationUtils.validate(workcase, Arrays.asList( - ValidationUtils.requiredString("workcaseId", "工单ID") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.syncWorkcaseToCrm(workcase); - } - - @Operation(summary = "接收CRM工单更新(CRM回调)") - @PostMapping("/receive/crm") - public ResultDomain receiveWorkcaseFromCrm(@RequestBody String jsonBody) { - JSONObject json = JSONObject.parseObject(jsonBody); - return workcaseService.receiveWorkcaseFromCrm(json); - } - - // ========================= 工单处理过程 ========================= - - @Operation(summary = "创建工单处理过程") - @PreAuthorize("hasAuthority('workcase:ticket:process')") - @PostMapping("/process") - public ResultDomain createWorkcaseProcess(@RequestBody TbWorkcaseProcessDTO process) { - ValidationResult vr = ValidationUtils.validate(process, Arrays.asList( - ValidationUtils.requiredString("workcaseId", "工单ID"), - ValidationUtils.requiredString("action", "操作类型") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.createWorkcaseProcess(process); - } - - @Operation(summary = "更新工单处理过程") - @PreAuthorize("hasAuthority('workcase:ticket:process')") - @PutMapping("/process") - public ResultDomain updateWorkcaseProcess(@RequestBody TbWorkcaseProcessDTO process) { - ValidationResult vr = ValidationUtils.validate(process, Arrays.asList( - ValidationUtils.requiredString("processId", "处理过程ID") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.updateWorkcaseProcess(process); - } - - @Operation(summary = "删除工单处理过程") - @PreAuthorize("hasAuthority('workcase:ticket:process')") - @DeleteMapping("/process/{processId}") - public ResultDomain deleteWorkcaseProcess(@PathVariable(value = "processId") String processId) { - TbWorkcaseProcessDTO process = new TbWorkcaseProcessDTO(); - process.setProcessId(processId); - return workcaseService.deleteWorkcaseProcess(process); - } - - @Operation(summary = "查询工单处理过程列表") - @PreAuthorize("hasAuthority('workcase:ticket:process')") - @PostMapping("/process/list") - public ResultDomain getWorkcaseProcessList(@RequestBody TbWorkcaseProcessDTO filter) { - return workcaseService.getWorkcaseProcessList(filter); - } - - @Operation(summary = "分页查询工单处理过程") - @PreAuthorize("hasAuthority('workcase:ticket:process')") - @PostMapping("/process/page") - public ResultDomain getWorkcaseProcessPage(@RequestBody PageRequest pageRequest) { - ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList( - ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null), - ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.getWorkcaseProcessPage(pageRequest); - } - - // ========================= 工单设备管理 ========================= - - @Operation(summary = "创建工单设备") - @PreAuthorize("hasAuthority('workcase:ticket:device')") - @PostMapping("/device") - public ResultDomain createWorkcaseDevice(@RequestBody TbWorkcaseDeviceDTO device) { - ValidationResult vr = ValidationUtils.validate(device, Arrays.asList( - ValidationUtils.requiredString("workcaseId", "工单ID"), - ValidationUtils.requiredString("device", "设备名称") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.createWorkcaseDevice(device); - } - - @Operation(summary = "更新工单设备") - @PreAuthorize("hasAuthority('workcase:ticket:device')") - @PutMapping("/device") - public ResultDomain updateWorkcaseDevice(@RequestBody TbWorkcaseDeviceDTO device) { - ValidationResult vr = ValidationUtils.validate(device, Arrays.asList( - ValidationUtils.requiredString("workcaseId", "工单ID"), - ValidationUtils.requiredString("device", "设备名称") - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.updateWorkcaseDevice(device); - } - - @Operation(summary = "删除工单设备") - @PreAuthorize("hasAuthority('workcase:ticket:device')") - @DeleteMapping("/device/{workcaseId}/{device}") - public ResultDomain deleteWorkcaseDevice(@PathVariable(value = "workcaseId") String workcaseId, @PathVariable(value = "device") String device) { - TbWorkcaseDeviceDTO deviceDTO = new TbWorkcaseDeviceDTO(); - deviceDTO.setWorkcaseId(workcaseId); - deviceDTO.setDevice(device); - return workcaseService.deleteWorkcaseDevice(deviceDTO); - } - - @Operation(summary = "查询工单设备列表") - @PreAuthorize("hasAuthority('workcase:ticket:device')") - @PostMapping("/device/list") - public ResultDomain getWorkcaseDeviceList(@RequestBody TbWorkcaseDeviceDTO filter) { - return workcaseService.getWorkcaseDeviceList(filter); - } - - @Operation(summary = "分页查询工单设备") - @PreAuthorize("hasAuthority('workcase:ticket:device')") - @PostMapping("/device/page") - public ResultDomain getWorkcaseDevicePage(@RequestBody PageRequest pageRequest) { - ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList( - ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null), - ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100) - )); - if (!vr.isValid()) { - return ResultDomain.failure(vr.getAllErrors()); - } - return workcaseService.getWorkcaseDevicePage(pageRequest); - } - - // -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/enums/WorkcaseProcessAction.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/enums/WorkcaseProcessAction.java deleted file mode 100644 index 9df1ecc8..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/enums/WorkcaseProcessAction.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.xyzh.workcase.enums; - -public enum WorkcaseProcessAction { - CREATE("create", "创建"), - INFO("info", "记录"), - ASSIGN("assign","指派"), - REDEPLOY("redeploy", "转派"), - REPEAL("repeal", "撤销"), - FINISH("finish", "完成"); - - private String name; - private String description; - - WorkcaseProcessAction(String name, String description){ - this.name = name; - this.description = description; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/listener/ChatMessageListener.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/listener/ChatMessageListener.java deleted file mode 100644 index 1766832b..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/listener/ChatMessageListener.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.xyzh.workcase.listener; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.connection.Message; -import org.springframework.data.redis.connection.MessageListener; -import org.springframework.messaging.simp.SimpMessagingTemplate; -import org.springframework.stereotype.Component; - -import com.alibaba.fastjson2.JSON; - -import org.xyzh.api.workcase.constant.WorkcaseConstant; -import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO; -import org.xyzh.api.workcase.vo.ChatRoomMessageVO; -import org.xyzh.workcase.mapper.TbChatMessageMapper; - -/** - * @description 聊天消息Redis监听器,接收Pub/Sub消息并通过STOMP转发到WebSocket客户端 - * @filename ChatMessageListener.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Component -public class ChatMessageListener implements MessageListener { - private static final Logger logger = LoggerFactory.getLogger(ChatMessageListener.class); - - @Autowired(required = false) - private SimpMessagingTemplate messagingTemplate; - - @Autowired - private TbChatMessageMapper chatMessageMapper; - - @Override - public void onMessage(Message message, byte[] pattern) { - try { - String channel = new String(message.getChannel()); - String body = new String(message.getBody()); - - logger.debug("收到Redis消息: channel={}", channel); - - // 反序列化消息 - TbChatRoomMessageDTO chatMessage = JSON.parseObject(body, TbChatRoomMessageDTO.class); - - if (messagingTemplate == null) { - logger.warn("SimpMessagingTemplate未初始化,无法转发消息"); - return; - } - - // 处理聊天室消息频道: chat:room:{roomId} - if (channel.startsWith(WorkcaseConstant.REDIS_CHAT_PREFIX)) { - String roomId = channel.substring(WorkcaseConstant.REDIS_CHAT_PREFIX.length()); - - // 查询完整的VO数据(包含senderAvatar等额外字段) - ChatRoomMessageVO messageVO = chatMessageMapper.selectChatMessageVOById(chatMessage.getMessageId()); - if (messageVO != null) { - // 转发完整VO到聊天窗口订阅者 - messagingTemplate.convertAndSend("/topic/chat/" + roomId, messageVO); - logger.debug("消息已转发到STOMP: /topic/chat/{}", roomId); - } else { - logger.warn("未找到消息VO: messageId={}", chatMessage.getMessageId()); - } - } - // 处理列表更新频道: chat:list:update - else if (WorkcaseConstant.REDIS_CHAT_LIST_UPDATE.equals(channel)) { - // 转发到聊天室列表订阅者,前端刷新列表状态 - messagingTemplate.convertAndSend("/topic/chat/list-update", chatMessage); - logger.debug("列表更新已转发到STOMP: /topic/chat/list-update"); - - // 同时转发到对应聊天室频道,确保聊天窗口也能收到消息 - String roomId = chatMessage.getRoomId(); - if (roomId != null && !roomId.isEmpty()) { - // 查询完整的VO数据 - ChatRoomMessageVO messageVO = chatMessageMapper.selectChatMessageVOById(chatMessage.getMessageId()); - if (messageVO != null) { - messagingTemplate.convertAndSend("/topic/chat/" + roomId, messageVO); - logger.debug("列表更新消息同时转发到聊天室: /topic/chat/{}", roomId); - } else { - // 如果查不到VO(可能事务未提交),直接用DTO转发 - logger.warn("未找到消息VO,使用DTO转发: messageId={}", chatMessage.getMessageId()); - messagingTemplate.convertAndSend("/topic/chat/" + roomId, chatMessage); - } - } - } - } catch (Exception e) { - logger.error("处理Redis消息失败", e); - } - } -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatMessageMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatMessageMapper.java deleted file mode 100644 index dcbded3b..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatMessageMapper.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO; -import org.xyzh.api.workcase.vo.ChatRoomMessageVO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 聊天消息数据访问层 - * @filename TbChatMessageMapper.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Mapper -public interface TbChatMessageMapper { - - /** - * 插入聊天消息 - */ - int insertChatMessage(TbChatRoomMessageDTO message); - - /** - * 更新聊天消息(只更新非null字段) - */ - int updateChatMessage(TbChatRoomMessageDTO message); - - /** - * 删除聊天消息 - */ - int deleteChatMessage(TbChatRoomMessageDTO message); - - /** - * 根据ID查询聊天消息 - */ - TbChatRoomMessageDTO selectChatMessageById(@Param("messageId") String messageId); - - /** - * 查询聊天消息列表 - */ - List selectChatMessageList(@Param("filter") TbChatRoomMessageDTO filter); - - /** - * 分页查询聊天消息 - */ - List selectChatMessagePage(@Param("filter") TbChatRoomMessageDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计聊天消息数量 - */ - long countChatMessages(@Param("filter") TbChatRoomMessageDTO filter); - - /** - * 根据消息ID查询完整VO - */ - ChatRoomMessageVO selectChatMessageVOById(@Param("messageId") String messageId); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomMapper.java deleted file mode 100644 index 78275944..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomMapper.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbChatRoomDTO; -import org.xyzh.api.workcase.vo.ChatRoomVO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 聊天室数据访问层 - * @filename TbChatRoomMapper.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Mapper -public interface TbChatRoomMapper { - - /** - * 插入聊天室 - */ - int insertChatRoom(TbChatRoomDTO chatRoom); - - /** - * 更新聊天室(只更新非null字段) - */ - int updateChatRoom(TbChatRoomDTO chatRoom); - - /** - * 逻辑删除聊天室 - */ - int deleteChatRoom(TbChatRoomDTO chatRoom); - - /** - * 根据ID查询聊天室 - */ - TbChatRoomDTO selectChatRoomById(@Param("roomId") String roomId); - - /** - * 查询聊天室列表 - */ - List selectChatRoomList(@Param("filter") TbChatRoomDTO filter); - - /** - * 分页查询聊天室(含未读数) - */ - List selectChatRoomPage(@Param("filter") TbChatRoomDTO filter, @Param("pageParam") PageParam pageParam, @Param("userId") String userId); - - /** - * 统计聊天室数量 - */ - long countChatRooms(@Param("filter") TbChatRoomDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomMemberMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomMemberMapper.java deleted file mode 100644 index 35314117..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomMemberMapper.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbChatRoomMemberDTO; -import org.xyzh.api.workcase.vo.ChatMemberVO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 聊天室成员数据访问层 - * @filename TbChatRoomMemberMapper.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Mapper -public interface TbChatRoomMemberMapper { - - /** - * 插入聊天室成员 - */ - int insertChatRoomMember(TbChatRoomMemberDTO member); - - /** - * 更新聊天室成员(只更新非null字段) - */ - int updateChatRoomMember(TbChatRoomMemberDTO member); - - /** - * 删除聊天室成员 - */ - int deleteChatRoomMember(TbChatRoomMemberDTO member); - - /** - * 根据ID查询聊天室成员 - */ - TbChatRoomMemberDTO selectChatRoomMemberById(@Param("memberId") String memberId); - - /** - * 查询聊天室成员列表 - */ - List selectChatRoomMemberList(@Param("filter") TbChatRoomMemberDTO filter); - - /** - * 分页查询聊天室成员 - */ - List selectChatRoomMemberPage(@Param("filter") TbChatRoomMemberDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计聊天室成员数量 - */ - long countChatRoomMembers(@Param("filter") TbChatRoomMemberDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomSummaryMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomSummaryMapper.java deleted file mode 100644 index 40e2b20a..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbChatRoomSummaryMapper.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbChatRoomSummaryDTO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 聊天室总结数据访问层 - * @filename TbChatRoomSummaryMapper.java - * @author system - * @copyright xyzh - * @since 2026-01-01 - */ -@Mapper -public interface TbChatRoomSummaryMapper { - - /** - * 插入聊天室总结 - */ - int insertChatRoomSummary(TbChatRoomSummaryDTO summary); - - /** - * 更新聊天室总结(只更新非null字段) - */ - int updateChatRoomSummary(TbChatRoomSummaryDTO summary); - - /** - * 根据ID查询聊天室总结 - */ - TbChatRoomSummaryDTO selectChatRoomSummaryById(@Param("summaryId") String summaryId); - - /** - * 根据聊天室ID查询最新一条总结 - */ - TbChatRoomSummaryDTO selectLatestSummaryByRoomId(@Param("roomId") String roomId); - - /** - * 查询聊天室总结列表 - */ - List selectChatRoomSummaryList(@Param("filter") TbChatRoomSummaryDTO filter); - - /** - * 分页查询聊天室总结 - */ - List selectChatRoomSummaryPage(@Param("filter") TbChatRoomSummaryDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计聊天室总结数量 - */ - long countChatRoomSummaries(@Param("filter") TbChatRoomSummaryDTO filter); - - /** - * 删除聊天室总结(逻辑删除) - */ - int deleteChatRoomSummary(@Param("summaryId") String summaryId); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbCustomerServiceMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbCustomerServiceMapper.java deleted file mode 100644 index 17a3c6dd..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbCustomerServiceMapper.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbCustomerServiceDTO; -import org.xyzh.api.workcase.vo.CustomerServiceVO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 客服人员配置数据访问层 - * @filename TbCustomerServiceMapper.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Mapper -public interface TbCustomerServiceMapper { - - /** - * 插入客服人员配置 - */ - int insertCustomerService(TbCustomerServiceDTO customerService); - - /** - * 更新客服人员配置(只更新非null字段) - */ - int updateCustomerService(TbCustomerServiceDTO customerService); - - /** - * 逻辑删除客服人员配置 - */ - int deleteCustomerService(TbCustomerServiceDTO customerService); - - /** - * 根据ID查询客服人员配置 - */ - TbCustomerServiceDTO selectCustomerServiceById(@Param("userId") String userId); - - /** - * 查询客服人员配置列表 - */ - List selectCustomerServiceList(@Param("filter") TbCustomerServiceDTO filter); - - /** - * 分页查询客服人员配置 - */ - List selectCustomerServicePage(@Param("filter") TbCustomerServiceDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计客服人员配置数量 - */ - long countCustomerServices(@Param("filter") TbCustomerServiceDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbMeetingParticipantMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbMeetingParticipantMapper.java deleted file mode 100644 index ed1c3ae3..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbMeetingParticipantMapper.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbMeetingParticipantDTO; -import org.xyzh.api.workcase.vo.MeetingParticipantVO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 会议参与记录数据访问层 - * @filename TbMeetingParticipantMapper.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Mapper -public interface TbMeetingParticipantMapper { - - /** - * 插入会议参与记录 - */ - int insertMeetingParticipant(TbMeetingParticipantDTO participant); - - /** - * 更新会议参与记录(只更新非null字段) - */ - int updateMeetingParticipant(TbMeetingParticipantDTO participant); - - /** - * 删除会议参与记录 - */ - int deleteMeetingParticipant(TbMeetingParticipantDTO participant); - - /** - * 根据ID查询会议参与记录 - */ - TbMeetingParticipantDTO selectMeetingParticipantById(@Param("participantId") String participantId); - - /** - * 查询会议参与记录列表 - */ - List selectMeetingParticipantList(@Param("filter") TbMeetingParticipantDTO filter); - - /** - * 分页查询会议参与记录 - */ - List selectMeetingParticipantPage(@Param("filter") TbMeetingParticipantDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计会议参与记录数量 - */ - long countMeetingParticipants(@Param("filter") TbMeetingParticipantDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbMeetingTranscriptionMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbMeetingTranscriptionMapper.java deleted file mode 100644 index 00128631..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbMeetingTranscriptionMapper.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbMeetingTranscriptionDTO; -import org.xyzh.api.workcase.vo.MeetingTranscriptionVO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 会议转录记录数据访问层 - * @filename TbMeetingTranscriptionMapper.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Mapper -public interface TbMeetingTranscriptionMapper { - - /** - * 插入会议转录记录 - */ - int insertMeetingTranscription(TbMeetingTranscriptionDTO transcription); - - /** - * 更新会议转录记录(只更新非null字段) - */ - int updateMeetingTranscription(TbMeetingTranscriptionDTO transcription); - - /** - * 删除会议转录记录 - */ - int deleteMeetingTranscription(TbMeetingTranscriptionDTO transcription); - - /** - * 根据ID查询会议转录记录 - */ - TbMeetingTranscriptionDTO selectMeetingTranscriptionById(@Param("transcriptionId") String transcriptionId); - - /** - * 查询会议转录记录列表 - */ - List selectMeetingTranscriptionList(@Param("filter") TbMeetingTranscriptionDTO filter); - - /** - * 分页查询会议转录记录 - */ - List selectMeetingTranscriptionPage(@Param("filter") TbMeetingTranscriptionDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计会议转录记录数量 - */ - long countMeetingTranscriptions(@Param("filter") TbMeetingTranscriptionDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbVideoMeetingMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbVideoMeetingMapper.java deleted file mode 100644 index b228fdd0..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbVideoMeetingMapper.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbVideoMeetingDTO; -import org.xyzh.api.workcase.vo.VideoMeetingVO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 视频会议数据访问层 - * @filename TbVideoMeetingMapper.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@Mapper -public interface TbVideoMeetingMapper { - - /** - * 插入视频会议 - */ - int insertVideoMeeting(TbVideoMeetingDTO meeting); - - /** - * 更新视频会议(只更新非null字段) - */ - int updateVideoMeeting(TbVideoMeetingDTO meeting); - - /** - * 逻辑删除视频会议 - */ - int deleteVideoMeeting(TbVideoMeetingDTO meeting); - - /** - * 根据ID查询视频会议 - */ - TbVideoMeetingDTO selectVideoMeetingById(@Param("meetingId") String meetingId); - - /** - * 查询视频会议列表 - */ - List selectVideoMeetingList(@Param("filter") TbVideoMeetingDTO filter); - - /** - * 分页查询视频会议 - */ - List selectVideoMeetingPage(@Param("filter") TbVideoMeetingDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计视频会议数量 - */ - long countVideoMeetings(@Param("filter") TbVideoMeetingDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWordCloudMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWordCloudMapper.java deleted file mode 100644 index 544879d6..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWordCloudMapper.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbWordCloudDTO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 词云数据访问层 - * @filename TbWordCloudMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -@Mapper -public interface TbWordCloudMapper { - - /** - * 插入词云 - */ - int insertWordCloud(TbWordCloudDTO wordCloud); - - /** - * 更新词云(只更新非null字段) - */ - int updateWordCloud(TbWordCloudDTO wordCloud); - - /** - * 根据ID查询词云 - */ - TbWordCloudDTO selectWordCloudById(@Param("wordId") String wordId); - - /** - * 查询单条词云(用于更新词频等场景) - */ - TbWordCloudDTO selectWordCloudOne(@Param("filter") TbWordCloudDTO filter); - - /** - * 查询词云列表 - */ - List selectWordCloudList(@Param("filter") TbWordCloudDTO filter); - - /** - * 分页查询词云 - */ - List selectWordCloudPage(@Param("filter") TbWordCloudDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计词云数量 - */ - long countWordClouds(@Param("filter") TbWordCloudDTO filter); - - /** - * 增加词频 - */ - int incrementFrequency(@Param("wordId") String wordId, @Param("count") int count); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseDeviceMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseDeviceMapper.java deleted file mode 100644 index 16cdf48c..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseDeviceMapper.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbWorkcaseDeviceDTO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 工单设备文件数据访问层 - * @filename TbWorkcaseDeviceMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Mapper -public interface TbWorkcaseDeviceMapper { - - /** - * 插入工单设备文件 - */ - int insertWorkcaseDevice(TbWorkcaseDeviceDTO device); - - /** - * 更新工单设备文件(只更新非null字段) - */ - int updateWorkcaseDevice(TbWorkcaseDeviceDTO device); - - /** - * 删除工单设备文件 - */ - int deleteWorkcaseDevice(@Param("workcaseId") String workcaseId, @Param("fileId") String fileId); - - /** - * 根据工单ID和文件ID查询 - */ - TbWorkcaseDeviceDTO selectWorkcaseDeviceById(@Param("workcaseId") String workcaseId, @Param("fileId") String fileId); - - /** - * 查询工单设备文件列表 - */ - List selectWorkcaseDeviceList(@Param("filter") TbWorkcaseDeviceDTO filter); - - /** - * 分页查询工单设备文件 - */ - List selectWorkcaseDevicePage(@Param("filter") TbWorkcaseDeviceDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计工单设备文件数量 - */ - long countWorkcaseDevices(@Param("filter") TbWorkcaseDeviceDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseMapper.java deleted file mode 100644 index 9e52ab0b..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseMapper.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbWorkcaseDTO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 工单数据访问层 - * @filename TbWorkcaseMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Mapper -public interface TbWorkcaseMapper { - - /** - * 插入工单 - */ - int insertWorkcase(TbWorkcaseDTO workcase); - - /** - * 更新工单(只更新非null字段) - */ - int updateWorkcase(TbWorkcaseDTO workcase); - - /** - * 逻辑删除工单 - */ - int deleteWorkcase(TbWorkcaseDTO workcase); - - /** - * 根据ID查询工单 - */ - TbWorkcaseDTO selectWorkcaseById(@Param("workcaseId") String workcaseId); - - /** - * 查询工单列表 - */ - List selectWorkcaseList(@Param("filter") TbWorkcaseDTO filter); - - /** - * 分页查询工单 - */ - List selectWorkcasePage(@Param("filter") TbWorkcaseDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计工单数量 - */ - long countWorkcases(@Param("filter") TbWorkcaseDTO filter); - - List countWorkcasesByType(@Param("filter") TbWorkcaseDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseProcessMapper.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseProcessMapper.java deleted file mode 100644 index 6ddaa0ad..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/mapper/TbWorkcaseProcessMapper.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xyzh.workcase.mapper; - -import java.util.List; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO; -import org.xyzh.api.workcase.vo.WorkcaseProcessVO; -import org.xyzh.common.core.page.PageParam; - -/** - * @description 工单过程数据访问层 - * @filename TbWorkcaseProcessMapper.java - * @author yslg - * @copyright xyzh - * @since 2025-12-18 - */ -@Mapper -public interface TbWorkcaseProcessMapper { - - /** - * 插入工单过程 - */ - int insertWorkcaseProcess(TbWorkcaseProcessDTO process); - - /** - * 更新工单过程(只更新非null字段) - */ - int updateWorkcaseProcess(TbWorkcaseProcessDTO process); - - /** - * 删除工单过程 - */ - int deleteWorkcaseProcess(@Param("processId") String processId); - - /** - * 根据ID查询工单过程 - */ - TbWorkcaseProcessDTO selectWorkcaseProcessById(@Param("processId") String processId); - - /** - * 查询工单过程列表 - */ - List selectWorkcaseProcessList(@Param("filter") TbWorkcaseProcessDTO filter); - - /** - * 分页查询工单过程 - */ - List selectWorkcaseProcessPage(@Param("filter") TbWorkcaseProcessDTO filter, @Param("pageParam") PageParam pageParam); - - /** - * 统计工单过程数量 - */ - long countWorkcaseProcesses(@Param("filter") TbWorkcaseProcessDTO filter); - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/AgentServiceImpl.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/AgentServiceImpl.java deleted file mode 100644 index a2139efc..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/AgentServiceImpl.java +++ /dev/null @@ -1,355 +0,0 @@ -package org.xyzh.workcase.service; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; - -import org.xyzh.api.ai.dto.ChatPrepareData; -import org.xyzh.api.ai.dto.TbAgent; -import org.xyzh.api.ai.service.AgentChatService; -import org.xyzh.api.system.service.SysConfigService; -import org.xyzh.api.workcase.dto.ChatRoomSummaryRequest; -import org.xyzh.api.workcase.dto.ChatRoomSummaryResponse; -import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO; -import org.xyzh.api.workcase.dto.TbChatRoomSummaryDTO; -import org.xyzh.api.workcase.dto.TbWordCloudDTO; -import org.xyzh.api.workcase.service.AgentService; -import org.xyzh.api.workcase.vo.ChatRoomMessageVO; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.workcase.mapper.TbChatMessageMapper; -import org.xyzh.workcase.mapper.TbChatRoomSummaryMapper; -import org.xyzh.workcase.mapper.TbWordCloudMapper; - -/** - * @description 智能体服务实现类,提供AI相关的业务功能 - * @filename AgentServiceImpl.java - * @author system - * @copyright xyzh - * @since 2026-01-01 - */ -@DubboService(version = "1.0.0", group = "workcase", timeout = 30000, retries = 0) -public class AgentServiceImpl implements AgentService { - private static final Logger logger = LoggerFactory.getLogger(AgentServiceImpl.class); - - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - - // 系统配置键名 - private static final String CONFIG_KEY_SUMMARY_API = "dify.workcase.workflow.summary"; - - @Autowired - private TbChatMessageMapper chatMessageMapper; - - @Autowired - private TbWordCloudMapper wordCloudMapper; - - @Autowired - private TbChatRoomSummaryMapper chatRoomSummaryMapper; - - @DubboReference(version = "1.0.0", group = "system", timeout = 30000, retries = 0) - private SysConfigService sysConfigService; - - @DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0) - private org.xyzh.api.ai.service.AgentService aiAgentService; - - @DubboReference(version = "1.0.0", group = "ai", timeout = 60000, retries = 0) - private AgentChatService agentChatService; - - @Override - public ResultDomain summaryChatRoom(ChatRoomSummaryRequest request) { - try { - logger.info("开始总结聊天室: roomId={}", request.getRoomId()); - - // 1. 从系统配置获取API Key - String apiKey = sysConfigService.getStringConfig(CONFIG_KEY_SUMMARY_API); - if (apiKey == null || apiKey.isEmpty()) { - logger.error("未配置聊天室总结工作流的API Key: {}", CONFIG_KEY_SUMMARY_API); - return ResultDomain.failure("系统未配置聊天室总结功能"); - } - - // 2. 根据API Key查询对应的Agent - TbAgent agentFilter = new TbAgent(); - agentFilter.setApiKey(apiKey); - ResultDomain agentResult = aiAgentService.getAgentList(agentFilter); - if (!agentResult.getSuccess() || agentResult.getDataList() == null || agentResult.getDataList().isEmpty()) { - logger.error("未找到API Key对应的智能体: {}", apiKey); - return ResultDomain.failure("未找到对应的智能体配置"); - } - - TbAgent agent = agentResult.getDataList().get(0); - logger.info("找到智能体: agentId={}, name={}", agent.getAgentId(), agent.getName()); - - // 3. 获取聊天室的所有消息 - TbChatRoomMessageDTO filter = new TbChatRoomMessageDTO(); - filter.setRoomId(request.getRoomId()); - - List messages = chatMessageMapper.selectChatMessageList(filter); - if (messages == null || messages.isEmpty()) { - return ResultDomain.failure("聊天室没有消息"); - } - - // 4. 过滤消息(根据请求参数) - List> filteredMessages = new ArrayList<>(); - for (ChatRoomMessageVO message : messages) { - String messageType = message.getMessageType(); - - // 根据请求参数决定是否包含系统消息和会议消息 - boolean shouldInclude = true; - if ("system".equals(messageType) && !Boolean.TRUE.equals(request.getIncludeSystemMessages())) { - shouldInclude = false; - } - if ("meeting".equals(messageType) && !Boolean.TRUE.equals(request.getIncludeMeetingMessages())) { - shouldInclude = false; - } - - if (shouldInclude) { - Map msgMap = new HashMap<>(); - msgMap.put("senderType", message.getSenderType()); // guest/ai/agent - msgMap.put("content", message.getContent()); - msgMap.put("send_time", DATE_FORMAT.format(message.getSendTime())); - filteredMessages.add(msgMap); - } - } - - if (filteredMessages.isEmpty()) { - return ResultDomain.failure("聊天室没有有效的对话消息"); - } - - logger.info("聊天室 {} 共有 {} 条有效消息", request.getRoomId(), filteredMessages.size()); - - // 5. 将消息列表转换为JSON字符串 - String chatMessagesJson = JSON.toJSONString(filteredMessages); - - // 6. 准备调用工作流的参数 - ChatPrepareData prepareData = new ChatPrepareData(); - prepareData.setAgentId(agent.getAgentId()); - prepareData.setQuery("总结聊天内容"); - prepareData.setUserId("system_summary"); - prepareData.setUserType(true); // 作为员工身份调用 - prepareData.setAppType("workflow"); // 设置为workflow类型 - - // 7. 设置工作流的输入参数 - Map inputsMap = new HashMap<>(); - inputsMap.put("chatMessages", chatMessagesJson); // 工作流期望的输入参数名 - prepareData.setInputsMap(inputsMap); - - logger.info("准备工作流会话,输入参数: chatMessages长度={}", chatMessagesJson.length()); - - // 8. 调用准备会话 - ResultDomain prepareResult = agentChatService.prepareChatMessageSession(prepareData); - if (!prepareResult.getSuccess()) { - logger.error("准备工作流会话失败: {}", prepareResult.getMessage()); - return ResultDomain.failure("准备会话失败: " + prepareResult.getMessage()); - } - - String sessionId = prepareResult.getData(); - logger.info("工作流会话准备成功: sessionId={}", sessionId); - - // 9. 调用工作流执行,获取完整结果 - ResultDomain workflowResult = agentChatService.runWorkflowWithSession(sessionId); - if (!workflowResult.getSuccess()) { - logger.error("工作流执行失败: {}", workflowResult.getMessage()); - return ResultDomain.failure("总结失败: " + workflowResult.getMessage()); - } - - String outputsJson = workflowResult.getData(); - logger.debug("工作流返回结果: {}", outputsJson); - - // 10. 解析工作流返回的outputs(JSON格式) - JSONObject outputsObject; - try { - outputsObject = JSON.parseObject(outputsJson); - } catch (Exception e) { - logger.error("解析工作流输出失败: {}", outputsJson, e); - return ResultDomain.failure("工作流输出格式错误"); - } - - // 11. 从outputs中获取text字段(工作流的输出节点) - String text = outputsObject.getString("text"); - if (text == null || text.isEmpty()) { - logger.error("工作流输出中没有text字段: {}", outputsJson); - return ResultDomain.failure("工作流输出缺少text字段"); - } - - // 12. 解析text中的JSON结果 - JSONObject resultJson; - try { - resultJson = JSON.parseObject(text); - } catch (Exception e) { - logger.error("解析工作流text字段失败: {}", text, e); - return ResultDomain.failure("工作流返回结果格式错误"); - } - - // 13. 构建响应对象 - ChatRoomSummaryResponse response = new ChatRoomSummaryResponse(); - response.setRoomId(request.getRoomId()); - response.setQuestion(resultJson.getString("question")); - - // 安全获取needs数组 - List needs = resultJson.getList("needs", String.class); - response.setNeeds(needs != null ? needs : new ArrayList<>()); - - response.setAnswer(resultJson.getString("answer")); - - // 安全获取workcloud数组 - List workcloud = resultJson.getList("workcloud", String.class); - response.setWorkcloud(workcloud != null ? workcloud : new ArrayList<>()); - - response.setSummaryTime(DATE_FORMAT.format(new java.util.Date())); - response.setMessageCount(filteredMessages.size()); - - // 14. 保存词云数据到数据库 - if (workcloud != null && !workcloud.isEmpty()) { - saveWordCloudData(request.getRoomId(), workcloud); - } - - // 15. 保存总结数据到数据库 - saveChatRoomSummary(request.getRoomId(), resultJson, filteredMessages.size()); - - logger.info("聊天室总结完成: roomId={}, question={}, wordcloud数量={}", - request.getRoomId(), response.getQuestion(), workcloud != null ? workcloud.size() : 0); - - return ResultDomain.success("总结成功", response); - - } catch (Exception e) { - logger.error("总结聊天室异常: roomId={}", request.getRoomId(), e); - return ResultDomain.failure("总结失败: " + e.getMessage()); - } - } - - /** - * 保存词云数据到数据库 - * @param roomId 聊天室ID - * @param wordList 词云关键词列表 - */ - private void saveWordCloudData(String roomId, List wordList) { - try { - String today = new SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date()); - - for (String word : wordList) { - if (word == null || word.trim().isEmpty()) { - continue; - } - - // 查询是否已存在该词条(同一天、同一分类) - TbWordCloudDTO filter = new TbWordCloudDTO(); - filter.setWord(word.trim()); - filter.setCategory("chatroom_summary"); // 分类:聊天室总结 - filter.setStatDate(today); - - TbWordCloudDTO existing = wordCloudMapper.selectWordCloudOne(filter); - - if (existing != null) { - // 已存在,增加词频 - wordCloudMapper.incrementFrequency(existing.getWordId(), 1); - logger.debug("词云词频递增: word={}, wordId={}", word, existing.getWordId()); - } else { - // 不存在,插入新词条 - TbWordCloudDTO newWord = new TbWordCloudDTO(); - newWord.setWordId(IdUtil.getSnowflakeId()); - newWord.setOptsn(IdUtil.getOptsn()); - newWord.setWord(word.trim()); - newWord.setFrequency("1"); - newWord.setCategory("chatroom_summary"); - newWord.setStatDate(today); - - wordCloudMapper.insertWordCloud(newWord); - logger.debug("插入新词云: word={}, wordId={}", word, newWord.getWordId()); - } - } - - logger.info("词云数据保存完成: roomId={}, 词条数量={}", roomId, wordList.size()); - } catch (Exception e) { - logger.error("保存词云数据失败: roomId={}", roomId, e); - // 词云保存失败不影响总结流程,仅记录日志 - } - } - - /** - * 保存聊天室总结数据到数据库 - * @param roomId 聊天室ID - * @param resultJson 工作流返回的JSON结果 - * @param messageCount 参与总结的消息数量 - */ - private void saveChatRoomSummary(String roomId, JSONObject resultJson, int messageCount) { - try { - TbChatRoomSummaryDTO summary = new TbChatRoomSummaryDTO(); - summary.setSummaryId(IdUtil.getSnowflakeId()); - summary.setOptsn(IdUtil.getOptsn()); - summary.setRoomId(roomId); - summary.setQuestion(resultJson.getString("question")); - - // 获取needs数组并转换为String[] - List needsList = resultJson.getList("needs", String.class); - if (needsList != null && !needsList.isEmpty()) { - summary.setNeeds(needsList); - } else { - summary.setNeeds(new ArrayList<>()); - } - - summary.setAnswer(resultJson.getString("answer")); - - // 获取workcloud数组并转换为String[] - List workcloudList = resultJson.getList("workcloud", String.class); - if (workcloudList != null && !workcloudList.isEmpty()) { - summary.setWorkcloud(workcloudList); - } else { - summary.setWorkcloud(new ArrayList<>()); - } - - summary.setMessageCount(messageCount); - summary.setSummaryTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date())); - summary.setCreator("system"); - - chatRoomSummaryMapper.insertChatRoomSummary(summary); - - logger.info("聊天室总结数据保存成功: roomId={}, summaryId={}", roomId, summary.getSummaryId()); - } catch (Exception e) { - logger.error("保存聊天室总结数据失败: roomId={}", roomId, e); - // 总结数据保存失败不影响主流程,仅记录日志 - } - } - - @Override - public ResultDomain getLatestSummary(String roomId) { - try { - logger.info("查询聊天室最新总结: roomId={}", roomId); - - // 查询最新的总结记录 - TbChatRoomSummaryDTO summary = chatRoomSummaryMapper.selectLatestSummaryByRoomId(roomId); - - if (summary == null) { - logger.info("未找到聊天室总结: roomId={}", roomId); - return ResultDomain.failure("暂无总结数据"); - } - - // 构建响应对象 - ChatRoomSummaryResponse response = new ChatRoomSummaryResponse(); - response.setRoomId(summary.getRoomId()); - response.setQuestion(summary.getQuestion()); - response.setNeeds(summary.getNeeds()); - response.setAnswer(summary.getAnswer()); - response.setWorkcloud(summary.getWorkcloud()); - response.setSummaryTime(summary.getSummaryTime()); - response.setMessageCount(summary.getMessageCount()); - - logger.info("查询聊天室总结成功: roomId={}, summaryId={}", roomId, summary.getSummaryId()); - return ResultDomain.success("查询成功", response); - - } catch (Exception e) { - logger.error("查询聊天室总结异常: roomId={}", roomId, e); - return ResultDomain.failure("查询失败: " + e.getMessage()); - } - } -} \ No newline at end of file diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/ChatRoomServiceImpl.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/ChatRoomServiceImpl.java deleted file mode 100644 index 294af30e..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/ChatRoomServiceImpl.java +++ /dev/null @@ -1,834 +0,0 @@ -package org.xyzh.workcase.service; - -import java.util.Date; -import java.util.List; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.common.redis.service.RedisService; -import org.springframework.transaction.annotation.Transactional; -import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO; -import org.xyzh.api.workcase.dto.TbChatRoomDTO; -import org.xyzh.api.workcase.dto.TbChatRoomMemberDTO; -import org.xyzh.api.workcase.dto.TbCustomerServiceDTO; -import org.xyzh.api.workcase.service.ChatRoomService; -import org.xyzh.api.workcase.vo.ChatMemberVO; -import org.xyzh.api.workcase.vo.ChatRoomMessageVO; -import org.xyzh.api.workcase.vo.ChatRoomVO; -import org.xyzh.api.workcase.vo.CustomerServiceVO; -import org.xyzh.api.ai.dto.TbChat; -import org.xyzh.api.ai.dto.TbChatMessage; -import org.xyzh.api.ai.service.AgentChatService; -import org.xyzh.api.workcase.constant.WorkcaseConstant; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.NonUtils; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.workcase.mapper.TbChatMessageMapper; -import org.xyzh.workcase.mapper.TbChatRoomMapper; -import org.xyzh.workcase.mapper.TbChatRoomMemberMapper; -import org.xyzh.workcase.mapper.TbCustomerServiceMapper; - - -/** - * @description 聊天室服务实现类 - * @filename ChatRoomServiceImpl.java - * @author cascade - * @copyright xyzh - * @since 2025-12-22 - */ -@DubboService(version = "1.0.0", group = "workcase", timeout = 30000, retries = 0) -public class ChatRoomServiceImpl implements ChatRoomService { - private static final Logger logger = LoggerFactory.getLogger(ChatRoomServiceImpl.class); - - @Autowired - private TbChatRoomMapper chatRoomMapper; - - @Autowired - private TbChatRoomMemberMapper chatRoomMemberMapper; - - @Autowired - private TbChatMessageMapper chatMessageMapper; - - @Autowired - private TbCustomerServiceMapper customerServiceMapper; - - @Autowired - private RedisService redisService; - - @DubboReference(version = "1.0.0", group = "ai", timeout = 30000, retries = 0) - private AgentChatService agentChatService; - - // ========================= 聊天室管理 ========================== - - @Override - @Transactional - public ResultDomain createChatRoom(TbChatRoomDTO chatRoom) { - logger.info("创建聊天室: guestId={}, aiSessionId={}", chatRoom.getGuestId(), chatRoom.getAiSessionId()); - - // 如果关联工单,检查工单是否已有聊天室 - if (chatRoom.getWorkcaseId() != null && !chatRoom.getWorkcaseId().isEmpty()) { - TbChatRoomDTO filter = new TbChatRoomDTO(); - filter.setWorkcaseId(chatRoom.getWorkcaseId()); - List existingRooms = chatRoomMapper.selectChatRoomList(filter); - if (existingRooms != null && !existingRooms.isEmpty()) { - return ResultDomain.failure("该工单已存在聊天室"); - } - } - - if (chatRoom.getRoomId() == null || chatRoom.getRoomId().isEmpty()) { - chatRoom.setRoomId(IdUtil.generateUUID()); - } - if (chatRoom.getOptsn() == null || chatRoom.getOptsn().isEmpty()) { - chatRoom.setOptsn(IdUtil.getOptsn()); - } - if (chatRoom.getStatus() == null || chatRoom.getStatus().isEmpty()) { - chatRoom.setStatus("active"); - } - - int rows = chatRoomMapper.insertChatRoom(chatRoom); - if (rows > 0) { - logger.info("聊天室创建成功: roomId={}", chatRoom.getRoomId()); - - // 添加来客到成员表 - if (chatRoom.getGuestId() != null && !chatRoom.getGuestId().isEmpty()) { - TbChatRoomMemberDTO guestMember = new TbChatRoomMemberDTO(); - guestMember.setMemberId(IdUtil.generateUUID()); - guestMember.setOptsn(IdUtil.getOptsn()); - guestMember.setRoomId(chatRoom.getRoomId()); - guestMember.setUserId(chatRoom.getGuestId()); - guestMember.setUserName(chatRoom.getGuestName()); - guestMember.setUserType("guest"); - guestMember.setStatus("active"); - guestMember.setJoinTime(new Date()); - guestMember.setCreator(chatRoom.getGuestId()); - guestMember.setUnreadCount(0); - chatRoomMemberMapper.insertChatRoomMember(guestMember); - } - - // 自动分配客服并添加到成员表 - ResultDomain assignResult = assignCustomerService(chatRoom.getRoomId()); - if (Boolean.TRUE.equals(assignResult.getSuccess()) && assignResult.getData() != null) { - // 更新聊天室当前客服ID - TbChatRoomDTO updateRoom = new TbChatRoomDTO(); - updateRoom.setRoomId(chatRoom.getRoomId()); - updateRoom.setCurrentAgentId(assignResult.getData().getUserId()); - chatRoomMapper.updateChatRoom(updateRoom); - } - // 从AI同步对话历史 - if(NonUtils.isNotEmpty(chatRoom.getAiSessionId())){ - try{ - syncAiChatMessages(chatRoom); - }catch(Exception ex){ - return ResultDomain.failure("创建失败"); - } - } - - return ResultDomain.success("创建成功", chatRoom); - } - return ResultDomain.failure("创建失败"); - } - - @Override - public ResultDomain updateChatRoom(TbChatRoomDTO chatRoom) { - logger.info("更新聊天室: roomId={}", chatRoom.getRoomId()); - - TbChatRoomDTO existing = chatRoomMapper.selectChatRoomById(chatRoom.getRoomId()); - if (existing == null) { - return ResultDomain.failure("聊天室不存在"); - } - - int rows = chatRoomMapper.updateChatRoom(chatRoom); - if (rows > 0) { - TbChatRoomDTO updated = chatRoomMapper.selectChatRoomById(chatRoom.getRoomId()); - return ResultDomain.success("更新成功", updated); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain closeChatRoom(String roomId, String closedBy) { - logger.info("关闭聊天室: roomId={}, closedBy={}", roomId, closedBy); - - TbChatRoomDTO existing = chatRoomMapper.selectChatRoomById(roomId); - if (existing == null) { - return ResultDomain.failure("聊天室不存在"); - } - - TbChatRoomDTO chatRoom = new TbChatRoomDTO(); - chatRoom.setRoomId(roomId); - chatRoom.setStatus("closed"); - chatRoom.setClosedBy(closedBy); - chatRoom.setClosedTime(new Date()); - - int rows = chatRoomMapper.updateChatRoom(chatRoom); - if (rows > 0) { - // 清理Redis中的在线用户 - String onlineUsersKey = WorkcaseConstant.REDIS_CHAT_ONLINE + roomId; - redisService.delete(onlineUsersKey); - return ResultDomain.success("关闭成功", true); - } - return ResultDomain.failure("关闭失败"); - } - - @Override - public ResultDomain deleteChatRoom(String roomId) { - logger.info("删除聊天室: roomId={}", roomId); - - TbChatRoomDTO existing = chatRoomMapper.selectChatRoomById(roomId); - if (existing == null) { - return ResultDomain.failure("聊天室不存在"); - } - - TbChatRoomDTO chatRoom = new TbChatRoomDTO(); - chatRoom.setRoomId(roomId); - int rows = chatRoomMapper.deleteChatRoom(chatRoom); - if (rows > 0) { - return ResultDomain.success("删除成功", true); - } - return ResultDomain.failure("删除失败"); - } - - @Override - public ResultDomain getChatRoomById(String roomId) { - TbChatRoomDTO chatRoom = chatRoomMapper.selectChatRoomById(roomId); - if (chatRoom != null) { - return ResultDomain.success("查询聊天室成功", chatRoom); - } - return ResultDomain.failure("聊天室不存在"); - } - - @Override - public ResultDomain getChatRoomPage(PageRequest pageRequest, String userId) { - TbChatRoomDTO filter = pageRequest.getFilter(); - if (filter == null) { - filter = new TbChatRoomDTO(); - } - - PageParam pageParam = pageRequest.getPageParam(); - List list = chatRoomMapper.selectChatRoomPage(filter, pageParam, userId); - long total = chatRoomMapper.countChatRooms(filter); - pageParam.setTotal((int)total); - - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询聊天室成功", pageDomain); - } - - @Override - public ResultDomain countChatRooms(TbChatRoomDTO filter) { - long count = chatRoomMapper.countChatRooms(filter); - return ResultDomain.success("查询成功", count); - } - - // ========================= 聊天室成员管理 ========================== - - @Override - public ResultDomain addChatRoomMember(TbChatRoomMemberDTO member) { - logger.info("添加聊天室成员: roomId={}, userId={}", member.getRoomId(), member.getUserId()); - - // 检查聊天室是否存在 - TbChatRoomDTO room = chatRoomMapper.selectChatRoomById(member.getRoomId()); - if (room == null) { - return ResultDomain.failure("聊天室不存在"); - } - - // 检查是否已是成员 - TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO(); - filter.setRoomId(member.getRoomId()); - filter.setUserId(member.getUserId()); - List existingMembers = chatRoomMemberMapper.selectChatRoomMemberList(filter); - if (existingMembers != null && !existingMembers.isEmpty()) { - // 重置未读数量 - TbChatRoomMemberDTO updateMember = new TbChatRoomMemberDTO(); - updateMember.setMemberId(existingMembers.get(0).getMemberId()); - updateMember.setUnreadCount(0); - chatRoomMemberMapper.updateChatRoomMember(updateMember); - - return ResultDomain.failure("用户已是聊天室成员,更新未读"); - } - - if (member.getMemberId() == null || member.getMemberId().isEmpty()) { - member.setMemberId(IdUtil.generateUUID()); - } - if (member.getOptsn() == null || member.getOptsn().isEmpty()) { - member.setOptsn(IdUtil.getOptsn()); - } - if (member.getStatus() == null || member.getStatus().isEmpty()) { - member.setStatus("active"); - } - member.setJoinTime(new Date()); - member.setCreator(member.getUserId()); - - int rows = chatRoomMemberMapper.insertChatRoomMember(member); - if (rows > 0) { - // 更新聊天室成员数 - TbChatRoomDTO updateRoom = new TbChatRoomDTO(); - updateRoom.setRoomId(member.getRoomId()); - updateRoom.setAgentCount(room.getAgentCount() != null ? room.getAgentCount() + 1 : 1); - chatRoomMapper.updateChatRoom(updateRoom); - - return ResultDomain.success("添加成功", member); - } - return ResultDomain.failure("添加失败"); - } - - @Override - public ResultDomain removeChatRoomMember(String memberId) { - logger.info("移除聊天室成员: memberId={}", memberId); - - TbChatRoomMemberDTO existing = chatRoomMemberMapper.selectChatRoomMemberById(memberId); - if (existing == null) { - return ResultDomain.failure("成员不存在"); - } - - TbChatRoomMemberDTO member = new TbChatRoomMemberDTO(); - member.setMemberId(memberId); - int rows = chatRoomMemberMapper.deleteChatRoomMember(member); - if (rows > 0) { - // 更新聊天室成员数 - TbChatRoomDTO room = chatRoomMapper.selectChatRoomById(existing.getRoomId()); - if (room != null && room.getAgentCount() != null && room.getAgentCount() > 0) { - TbChatRoomDTO updateRoom = new TbChatRoomDTO(); - updateRoom.setRoomId(existing.getRoomId()); - updateRoom.setAgentCount(room.getAgentCount() - 1); - chatRoomMapper.updateChatRoom(updateRoom); - } - - // 从Redis移除在线状态 - String onlineUsersKey = WorkcaseConstant.REDIS_CHAT_ONLINE + existing.getRoomId(); - redisService.sRemove(onlineUsersKey, existing.getUserId()); - - return ResultDomain.success("移除成功", true); - } - return ResultDomain.failure("移除失败"); - } - - @Override - public ResultDomain updateChatRoomMember(TbChatRoomMemberDTO member) { - logger.info("更新聊天室成员: memberId={}", member.getMemberId()); - - TbChatRoomMemberDTO existing = chatRoomMemberMapper.selectChatRoomMemberById(member.getMemberId()); - if (existing == null) { - return ResultDomain.failure("成员不存在"); - } - - int rows = chatRoomMemberMapper.updateChatRoomMember(member); - if (rows > 0) { - TbChatRoomMemberDTO updated = chatRoomMemberMapper.selectChatRoomMemberById(member.getMemberId()); - return ResultDomain.success("更新成功", updated); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain getChatRoomMemberList(String roomId) { - TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO(); - filter.setRoomId(roomId); - List list = chatRoomMemberMapper.selectChatRoomMemberList(filter); - return ResultDomain.success("查询成功", list); - } - - @Override - public ResultDomain updateMemberReadStatus(String memberId, String lastReadMsgId) { - logger.info("更新已读状态: memberId={}, lastReadMsgId={}", memberId, lastReadMsgId); - - TbChatRoomMemberDTO member = new TbChatRoomMemberDTO(); - member.setMemberId(memberId); - member.setLastReadMsgId(lastReadMsgId); - member.setLastReadTime(new Date()); - - int rows = chatRoomMemberMapper.updateChatRoomMember(member); - if (rows > 0) { - return ResultDomain.success("更新成功", true); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain getUnreadCount(String roomId, String userId) { - logger.info("查询未读消息数: roomId={}, userId={}", roomId, userId); - - TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO(); - filter.setRoomId(roomId); - filter.setUserId(userId); - List members = chatRoomMemberMapper.selectChatRoomMemberList(filter); - - if (members.isEmpty()) { - return ResultDomain.success("查询成功", 0); - } - - Integer unreadCount = members.get(0).getUnreadCount(); - return ResultDomain.success("查询成功", unreadCount != null ? unreadCount : 0); - } - - // ========================= 聊天消息管理 ========================== - - @Override - public ResultDomain sendMessage(TbChatRoomMessageDTO message) { - logger.info("发送消息: roomId={}, senderId={}, messageType={}", - message.getRoomId(), message.getSenderId(), message.getMessageType()); - - // 检查聊天室是否存在 - TbChatRoomDTO room = chatRoomMapper.selectChatRoomById(message.getRoomId()); - if (room == null) { - return ResultDomain.failure("聊天室不存在"); - } - if ("closed".equals(room.getStatus())) { - return ResultDomain.failure("聊天室已关闭"); - } - - if (message.getMessageId() == null || message.getMessageId().isEmpty()) { - message.setMessageId(IdUtil.generateUUID()); - } - if (message.getOptsn() == null || message.getOptsn().isEmpty()) { - message.setOptsn(IdUtil.getOptsn()); - } - if (message.getStatus() == null || message.getStatus().isEmpty()) { - message.setStatus("sent"); - } - message.setCreator(message.getSenderId()); - - // 使用Redis保证消息时间戳递增,避免并发乱序 - String lockKey = WorkcaseConstant.REDIS_CHAT_LOCK + message.getRoomId(); - String timeKey = WorkcaseConstant.REDIS_CHAT_LASTTIME + message.getRoomId(); - - try { - // 获取分布式锁(简单实现:SETNX + 过期时间) - int maxRetry = 10; - int retry = 0; - while (retry < maxRetry) { - Boolean locked = redisService.setIfAbsent(lockKey, "1", 5); - if (Boolean.TRUE.equals(locked)) { - break; - } - retry++; - Thread.sleep(50); - } - if (retry >= maxRetry) { - return ResultDomain.failure("消息发送繁忙,请稍后重试"); - } - - // 获取上一条消息的时间戳,确保时间递增 - long currentTime = System.currentTimeMillis(); - Object lastTimeObj = redisService.get(timeKey); - if (lastTimeObj != null) { - long lastTime = Long.parseLong(lastTimeObj.toString()); - if (currentTime <= lastTime) { - currentTime = lastTime + 1; - } - } - message.setSendTime(new Date(currentTime)); - - // 更新Redis中的最后消息时间 - redisService.set(timeKey, String.valueOf(currentTime)); - - int rows = chatMessageMapper.insertChatMessage(message); - if (rows > 0) { - // 更新聊天室最后消息信息 - TbChatRoomDTO updateRoom = new TbChatRoomDTO(); - updateRoom.setRoomId(message.getRoomId()); - updateRoom.setLastMessage(message.getContent()); - updateRoom.setLastMessageTime(message.getSendTime()); - updateRoom.setMessageCount(room.getMessageCount() != null ? room.getMessageCount() + 1 : 1); - chatRoomMapper.updateChatRoom(updateRoom); - - // 更新聊天室成员的未读数(除发送者外的所有成员 +1) - updateMembersUnreadCount(message.getRoomId(), message.getSenderId()); - - // 发布消息到Redis Pub/Sub(聊天窗口) - publishMessageToRedis(message); - - // 发布列表更新通知(聊天室列表) - publishListUpdateToRedis(message); - - return ResultDomain.success("发送成功", message); - } - return ResultDomain.failure("发送失败"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return ResultDomain.failure("消息发送被中断"); - } finally { - // 释放锁 - redisService.delete(lockKey); - } - } - - @Override - public ResultDomain getChatMessagePage(PageRequest pageRequest) { - TbChatRoomMessageDTO filter = pageRequest.getFilter(); - if (filter == null) { - filter = new TbChatRoomMessageDTO(); - } - - PageParam pageParam = pageRequest.getPageParam(); - List list = chatMessageMapper.selectChatMessagePage(filter, pageParam); - long total = chatMessageMapper.countChatMessages(filter); - pageParam.setTotal((int) total); - - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - - @Override - public ResultDomain deleteMessage(String messageId) { - logger.info("删除消息: messageId={}", messageId); - - TbChatRoomMessageDTO existing = chatMessageMapper.selectChatMessageById(messageId); - if (existing == null) { - return ResultDomain.failure("消息不存在"); - } - - TbChatRoomMessageDTO message = new TbChatRoomMessageDTO(); - message.setMessageId(messageId); - int rows = chatMessageMapper.deleteChatMessage(message); - if (rows > 0) { - return ResultDomain.success("删除成功", true); - } - return ResultDomain.failure("删除失败"); - } - - // ========================= 客服人员管理 ========================== - - @Override - public ResultDomain addCustomerService(TbCustomerServiceDTO customerService) { - logger.info("添加客服人员: userId={}, username={}", customerService.getUserId(), customerService.getUsername()); - - // 检查是否已存在 - TbCustomerServiceDTO existing = customerServiceMapper.selectCustomerServiceById(customerService.getUserId()); - if (existing != null) { - return ResultDomain.failure("该员工已是客服人员"); - } - - if (customerService.getOptsn() == null || customerService.getOptsn().isEmpty()) { - customerService.setOptsn(IdUtil.getOptsn()); - } - if (customerService.getStatus() == null || customerService.getStatus().isEmpty()) { - customerService.setStatus("offline"); - } - if (customerService.getMaxConcurrent() == null) { - customerService.setMaxConcurrent(5); - } - if (customerService.getCurrentWorkload() == null) { - customerService.setCurrentWorkload(0); - } - - int rows = customerServiceMapper.insertCustomerService(customerService); - if (rows > 0) { - return ResultDomain.success("添加成功", customerService); - } - return ResultDomain.failure("添加失败"); - } - - @Override - public ResultDomain updateCustomerService(TbCustomerServiceDTO customerService) { - logger.info("更新客服人员: userId={}", customerService.getUserId()); - - TbCustomerServiceDTO existing = customerServiceMapper.selectCustomerServiceById(customerService.getUserId()); - if (existing == null) { - return ResultDomain.failure("客服人员不存在"); - } - - int rows = customerServiceMapper.updateCustomerService(customerService); - if (rows > 0) { - TbCustomerServiceDTO updated = customerServiceMapper.selectCustomerServiceById(customerService.getUserId()); - return ResultDomain.success("更新成功", updated); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain deleteCustomerService(String userId) { - logger.info("删除客服人员: userId={}", userId); - - TbCustomerServiceDTO existing = customerServiceMapper.selectCustomerServiceById(userId); - if (existing == null) { - return ResultDomain.failure("客服人员不存在"); - } - - TbCustomerServiceDTO customerService = new TbCustomerServiceDTO(); - customerService.setUserId(userId); - int rows = customerServiceMapper.deleteCustomerService(customerService); - if (rows > 0) { - return ResultDomain.success("删除成功", true); - } - return ResultDomain.failure("删除失败"); - } - - @Override - public ResultDomain getCustomerServicePage(PageRequest pageRequest) { - TbCustomerServiceDTO filter = pageRequest.getFilter(); - if (filter == null) { - filter = new TbCustomerServiceDTO(); - } - - PageParam pageParam = pageRequest.getPageParam(); - List list = customerServiceMapper.selectCustomerServicePage(filter, pageParam); - long total = customerServiceMapper.countCustomerServices(filter); - pageParam.setTotal((int) total); - - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - - @Override - public ResultDomain updateCustomerServiceStatus(String userId, String status) { - logger.info("更新客服状态: userId={}, status={}", userId, status); - - TbCustomerServiceDTO customerService = new TbCustomerServiceDTO(); - customerService.setUserId(userId); - customerService.setStatus(status); - - int rows = customerServiceMapper.updateCustomerService(customerService); - if (rows > 0) { - return ResultDomain.success("更新成功", true); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain getAvailableCustomerServices() { - TbCustomerServiceDTO filter = new TbCustomerServiceDTO(); - filter.setStatus("online"); - List list = customerServiceMapper.selectCustomerServiceList(filter); - - return ResultDomain.success("查询成功", list); - } - - @Override - @Transactional - public ResultDomain assignCustomerService(String roomId) { - logger.info("分配所有客服到聊天室: roomId={}", roomId); - - // 获取所有在线客服列表 - TbCustomerServiceDTO filter = new TbCustomerServiceDTO(); - filter.setStatus("online"); - List allServices = customerServiceMapper.selectCustomerServiceList(filter); - - if (allServices == null || allServices.isEmpty()) { - return ResultDomain.failure("当前没有在线的客服人员"); - } - - // 把所有客服都加入聊天室 - int addedCount = 0; - for (CustomerServiceVO service : allServices) { - TbChatRoomMemberDTO member = new TbChatRoomMemberDTO(); - member.setMemberId(IdUtil.generateUUID()); - member.setOptsn(IdUtil.getOptsn()); - member.setRoomId(roomId); - member.setUserId(service.getUserId()); - member.setCreator(service.getUserId()); - member.setUserType("staff"); - member.setUserName(service.getUsername()); - member.setStatus("active"); - member.setJoinTime(new Date()); - member.setUnreadCount(0); - chatRoomMemberMapper.insertChatRoomMember(member); - - // 更新客服工作量 - TbCustomerServiceDTO updateService = new TbCustomerServiceDTO(); - updateService.setUserId(service.getUserId()); - updateService.setCurrentWorkload( - (service.getCurrentWorkload() != null ? service.getCurrentWorkload() : 0) + 1); - customerServiceMapper.updateCustomerService(updateService); - addedCount++; - } - - // 更新聊天室客服人数 - TbChatRoomDTO updateRoom = new TbChatRoomDTO(); - updateRoom.setRoomId(roomId); - updateRoom.setAgentCount(addedCount); - chatRoomMapper.updateChatRoom(updateRoom); - - logger.info("已添加{}名客服到聊天室: roomId={}", addedCount, roomId); - return ResultDomain.success("分配成功,共添加" + addedCount + "名客服", allServices.get(0)); - } - - // ========================= 私有方法 ========================== - - /** - * 从AI同步对话历史到聊天室 - * @param chatRoom 聊天室信息(包含aiSessionId和guestId) - */ - private void syncAiChatMessages(TbChatRoomDTO chatRoom) { - try { - // 1. 构建查询条件获取AI对话消息列表 - TbChat filter = new TbChat(); - filter.setChatId(chatRoom.getAiSessionId()); - filter.setUserId(chatRoom.getGuestId()); - filter.setUserType(false); // 来客 - - ResultDomain result = agentChatService.getChatMessageList(filter); - if (!Boolean.TRUE.equals(result.getSuccess()) || result.getDataList() == null) { - logger.warn("获取AI对话消息失败: aiSessionId={}, message={}", - chatRoom.getAiSessionId(), result.getMessage()); - return; - } - - List aiMessages = result.getDataList(); - if (aiMessages.isEmpty()) { - logger.info("AI对话消息为空: aiSessionId={}", chatRoom.getAiSessionId()); - return; - } - - // 2. 转换并存入聊天室消息表 - int syncCount = 0; - long baseTime = System.currentTimeMillis() - aiMessages.size() * 1000L; // 保持消息顺序 - - for (int i = 0; i < aiMessages.size(); i++) { - TbChatMessage aiMsg = aiMessages.get(i); - TbChatRoomMessageDTO roomMsg = new TbChatRoomMessageDTO(); - - roomMsg.setMessageId(IdUtil.generateUUID()); - roomMsg.setOptsn(IdUtil.getOptsn()); - roomMsg.setRoomId(chatRoom.getRoomId()); - roomMsg.setContent(aiMsg.getContent()); - roomMsg.setMessageType("text"); - roomMsg.setStatus("sent"); - roomMsg.setFiles(aiMsg.getFiles()); - roomMsg.setSendTime(aiMsg.getCreateTime()); - roomMsg.setCreateTime(aiMsg.getCreateTime()); - roomMsg.setIsAiMessage(true); - roomMsg.setAiMessageId(aiMsg.getMessageId()); - roomMsg.setCreator(chatRoom.getGuestId()); - - // 根据角色设置发送者信息 - if ("user".equals(aiMsg.getRole())) { - roomMsg.setSenderId(chatRoom.getGuestId()); - roomMsg.setSenderName(chatRoom.getGuestName()); - roomMsg.setSenderType("guest"); - roomMsg.setIsAiMessage(false); - } else { - // AI回复 - roomMsg.setSenderId("AI"); - roomMsg.setSenderName("智能助手"); - roomMsg.setSenderType("ai"); - } - - chatMessageMapper.insertChatMessage(roomMsg); - syncCount++; - } - - // 3. 更新聊天室消息数和最后消息 - if (syncCount > 0) { - TbChatMessage lastAiMsg = aiMessages.get(aiMessages.size() - 1); - TbChatRoomDTO updateRoom = new TbChatRoomDTO(); - updateRoom.setRoomId(chatRoom.getRoomId()); - updateRoom.setLastMessage(lastAiMsg.getContent()); - updateRoom.setLastMessageTime(new Date()); - updateRoom.setMessageCount(syncCount); - chatRoomMapper.updateChatRoom(updateRoom); - } - - logger.info("AI对话同步完成: roomId={}, aiSessionId={}, syncCount={}", - chatRoom.getRoomId(), chatRoom.getAiSessionId(), syncCount); - - } catch (Exception e) { - logger.error("同步AI对话失败: aiSessionId={}", chatRoom.getAiSessionId(), e); - } - } - - /** - * 更新聊天室成员的未读数(除发送者外的所有成员 +1) - */ - private void updateMembersUnreadCount(String roomId, String senderId) { - try { - TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO(); - filter.setRoomId(roomId); - List members = chatRoomMemberMapper.selectChatRoomMemberList(filter); - - for (ChatMemberVO member : members) { - if (!senderId.equals(member.getUserId())) { - TbChatRoomMemberDTO updateMember = new TbChatRoomMemberDTO(); - updateMember.setMemberId(member.getMemberId()); - updateMember.setUnreadCount((member.getUnreadCount() != null ? member.getUnreadCount() : 0) + 1); - chatRoomMemberMapper.updateChatRoomMember(updateMember); - } - } - logger.debug("已更新聊天室成员未读数: roomId={}, 更新成员数={}", roomId, members.size() - 1); - } catch (Exception e) { - logger.error("更新聊天室成员未读数失败: roomId={}", roomId, e); - } - } - - private void publishMessageToRedis(TbChatRoomMessageDTO message) { - try { - String channel = WorkcaseConstant.REDIS_CHAT_PREFIX + message.getRoomId(); - // RedisService内部已配置FastJson2JsonRedisSerializer,会自动序列化 - redisService.publish(channel, message); - logger.debug("消息已发布到Redis频道: {}", channel); - } catch (Exception e) { - logger.error("发布消息到Redis失败", e); - } - } - - private void publishListUpdateToRedis(TbChatRoomMessageDTO message) { - try { - // 发布到列表更新频道,前端订阅此频道刷新聊天室列表 - redisService.publish(WorkcaseConstant.REDIS_CHAT_LIST_UPDATE, message); - logger.debug("列表更新已发布到Redis频道: {}", WorkcaseConstant.REDIS_CHAT_LIST_UPDATE); - } catch (Exception e) { - logger.error("发布列表更新到Redis失败", e); - } - } - - // ========================= 聊天室评分管理 ========================== - - @Override - @Transactional - public ResultDomain submitCommentLevel(String roomId, Integer commentLevel, String userId) { - logger.info("提交聊天室服务评分: roomId={}, commentLevel={}, userId={}", roomId, commentLevel, userId); - - // 参数校验 - if (NonUtils.isEmpty(roomId)) { - return ResultDomain.failure("聊天室ID不能为空"); - } - if (commentLevel == null || commentLevel < 1 || commentLevel > 5) { - return ResultDomain.failure("评分必须在1-5星之间"); - } - - try { - // 1. 检查聊天室是否存在 - TbChatRoomDTO chatRoom = chatRoomMapper.selectChatRoomById(roomId); - if (chatRoom == null) { - return ResultDomain.failure("聊天室不存在"); - } - - // 2. 检查用户是否是聊天室成员(来客) - if (!userId.equals(chatRoom.getGuestId())) { - return ResultDomain.failure("只有来客可以对服务进行评分"); - } - - // 3. 检查是否已评分 - if (chatRoom.getCommentLevel() != null && chatRoom.getCommentLevel() > 0) { - return ResultDomain.failure("已经评分过了,不能重复评分"); - } - - // 4. 更新评分 - TbChatRoomDTO updateRoom = new TbChatRoomDTO(); - updateRoom.setRoomId(roomId); - updateRoom.setCommentLevel(commentLevel); - - int rows = chatRoomMapper.updateChatRoom(updateRoom); - if (rows > 0) { - logger.info("聊天室服务评分成功: roomId={}, commentLevel={}", roomId, commentLevel); - - // TODO: 后续可以在这里更新客服人员的平均满意度评分 - // updateCustomerServiceSatisfaction(chatRoom, commentLevel); - - return ResultDomain.success("评分成功",true); - } else { - return ResultDomain.failure("评分提交失败"); - } - - } catch (Exception e) { - logger.error("提交聊天室服务评分失败: roomId={}, commentLevel={}", roomId, commentLevel, e); - return ResultDomain.failure("评分提交失败: " + e.getMessage()); - } - } -} - diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/JitsiTokenServiceImpl.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/JitsiTokenServiceImpl.java deleted file mode 100644 index 6369228d..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/JitsiTokenServiceImpl.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.xyzh.workcase.service; - -import com.alibaba.fastjson2.JSONObject; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.api.workcase.service.JitsiTokenService; -import org.xyzh.workcase.config.JitsiProperties; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -/** - * @description Jitsi Meet JWT Token服务实现类 - * @filename JitsiTokenServiceImpl.java - * @author claude - * @copyright xyzh - * @since 2025-12-25 - */ -@DubboService(version = "1.0.0", group = "workcase", timeout = 30000, retries = 0) -public class JitsiTokenServiceImpl implements JitsiTokenService { - private static final Logger logger = LoggerFactory.getLogger(JitsiTokenServiceImpl.class); - - @Autowired - private JitsiProperties jitsiProperties; - - @Override - public String generateJwtToken(String roomName, String userId, String userName, boolean isModerator) { - logger.info("生成Jitsi JWT Token: roomName={}, userId={}, userName={}, isModerator={}", - roomName, userId, userName, isModerator); - - try { - long now = System.currentTimeMillis(); - long exp = now + jitsiProperties.getToken().getExpiration(); - - // 构建用户上下文 - Map userContext = new HashMap<>(); - userContext.put("id", userId); - userContext.put("name", userName); - userContext.put("moderator", isModerator); - - // 构建affiliation (这是Jitsi识别主持人的关键字段) - Map user = new HashMap<>(); - user.put("id", userId); - user.put("name", userName); - user.put("moderator", isModerator); - user.put("affiliation", isModerator ? "owner" : "member"); // owner=主持人, member=普通成员 - - // 构建context - Map context = new HashMap<>(); - context.put("user", user); - - // 【调试日志】打印用户上下文 - logger.info("【JWT用户上下文】roomName={}, userId={}, userName={}, isModerator={}, affiliation={}, user={}", - roomName, userId, userName, isModerator, isModerator ? "owner" : "member", user); - - // 构建JWT claims - Map claims = new HashMap<>(); - claims.put("context", context); - claims.put("room", roomName); - claims.put("iss", jitsiProperties.getApp().getId()); - claims.put("aud", "jitsi"); - claims.put("sub", jitsiProperties.getServer().getUrl()); - claims.put("exp", exp / 1000); // 秒级时间戳 - claims.put("nbf", now / 1000); - claims.put("moderator", isModerator); // 在顶层也添加moderator字段 - - // 【调试日志】打印完整claims - logger.info("【JWT Claims】roomName={}, claims={}", roomName, claims); - - // 构建JWT Header,必须包含 typ: JWT - Map header = new HashMap<>(); - header.put("alg", "HS256"); - header.put("typ", "JWT"); - - // 生成JWT Token - String token = Jwts.builder() - .setHeader(header) - .setClaims(claims) - .setIssuedAt(new Date(now)) - .setExpiration(new Date(exp)) - .signWith(SignatureAlgorithm.HS256, jitsiProperties.getApp().getSecret().getBytes()) - .compact(); - - logger.info("JWT Token生成成功: roomName={}", roomName); - return token; - } catch (Exception e) { - logger.error("生成JWT Token失败: roomName={}, error={}", roomName, e.getMessage(), e); - throw new RuntimeException("生成JWT Token失败: " + e.getMessage()); - } - } - - @Override - public boolean validateJwtToken(String token) { - try { - Claims claims = Jwts.parser() - .setSigningKey(jitsiProperties.getApp().getSecret().getBytes()) - .parseClaimsJws(token) - .getBody(); - - // 检查过期时间 - Date expiration = claims.getExpiration(); - return expiration.after(new Date()); - } catch (Exception e) { - logger.warn("JWT Token验证失败: error={}", e.getMessage()); - return false; - } - } - - @Override - public String buildIframeUrl(String roomName, String jwtToken, JSONObject config) { - logger.info("构建Jitsi iframe URL: roomName={}", roomName); - - StringBuilder url = new StringBuilder(); - url.append(jitsiProperties.getServer().getUrl()).append("/").append(roomName); - - // 添加JWT Token - url.append("?jwt=").append(jwtToken); - - // 添加默认配置 - url.append("&config.startWithAudioMuted=false"); - url.append("&config.startWithVideoMuted=false"); - url.append("&config.enableWelcomePage=false"); - url.append("&config.prejoinPageEnabled=false"); - url.append("&config.disableDeepLinking=true"); - url.append("&config.enableChat=true"); - url.append("&config.enableScreenSharing=true"); - - // 界面配置 - url.append("&interfaceConfig.SHOW_JITSI_WATERMARK=false"); - url.append("&interfaceConfig.SHOW_WATERMARK_FOR_GUESTS=false"); - url.append("&interfaceConfig.DISABLE_JOIN_LEAVE_NOTIFICATIONS=false"); - url.append("&interfaceConfig.DEFAULT_BACKGROUND=#474747"); - - // 添加自定义配置 - if (config != null && !config.isEmpty()) { - config.forEach((key, value) -> { - url.append("&config.").append(key).append("=").append(value); - }); - } - - String iframeUrl = url.toString(); - logger.info("iframe URL构建成功: url={}", iframeUrl); - return iframeUrl; - } - - @Override - public String generateRoomName(String workcaseId) { - // 格式: workcase_{workcaseId}_{timestamp} - String roomName = String.format("workcase_%s_%d", - workcaseId != null ? workcaseId : "default", - System.currentTimeMillis()); - - logger.info("生成Jitsi房间名: roomName={}", roomName); - return roomName; - } -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/VideoMeetingServiceImpl.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/VideoMeetingServiceImpl.java deleted file mode 100644 index 2bf8207b..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/VideoMeetingServiceImpl.java +++ /dev/null @@ -1,743 +0,0 @@ -package org.xyzh.workcase.service; - -import com.alibaba.fastjson2.JSONObject; -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; -import org.xyzh.api.auth.service.AuthService; -import org.xyzh.api.workcase.dto.TbChatRoomMemberDTO; -import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO; -import org.xyzh.api.workcase.dto.TbVideoMeetingDTO; -import org.xyzh.api.workcase.service.ChatRoomService; -import org.xyzh.api.workcase.service.JitsiTokenService; -import org.xyzh.api.workcase.service.VideoMeetingService; -import org.xyzh.api.workcase.vo.ChatMemberVO; -import org.xyzh.api.workcase.vo.VideoMeetingVO; -import org.xyzh.common.auth.utils.LoginUtil; -import org.xyzh.common.core.domain.LoginDomain; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.workcase.config.JitsiProperties; -import org.xyzh.workcase.mapper.TbChatRoomMemberMapper; -import org.xyzh.workcase.mapper.TbVideoMeetingMapper; - -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantLock; - -/** - * @description 视频会议服务实现类 - * @filename VideoMeetingServiceImpl.java - * @author claude - * @copyright xyzh - * @since 2025-12-25 - */ -@DubboService(version = "1.0.0", group = "workcase", timeout = 30000, retries = 0) -public class VideoMeetingServiceImpl implements VideoMeetingService { - private static final Logger logger = LoggerFactory.getLogger(VideoMeetingServiceImpl.class); - - @Autowired - private TbVideoMeetingMapper videoMeetingMapper; - - @Autowired - private TbChatRoomMemberMapper chatRoomMemberMapper; - - @Autowired - private JitsiTokenService jitsiTokenService; - - @Autowired - private ChatRoomService chatRoomService; - - @Autowired - private JitsiProperties jitsiProperties; - - @DubboReference(version = "1.0.0", group = "auth", timeout = 30000, retries = 0) - private AuthService authService; - - // 会议创建锁映射表:每个meetingId对应一个ReentrantLock - private final ConcurrentHashMap meetingLocks = new ConcurrentHashMap<>(); - - @Override - @Transactional - public ResultDomain createMeeting(TbVideoMeetingDTO meetingDTO) { - // 获取当前用户ID - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - String userId = loginDomain.getUser().getUserId(); - logger.info("创建视频会议预约: roomId={}, workcaseId={}, userId={}, startTime={}, endTime={}", - meetingDTO.getRoomId(), meetingDTO.getWorkcaseId(), userId, - meetingDTO.getStartTime(), meetingDTO.getEndTime()); - - try { - // 1. 验证用户是否为聊天室成员 - if (!isMemberOfRoom(meetingDTO.getRoomId(), userId)) { - logger.warn("用户不是聊天室成员,无法创建会议: roomId={}, userId={}", - meetingDTO.getRoomId(), userId); - return ResultDomain.failure("您不是聊天室成员,无法创建会议"); - } - - // 2. 检查聊天室是否已有时间冲突的会议 - TbVideoMeetingDTO conflictFilter = new TbVideoMeetingDTO(); - conflictFilter.setRoomId(meetingDTO.getRoomId()); - conflictFilter.setStatus("scheduled"); // 只检查已安排的会议 - List existingMeetings = videoMeetingMapper.selectVideoMeetingList(conflictFilter); - - if (existingMeetings != null && !existingMeetings.isEmpty()) { - for (VideoMeetingVO existing : existingMeetings) { - // 检查时间是否冲突 - if (isTimeConflict(meetingDTO.getStartTime(), meetingDTO.getEndTime(), - existing.getStartTime(), existing.getEndTime())) { - logger.warn("会议时间冲突: roomId={}, existingMeetingId={}", - meetingDTO.getRoomId(), existing.getMeetingId()); - return ResultDomain.failure("该时间段已有会议安排,请选择其他时间"); - } - } - } - - // 3. 生成会议ID和房间名(房间名暂时生成,真正创建Jitsi时会重新生成) - String meetingId = IdUtil.generateUUID(); - String jitsiRoomName = jitsiTokenService.generateRoomName(meetingDTO.getWorkcaseId()); - - // 4. 获取用户信息(从聊天室成员表) - TbChatRoomMemberDTO memberFilter = new TbChatRoomMemberDTO(); - memberFilter.setRoomId(meetingDTO.getRoomId()); - memberFilter.setUserId(userId); - List members = chatRoomMemberMapper.selectChatRoomMemberList(memberFilter); - - String userName = loginDomain.getUserInfo().getUsername(); - String userType = "guest".equals(loginDomain.getUser().getStatus())?"guest":"user"; - if (members != null && !members.isEmpty()) { - ChatMemberVO member = members.get(0); - userName = member.getUserName(); - userType = member.getUserType(); - } - - // 5. 填充会议预约信息(不生成JWT Token和iframe URL) - meetingDTO.setMeetingId(meetingId); - meetingDTO.setJitsiRoomName(jitsiRoomName); - meetingDTO.setJwtToken(null); // 预约阶段不生成token - meetingDTO.setIframeUrl(null); // 预约阶段不生成URL - meetingDTO.setStatus("scheduled"); // 状态为已安排 - meetingDTO.setCreator(userId); - meetingDTO.setCreatorType(userType); - meetingDTO.setCreatorName(userName); - - // 【调试日志】打印会议创建者信息 - logger.info("【创建会议】meetingId={}, 创建者userId=[{}](类型:{}), creatorName={}, creatorType={}", - meetingId, userId, userId.getClass().getSimpleName(), userName, userType); - - meetingDTO.setParticipantCount(0); - meetingDTO.setOptsn(IdUtil.getOptsn()); - - if (meetingDTO.getMaxParticipants() == null) { - meetingDTO.setMaxParticipants(10); - } - - if (meetingDTO.getAdvance() == null) { - meetingDTO.setAdvance(5); // 默认提前5分钟可入会 - } - meetingDTO.setJitsiServerUrl(jitsiProperties.getServer().getUrl()); - // 6. 插入数据库 - int rows = videoMeetingMapper.insertVideoMeeting(meetingDTO); - if (rows > 0) { - logger.info("视频会议预约创建成功: meetingId={}, jitsiRoomName={}, startTime={}, endTime={}", - meetingId, jitsiRoomName, meetingDTO.getStartTime(), meetingDTO.getEndTime()); - - // 7. 发送会议通知消息到聊天室(内容为meetingId而非URL) - sendMeetingNotification(meetingDTO, userName); - - // 8. 返回VO - VideoMeetingVO meetingVO = new VideoMeetingVO(); - BeanUtils.copyProperties(meetingDTO, meetingVO); - return ResultDomain.success("创建会议预约成功", meetingVO); - } else { - logger.error("插入会议记录失败: meetingId={}", meetingId); - return ResultDomain.failure("创建会议预约失败"); - } - } catch (Exception e) { - logger.error("创建视频会议预约异常: roomId={}, error={}", - meetingDTO.getRoomId(), e.getMessage(), e); - return ResultDomain.failure("创建会议预约失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain getMeetingInfo(String meetingId, String userId) { - logger.info("获取会议信息: meetingId={}, userId={}", meetingId, userId); - - try { - TbVideoMeetingDTO filter = new TbVideoMeetingDTO(); - filter.setMeetingId(meetingId); - List meetings = videoMeetingMapper.selectVideoMeetingList(filter); - - if (meetings == null || meetings.isEmpty()) { - logger.warn("会议不存在: meetingId={}", meetingId); - return ResultDomain.failure("会议不存在"); - } - - VideoMeetingVO meeting = meetings.get(0); - - // 验证访问权限 - ResultDomain accessCheck = validateMeetingAccess(meetingId, userId); - if (!accessCheck.getSuccess() || !accessCheck.getData()) { - logger.warn("用户无权访问会议: meetingId={}, userId={}", meetingId, userId); - return ResultDomain.failure("您无权访问此会议"); - } - - logger.info("获取会议信息成功: meetingId={}", meetingId); - return ResultDomain.success("获取会议信息成功", meeting); - } catch (Exception e) { - logger.error("获取会议信息异常: meetingId={}, error={}", meetingId, e.getMessage(), e); - return ResultDomain.failure("获取会议信息失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain validateMeetingAccess(String meetingId, String userId) { - logger.info("验证会议访问权限: meetingId={}, userId={}", meetingId, userId); - - try { - // 1. 获取会议信息 - TbVideoMeetingDTO filter = new TbVideoMeetingDTO(); - filter.setMeetingId(meetingId); - List meetings = videoMeetingMapper.selectVideoMeetingList(filter); - - if (meetings == null || meetings.isEmpty()) { - logger.warn("会议不存在: meetingId={}", meetingId); - return ResultDomain.success("会议不存在", false); - } - - VideoMeetingVO meeting = meetings.get(0); - - // 2. 检查用户是否为聊天室成员 - boolean isMember = isMemberOfRoom(meeting.getRoomId(), userId); - - logger.info("会议访问权限验证结果: meetingId={}, userId={}, hasAccess={}", - meetingId, userId, isMember); - return ResultDomain.success("会议访问权限验证成功", isMember); - } catch (Exception e) { - logger.error("验证会议访问权限异常: meetingId={}, error={}", meetingId, e.getMessage(), e); - return ResultDomain.failure("验证访问权限失败: " + e.getMessage()); - } - } - - @Override - @Transactional - public ResultDomain generateUserMeetingUrl(String meetingId, String userId) { - logger.info("生成用户专属会议URL: meetingId={}, userId={}", meetingId, userId); - - try { - // 1. 获取会议信息 - TbVideoMeetingDTO filter = new TbVideoMeetingDTO(); - filter.setMeetingId(meetingId); - List meetings = videoMeetingMapper.selectVideoMeetingList(filter); - - if (meetings == null || meetings.isEmpty()) { - logger.warn("会议不存在: meetingId={}", meetingId); - return ResultDomain.failure("会议不存在"); - } - - VideoMeetingVO meeting = meetings.get(0); - - // 2. 验证访问权限 - ResultDomain accessCheck = validateMeetingAccess(meetingId, userId); - if (!accessCheck.getSuccess() || !accessCheck.getData()) { - logger.warn("用户无权访问会议: meetingId={}, userId={}", meetingId, userId); - return ResultDomain.failure("您无权访问此会议"); - } - - // 3. 检查会议时间窗口(仅对scheduled状态的会议检查) - if ("scheduled".equals(meeting.getStatus())) { - Date now = new Date(); - - // 计算提前入会时间点(开始时间 - advance 分钟) - Calendar calendar = Calendar.getInstance(); - calendar.setTime(meeting.getStartTime()); - calendar.add(Calendar.MINUTE, -meeting.getAdvance()); - Date advanceTime = calendar.getTime(); - - // 检查当前时间是否在允许入会的时间窗口内 - if (now.before(advanceTime)) { - logger.warn("会议未到入会时间: meetingId={}, 当前时间={}, 提前入会时间={}", - meetingId, now, advanceTime); - return ResultDomain.failure("会议未到入会时间,请在 " + advanceTime + " 之后加入"); - } - - if (now.after(meeting.getEndTime())) { - logger.warn("会议已结束: meetingId={}, 当前时间={}, 结束时间={}", - meetingId, now, meeting.getEndTime()); - return ResultDomain.failure("会议已结束"); - } - - // 4. 使用ReentrantLock进行双检锁:首次用户入会时创建Jitsi会议室 - // 获取或创建该会议的锁对象 - ReentrantLock lock = meetingLocks.computeIfAbsent(meetingId, k -> new ReentrantLock()); - - logger.info("尝试获取会议创建锁: meetingId={}", meetingId); - lock.lock(); // 阻塞等待获取锁 - try { - logger.info("成功获取会议创建锁: meetingId={}, userId={}", meetingId, userId); - - // 双重检查:再次查询数据库确认会议状态(防止其他线程已创建) - List recheck = videoMeetingMapper.selectVideoMeetingList(filter); - if (recheck != null && !recheck.isEmpty()) { - VideoMeetingVO recheckMeeting = recheck.get(0); - - if ("scheduled".equals(recheckMeeting.getStatus())) { - logger.info("首次创建Jitsi会议室: meetingId={}", meetingId); - - // 更新会议状态为进行中 - TbVideoMeetingDTO updateDTO = new TbVideoMeetingDTO(); - updateDTO.setMeetingId(meetingId); - updateDTO.setStatus("ongoing"); - updateDTO.setActualStartTime(new Date()); - - int rows = videoMeetingMapper.updateVideoMeeting(updateDTO); - if (rows > 0) { - logger.info("Jitsi会议室创建成功,会议状态已更新: meetingId={}", meetingId); - meeting.setStatus("ongoing"); - meeting.setActualStartTime(new Date()); - } else { - logger.error("更新会议状态失败: meetingId={}", meetingId); - return ResultDomain.failure("创建会议失败"); - } - } else { - logger.info("会议已被其他用户创建: meetingId={}, status={}", - meetingId, recheckMeeting.getStatus()); - meeting.setStatus(recheckMeeting.getStatus()); - meeting.setActualStartTime(recheckMeeting.getActualStartTime()); - } - } - } finally { - lock.unlock(); - logger.info("释放会议创建锁: meetingId={}", meetingId); - - // 清理锁对象:如果没有其他线程在等待,则移除锁 - if (!lock.hasQueuedThreads()) { - meetingLocks.remove(meetingId); - logger.debug("清理会议锁对象: meetingId={}", meetingId); - } - } - } - - // 5. 获取用户信息 - TbChatRoomMemberDTO memberFilter = new TbChatRoomMemberDTO(); - memberFilter.setRoomId(meeting.getRoomId()); - memberFilter.setUserId(userId); - List members = chatRoomMemberMapper.selectChatRoomMemberList(memberFilter); - - String userName = "用户"; - // 会议创建人才是主持人 - boolean isModerator = userId.equals(meeting.getCreator()); - - // 【调试日志】打印主持人判断详情 - logger.info("【主持人判断】meetingId={}, 当前用户ID=[{}](类型:{}), 创建者ID=[{}](类型:{}), isModerator={}", - meetingId, - userId, userId.getClass().getSimpleName(), - meeting.getCreator(), meeting.getCreator() != null ? meeting.getCreator().getClass().getSimpleName() : "null", - isModerator); - - if (members != null && !members.isEmpty()) { - ChatMemberVO member = members.get(0); - userName = member.getUserName(); - } - - // 6. 生成用户专属JWT Token(用于Jitsi内部认证) - String userJwtToken = jitsiTokenService.generateJwtToken( - meeting.getJitsiRoomName(), - userId, - userName, - isModerator - ); - - logger.info("【JWT Token生成】meetingId={}, userId={}, userName={}, isModerator={}", - meetingId, userId, userName, isModerator); - - // 7. 构建真正的Jitsi iframe URL - String jitsiIframeUrl = jitsiTokenService.buildIframeUrl( - meeting.getJitsiRoomName(), - userJwtToken, - meeting.getConfig() - ); - - // 8. 构建会议页面URL(用于Web端路由跳转和小程序外部访问) - // 获取当前用户的登录token(用于页面token认证) - String userToken = LoginUtil.getToken(); - // 注意:URL不包含/workcase前缀,因为workcase应用的路由base已经是/workcase - String meetingPageUrl = "/meeting?meetingId=" + meetingId + - "&token=" + (userToken != null ? userToken : ""); - - // 9. 更新VO - meeting.setJwtToken(userJwtToken); - meeting.setJitsiIframeUrl(jitsiIframeUrl); // 真正的Jitsi URL - meeting.setIframeUrl(meetingPageUrl); // 会议页面URL(用于router跳转) - meeting.setJitsiServerUrl(jitsiProperties.getServer().getUrl()); // 使用当前配置的服务器URL - - logger.info("生成用户专属会议URL成功: meetingId={}, userId={}, status={}", - meetingId, userId, meeting.getStatus()); - return ResultDomain.success("生成用户专属会议URL成功", meeting); - } catch (Exception e) { - logger.error("生成用户专属会议URL异常: meetingId={}, error={}", meetingId, e.getMessage(), e); - return ResultDomain.failure("生成会议URL失败: " + e.getMessage()); - } - } - - @Override - @Transactional - public ResultDomain startMeeting(String meetingId) { - logger.info("开始会议: meetingId={}", meetingId); - - try { - TbVideoMeetingDTO updateDTO = new TbVideoMeetingDTO(); - updateDTO.setMeetingId(meetingId); - updateDTO.setStatus("ongoing"); - updateDTO.setActualStartTime(new Date()); - - int rows = videoMeetingMapper.updateVideoMeeting(updateDTO); - if (rows > 0) { - logger.info("会议开始成功: meetingId={}", meetingId); - return ResultDomain.success("会议开始成功", true); - } else { - logger.warn("会议开始失败(可能不存在): meetingId={}", meetingId); - return ResultDomain.failure("会议不存在或已开始"); - } - } catch (Exception e) { - logger.error("开始会议异常: meetingId={}, error={}", meetingId, e.getMessage(), e); - return ResultDomain.failure("开始会议失败: " + e.getMessage()); - } - } - - @Override - @Transactional - public ResultDomain endMeeting(String meetingId) { - logger.info("结束会议: meetingId={}", meetingId); - - try { - // 1. 获取会议信息 - TbVideoMeetingDTO filter = new TbVideoMeetingDTO(); - filter.setMeetingId(meetingId); - List meetings = videoMeetingMapper.selectVideoMeetingList(filter); - - if (meetings == null || meetings.isEmpty()) { - logger.warn("会议不存在: meetingId={}", meetingId); - return ResultDomain.failure("会议不存在"); - } - - VideoMeetingVO meeting = meetings.get(0); - - // 2. 计算会议时长 - Integer durationSeconds = null; - if (meeting.getActualStartTime() != null) { - long duration = (System.currentTimeMillis() - meeting.getActualStartTime().getTime()) / 1000; - durationSeconds = (int) duration; - } - - // 3. 更新会议状态 - TbVideoMeetingDTO updateDTO = new TbVideoMeetingDTO(); - updateDTO.setMeetingId(meetingId); - updateDTO.setStatus("ended"); - updateDTO.setActualEndTime(new Date()); - updateDTO.setDurationSeconds(durationSeconds); - - int rows = videoMeetingMapper.updateVideoMeeting(updateDTO); - if (rows > 0) { - // 4. 更新VO - meeting.setStatus("ended"); - meeting.setActualEndTime(new Date()); - meeting.setDurationSeconds(durationSeconds); - - logger.info("会议结束成功: meetingId={}, duration={}秒", meetingId, durationSeconds); - return ResultDomain.success("会议结束成功", meeting); - } else { - logger.warn("会议结束失败: meetingId={}", meetingId); - return ResultDomain.failure("结束会议失败"); - } - } catch (Exception e) { - logger.error("结束会议异常: meetingId={}, error={}", meetingId, e.getMessage(), e); - return ResultDomain.failure("结束会议失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain getActiveMeetingByRoom(String roomId) { - logger.info("获取聊天室活跃会议: roomId={}", roomId); - - try { - TbVideoMeetingDTO filter = new TbVideoMeetingDTO(); - filter.setRoomId(roomId); - filter.setStatus("ongoing"); - List meetings = videoMeetingMapper.selectVideoMeetingList(filter); - - if (meetings == null || meetings.isEmpty()) { - logger.info("聊天室无活跃会议: roomId={}", roomId); - return ResultDomain.failure("无活跃会议"); - } - - VideoMeetingVO meeting = meetings.get(0); - logger.info("找到活跃会议: roomId={}, meetingId={}", roomId, meeting.getMeetingId()); - return ResultDomain.success("找到活跃会议", meeting); - } catch (Exception e) { - logger.error("获取活跃会议异常: roomId={}, error={}", roomId, e.getMessage(), e); - return ResultDomain.failure("获取活跃会议失败: " + e.getMessage()); - } - } - - @Override - public boolean isMemberOfRoom(String roomId, String userId) { - logger.debug("检查用户是否为聊天室成员: roomId={}, userId={}", roomId, userId); - - try { - TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO(); - filter.setRoomId(roomId); - filter.setUserId(userId); - filter.setStatus("active"); - - List members = chatRoomMemberMapper.selectChatRoomMemberList(filter); - boolean isMember = members != null && !members.isEmpty(); - - logger.debug("用户成员检查结果: roomId={}, userId={}, isMember={}", - roomId, userId, isMember); - return isMember; - } catch (Exception e) { - logger.error("检查用户成员身份异常: roomId={}, userId={}, error={}", - roomId, userId, e.getMessage(), e); - return false; - } - } - - /** - * 发送会议通知消息到聊天室 - * @param meetingDTO 会议信息 - * @param creatorName 创建者名称 - */ - private void sendMeetingNotification(TbVideoMeetingDTO meetingDTO, String creatorName) { - logger.info("发送会议通知消息: roomId={}, meetingId={}", - meetingDTO.getRoomId(), meetingDTO.getMeetingId()); - - // 构建消息内容 - TbChatRoomMessageDTO message = new TbChatRoomMessageDTO(); - message.setMessageId(IdUtil.generateUUID()); - message.setRoomId(meetingDTO.getRoomId()); - message.setSenderId(meetingDTO.getCreator()); - message.setSenderType(meetingDTO.getCreatorType()); - message.setSenderName(creatorName); - message.setMessageType("meet"); // 会议类型消息 - message.setContent(meetingDTO.getMeetingId()); // 会议ID作为内容(前端根据ID查询会议详情) - message.setStatus("sent"); - message.setReadCount(0); - message.setSendTime(new Date()); - - // 构建扩展信息(会议详情) - JSONObject contentExtra = new JSONObject(); - contentExtra.put("meetingId", meetingDTO.getMeetingId()); - contentExtra.put("meetingName", meetingDTO.getMeetingName()); - contentExtra.put("jitsiRoomName", meetingDTO.getJitsiRoomName()); - contentExtra.put("startTime", meetingDTO.getStartTime()); - contentExtra.put("endTime", meetingDTO.getEndTime()); - contentExtra.put("advance", meetingDTO.getAdvance()); - contentExtra.put("maxParticipants", meetingDTO.getMaxParticipants()); - contentExtra.put("creatorName", creatorName); - contentExtra.put("workcaseId", meetingDTO.getWorkcaseId()); - contentExtra.put("status", meetingDTO.getStatus()); - message.setContentExtra(contentExtra); - - // 发送消息 - ResultDomain sendResult = chatRoomService.sendMessage(message); - if (sendResult.getSuccess()) { - logger.info("会议通知消息发送成功: messageId={}", message.getMessageId()); - } else { - logger.warn("会议通知消息发送失败: {}", sendResult.getMessage()); - } - } - - /** - * 检查时间是否冲突 - * @param start1 时间段1开始时间 - * @param end1 时间段1结束时间 - * @param start2 时间段2开始时间 - * @param end2 时间段2结束时间 - * @return 是否冲突 - */ - private boolean isTimeConflict(Date start1, Date end1, Date start2, Date end2) { - // 时间段1的结束时间 > 时间段2的开始时间 AND 时间段1的开始时间 < 时间段2的结束时间 - return end1.after(start2) && start1.before(end2); - } - - @Override - @Transactional - public ResultDomain getMeetingEntryByToken(String meetingId, String token) { - logger.info("通过token获取会议入口: meetingId={}", meetingId); - - try { - // 1. 验证token并获取用户信息 - if (token == null || token.trim().isEmpty()) { - logger.warn("token为空: meetingId={}", meetingId); - return ResultDomain.failure("认证token不能为空"); - } - - // 去除Bearer前缀(如果有) - if (token.startsWith("Bearer ")) { - token = token.substring(7); - } - - ResultDomain loginResult = authService.getLoginByToken(token); - if (!loginResult.getSuccess() || loginResult.getData() == null) { - logger.warn("token验证失败: meetingId={}, error={}", meetingId, loginResult.getMessage()); - return ResultDomain.failure("认证失败: " + loginResult.getMessage()); - } - - LoginDomain loginDomain = loginResult.getData(); - String userId = loginDomain.getUser().getUserId(); - logger.info("token验证成功: meetingId={}, userId={}", meetingId, userId); - - // 2. 调用现有的generateUserMeetingUrl方法生成会议URL - // 但需要先设置当前登录上下文(因为generateUserMeetingUrl可能依赖LoginUtil) - // 这里直接复用generateUserMeetingUrl的核心逻辑 - - // 获取会议信息 - TbVideoMeetingDTO filter = new TbVideoMeetingDTO(); - filter.setMeetingId(meetingId); - List meetings = videoMeetingMapper.selectVideoMeetingList(filter); - - if (meetings == null || meetings.isEmpty()) { - logger.warn("会议不存在: meetingId={}", meetingId); - return ResultDomain.failure("会议不存在"); - } - - VideoMeetingVO meeting = meetings.get(0); - - // 3. 验证访问权限(用户必须是聊天室成员) - if (!isMemberOfRoom(meeting.getRoomId(), userId)) { - logger.warn("用户无权访问会议: meetingId={}, userId={}", meetingId, userId); - return ResultDomain.failure("您无权访问此会议"); - } - - // 4. 检查会议状态和时间窗口 - if ("ended".equals(meeting.getStatus())) { - logger.warn("会议已结束: meetingId={}", meetingId); - return ResultDomain.failure("会议已结束"); - } - - if ("scheduled".equals(meeting.getStatus())) { - Date now = new Date(); - - // 计算提前入会时间点 - Calendar calendar = Calendar.getInstance(); - calendar.setTime(meeting.getStartTime()); - calendar.add(Calendar.MINUTE, -meeting.getAdvance()); - Date advanceTime = calendar.getTime(); - - if (now.before(advanceTime)) { - logger.warn("会议未到入会时间: meetingId={}", meetingId); - return ResultDomain.failure("会议未到入会时间,请在 " + advanceTime + " 之后加入"); - } - - if (now.after(meeting.getEndTime())) { - logger.warn("会议已过期: meetingId={}", meetingId); - return ResultDomain.failure("会议已结束"); - } - - // 首次入会时更新会议状态 - ReentrantLock lock = meetingLocks.computeIfAbsent(meetingId, k -> new ReentrantLock()); - lock.lock(); - try { - List recheck = videoMeetingMapper.selectVideoMeetingList(filter); - if (recheck != null && !recheck.isEmpty() && "scheduled".equals(recheck.get(0).getStatus())) { - TbVideoMeetingDTO updateDTO = new TbVideoMeetingDTO(); - updateDTO.setMeetingId(meetingId); - updateDTO.setStatus("ongoing"); - updateDTO.setActualStartTime(new Date()); - videoMeetingMapper.updateVideoMeeting(updateDTO); - meeting.setStatus("ongoing"); - meeting.setActualStartTime(new Date()); - logger.info("会议状态已更新为进行中: meetingId={}", meetingId); - } - } finally { - lock.unlock(); - if (!lock.hasQueuedThreads()) { - meetingLocks.remove(meetingId); - } - } - } - - // 5. 获取用户信息 - TbChatRoomMemberDTO memberFilter = new TbChatRoomMemberDTO(); - memberFilter.setRoomId(meeting.getRoomId()); - memberFilter.setUserId(userId); - List members = chatRoomMemberMapper.selectChatRoomMemberList(memberFilter); - - String userName = loginDomain.getUserInfo().getUsername(); - boolean isModerator = userId.equals(meeting.getCreator()); - - if (members != null && !members.isEmpty()) { - userName = members.get(0).getUserName(); - } - - // 6. 生成用户专属JWT Token - String userJwtToken = jitsiTokenService.generateJwtToken( - meeting.getJitsiRoomName(), - userId, - userName, - isModerator - ); - - // 7. 构建真正的Jitsi iframe URL - String jitsiIframeUrl = jitsiTokenService.buildIframeUrl( - meeting.getJitsiRoomName(), - userJwtToken, - meeting.getConfig() - ); - - // 8. 构建会议页面URL(用于Web端路由跳转和小程序外部访问) - // 注意:使用提供的token参数而非LoginUtil.getToken() - String meetingPageUrl = "/meeting?meetingId=" + meetingId + - "&token=" + token; - - // 9. 更新VO并返回 - meeting.setJwtToken(userJwtToken); - meeting.setJitsiIframeUrl(jitsiIframeUrl); // 真正的Jitsi URL - meeting.setIframeUrl(meetingPageUrl); // 会议页面URL(用于router跳转) - - logger.info("通过token获取会议入口成功: meetingId={}, userId={}, isModerator={}", - meetingId, userId, isModerator); - return ResultDomain.success("获取会议入口成功", meeting); - - } catch (Exception e) { - logger.error("通过token获取会议入口异常: meetingId={}, error={}", meetingId, e.getMessage(), e); - return ResultDomain.failure("获取会议入口失败: " + e.getMessage()); - } - } - - @Override - public ResultDomain generateMeetingEntryUrl(String meetingId, String baseUrl) { - logger.info("生成会议入口URL: meetingId={}, baseUrl={}", meetingId, baseUrl); - - try { - // 获取当前用户token - LoginDomain loginDomain = LoginUtil.getCurrentLogin(); - if (loginDomain == null || loginDomain.getToken() == null) { - logger.warn("无法获取当前用户token: meetingId={}", meetingId); - return ResultDomain.failure("无法获取当前用户认证信息"); - } - - // 构建完整URL: {baseUrl}/meeting/{meetingId}?token={token} - String entryUrl = String.format("%s/meeting/%s?token=%s", - baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl, - meetingId, - loginDomain.getToken() - ); - - logger.info("会议入口URL生成成功: meetingId={}", meetingId); - return ResultDomain.success("生成会议入口URL成功", entryUrl); - - } catch (Exception e) { - logger.error("生成会议入口URL异常: meetingId={}, error={}", meetingId, e.getMessage(), e); - return ResultDomain.failure("生成会议入口URL失败: " + e.getMessage()); - } - } -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseChatServiceImpl.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseChatServiceImpl.java deleted file mode 100644 index 250a7d48..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseChatServiceImpl.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.xyzh.workcase.service; - -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.List; - -import org.apache.dubbo.config.annotation.DubboService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.xyzh.api.workcase.dto.TbWordCloudDTO; -import org.xyzh.api.workcase.service.WorkcaseChatService; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.workcase.mapper.TbWordCloudMapper; - -@DubboService(version = "1.0.0",group = "workcase",timeout = 30000,retries = 0) -public class WorkcaseChatServiceImpl implements WorkcaseChatService{ - - private static final Logger logger = LoggerFactory.getLogger(WorkcaseChatServiceImpl.class); - - @Autowired - private TbWordCloudMapper wordCloudMapper; - - // =============================== 词云管理 ========================== - - @Override - public ResultDomain addWordCloud(TbWordCloudDTO wordCloud) { - logger.info("添加词云: word={}", wordCloud.getWord()); - - if (wordCloud.getWordId() == null || wordCloud.getWordId().isEmpty()) { - wordCloud.setWordId(IdUtil.generateUUID()); - } - if (wordCloud.getStatDate() == null || wordCloud.getStatDate().isEmpty()) { - wordCloud.setStatDate(LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE)); - } - if (wordCloud.getFrequency() == null) { - wordCloud.setFrequency("1"); - } - - TbWordCloudDTO queryFilter = new TbWordCloudDTO(); - queryFilter.setWord(wordCloud.getWord()); - queryFilter.setCategory(wordCloud.getCategory()); - queryFilter.setStatDate(wordCloud.getStatDate()); - TbWordCloudDTO existing = wordCloudMapper.selectWordCloudOne(queryFilter); - - if (existing != null) { - wordCloudMapper.incrementFrequency(existing.getWordId(), Integer.parseInt(wordCloud.getFrequency())); - TbWordCloudDTO updated = wordCloudMapper.selectWordCloudById(existing.getWordId()); - return ResultDomain.success("词频更新成功", updated); - } - - int rows = wordCloudMapper.insertWordCloud(wordCloud); - if (rows > 0) { - return ResultDomain.success("添加成功", wordCloud); - } - return ResultDomain.failure("添加失败"); - } - - @Override - public ResultDomain updateWordCloud(TbWordCloudDTO wordCloud) { - logger.info("更新词云: wordId={}", wordCloud.getWordId()); - - int rows = wordCloudMapper.updateWordCloud(wordCloud); - if (rows > 0) { - TbWordCloudDTO updated = wordCloudMapper.selectWordCloudById(wordCloud.getWordId()); - return ResultDomain.success("更新成功", updated); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain getWordCloudList(TbWordCloudDTO filter) { - List list = wordCloudMapper.selectWordCloudList(filter); - return ResultDomain.success("查询成功", list); - } - - @Override - public ResultDomain getWordCloudPage(PageRequest pageRequest) { - TbWordCloudDTO filter = pageRequest.getFilter(); - PageParam pageParam = pageRequest.getPageParam(); - - List list = wordCloudMapper.selectWordCloudPage(filter, pageParam); - long total = wordCloudMapper.countWordClouds(filter); - - pageParam.setTotal((int) total); - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - -} diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseServiceImpl.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseServiceImpl.java deleted file mode 100644 index 3c0e2312..00000000 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseServiceImpl.java +++ /dev/null @@ -1,914 +0,0 @@ -package org.xyzh.workcase.service; - -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import javax.imageio.ImageIO; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.config.annotation.DubboService; -import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; -import org.xyzh.api.file.dto.TbSysFileDTO; -import org.xyzh.api.workcase.dto.TbWorkcaseDTO; -import org.xyzh.api.workcase.dto.TbWorkcaseDeviceDTO; -import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO; -import org.xyzh.api.workcase.service.WorkcaseService; -import org.xyzh.api.workcase.vo.WorkcaseProcessVO; -import org.xyzh.common.auth.utils.LoginUtil; -import org.xyzh.common.core.domain.ResultDomain; -import org.xyzh.common.core.page.PageDomain; -import org.xyzh.common.core.page.PageParam; -import org.xyzh.common.core.page.PageRequest; -import org.xyzh.common.utils.id.IdUtil; -import org.xyzh.workcase.enums.WorkcaseProcessAction; -import org.xyzh.workcase.mapper.TbWorkcaseDeviceMapper; -import org.xyzh.workcase.mapper.TbWorkcaseMapper; -import org.xyzh.workcase.mapper.TbWorkcaseProcessMapper; -import org.xyzh.api.file.service.FileService; -import org.xyzh.api.workcase.dto.TbChatRoomDTO; -import org.xyzh.api.workcase.service.ChatRoomService; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; -import com.google.zxing.BinaryBitmap; -import com.google.zxing.DecodeHintType; -import com.google.zxing.MultiFormatReader; -import com.google.zxing.Result; -import com.google.zxing.client.j2se.BufferedImageLuminanceSource; -import com.google.zxing.common.HybridBinarizer; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -@DubboService(version = "1.0.0",group = "workcase",timeout = 30000,retries = 0) -public class WorkcaseServiceImpl implements WorkcaseService { - private static final Logger logger = LoggerFactory.getLogger(WorkcaseServiceImpl.class); - - @Autowired - private TbWorkcaseMapper workcaseMapper; - - @Autowired - private TbWorkcaseProcessMapper workcaseProcessMapper; - - @Autowired - private TbWorkcaseDeviceMapper workcaseDeviceMapper; - - @Autowired - private ChatRoomService chatRoomService; - - @DubboReference(version = "1.0.0",group = "file",timeout = 30000,retries = 0) - private FileService fileService; - - // ====================== 工单管理 ====================== - - @Override - @Transactional - public ResultDomain createWorkcase(TbWorkcaseDTO workcase) { - logger.info("创建工单: userId={}, type={}, roomId={}", workcase.getUserId(), workcase.getType(), workcase.getRoomId()); - - // 前端应确保 roomId 已创建并传入 - if (workcase.getRoomId() == null || workcase.getRoomId().isEmpty()) { - logger.error("创建工单失败: roomId 不能为空"); - return ResultDomain.failure("缺少聊天室ID (roomId),无法创建工单"); - } - - - if (workcase.getWorkcaseId() == null || workcase.getWorkcaseId().isEmpty()) { - workcase.setWorkcaseId(IdUtil.generateUUID()); - } - if (workcase.getOptsn() == null || workcase.getOptsn().isEmpty()) { - workcase.setOptsn(IdUtil.getOptsn()); - } - if (workcase.getStatus() == null || workcase.getStatus().isEmpty()) { - workcase.setStatus("pending"); - } - if (workcase.getEmergency() == null || workcase.getEmergency().isEmpty()) { - workcase.setEmergency("normal"); - } - // 统一由后端从登录态设置 creator,避免前端传入不可信 - workcase.setCreator(LoginUtil.getCurrentUserId()); - - // 解析设备铭牌二维码 - // ResultDomain deviceResult = anylizeQrCode(workcase.getDeviceNamePlateImg()); - - int rows = workcaseMapper.insertWorkcase(workcase); - if (rows > 0) { - // 创建工单处理记录 - TbWorkcaseProcessDTO process = new TbWorkcaseProcessDTO(); - process.setProcessId(IdUtil.generateUUID()); - process.setOptsn(IdUtil.getOptsn()); - process.setWorkcaseId(workcase.getWorkcaseId()); - process.setAction(WorkcaseProcessAction.CREATE.getName()); - process.setMessage("工单创建"); - process.setCreator(workcase.getCreator()); - workcaseProcessMapper.insertWorkcaseProcess(process); - - // 如果是新创建的聊天室,更新聊天室的 workcaseId - - logger.info("更新聊天室的工单ID: roomId={}, workcaseId={}", workcase.getRoomId(), workcase.getWorkcaseId()); - TbChatRoomDTO updateRoom = new TbChatRoomDTO(); - updateRoom.setRoomId(workcase.getRoomId()); - updateRoom.setWorkcaseId(workcase.getWorkcaseId()); - chatRoomService.updateChatRoom(updateRoom); - - // 插入设备文件记录到数据库 - // if (deviceResult.getSuccess() && deviceResult.getData() != null) { - // List deviceList = (List) deviceResult.getData(); - // for (TbWorkcaseDeviceDTO deviceDTO : deviceList) { - // deviceDTO.setWorkcaseId(workcase.getWorkcaseId()); - // try { - // workcaseDeviceMapper.insertWorkcaseDevice(deviceDTO); - // logger.info("设备文件记录插入成功: workcaseId={}, fileName={}", - // workcase.getWorkcaseId(), deviceDTO.getFileName()); - // } catch (Exception e) { - // logger.error("设备文件记录插入失败: " + deviceDTO.getFileName(), e); - // } - // } - // } - - syncWorkcaseToCrm(workcase); - return ResultDomain.success("创建成功", workcase); - // return ResultDomain.success(deviceResult.getSuccess() ? "创建成功" : "设备铭牌二维码解析失败", workcase); - } - return ResultDomain.failure("创建失败"); - } - - @Override - public ResultDomain updateWorkcase(TbWorkcaseDTO workcase) { - logger.info("更新工单: workcaseId={}, status={}", workcase.getWorkcaseId(), workcase.getStatus()); - - TbWorkcaseDTO existing = workcaseMapper.selectWorkcaseById(workcase.getWorkcaseId()); - if (existing == null) { - return ResultDomain.failure("工单不存在"); - } - - String oldStatus = existing.getStatus(); - int rows = workcaseMapper.updateWorkcase(workcase); - - if (rows > 0) { - TbWorkcaseDTO updated = workcaseMapper.selectWorkcaseById(workcase.getWorkcaseId()); - - if (workcase.getStatus() != null && !workcase.getStatus().equals(oldStatus)) { - TbWorkcaseProcessDTO process = new TbWorkcaseProcessDTO(); - process.setProcessId(IdUtil.generateUUID()); - process.setOptsn(IdUtil.getOptsn()); - process.setWorkcaseId(workcase.getWorkcaseId()); - process.setCreator(workcase.getCreator()); - - if ("done".equals(workcase.getStatus())) { - process.setAction(WorkcaseProcessAction.FINISH.getName()); - process.setMessage("工单完成"); - } else if ("cancelled".equals(workcase.getStatus())) { - process.setAction(WorkcaseProcessAction.REPEAL.getName()); - process.setMessage("工单撤销"); - } else { - process.setAction(WorkcaseProcessAction.INFO.getName()); - process.setMessage("状态变更: " + oldStatus + " -> " + workcase.getStatus()); - } - workcaseProcessMapper.insertWorkcaseProcess(process); - } - - syncWorkcaseToCrm(updated); - - return ResultDomain.success("更新成功", updated); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain deleteWorkcase(TbWorkcaseDTO workcase) { - logger.info("删除工单: workcaseId={}", workcase.getWorkcaseId()); - - int rows = workcaseMapper.deleteWorkcase(workcase); - if (rows > 0) { - return ResultDomain.success("删除成功", workcase); - } - return ResultDomain.failure("删除失败"); - } - - @Override - public ResultDomain getWorkcaseById(String workcaseId) { - TbWorkcaseDTO workcase = workcaseMapper.selectWorkcaseById(workcaseId); - if (workcase != null) { - return ResultDomain.success("查询成功", workcase); - } - return ResultDomain.failure("工单不存在"); - } - - @Override - public ResultDomain getWorkcaseList(TbWorkcaseDTO filter) { - List list = workcaseMapper.selectWorkcaseList(filter); - return ResultDomain.success("查询成功", list); - } - - @Override - public ResultDomain getWorkcasePage(PageRequest pageRequest) { - TbWorkcaseDTO filter = pageRequest.getFilter(); - PageParam pageParam = pageRequest.getPageParam(); - - List list = workcaseMapper.selectWorkcasePage(filter, pageParam); - long total = workcaseMapper.countWorkcases(filter); - - pageParam.setTotal((int) total); - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - - @Override - public ResultDomain countWorkcasesByType(TbWorkcaseDTO filter) { - List workcases = workcaseMapper.countWorkcasesByType(filter); - return ResultDomain.success("查询成功", workcases); - } - - @Override - public ResultDomain countWorkcases(TbWorkcaseDTO filter) { - long count = workcaseMapper.countWorkcases(filter); - return ResultDomain.success("查询成功", count); - } - - // ====================== 同步到CRM和接收 =================== - - @Override - public ResultDomain syncWorkcaseToCrm(TbWorkcaseDTO workcase) { - logger.info("同步工单到CRM: workcaseId={}", workcase.getWorkcaseId()); - - // ============== 伪代码:同步工单到CRM系统 ============== - // 1. 构建CRM请求数据 - // JSONObject crmData = new JSONObject(); - // crmData.put("workcaseId", workcase.getWorkcaseId()); - // crmData.put("userId", workcase.getUserId()); - // crmData.put("username", workcase.getUsername()); - // crmData.put("phone", workcase.getPhone()); - // crmData.put("type", workcase.getType()); - // crmData.put("device", workcase.getDevice()); - // crmData.put("deviceCode", workcase.getDeviceCode()); - // crmData.put("emergency", workcase.getEmergency()); - // crmData.put("status", workcase.getStatus()); - // crmData.put("createTime", workcase.getCreateTime()); - - // 2. 调用CRM接口 - // String crmApiUrl = "https://crm.example.com/api/workcase/sync"; - // HttpHeaders headers = new HttpHeaders(); - // headers.setContentType(MediaType.APPLICATION_JSON); - // headers.set("Authorization", "Bearer " + crmToken); - // HttpEntity request = new HttpEntity<>(crmData.toJSONString(), headers); - // ResponseEntity response = restTemplate.postForEntity(crmApiUrl, request, String.class); - - // 3. 处理响应 - // if (response.getStatusCode() == HttpStatus.OK) { - // JSONObject result = JSON.parseObject(response.getBody()); - // String crmWorkcaseId = result.getString("crmWorkcaseId"); - // logger.info("同步成功,CRM工单ID: {}", crmWorkcaseId); - // } else { - // logger.error("同步失败: {}", response.getBody()); - // return ResultDomain.failure("同步CRM失败"); - // } - // ============== 伪代码结束 ============== - - logger.info("CRM同步完成(伪代码): workcaseId={}", workcase.getWorkcaseId()); - return ResultDomain.success("同步成功"); - } - - @Override - public ResultDomain receiveWorkcaseFromCrm(JSONObject json) { - logger.info("接收CRM工单更新"); - - // ============== 伪代码:接收CRM的工单处理结果 ============== - // 1. 解析CRM推送的数据 - // JSONObject crmData = (JSONObject) json; - // String workcaseId = crmData.getString("workcaseId"); - // String status = crmData.getString("status"); - // String processor = crmData.getString("processor"); - // String message = crmData.getString("message"); - - // 2. 更新本地工单 - // TbWorkcaseDTO workcase = new TbWorkcaseDTO(); - // workcase.setWorkcaseId(workcaseId); - // workcase.setStatus(status); - // workcase.setProcessor(processor); - // workcaseMapper.updateWorkcase(workcase); - - // 3. 记录处理过程 - // TbWorkcaseProcessDTO process = new TbWorkcaseProcessDTO(); - // process.setProcessId(UUID.randomUUID().toString().replace("-", "")); - // process.setOptsn(SnowflakeIdUtil.nextIdStr()); - // process.setWorkcaseId(workcaseId); - // process.setAction(WorkcaseProcessAction.INFO.getName()); - // process.setMessage("CRM更新: " + message); - // process.setProcessor(processor); - // process.setCreator("CRM_SYSTEM"); - // workcaseProcessMapper.insertWorkcaseProcess(process); - - // 4. 如果工单完成或撤销,触发总结 - // if ("done".equals(status) || "cancelled".equals(status)) { - // workcaseChatService.summaryChat(workcaseId); - // } - // ============== 伪代码结束 ============== - - logger.info("CRM工单接收处理完成(伪代码)"); - return ResultDomain.success("接收成功"); - } - - private void sendWechatKefuWelcome(TbWorkcaseDTO workcase) { - logger.info("发送微信客服欢迎语: workcaseId={}", workcase.getWorkcaseId()); - - // ============== 伪代码:发送微信客服欢迎语 ============== - // 1. 构建欢迎语内容(包含工单基本信息) - // StringBuilder welcomeMsg = new StringBuilder(); - // welcomeMsg.append("【工单信息】\n"); - // welcomeMsg.append("工单编号:").append(workcase.getOptsn()).append("\n"); - // welcomeMsg.append("故障类型:").append(workcase.getType()).append("\n"); - // welcomeMsg.append("设备名称:").append(workcase.getDevice()).append("\n"); - // welcomeMsg.append("紧急程度:").append("emergency".equals(workcase.getEmergency()) ? "紧急" : "普通").append("\n"); - // welcomeMsg.append("联系人:").append(workcase.getUsername()).append("\n"); - // welcomeMsg.append("联系电话:").append(workcase.getPhone()).append("\n"); - // welcomeMsg.append("\n客服将尽快为您处理,请稍候..."); - - // 2. 获取微信客服接入链接 - // String kefuUrl = wechatKefuService.getKefuUrl(workcase.getUserId()); - - // 3. 调用微信客服API发送欢迎语 - // JSONObject msgBody = new JSONObject(); - // msgBody.put("touser", workcase.getUserId()); // 微信openid - // msgBody.put("msgtype", "text"); - // JSONObject textContent = new JSONObject(); - // textContent.put("content", welcomeMsg.toString()); - // msgBody.put("text", textContent); - - // String accessToken = wechatService.getAccessToken(); - // String apiUrl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + accessToken; - // restTemplate.postForEntity(apiUrl, msgBody.toJSONString(), String.class); - - // 4. 记录客服会话开始 - // wechatKefuService.startSession(workcase.getUserId(), workcase.getWorkcaseId()); - // ============== 伪代码结束 ============== - - logger.info("微信客服欢迎语发送完成(伪代码): workcaseId={}", workcase.getWorkcaseId()); - } - - // ====================== 工单处理过程 ====================== - - @Override - public ResultDomain createWorkcaseProcess(TbWorkcaseProcessDTO workcaseProcess) { - logger.info("创建工单过程: workcaseId={}, action={}", workcaseProcess.getWorkcaseId(), workcaseProcess.getAction()); - - if (workcaseProcess.getProcessId() == null || workcaseProcess.getProcessId().isEmpty()) { - workcaseProcess.setProcessId(IdUtil.generateUUID()); - } - if (workcaseProcess.getOptsn() == null || workcaseProcess.getOptsn().isEmpty()) { - workcaseProcess.setOptsn(IdUtil.getOptsn()); - } - - String action = workcaseProcess.getAction(); - if (WorkcaseProcessAction.ASSIGN.getName().equals(action) || - WorkcaseProcessAction.REDEPLOY.getName().equals(action)) { - if (workcaseProcess.getProcessor() != null) { - TbWorkcaseDTO workcase = new TbWorkcaseDTO(); - workcase.setWorkcaseId(workcaseProcess.getWorkcaseId()); - workcase.setProcessor(workcaseProcess.getProcessor()); - workcase.setStatus("processing"); - workcaseMapper.updateWorkcase(workcase); - } - } else if (WorkcaseProcessAction.FINISH.getName().equals(action)) { - // 1. 更新工单状态为已完成 - TbWorkcaseDTO workcase = new TbWorkcaseDTO(); - workcase.setWorkcaseId(workcaseProcess.getWorkcaseId()); - workcase.setStatus("done"); - workcaseMapper.updateWorkcase(workcase); - - // 2. 发送系统评分消息到聊天室 - try { - TbWorkcaseDTO workcaseData = workcaseMapper.selectWorkcaseById(workcaseProcess.getWorkcaseId()); - if (workcaseData != null && workcaseData.getRoomId() != null) { - // 创建系统评分消息 - org.xyzh.api.workcase.dto.TbChatRoomMessageDTO commentMessage = new org.xyzh.api.workcase.dto.TbChatRoomMessageDTO(); - commentMessage.setMessageId(IdUtil.generateUUID()); - commentMessage.setOptsn(IdUtil.getOptsn()); - commentMessage.setRoomId(workcaseData.getRoomId()); - commentMessage.setSenderId("system"); - commentMessage.setSenderType("system"); // 系统消息 - commentMessage.setSenderName("系统"); - commentMessage.setMessageType("comment"); // 评分消息 - commentMessage.setContent("请为本次服务评分"); - commentMessage.setStatus("sent"); - commentMessage.setCreator("system"); - - // 发送消息到聊天室 - chatRoomService.sendMessage(commentMessage); - logger.info("工单完成,已发送系统评分消息: workcaseId={}, roomId={}", - workcaseProcess.getWorkcaseId(), workcaseData.getRoomId()); - } - } catch (Exception e) { - logger.error("发送系统评分消息失败: workcaseId={}", workcaseProcess.getWorkcaseId(), e); - // 不影响工单完成流程,只记录错误日志 - } - } else if (WorkcaseProcessAction.REPEAL.getName().equals(action)) { - // 1. 更新工单状态为已撤销 - TbWorkcaseDTO workcase = new TbWorkcaseDTO(); - workcase.setWorkcaseId(workcaseProcess.getWorkcaseId()); - workcase.setStatus("cancelled"); - workcaseMapper.updateWorkcase(workcase); - - // 2. 发送系统评分消息到聊天室 - try { - TbWorkcaseDTO workcaseData = workcaseMapper.selectWorkcaseById(workcaseProcess.getWorkcaseId()); - if (workcaseData != null && workcaseData.getRoomId() != null) { - // 创建系统评分消息 - org.xyzh.api.workcase.dto.TbChatRoomMessageDTO commentMessage = new org.xyzh.api.workcase.dto.TbChatRoomMessageDTO(); - commentMessage.setMessageId(IdUtil.generateUUID()); - commentMessage.setOptsn(IdUtil.getOptsn()); - commentMessage.setRoomId(workcaseData.getRoomId()); - commentMessage.setSenderId("system"); - commentMessage.setSenderType("system"); // 系统消息 - commentMessage.setSenderName("系统"); - commentMessage.setMessageType("comment"); // 评分消息 - commentMessage.setContent("工单已撤销,请为本次服务评分"); - commentMessage.setStatus("sent"); - commentMessage.setCreator("system"); - - // 发送消息到聊天室 - chatRoomService.sendMessage(commentMessage); - logger.info("工单撤销,已发送系统评分消息: workcaseId={}, roomId={}", - workcaseProcess.getWorkcaseId(), workcaseData.getRoomId()); - } - } catch (Exception e) { - logger.error("发送系统评分消息失败: workcaseId={}", workcaseProcess.getWorkcaseId(), e); - // 不影响工单撤销流程,只记录错误日志 - } - } - workcaseProcess.setCreator(LoginUtil.getCurrentUserId()); - - int rows = workcaseProcessMapper.insertWorkcaseProcess(workcaseProcess); - if (rows > 0) { - TbWorkcaseDTO workcase = workcaseMapper.selectWorkcaseById(workcaseProcess.getWorkcaseId()); - if (workcase != null) { - syncWorkcaseToCrm(workcase); - } - return ResultDomain.success("创建成功", workcaseProcess); - } - return ResultDomain.failure("创建失败"); - } - - @Override - public ResultDomain updateWorkcaseProcess(TbWorkcaseProcessDTO workcaseProcess) { - logger.info("更新工单过程: processId={}", workcaseProcess.getProcessId()); - - int rows = workcaseProcessMapper.updateWorkcaseProcess(workcaseProcess); - if (rows > 0) { - TbWorkcaseProcessDTO updated = workcaseProcessMapper.selectWorkcaseProcessById(workcaseProcess.getProcessId()); - return ResultDomain.success("更新成功", updated); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain deleteWorkcaseProcess(TbWorkcaseProcessDTO workcaseProcess) { - logger.info("删除工单过程: processId={}", workcaseProcess.getProcessId()); - - int rows = workcaseProcessMapper.deleteWorkcaseProcess(workcaseProcess.getProcessId()); - if (rows > 0) { - return ResultDomain.success("删除成功", workcaseProcess); - } - return ResultDomain.failure("删除失败"); - } - - @Override - public ResultDomain getWorkcaseProcessList(TbWorkcaseProcessDTO filter) { - List list = workcaseProcessMapper.selectWorkcaseProcessList(filter); - return ResultDomain.success("查询成功", list); - } - - @Override - public ResultDomain getWorkcaseProcessPage(PageRequest pageRequest) { - TbWorkcaseProcessDTO filter = pageRequest.getFilter(); - PageParam pageParam = pageRequest.getPageParam(); - - List list = workcaseProcessMapper.selectWorkcaseProcessPage(filter, pageParam); - long total = workcaseProcessMapper.countWorkcaseProcesses(filter); - - pageParam.setTotal((int) total); - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - - // ====================== 工单设备管理 ====================== - - @Override - public ResultDomain createWorkcaseDevice(TbWorkcaseDeviceDTO workcaseDevice) { - logger.info("创建工单设备: workcaseId={}, device={}", workcaseDevice.getWorkcaseId(), workcaseDevice.getDevice()); - - if (workcaseDevice.getOptsn() == null || workcaseDevice.getOptsn().isEmpty()) { - workcaseDevice.setOptsn(IdUtil.getOptsn()); - } - - int rows = workcaseDeviceMapper.insertWorkcaseDevice(workcaseDevice); - if (rows > 0) { - return ResultDomain.success("创建成功", workcaseDevice); - } - return ResultDomain.failure("创建失败"); - } - - @Override - public ResultDomain updateWorkcaseDevice(TbWorkcaseDeviceDTO workcaseDevice) { - logger.info("更新工单设备: workcaseId={}, fileId={}", workcaseDevice.getWorkcaseId(), workcaseDevice.getFileId()); - - int rows = workcaseDeviceMapper.updateWorkcaseDevice(workcaseDevice); - if (rows > 0) { - TbWorkcaseDeviceDTO updated = workcaseDeviceMapper.selectWorkcaseDeviceById( - workcaseDevice.getWorkcaseId(), workcaseDevice.getFileId()); - return ResultDomain.success("更新成功", updated); - } - return ResultDomain.failure("更新失败"); - } - - @Override - public ResultDomain deleteWorkcaseDevice(TbWorkcaseDeviceDTO workcaseDevice) { - logger.info("删除工单设备: workcaseId={}, fileId={}", workcaseDevice.getWorkcaseId(), workcaseDevice.getFileId()); - - int rows = workcaseDeviceMapper.deleteWorkcaseDevice(workcaseDevice.getWorkcaseId(), workcaseDevice.getFileId()); - if (rows > 0) { - return ResultDomain.success("删除成功", workcaseDevice); - } - return ResultDomain.failure("删除失败"); - } - - @Override - public ResultDomain getWorkcaseDeviceList(TbWorkcaseDeviceDTO filter) { - List list = workcaseDeviceMapper.selectWorkcaseDeviceList(filter); - return ResultDomain.success("查询成功", list); - } - - @Override - public ResultDomain getWorkcaseDevicePage(PageRequest pageRequest) { - TbWorkcaseDeviceDTO filter = pageRequest.getFilter(); - PageParam pageParam = pageRequest.getPageParam(); - - List list = workcaseDeviceMapper.selectWorkcaseDevicePage(filter, pageParam); - long total = workcaseDeviceMapper.countWorkcaseDevices(filter); - - pageParam.setTotal((int) total); - PageDomain pageDomain = new PageDomain<>(pageParam, list); - return ResultDomain.success("查询成功", pageDomain); - } - - /** - * @description 扫描设备铭牌二维码,并下载其中的文件,构建WorkDeviceDTO列表 - * @param qrcodeFileId 二维码文件id - * @return WorkDeviceDTO列表 - * @author yslg - * @since 2025-12-25 - */ - private ResultDomain anylizeQrCode(String qrcodeFileId){ - List workDeviceList = new ArrayList<>(); - - try { - logger.info("开始解析设备铭牌二维码: qrcodeFileId={}", qrcodeFileId); - - // 1. 从 FileService 获取二维码图片 - ResultDomain downloadResult = fileService.downloadFile(qrcodeFileId); - if (!downloadResult.getSuccess()) { - logger.error("下载二维码图片失败: {}", downloadResult.getMessage()); - return ResultDomain.failure("下载二维码图片失败: " + downloadResult.getMessage()); - } - - byte[] qrcodeImageBytes = downloadResult.getData(); - logger.info("二维码图片下载成功,大小: {} bytes", qrcodeImageBytes.length); - - // 2. 解析二维码内容 - String qrcodeContent = decodeQRCode(qrcodeImageBytes); - if (qrcodeContent == null || qrcodeContent.isEmpty()) { - logger.error("二维码解析失败或内容为空"); - return ResultDomain.failure("二维码解析失败或内容为空"); - } - - logger.info("二维码解析成功,内容: {}", qrcodeContent); - - // 3. 判断二维码内容类型并解析 - String deviceCode = null; - String device = null; - JSONArray files = null; - - // 尝试判断是 URL 还是 JSON - if (qrcodeContent.startsWith("http://") || qrcodeContent.startsWith("https://")) { - // 二维码包含 URL,需要访问 H5 页面解析 - logger.info("检测到二维码包含URL,开始访问页面: {}", qrcodeContent); - JSONObject pageData = parseDevicePageFromUrl(qrcodeContent); - - if (pageData == null) { - logger.error("访问URL并解析页面失败"); - return ResultDomain.failure("访问设备信息页面失败"); - } - - deviceCode = pageData.getString("deviceCode"); - device = pageData.getString("device"); - files = pageData.getJSONArray("files"); - } else { - // 二维码直接包含 JSON 数据 - logger.info("检测到二维码包含JSON数据,直接解析"); - JSONObject qrcodeData = JSON.parseObject(qrcodeContent); - deviceCode = qrcodeData.getString("deviceCode"); - device = qrcodeData.getString("device"); - files = qrcodeData.getJSONArray("files"); - } - - if (files == null || files.isEmpty()) { - logger.warn("二维码中没有文件信息"); - return ResultDomain.success("二维码中没有文件信息", workDeviceList); - } - - logger.info("设备编号: {}, 设备名称: {}, 文件数量: {}", deviceCode, device, files.size()); - - // 4. 下载并存储每个文件 - for (int i = 0; i < files.size(); i++) { - JSONObject fileInfo = files.getJSONObject(i); - String fileName = fileInfo.getString("fileName"); - String fileUrl = fileInfo.getString("url"); - - logger.info("开始下载文件 [{}/{}]: {}", i + 1, files.size(), fileName); - - try { - // 下载文件 - byte[] fileBytes = downloadFileFromUrl(fileUrl); - if (fileBytes == null || fileBytes.length == 0) { - logger.error("文件下载失败: {}", fileName); - continue; - } - - logger.info("文件下载成功: {}, 大小: {} bytes", fileName, fileBytes.length); - - // 推断文件类型 - String contentType = getContentTypeFromFileName(fileName); - - // 通过 FileService 存储文件 - ResultDomain uploadResult = fileService.uploadFileBytes( - fileBytes, - fileName, - contentType, - "workcase", - deviceCode - ); - - if (uploadResult.getSuccess()) { - TbSysFileDTO uploadedFile = uploadResult.getData(); - logger.info("文件上传成功: fileId={}, fileName={}", uploadedFile.getFileId(), fileName); - - // 创建 TbWorkcaseDeviceDTO 对象 - TbWorkcaseDeviceDTO deviceDTO = new TbWorkcaseDeviceDTO(); - deviceDTO.setDevice(device); - deviceDTO.setDeviceCode(deviceCode); - deviceDTO.setFileId(uploadedFile.getFileId()); - deviceDTO.setFileName(fileName); - deviceDTO.setFileRootId(uploadedFile.getFileRootId()); - deviceDTO.setOptsn(IdUtil.getOptsn()); - - workDeviceList.add(deviceDTO); - } else { - logger.error("文件上传失败: {}, 原因: {}", fileName, uploadResult.getMessage()); - } - - } catch (Exception e) { - logger.error("处理文件失败: " + fileName, e); - } - } - - logger.info("二维码解析完成,成功处理 {} 个文件", workDeviceList.size()); - return ResultDomain.success("解析成功,处理了 " + workDeviceList.size() + " 个文件", workDeviceList); - - } catch (Exception e) { - logger.error("解析设备铭牌二维码失败", e); - return ResultDomain.failure("解析设备铭牌二维码失败: " + e.getMessage()); - } - } - - /** - * 从 URL 解析设备页面信息 - */ - private JSONObject parseDevicePageFromUrl(String url) { - try { - logger.info("开始访问设备信息页面: {}", url); - - // 访问 URL 并获取 HTML 内容 - Document doc = Jsoup.connect(url) - .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") - .timeout(10000) - .followRedirects(true) - .get(); - - logger.info("页面访问成功,开始解析内容"); - - // 解析设备编号和型号(从页面标题或特定元素中) - String deviceInfo = doc.select("body").text(); - - // 尝试匹配设备编号模式:数字格式如 202508012 - String deviceCode = null; - String device = null; - - // 从页面内容中提取设备编号和型号 - if (deviceInfo.contains("(") && deviceInfo.contains(")")) { - // 例如: "202508012 (THHM1800PL)" - int start = deviceInfo.indexOf("("); - int end = deviceInfo.indexOf(")", start); - if (start > 0 && end > start) { - // 提取括号前的设备编号 - String beforeBracket = deviceInfo.substring(Math.max(0, start - 20), start).trim(); - String[] parts = beforeBracket.split("\\s+"); - if (parts.length > 0) { - deviceCode = parts[parts.length - 1].trim(); - } - - // 提取括号内的型号 - device = deviceInfo.substring(start + 1, end).trim(); - } - } - - logger.info("提取的设备信息 - 编号: {}, 型号: {}", deviceCode, device); - - // 解析文件列表 - JSONArray files = new JSONArray(); - - // 查找所有下载链接(通常是 PDF、图片等文件) - Elements links = doc.select("a[href]"); - for (Element link : links) { - String href = link.attr("abs:href"); // 获取绝对 URL - String text = link.text().trim(); - - // 过滤出文件下载链接(包含文件扩展名) - if (isFileLink(href) && !text.isEmpty()) { - JSONObject fileInfo = new JSONObject(); - fileInfo.put("fileName", text); - fileInfo.put("url", href); - files.add(fileInfo); - logger.info("发现文件: {} -> {}", text, href); - } - } - - // 如果没找到链接,尝试从 script 标签中查找 JSON 数据 - if (files.isEmpty()) { - Elements scripts = doc.select("script"); - for (Element script : scripts) { - String scriptContent = script.html(); - // 尝试查找 JSON 数据 - if (scriptContent.contains("files") || scriptContent.contains("fileName")) { - try { - // 尝试解析嵌入的 JSON - int jsonStart = scriptContent.indexOf("{"); - int jsonEnd = scriptContent.lastIndexOf("}") + 1; - if (jsonStart >= 0 && jsonEnd > jsonStart) { - String jsonStr = scriptContent.substring(jsonStart, jsonEnd); - JSONObject embedded = JSON.parseObject(jsonStr); - if (embedded.containsKey("files")) { - files = embedded.getJSONArray("files"); - if (deviceCode == null) { - deviceCode = embedded.getString("deviceCode"); - } - if (device == null) { - device = embedded.getString("device"); - } - break; - } - } - } catch (Exception e) { - // 忽略解析错误,继续下一个 script - } - } - } - } - - if (deviceCode == null || files.isEmpty()) { - logger.error("无法从页面中提取完整的设备信息"); - return null; - } - - JSONObject result = new JSONObject(); - result.put("deviceCode", deviceCode); - result.put("device", device != null ? device : "Unknown"); - result.put("files", files); - - logger.info("页面解析成功,设备编号: {}, 文件数量: {}", deviceCode, files.size()); - return result; - - } catch (Exception e) { - logger.error("解析设备页面失败: " + url, e); - return null; - } - } - - /** - * 判断是否为文件下载链接 - */ - private boolean isFileLink(String url) { - if (url == null || url.isEmpty()) { - return false; - } - String lowerUrl = url.toLowerCase(); - return lowerUrl.endsWith(".pdf") || - lowerUrl.endsWith(".jpg") || - lowerUrl.endsWith(".jpeg") || - lowerUrl.endsWith(".png") || - lowerUrl.endsWith(".doc") || - lowerUrl.endsWith(".docx") || - lowerUrl.endsWith(".xls") || - lowerUrl.endsWith(".xlsx") || - lowerUrl.contains("/download") || - lowerUrl.contains("/file/") || - lowerUrl.contains(".pdf?") || - lowerUrl.contains(".jpg?"); - } - - /** - * 解码二维码图片 - */ - private String decodeQRCode(byte[] imageBytes) { - try { - InputStream inputStream = new ByteArrayInputStream(imageBytes); - BufferedImage bufferedImage = ImageIO.read(inputStream); - - if (bufferedImage == null) { - logger.error("无法读取图片"); - return null; - } - - BinaryBitmap binaryBitmap = new BinaryBitmap( - new HybridBinarizer( - new BufferedImageLuminanceSource(bufferedImage) - ) - ); - - MultiFormatReader reader = new MultiFormatReader(); - java.util.Map hints = new java.util.HashMap<>(); - hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); - - Result result = reader.decode(binaryBitmap, hints); - return result.getText(); - - } catch (Exception e) { - logger.error("解码二维码失败", e); - return null; - } - } - - /** - * 从URL下载文件 - */ - private byte[] downloadFileFromUrl(String fileUrl) { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpGet httpGet = new HttpGet(URI.create(fileUrl)); - - try (CloseableHttpResponse response = httpClient.execute(httpGet)) { - if (response.getCode() == 200) { - return EntityUtils.toByteArray(response.getEntity()); - } else { - logger.error("下载文件失败,HTTP状态码: {}", response.getCode()); - return null; - } - } - } catch (Exception e) { - logger.error("下载文件失败: " + fileUrl, e); - return null; - } - } - - /** - * 根据文件名推断 Content-Type - */ - private String getContentTypeFromFileName(String fileName) { - if (fileName == null) { - return "application/octet-stream"; - } - - String lowerFileName = fileName.toLowerCase(); - if (lowerFileName.endsWith(".pdf")) { - return "application/pdf"; - } else if (lowerFileName.endsWith(".jpg") || lowerFileName.endsWith(".jpeg")) { - return "image/jpeg"; - } else if (lowerFileName.endsWith(".png")) { - return "image/png"; - } else if (lowerFileName.endsWith(".doc")) { - return "application/msword"; - } else if (lowerFileName.endsWith(".docx")) { - return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; - } else if (lowerFileName.endsWith(".xls")) { - return "application/vnd.ms-excel"; - } else if (lowerFileName.endsWith(".xlsx")) { - return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; - } else { - return "application/octet-stream"; - } - } - -} diff --git a/urbanLifelineServ/workcase/src/main/resources/application.yml b/urbanLifelineServ/workcase/src/main/resources/application.yml deleted file mode 100644 index c571cd3a..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/application.yml +++ /dev/null @@ -1,55 +0,0 @@ -# ================== Workcase 工单服务配置 ================== -server: - port: 8088 - -spring: - application: - name: workcase-service - servlet: - multipart: - enabled: true - max-file-size: 500MB - max-request-size: 500MB - -# ================== Auth ================== -auth: - enabled: true - gateway-mode: true - whitelist: - - /swagger-ui/** - - /swagger-ui.html - - /v3/api-docs/** - - /webjars/** - - /favicon.ico - - /error - - /actuator/health - - /actuator/info - - /workcase/chat/kefu/callback - - /workcase/receive/crm - -# ================== SpringDoc ================== -springdoc: - group-configs: - - group: 'default' - display-name: '工单服务 API' - paths-to-match: '/**' - -# ================== Dubbo ================== -dubbo: - application: - name: urban-lifeline-workcase - qos-enable: false - protocol: - payload: 110100480 - scan: - base-packages: org.xyzh.workcase.service.impl - -# ================== Jitsi Meet 视频会议配置 ================== -jitsi: - app: - id: ${JITSI_APP_ID:urbanLifeline} - secret: ${JITSI_APP_SECRET:urbanLifeline-jitsi-secret-key-2025-production-safe-hs256} - server: - url: ${JITSI_SERVER_URL:https://org.xyzh.yslg.jitsi} - token: - expiration: 7200000 diff --git a/urbanLifelineServ/workcase/src/main/resources/bootstrap.yml b/urbanLifelineServ/workcase/src/main/resources/bootstrap.yml deleted file mode 100644 index 60998f2b..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,64 +0,0 @@ -# ================================================ -# Urban Lifeline - 通用 Bootstrap 配置 -# 所有微服务共享的基础配置 -# ================================================ - -# ================== Spring Cloud Nacos ================== -spring: - cloud: - nacos: - discovery: - server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} - namespace: ${NACOS_NAMESPACE:dev} - group: ${NACOS_GROUP:DEFAULT_GROUP} - - # ================== DataSource ================== - datasource: - url: ${DB_URL:jdbc:postgresql://127.0.0.1:5432/urban_lifeline} - username: ${DB_USERNAME:postgres} - password: ${DB_PASSWORD:postgres} - driver-class-name: org.postgresql.Driver - - # ================== Redis ================== - data: - redis: - host: ${REDIS_HOST:127.0.0.1} - port: ${REDIS_PORT:6379} - database: ${REDIS_DATABASE:0} - password: ${REDIS_PASSWORD:123456} - -# ================== Security AES ================== -security: - aes: - # AES-256 密钥(Base64编码,必须与所有服务保持一致) - # 警告:这是开发环境密钥,生产环境请使用密钥管理系统 - secret-key: ${AES_SECRET_KEY:MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=} - -# ================== Dubbo ================== -dubbo: - protocol: - name: dubbo - port: -1 - registry: - address: nacos://${NACOS_SERVER_ADDR:127.0.0.1:8848} - -# ================== MyBatis-Plus ================== -mybatis-plus: - mapper-locations: classpath:mapper/**/*.xml - type-aliases-package: org.xyzh.common.dto, org.xyzh.api - -# ================== SpringDoc 基础配置 ================== -springdoc: - api-docs: - enabled: true - path: /v3/api-docs - swagger-ui: - enabled: true - path: /swagger-ui.html - -# ================== Logging ================== -logging: - config: classpath:log4j2.xml - charset: - console: UTF-8 - file: UTF-8 diff --git a/urbanLifelineServ/workcase/src/main/resources/log4j2.xml b/urbanLifelineServ/workcase/src/main/resources/log4j2.xml deleted file mode 100644 index 1eb66924..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/log4j2.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatMessageMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatMessageMapper.xml deleted file mode 100644 index 065bc8a6..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatMessageMapper.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - message_id, optsn, room_id, sender_id, sender_type, sender_name, message_type, - content, files, content_extra, reply_to_msg_id, is_ai_message, ai_message_id, - status, read_count, send_time, creator, create_time, update_time - - - - INSERT INTO workcase.tb_chat_room_message ( - optsn, message_id, room_id, sender_id, sender_type, sender_name, content, creator,send_time - , message_type - , files - , content_extra - , reply_to_msg_id - , is_ai_message - , ai_message_id - , status - , create_time - ) VALUES ( - #{optsn}, #{messageId}, #{roomId}, #{senderId}, #{senderType}, #{senderName}, #{content}, #{creator},#{sendTime} - , #{messageType} - , #{files, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler} - , #{contentExtra, typeHandler=org.xyzh.common.jdbc.handler.FastJson2TypeHandler}::jsonb - , #{replyToMsgId} - , #{isAiMessage} - , #{aiMessageId} - , #{status} - , #{createTime} - ) - - - - UPDATE workcase.tb_chat_room_message - - content = #{content}, - status = #{status}, - read_count = #{readCount}, - update_time = now() - - WHERE message_id = #{messageId} - - - - DELETE FROM workcase.tb_chat_room_message - WHERE message_id = #{messageId} - - - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMapper.xml deleted file mode 100644 index e10bab7e..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMapper.xml +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - room_id, optsn, workcase_id, room_name, room_type, status, guest_id, guest_name, - ai_session_id, message_count, device_code, last_message_time, last_message, comment_level, closed_by, closed_time, - creator, create_time, update_time, delete_time, deleted - - - - INSERT INTO workcase.tb_chat_room ( - optsn, room_id, workcase_id, room_name, guest_id, guest_name, device_code, creator - , room_type - , status - , ai_session_id - , message_count - , last_message_time - , last_message - ) VALUES ( - #{optsn}, #{roomId}, #{workcaseId}, #{roomName}, #{guestId}, #{guestName}, #{deviceCode}, #{creator} - , #{roomType} - , #{status} - , #{aiSessionId} - , #{messageCount} - , #{lastMessageTime} - , #{lastMessage} - ) - - - - UPDATE workcase.tb_chat_room - - workcase_id = #{workcaseId}, - room_name = #{roomName}, - room_type = #{roomType}, - status = #{status}, - ai_session_id = #{aiSessionId}, - message_count = #{messageCount}, - device_code = #{deviceCode}, - last_message_time = #{lastMessageTime}, - last_message = #{lastMessage}, - comment_level = #{commentLevel}, - closed_by = #{closedBy}, - closed_time = #{closedTime}, - update_time = now() - - WHERE room_id = #{roomId} AND deleted = false - - - - UPDATE workcase.tb_chat_room - SET deleted = true, delete_time = now() - WHERE room_id = #{roomId} AND deleted = false - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMemberMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMemberMapper.xml deleted file mode 100644 index c9648bbb..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMemberMapper.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - member_id, optsn, room_id, user_id, user_type, user_name, status, - unread_count, last_read_time, last_read_msg_id, join_time, leave_time, - creator, create_time, update_time - - - - INSERT INTO workcase.tb_chat_room_member ( - optsn, member_id, room_id, user_id, user_type, user_name, creator - , status - , unread_count - ) VALUES ( - #{optsn}, #{memberId}, #{roomId}, #{userId}, #{userType}, #{userName}, #{creator} - , #{status} - , #{unreadCount} - ) - - - - UPDATE workcase.tb_chat_room_member - - status = #{status}, - unread_count = #{unreadCount}, - last_read_time = #{lastReadTime}, - last_read_msg_id = #{lastReadMsgId}, - leave_time = #{leaveTime}, - update_time = now() - - WHERE member_id = #{memberId} - - - - DELETE FROM workcase.tb_chat_room_member - WHERE member_id = #{memberId} - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomSummaryMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomSummaryMapper.xml deleted file mode 100644 index 1ff38749..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomSummaryMapper.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - summary_id, room_id, question, needs, answer, workcloud, message_count, summary_time, - optsn, creator, create_time, update_time, delete_time, deleted - - - - INSERT INTO workcase.tb_chat_room_summary ( - optsn, summary_id, room_id, creator - , question - , needs - , answer - , workcloud - , message_count - , summary_time - ) VALUES ( - #{optsn}, #{summaryId}, #{roomId}, #{creator} - , #{question} - , #{needs, jdbcType=ARRAY, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler} - , #{answer} - , #{workcloud, jdbcType=ARRAY, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler} - , #{messageCount} - , #{summaryTime}::timestamptz - ) - - - - UPDATE workcase.tb_chat_room_summary - - question = #{question}, - needs = #{needs, jdbcType=ARRAY, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler}, - answer = #{answer}, - workcloud = #{workcloud, jdbcType=ARRAY, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler}, - message_count = #{messageCount}, - summary_time = #{summaryTime}::timestamptz, - update_time = now() - - WHERE summary_id = #{summaryId} - - - - - - - - - - - - - - UPDATE workcase.tb_chat_room_summary - SET deleted = true, delete_time = now() - WHERE summary_id = #{summaryId} - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbCustomerServiceMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbCustomerServiceMapper.xml deleted file mode 100644 index 72514ae6..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbCustomerServiceMapper.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - user_id, optsn, username, user_code, status, skill_tags, max_concurrent, current_workload, - total_served, avg_response_time, satisfaction_score, creator, create_time, update_time, - delete_time, deleted - - - - INSERT INTO workcase.tb_customer_service ( - optsn, user_id, username, creator - , user_code - , status - , skill_tags - , max_concurrent - , current_workload - , total_served - , avg_response_time - , satisfaction_score - ) VALUES ( - #{optsn}, #{userId}, #{username}, #{creator} - , #{userCode} - , #{status} - , #{skillTags, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler} - , #{maxConcurrent} - , #{currentWorkload} - , #{totalServed} - , #{avgResponseTime} - , #{satisfactionScore} - ) - - - - UPDATE workcase.tb_customer_service - - username = #{username}, - user_code = #{userCode}, - status = #{status}, - skill_tags = #{skillTags, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler}, - max_concurrent = #{maxConcurrent}, - current_workload = #{currentWorkload}, - total_served = #{totalServed}, - avg_response_time = #{avgResponseTime}, - satisfaction_score = #{satisfactionScore}, - update_time = now() - - WHERE user_id = #{userId} AND deleted = false - - - - UPDATE workcase.tb_customer_service - SET deleted = true, delete_time = now() - WHERE user_id = #{userId} AND deleted = false - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbMeetingParticipantMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbMeetingParticipantMapper.xml deleted file mode 100644 index bde42c66..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbMeetingParticipantMapper.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - participant_id, optsn, meeting_id, user_id, user_type, user_name, join_time, leave_time, - duration_seconds, is_moderator, join_method, device_info, create_time, update_time - - - - INSERT INTO workcase.tb_meeting_participant ( - optsn, participant_id, meeting_id, user_id, user_type, user_name - , is_moderator - , join_method - , device_info - ) VALUES ( - #{optsn}, #{participantId}, #{meetingId}, #{userId}, #{userType}, #{userName} - , #{isModerator} - , #{joinMethod} - , #{deviceInfo} - ) - - - - UPDATE workcase.tb_meeting_participant - - leave_time = #{leaveTime}, - duration_seconds = #{durationSeconds}, - is_moderator = #{isModerator}, - device_info = #{deviceInfo}, - update_time = now() - - WHERE participant_id = #{participantId} - - - - DELETE FROM workcase.tb_meeting_participant - WHERE participant_id = #{participantId} - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbMeetingTranscriptionMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbMeetingTranscriptionMapper.xml deleted file mode 100644 index 39c2516c..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbMeetingTranscriptionMapper.xml +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - transcription_id, optsn, meeting_id, speaker_id, speaker_name, speaker_type, - content, content_raw, language, confidence, speech_start_time, speech_end_time, duration_ms, - audio_url, segment_index, is_final, service_provider, create_time - - - - INSERT INTO workcase.tb_meeting_transcription ( - optsn, transcription_id, meeting_id, speaker_id, speaker_name, speaker_type, - content, speech_start_time, speech_end_time, duration_ms - , content_raw - , language - , confidence - , audio_url - , segment_index - , is_final - , service_provider - ) VALUES ( - #{optsn}, #{transcriptionId}, #{meetingId}, #{speakerId}, #{speakerName}, #{speakerType}, - #{content}, #{speechStartTime}, #{speechEndTime}, #{durationMs} - , #{contentRaw} - , #{language} - , #{confidence} - , #{audioUrl} - , #{segmentIndex} - , #{isFinal} - , #{serviceProvider} - ) - - - - UPDATE workcase.tb_meeting_transcription - - content = #{content}, - content_raw = #{contentRaw}, - confidence = #{confidence}, - is_final = #{isFinal}, - - WHERE transcription_id = #{transcriptionId} - - - - DELETE FROM workcase.tb_meeting_transcription - WHERE transcription_id = #{transcriptionId} - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbVideoMeetingMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbVideoMeetingMapper.xml deleted file mode 100644 index 1d3a6f72..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbVideoMeetingMapper.xml +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - meeting_id, optsn, room_id, workcase_id, meeting_name, meeting_password, description, jwt_token, - jitsi_room_name, jitsi_server_url, status, creator_type, creator_name, - participant_count, max_participants, start_time, end_time, advance, - actual_start_time, actual_end_time, duration_seconds, iframe_url, - config, creator, create_time, update_time, delete_time, deleted - - - - INSERT INTO workcase.tb_video_meeting ( - optsn, meeting_id, room_id, workcase_id, meeting_name, jitsi_room_name, creator_type, creator_name, creator - , meeting_password - , description - , jwt_token - , jitsi_server_url - , status - , max_participants - , start_time - , end_time - , advance - , iframe_url - , config - ) VALUES ( - #{optsn}, #{meetingId}, #{roomId}, #{workcaseId}, #{meetingName}, #{jitsiRoomName}, #{creatorType}, #{creatorName}, #{creator} - , #{meetingPassword} - , #{description} - , #{jwtToken} - , #{jitsiServerUrl} - , #{status} - , #{maxParticipants} - , #{startTime} - , #{endTime} - , #{advance} - , #{iframeUrl} - , #{config, typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler} - ) - - - - UPDATE workcase.tb_video_meeting - - meeting_name = #{meetingName}, - meeting_password = #{meetingPassword}, - description = #{description}, - jwt_token = #{jwtToken}, - status = #{status}, - participant_count = #{participantCount}, - start_time = #{startTime}, - end_time = #{endTime}, - advance = #{advance}, - actual_start_time = #{actualStartTime}, - actual_end_time = #{actualEndTime}, - duration_seconds = #{durationSeconds}, - iframe_url = #{iframeUrl}, - config = #{config, typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler}, - update_time = now() - - WHERE meeting_id = #{meetingId} AND deleted = false - - - - UPDATE workcase.tb_video_meeting - SET deleted = true, delete_time = now() - WHERE meeting_id = #{meetingId} AND deleted = false - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWordCloudMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbWordCloudMapper.xml deleted file mode 100644 index 764bd9f7..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWordCloudMapper.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - - - - - - - - word_id, word, frequency, category, stat_date, create_time, update_time - - - - INSERT INTO workcase.tb_word_cloud ( - word_id, word, stat_date - , frequency - , category - ) VALUES ( - #{wordId}, #{word}, #{statDate}::date - , #{frequency} - , #{category} - ) - - - - UPDATE workcase.tb_word_cloud - - word = #{word}, - frequency = #{frequency}, - category = #{category}, - update_time = now() - - WHERE word_id = #{wordId} - - - - - - - - - - - - - - UPDATE workcase.tb_word_cloud - SET frequency = frequency + #{count}, update_time = now() - WHERE word_id = #{wordId} - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseDeviceMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseDeviceMapper.xml deleted file mode 100644 index 35024291..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseDeviceMapper.xml +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - workcase_id, file_id, optsn, device, device_code, file_name, file_root_id - - - - INSERT INTO workcase.tb_workcase_device ( - optsn, workcase_id, device, file_id, file_name - , device_code - , file_root_id - ) VALUES ( - #{optsn}, #{workcaseId}, #{device}, #{fileId}, #{fileName} - , #{deviceCode} - , #{fileRootId} - ) - - - - UPDATE workcase.tb_workcase_device - - device = #{device}, - device_code = #{deviceCode}, - file_name = #{fileName}, - file_root_id = #{fileRootId}, - - WHERE workcase_id = #{workcaseId} AND file_id = #{fileId} - - - - DELETE FROM workcase.tb_workcase_device - WHERE workcase_id = #{workcaseId} AND file_id = #{fileId} - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseMapper.xml deleted file mode 100644 index ebfb2a79..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseMapper.xml +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - workcase_id, room_id, optsn, user_id, username, phone, type, device, device_code, device_name_plate, device_name_plate_img, - address, description, imgs, emergency, status, processor, creator, create_time, update_time, delete_time, deleted - - - - INSERT INTO workcase.tb_workcase ( - optsn, workcase_id, room_id, user_id, username, phone, type, device_code,device_name_plate, creator - , device - , device_name_plate_img - , address - , description - , imgs - , emergency - , status - , processor - ) VALUES ( - #{optsn}, #{workcaseId}, #{roomId}, #{userId}, #{username}, #{phone}, #{type}, #{deviceCode}, #{deviceNamePlate}, #{creator} - , #{device} - , #{deviceNamePlateImg} - , #{address} - , #{description} - , #{imgs, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler} - , #{emergency} - , #{status} - , #{processor} - ) - - - - UPDATE workcase.tb_workcase - - user_id = #{userId}, - username = #{username}, - phone = #{phone}, - type = #{type}, - device = #{device}, - device_code = #{deviceCode}, - device_name_plate = #{deviceNamePlate}, - device_name_plate_img = #{deviceNamePlateImg}, - address = #{address}, - description = #{description}, - imgs = #{imgs, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler}, - emergency = #{emergency}, - status = #{status}, - processor = #{processor}, - update_time = now() - - WHERE workcase_id = #{workcaseId} AND deleted = false - - - - UPDATE workcase.tb_workcase - SET deleted = true, delete_time = now() - WHERE workcase_id = #{workcaseId} AND deleted = false - - - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseProcessMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseProcessMapper.xml deleted file mode 100644 index c06e1e8f..00000000 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseProcessMapper.xml +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - process_id, optsn, workcase_id, action, message, files, processor, remark, creator, create_time - - - - INSERT INTO workcase.tb_workcase_process ( - optsn, workcase_id, process_id, action, creator - , message - , files - , processor - , remark - ) VALUES ( - #{optsn}, #{workcaseId}, #{processId}, #{action}, #{creator} - , #{message} - , #{files, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler} - , #{processor} - , #{remark} - ) - - - - UPDATE workcase.tb_workcase_process - - action = #{action}, - message = #{message}, - files = #{files, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler}, - processor = #{processor}, - remark = #{remark}, - - WHERE process_id = #{processId} - - - - DELETE FROM workcase.tb_workcase_process - WHERE process_id = #{processId} - - - - - - - - - - - diff --git a/urbanLifelineServ/workcase/工单+Jitsi Meet技术方案.md b/urbanLifelineServ/workcase/工单+Jitsi Meet技术方案.md deleted file mode 100644 index 7c558ae2..00000000 --- a/urbanLifelineServ/workcase/工单+Jitsi Meet技术方案.md +++ /dev/null @@ -1,853 +0,0 @@ -# 工单服务 + Jitsi Meet 视频会议 技术方案 - -## 📋 目录 -1. [业务流程分析](#业务流程分析) -2. [数据表结构设计](#数据表结构设计) -3. [核心服务功能](#核心服务功能) -4. [API接口设计](#api接口设计) -5. [前端集成方案](#前端集成方案) -6. [安全方案](#安全方案) - ---- - -## 业务流程分析 - -### 完整业务流程 - -``` -用户进入小程序 - ↓ -AI客服对话(默认,存储在 ai.tb_chat 表) - ↓ -连续3次AI对话后询问是否转人工 - ↓ -用户触发转人工(可能一开始就手动触发,没有聊天记录) - ↓ -【核心变更】创建IM聊天室(取代微信客服) - ↓ -同步 ai.tb_chat 对话记录到聊天室 - ↓ -客服人员加入聊天室(AI退出) - ↓ -客服与客户IM对话(员工续接AI对话) - ↓ -【可选】发起Jitsi Meet视频会议 - ↓ -【可选】用户/员工在聊天室内创建工单(也可在web管理端) - ↓ -工单处理和状态更新 - ↓ -工单完成/撤销,生成总结和词云 -``` - -### 关键改动点 - -**AI对话 → 转人工 → 创建聊天室** -- AI对话存储在 `ai.tb_chat` 表(通过WorkcaseChatService调用AI接口) -- 转人工时创建IM聊天室,同步AI对话记录 -- 工单和会议没有前置关系,可在聊天室内随时创建 - -**取消微信客服 → 使用自建IM + Jitsi Meet** -- IM聊天室:文字、图片、文件、语音消息 -- 视频会议:通过iframe嵌入Jitsi Meet,最简实现 -- 权限控制:只有聊天室成员才能创建/加入会议 - ---- - -## 数据表结构设计 - -### 核心表结构(6+1张表) - -#### 1. **tb_chat_room** - 聊天室表 ⭐核心表 - -**用途**:转人工时创建的聊天室,可关联工单 - -```sql -room_id -- 聊天室ID(主键) -workcase_id -- 关联工单ID(可选,可后续绑定) -room_name -- 聊天室名称 -status -- 状态:active-活跃 closed-已关闭 archived-已归档 -guest_id -- 来客ID -guest_name -- 来客姓名 -ai_session_id -- AI对话会话ID(从ai.tb_chat同步) -current_agent_id -- 当前负责客服ID -agent_count -- 已加入客服人数 -message_count -- 消息总数 -unread_count -- 未读消息数(客服端) -last_message_time -- 最后消息时间 -last_message -- 最后消息内容(列表展示用) -``` - -**业务规则**: -- 转人工时创建聊天室,同步 ai.tb_chat 对话记录 -- 用户/员工可在聊天室内创建工单,绑定 workcase_id -- 聊天室可独立存在,无需绑定工单 -- 工单完成后聊天室归档 - ---- - -#### 2. **tb_chat_room_member** - 聊天室成员表 - -**用途**:记录聊天室内的所有成员 - -```sql -member_id -- 成员记录ID(主键) -room_id -- 聊天室ID -user_id -- 用户ID(来客ID或员工ID) -user_type -- 用户类型:guest-来客 agent-客服 ai-AI助手 -user_name -- 用户名称 -role -- 角色:owner-创建者 admin-管理员 member-普通成员 -status -- 状态:active-活跃 left-已离开 removed-被移除 -unread_count -- 该成员的未读消息数 -last_read_time -- 最后阅读时间 -last_read_msg_id -- 最后阅读的消息ID -join_time -- 加入时间 -leave_time -- 离开时间 -``` - -**业务规则**: -- 来客自动加入(创建者) -- 客服手动加入或系统分配 -- 用于权限校验:只有成员能发消息和发起会议 - ---- - -#### 3. **tb_chat_message** - 聊天室消息表 - -**用途**:存储所有聊天消息(AI对话+人工客服对话) - -```sql -message_id -- 消息ID(主键) -room_id -- 聊天室ID -sender_id -- 发送者ID -sender_type -- 发送者类型:guest-来客 agent-客服 ai-AI助手 system-系统消息 -sender_name -- 发送者名称 -message_type -- 消息类型:text image file voice video system meeting -content -- 消息内容 -content_extra -- 扩展内容(JSONB:图片URL、文件信息、会议链接等) -reply_to_msg_id -- 回复的消息ID(引用回复) -is_ai_message -- 是否AI消息 -ai_message_id -- AI原始消息ID(追溯用) -status -- 状态:sending sent delivered read failed recalled -read_count -- 已读人数 -send_time -- 发送时间 -``` - -**业务规则**: -- 从ai.tb_chat同步AI对话时设置 `is_ai_message=true` -- 会议通知作为系统消息 `message_type=meeting` -- 支持引用回复和消息撤回 - ---- - -#### 4. **tb_video_meeting** - 视频会议表 ⭐Jitsi Meet - -**用途**:记录聊天室内创建的视频会议 - -```sql -meeting_id -- 会议ID(主键,也是Jitsi房间名) -room_id -- 关联聊天室ID -workcase_id -- 关联工单ID -meeting_name -- 会议名称 -meeting_password -- 会议密码(可选) -jwt_token -- JWT Token(身份验证) -jitsi_room_name -- Jitsi房间名(格式:workcase_{workcase_id}_{timestamp}) -jitsi_server_url -- Jitsi服务器地址(默认:https://meet.jit.si) -status -- 状态:scheduled ongoing ended cancelled -creator_type -- 创建者类型:guest-来客 agent-客服 -creator_name -- 创建者名称 -participant_count -- 参与人数 -max_participants -- 最大参与人数 -start_time -- 实际开始时间 -end_time -- 实际结束时间 -duration_seconds -- 会议时长(秒) -iframe_url -- iframe嵌入URL(生成后存储) -config -- Jitsi配置项(JSONB自定义配置) -``` - -**业务规则**: -- 只有聊天室成员能创建会议 -- `jitsi_room_name`唯一,格式:`workcase_{workcaseId}_{timestamp}` -- `iframe_url`在创建时生成,前端直接使用 - ---- - -#### 5. **tb_meeting_participant** - 会议参与记录表(可选) - -**用途**:用于审计和统计 - -```sql -participant_id -- 参与记录ID(主键) -meeting_id -- 会议ID -user_id -- 用户ID -user_type -- 用户类型:guest-来客 agent-客服 -user_name -- 用户名称 -join_time -- 加入时间 -leave_time -- 离开时间 -duration_seconds -- 参与时长(秒) -is_moderator -- 是否主持人 -join_method -- 加入方式:web mobile desktop -device_info -- 设备信息 -``` - -**业务规则**: -- 记录每个参与者的加入和离开时间 -- 用于统计会议时长和参与情况 -- 可用于生成会议报告 - ---- - -#### 6. **tb_customer_service** - 客服人员配置表(可选) - -**用途**:管理有客服权限的员工 - -```sql -user_id -username ---- - -#### 7. **tb_word_cloud** - 词云统计表(已有) - -**用途**:记录聊天和工单中的关键词 - -```sql -word_id -- 词条ID(主键) -word -- 词语 -frequency -- 词频 -source_type -- 来源类型:chat workcase global -source_id -- 来源ID(room_id/workcase_id) -category -- 分类:fault device emotion等 -stat_date -- 统计日期(按天聚合) -``` - ---- - -## 核心服务功能 - -### Service层设计 - -#### 1. **ChatRoomService** - 聊天室服务 - -```java -// 创建聊天室(工单创建时调用) -ChatRoomVO createChatRoom(CreateChatRoomDTO dto); - -// 关闭聊天室(工单完成时调用) -void closeChatRoom(String roomId, String closedBy); - -// 获取聊天室详情 -ChatRoomVO getChatRoomByWorkcaseId(String workcaseId); - -// 同步AI对话记录到聊天室 -void syncAiMessages(String roomId, String aiSessionId); - -// 更新聊天室统计信息 -void updateChatRoomStats(String roomId); -``` - ---- - -#### 2. **ChatMemberService** - 聊天室成员服务 - -```java -// 添加成员到聊天室 -void addMember(String roomId, String userId, String userType); - -// 移除成员 -void removeMember(String roomId, String userId); - -// 检查用户是否是聊天室成员(权限校验) -boolean isMemberOfRoom(String roomId, String userId); - -// 获取聊天室成员列表 -List getRoomMembers(String roomId); - -// 更新成员未读数 -void updateMemberUnreadCount(String roomId, String userId); -``` - ---- - -#### 3. **ChatMessageService** - 聊天消息服务 - -```java -// 发送消息 -ChatMessageVO sendMessage(SendMessageDTO dto); - -// 获取聊天历史 -PageResult getChatHistory(String roomId, PageParam pageParam); - -// 标记消息已读 -void markMessagesAsRead(String roomId, String userId, List messageIds); - -// 撤回消息 -void recallMessage(String messageId, String userId); - -// 同步AI消息(从ai.tb_chat) -void syncAiMessages(String roomId, String aiSessionId); -``` - ---- - -#### 4. **VideoMeetingService** - 视频会议服务 ⭐核心 - -```java -// 创建会议 -VideoMeetingVO createMeeting(CreateMeetingDTO dto); - -// 验证加入会议权限 -boolean validateMeetingAccess(String meetingId, String userId); - -// 生成会议iframe URL -String generateMeetingIframeUrl(String meetingId, String userId); - -// 开始会议 -void startMeeting(String meetingId); - -// 结束会议 -void endMeeting(String meetingId); - -// 获取会议详情 -VideoMeetingVO getMeetingInfo(String meetingId); - -// 记录参与者加入 -void recordParticipantJoin(String meetingId, String userId); - -// 记录参与者离开 -void recordParticipantLeave(String meetingId, String userId); -``` - ---- - -#### 5. **JitsiTokenService** - Jitsi JWT Token服务 - -```java -// 生成JWT Token(用于身份验证) -String generateJwtToken(String roomName, String userId, String userName, boolean isModerator); - -// 验证JWT Token -boolean validateJwtToken(String token); - -// 生成iframe嵌入URL -String buildIframeUrl(String roomName, String jwtToken, JitsiConfig config); -``` - ---- - -## API接口设计 - -### 聊天室相关接口 - -#### 1. 创建聊天室 -``` -POST /api/workcase/chat-room/create -请求体:{ - "workcaseId": "WC20231220001", - "guestId": "GUEST001", - "guestName": "张三", - "aiSessionId": "AI_SESSION_123" -} -响应:{ - "code": 0, - "data": { - "roomId": "ROOM001", - "roomName": "工单#WC20231220001的客服支持", - "status": "active" - } -} -``` - -#### 2. 发送消息 -``` -POST /api/workcase/chat-room/send-message -请求体:{ - "roomId": "ROOM001", - "senderId": "USER001", - "senderType": "agent", - "messageType": "text", - "content": "您好,我是客服小李,请问有什么可以帮到您?" -} -响应:{ - "code": 0, - "data": { - "messageId": "MSG001", - "sendTime": "2023-12-20T10:00:00Z" - } -} -``` - -#### 3. 获取聊天历史 -``` -GET /api/workcase/chat-room/messages?roomId=ROOM001&page=1&size=50 -响应:{ - "code": 0, - "data": { - "total": 120, - "list": [ - { - "messageId": "MSG001", - "senderId": "USER001", - "senderName": "客服小李", - "senderType": "agent", - "messageType": "text", - "content": "您好,我是客服小李", - "sendTime": "2023-12-20T10:00:00Z", - "status": "read" - } - ] - } -} -``` - ---- - -### 视频会议相关接口 ⭐ - -#### 1. 创建视频会议 -``` -POST /api/workcase/meeting/create -请求头:Authorization: Bearer -请求体:{ - "roomId": "ROOM001", - "workcaseId": "WC20231220001", - "meetingName": "工单技术支持会议", - "maxParticipants": 10 -} -响应:{ - "code": 0, - "data": { - "meetingId": "MEET001", - "jitsiRoomName": "workcase_WC20231220001_1703059200", - "iframeUrl": "https://meet.jit.si/workcase_WC20231220001_1703059200?jwt=eyJhbGc...", - "status": "scheduled" - } -} -``` - -**业务逻辑**: -1. 验证请求用户是否是聊天室成员 -2. 生成唯一的 `jitsi_room_name` -3. 生成JWT Token(包含用户身份和权限) -4. 构建iframe URL -5. 发送系统消息到聊天室通知会议创建 - ---- - -#### 2. 获取会议信息(用于加入会议) -``` -GET /api/workcase/meeting/info/{meetingId} -请求头:Authorization: Bearer -响应:{ - "code": 0, - "data": { - "meetingId": "MEET001", - "meetingName": "工单技术支持会议", - "jitsiRoomName": "workcase_WC20231220001_1703059200", - "iframeUrl": "https://meet.jit.si/workcase_WC20231220001_1703059200?jwt=eyJhbGc...", - "status": "ongoing", - "participantCount": 2, - "maxParticipants": 10, - "canJoin": true - } -} -``` - -**业务逻辑**: -1. 验证请求用户是否是聊天室成员 -2. 生成用户专属的JWT Token -3. 返回带Token的iframe URL -4. 记录参与者加入时间 - ---- - -#### 3. 开始会议 -``` -POST /api/workcase/meeting/start/{meetingId} -响应:{ - "code": 0, - "message": "会议已开始" -} -``` - -#### 4. 结束会议 -``` -POST /api/workcase/meeting/end/{meetingId} -响应:{ - "code": 0, - "data": { - "durationSeconds": 1800, - "participantCount": 3 - } -} -``` - ---- - -## 前端集成方案 - -### 最简iframe嵌入实现 - -#### Vue 3 组件示例 - -```vue - - - - - -``` - ---- - -### API请求封装 - -```typescript -// src/api/workcase/meeting.ts -import { http } from '@/utils/http'; - -export interface CreateMeetingParams { - roomId: string; - workcaseId: string; - meetingName: string; - maxParticipants?: number; -} - -export interface VideoMeetingVO { - meetingId: string; - meetingName: string; - jitsiRoomName: string; - iframeUrl: string; - status: string; - participantCount: number; - maxParticipants: number; -} - -// 创建视频会议 -export const createVideoMeeting = (params: CreateMeetingParams) => { - return http.post('/api/workcase/meeting/create', params); -}; - -// 获取会议信息 -export const getMeetingInfo = (meetingId: string) => { - return http.get(`/api/workcase/meeting/info/${meetingId}`); -}; - -// 结束会议 -export const endVideoMeeting = (meetingId: string) => { - return http.post(`/api/workcase/meeting/end/${meetingId}`); -}; -``` - ---- - -### 移动端适配 - -```vue - - - -``` - ---- - -## 安全方案 - -### 1. **会议权限控制** - -#### 后端验证逻辑 -```java -public boolean validateMeetingAccess(String meetingId, String userId) { - // 1. 获取会议信息 - VideoMeetingDO meeting = meetingMapper.selectById(meetingId); - if (meeting == null) { - throw new BusinessException("会议不存在"); - } - - // 2. 检查用户是否是聊天室成员 - ChatRoomMemberDO member = memberMapper.selectByRoomAndUser( - meeting.getRoomId(), userId - ); - - if (member == null || !"active".equals(member.getStatus())) { - throw new BusinessException("您不是聊天室成员,无法加入会议"); - } - - return true; -} -``` - ---- - -### 2. **JWT Token生成** - -```java -public String generateJwtToken(String roomName, String userId, String userName, boolean isModerator) { - long now = System.currentTimeMillis(); - long exp = now + (2 * 60 * 60 * 1000); // 2小时有效期 - - return Jwts.builder() - .setIssuer("urbanLifeline") - .setSubject(roomName) - .setAudience("jitsi") - .claim("context", Map.of( - "user", Map.of( - "id", userId, - "name", userName, - "moderator", isModerator - ) - )) - .claim("room", roomName) - .setIssuedAt(new Date(now)) - .setExpiration(new Date(exp)) - .signWith(SignatureAlgorithm.HS256, jitsiSecretKey) - .compact(); -} -``` - ---- - -### 3. **iframe URL构建** - -```java -public String buildIframeUrl(String roomName, String jwtToken, JitsiConfig config) { - StringBuilder url = new StringBuilder(); - url.append(jitsiServerUrl).append("/").append(roomName); - - // JWT认证 - url.append("?jwt=").append(jwtToken); - - // Jitsi配置项 - url.append("&config.startWithAudioMuted=").append(config.isStartWithAudioMuted()); - url.append("&config.startWithVideoMuted=").append(config.isStartWithVideoMuted()); - url.append("&config.enableWelcomePage=false"); - url.append("&config.prejoinPageEnabled=false"); - url.append("&config.disableDeepLinking=true"); - - // 界面配置 - url.append("&interfaceConfig.SHOW_JITSI_WATERMARK=false"); - url.append("&interfaceConfig.SHOW_WATERMARK_FOR_GUESTS=false"); - url.append("&interfaceConfig.DISABLE_JOIN_LEAVE_NOTIFICATIONS=true"); - - return url.toString(); -} -``` - ---- - -### 4. **防止未授权访问** - -```java -@PostMapping("/create") -@PreAuthorize("hasAuthority('workcase:meeting:create')") -public ResultDomain createMeeting( - @RequestBody @Valid CreateMeetingDTO dto, - @RequestHeader("Authorization") String token -) { - // 1. 从token解析用户信息 - String userId = JwtUtil.getUserIdFromToken(token); - - // 2. 验证是否是聊天室成员 - if (!chatMemberService.isMemberOfRoom(dto.getRoomId(), userId)) { - return ResultDomain.failure("您不是聊天室成员,无法创建会议"); - } - - // 3. 创建会议 - VideoMeetingVO meeting = videoMeetingService.createMeeting(dto, userId); - - return ResultDomain.success(meeting); -} -``` - ---- - -## 技术要点总结 - -### ✅ 优势 - -1. **最简实现**:iframe嵌入,无需深度集成Jitsi服务端 -2. **权限安全**:JWT Token + 聊天室成员校验 -3. **无状态**:Jitsi Meet本身无状态,只记录必要的会议元数据 -4. **可扩展**:可后续升级为自建Jitsi服务器 -5. **成本低**:使用官方meet.jit.si服务器,免费 - -### ⚠️ 注意事项 - -1. **会议记录**:使用官方服务器无法录制,需自建服务器 -2. **并发限制**:官方服务器有并发限制,建议后续自建 -3. **网络要求**:需要良好的网络环境,可能需要科学上网 -4. **数据隐私**:敏感场景建议自建Jitsi服务器 - ---- - -## 下一步工作 - -1. ✅ 数据表已创建(createTableWorkcase.sql) -2. ⏳ 实现Service层业务逻辑 -3. ⏳ 实现Controller层API接口 -4. ⏳ 实现前端IM聊天室组件 -5. ⏳ 实现前端视频会议组件 -6. ⏳ 测试和调优 - ---- - -## 附录:Jitsi Meet配置参考 - -### 推荐配置项 - -```javascript -const jitsiConfig = { - // 音视频设置 - startWithAudioMuted: false, - startWithVideoMuted: false, - - // 功能开关 - enableWelcomePage: false, - prejoinPageEnabled: false, - disableDeepLinking: true, - - // 录制和直播 - recordingEnabled: false, - liveStreamingEnabled: false, - - // 聊天和屏幕共享 - enableChat: true, - enableScreenSharing: true, - - // 界面定制 - hideConferenceSubject: false, - hideConferenceTimer: false, - - // 安全设置 - enableE2EE: false, // 端到端加密 - requireDisplayName: true -}; -``` - ---- - -**文档版本**:v1.0 -**最后更新**:2023-12-20 -**作者**:Cascade AI Assistant diff --git a/urbanLifelineServ/workcase/工单流程.md b/urbanLifelineServ/workcase/工单流程.md deleted file mode 100644 index 1b11b09b..00000000 --- a/urbanLifelineServ/workcase/工单流程.md +++ /dev/null @@ -1,20 +0,0 @@ -# 小程序用户聊天和工单的产生逻辑 -接口实现方式: - 1. 用户进行微信小程序,进行AI问答,默认回复人员是ai,在ai.tb_chat表 - 2. 当连续3次ai聊天后,询问是否转人工 - 3. 用户触发转人工(可能是一开始,就手动触发,没有聊天记录) - 4. 创建一个IM聊天室,同步ai.tb_chat的聊天信息 - 5. 员工进入聊天室和客户聊天(ai退出聊天室)的聊天记录,同步到tb_chat表里面,对话人员是来客和客服。(把ai替换成员工进行对话的续接) - 6. 可以开启jitsi会议 - 7. 用户、员工在聊天室内创建工单(也可在web的管理端) - -# 聊天室的实现,改造Jitsi Meet -包含jitsiMeet所有功能 -对创建会议的人员需要校验:1.是当前工单聊天室内的成员 -对加入会议的人员需要校验:1.是当前工单聊天室内的成员 - -jitsiMeet要避免任何人都能创建会议的问题 - -有视频会议的需求 - -总体内容变化,交互逻辑改变,工单和会议没有前置关系。用户先ai对话,然后创建聊天室,可以随时在聊天室内创建工单;员工可以在聊天室和web端创建工单并更新状态。 \ No newline at end of file diff --git a/urbanLifelineServ/workcase/聊天室实现文档.md b/urbanLifelineServ/workcase/聊天室实现文档.md deleted file mode 100644 index e260fd02..00000000 --- a/urbanLifelineServ/workcase/聊天室实现文档.md +++ /dev/null @@ -1,233 +0,0 @@ -# 聊天室实现文档 - -## 1. 业务规则 - -- 一个工单只能创建一个聊天室,一个聊天室可以发起多次会议 -- 创建聊天室时自动添加来客和所有在线客服到成员表 -- 消息发送使用分布式锁保证时间戳递增,避免并发乱序 - ---- - -## 2. 核心文件结构 - -``` -workcase/ -├── src/main/java/org/xyzh/workcase/ -│ ├── service/ -│ │ ├── ChatRoomServiceImpl.java # 聊天室服务实现 -│ │ └── MeetServiceImpl.java # 会议服务实现(伪代码) -│ ├── listener/ -│ │ └── ChatMessageListener.java # Redis消息监听器 -│ ├── config/ -│ │ ├── WebSocketConfig.java # STOMP WebSocket配置 -│ │ └── RedisSubscriberConfig.java # Redis订阅配置 -│ └── mapper/ -│ ├── TbChatRoomMapper.java -│ ├── TbChatRoomMemberMapper.java -│ ├── TbChatMessageMapper.java -│ └── TbCustomerServiceMapper.java - -apis/api-workcase/ -├── src/main/java/org/xyzh/api/workcase/ -│ ├── constant/ -│ │ └── WorkcaseConstant.java # 常量定义 -│ ├── service/ -│ │ ├── ChatRoomService.java # 聊天室服务接口 -│ │ └── MeetService.java # 会议服务接口 -│ ├── dto/ -│ │ ├── TbChatRoomDTO.java -│ │ ├── TbChatRoomMemberDTO.java -│ │ └── TbChatMessageDTO.java -│ └── vo/ -│ ├── ChatRoomVO.java -│ ├── ChatMemberVO.java -│ └── ChatMessageVO.java -``` - ---- - -## 3. Redis Key 设计 - -| Key | 说明 | 示例 | -|-----|------|------| -| `chat:room:{roomId}` | 聊天室消息Pub/Sub频道 | `chat:room:abc123` | -| `chat:room:online:{roomId}` | 在线用户Set | `chat:room:online:abc123` | -| `chat:room:lock:{roomId}` | 消息发送锁 | `chat:room:lock:abc123` | -| `chat:room:lasttime:{roomId}` | 最后消息时间戳 | `chat:room:lasttime:abc123` | -| `chat:list:update` | 聊天室列表更新通知频道 | `chat:list:update` | - ---- - -## 4. 消息流转架构 - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ 消息发送流程 │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ 客户端 ──HTTP POST──> ChatRoomServiceImpl.sendMessage() │ -│ │ │ -│ ▼ │ -│ ┌─────────────────┐ │ -│ │ 获取分布式锁 │ │ -│ │ chat:room:lock │ │ -│ └────────┬────────┘ │ -│ │ │ -│ ▼ │ -│ ┌─────────────────┐ │ -│ │ 递增时间戳保证 │ │ -│ │ 消息顺序 │ │ -│ └────────┬────────┘ │ -│ │ │ -│ ▼ │ -│ ┌─────────────────┐ │ -│ │ 保存到数据库 │ │ -│ └────────┬────────┘ │ -│ │ │ -│ ▼ │ -│ redisService.publish("chat:room:{roomId}") │ -│ │ │ -│ ▼ │ -│ redisService.publish("chat:list:update") │ -│ │ │ -└──────────────────────────────┼──────────────────────────────────┘ - │ -┌──────────────────────────────┼──────────────────────────────────┐ -│ 消息接收流程 │ -├──────────────────────────────┼──────────────────────────────────┤ -│ │ │ -│ RedisSubscriberConfig (订阅 chat:room:*, chat:list:update)│ -│ │ │ -│ ▼ │ -│ ChatMessageListener.onMessage() │ -│ ┌────┴────┐ │ -│ │ │ │ -│ ▼ ▼ │ -│ /topic/chat/{roomId} /topic/chat/list-update │ -│ (聊天窗口消息) (聊天室列表更新) │ -│ │ │ │ -│ ▼ ▼ │ -│ 聊天窗口订阅者 列表页面订阅者 │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - ---- - -## 5. 用户类型常量 - -| 常量 | 值 | 说明 | -|------|-----|------| -| `USER_TYPE_GUEST` | `guest` | 来客 | -| `USER_TYPE_STAFF` | `staff` | 客服 | -| `USER_TYPE_AI` | `ai` | AI助手 | - ---- - -## 6. 状态常量 - -### 聊天室状态 -| 常量 | 值 | 说明 | -|------|-----|------| -| `ROOM_STATUS_ACTIVE` | `active` | 活跃 | -| `ROOM_STATUS_CLOSED` | `closed` | 已关闭 | - -### 成员状态 -| 常量 | 值 | 说明 | -|------|-----|------| -| `MEMBER_STATUS_ACTIVE` | `active` | 活跃 | -| `MEMBER_STATUS_LEFT` | `left` | 已离开 | -| `MEMBER_STATUS_REMOVED` | `removed` | 被移除 | - -### 消息状态 -| 常量 | 值 | 说明 | -|------|-----|------| -| `MESSAGE_STATUS_SENT` | `sent` | 已发送 | -| `MESSAGE_STATUS_RECALLED` | `recalled` | 已撤回 | - ---- - -## 7. 并发消息处理 - -```java -// 获取分布式锁 -String lockKey = WorkcaseConstant.REDIS_CHAT_LOCK + roomId; -redisService.setIfAbsent(lockKey, "1", 5); // 5秒过期 - -// 保证时间戳递增 -String timeKey = WorkcaseConstant.REDIS_CHAT_LASTTIME + roomId; -long lastTime = redisService.get(timeKey); -if (currentTime <= lastTime) { - currentTime = lastTime + 1; -} -message.setSendTime(new Date(currentTime)); -redisService.set(timeKey, currentTime); - -// 释放锁 -redisService.delete(lockKey); -``` - ---- - -## 8. 前端WebSocket连接示例 - -```javascript -// 连接WebSocket -const socket = new SockJS('/ws/chat'); -const stompClient = Stomp.over(socket); - -stompClient.connect({}, () => { - // 1. 订阅聊天室消息(聊天窗口使用) - stompClient.subscribe('/topic/chat/' + roomId, (message) => { - const chatMessage = JSON.parse(message.body); - // 处理收到的消息,添加到聊天窗口 - console.log('收到消息:', chatMessage); - }); - - // 2. 订阅聊天室列表更新(列表页面使用) - stompClient.subscribe('/topic/chat/list-update', (message) => { - const chatMessage = JSON.parse(message.body); - // 根据roomId更新对应聊天室的lastMessage和lastMessageTime - updateChatRoomInList(chatMessage.roomId, { - lastMessage: chatMessage.content, - lastMessageTime: chatMessage.sendTime, - senderName: chatMessage.senderName - }); - }); -}); - -// 断开连接 -stompClient.disconnect(); -``` - ---- - -## 9. API接口 - -### ChatRoomService - -| 方法 | 说明 | -|------|------| -| `createChatRoom(dto)` | 创建聊天室,自动添加来客和客服 | -| `updateChatRoom(dto)` | 更新聊天室信息 | -| `closeChatRoom(roomId, closedBy)` | 关闭聊天室 | -| `deleteChatRoom(roomId)` | 删除聊天室 | -| `getChatRoomById(roomId)` | 获取聊天室详情 | -| `getChatRoomPage(pageRequest)` | 分页查询聊天室 | -| `addChatRoomMember(member)` | 添加成员 | -| `removeChatRoomMember(memberId)` | 移除成员 | -| `sendMessage(message)` | 发送消息(含并发处理) | -| `getChatMessagePage(pageRequest)` | 分页查询消息 | -| `assignCustomerService(roomId)` | 分配所有客服到聊天室 | - -### MeetService(伪代码) - -| 方法 | 说明 | -|------|------| -| `createMeeting(dto)` | 创建会议 | -| `startMeeting(meetingId)` | 开始会议 | -| `endMeeting(meetingId)` | 结束会议 | -| `joinMeeting(participant)` | 参与者加入 | -| `leaveMeeting(participantId)` | 参与者离开 | -| `generateMeetingJoinUrl(...)` | 生成Jitsi加入链接 | -| `addTranscription(dto)` | 添加转录记录 | diff --git a/urbanLifelineServ/模型供应商.json b/urbanLifelineServ/模型供应商.json deleted file mode 100644 index 581fca5d..00000000 --- a/urbanLifelineServ/模型供应商.json +++ /dev/null @@ -1,3342 +0,0 @@ -{ - "data": [ - { - "model": "Pro\/moonshotai\/Kimi-K2-Instruct", - "label": { - "zh_Hans": "Pro\/moonshotai\/Kimi-K2-Instruct", - "en_US": "Pro\/moonshotai\/Kimi-K2-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "moonshotai\/Kimi-K2-Instruct", - "label": { - "zh_Hans": "moonshotai\/Kimi-K2-Instruct", - "en_US": "moonshotai\/Kimi-K2-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Pro\/deepseek-ai\/DeepSeek-R1", - "label": { - "zh_Hans": "Pro\/deepseek-ai\/DeepSeek-R1", - "en_US": "Pro\/deepseek-ai\/DeepSeek-R1" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 160000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Pro\/deepseek-ai\/DeepSeek-V3", - "label": { - "zh_Hans": "Pro\/deepseek-ai\/DeepSeek-V3", - "en_US": "Pro\/deepseek-ai\/DeepSeek-V3" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Pro\/deepseek-ai\/DeepSeek-V3.1", - "label": { - "zh_Hans": "Pro\/deepseek-ai\/DeepSeek-V3.1", - "en_US": "Pro\/deepseek-ai\/DeepSeek-V3.1" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 163840, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Pro\/deepseek-ai\/DeepSeek-V3.1-Terminus", - "label": { - "zh_Hans": "Pro\/deepseek-ai\/DeepSeek-V3.1-Terminus", - "en_US": "Pro\/deepseek-ai\/DeepSeek-V3.1-Terminus" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 163840, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Pro\/deepseek-ai\/DeepSeek-V3.2", - "label": { - "zh_Hans": "Pro\/deepseek-ai\/DeepSeek-V3.2", - "en_US": "Pro\/deepseek-ai\/DeepSeek-V3.2" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 163840, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-V3.2", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-V3.2", - "en_US": "deepseek-ai\/DeepSeek-V3.2" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 163840, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-OCR", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-OCR", - "en_US": "deepseek-ai\/DeepSeek-OCR" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "vision" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 8192, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-R1", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-R1", - "en_US": "deepseek-ai\/DeepSeek-R1" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 160000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-V3", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-V3", - "en_US": "deepseek-ai\/DeepSeek-V3" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-V3.1", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-V3.1", - "en_US": "deepseek-ai\/DeepSeek-V3.1" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 163840, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-V3.1-Terminus", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-V3.1-Terminus", - "en_US": "deepseek-ai\/DeepSeek-V3.1-Terminus" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 163840, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-32B", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-32B", - "en_US": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-32B" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-14B", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-14B", - "en_US": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-14B" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-7B", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-7B", - "en_US": "deepseek-ai\/DeepSeek-R1-Distill-Qwen-7B" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-Next-80B-A3B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen3-Next-80B-A3B-Instruct", - "en_US": "Qwen\/Qwen3-Next-80B-A3B-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 256000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-Next-80B-A3B-Thinking", - "label": { - "zh_Hans": "Qwen\/Qwen3-Next-80B-A3B-Thinking", - "en_US": "Qwen\/Qwen3-Next-80B-A3B-Thinking" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 256000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-235B-A22B", - "label": { - "zh_Hans": "Qwen\/Qwen3-235B-A22B", - "en_US": "Qwen\/Qwen3-235B-A22B" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-235B-A22B-Instruct-2507", - "label": { - "zh_Hans": "Qwen\/Qwen3-235B-A22B-Instruct-2507", - "en_US": "Qwen\/Qwen3-235B-A22B-Instruct-2507" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 256000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-235B-A22B-Thinking-2507", - "label": { - "zh_Hans": "Qwen\/Qwen3-235B-A22B-Thinking-2507", - "en_US": "Qwen\/Qwen3-235B-A22B-Thinking-2507" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 256000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-30B-A3B-Instruct-2507", - "label": { - "zh_Hans": "Qwen\/Qwen3-30B-A3B-Instruct-2507", - "en_US": "Qwen\/Qwen3-30B-A3B-Instruct-2507" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 256000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-32B", - "label": { - "zh_Hans": "Qwen\/Qwen3-32B", - "en_US": "Qwen\/Qwen3-32B" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-30B-A3B", - "label": { - "zh_Hans": "Qwen\/Qwen3-30B-A3B", - "en_US": "Qwen\/Qwen3-30B-A3B" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-14B", - "label": { - "zh_Hans": "Qwen\/Qwen3-14B", - "en_US": "Qwen\/Qwen3-14B" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-8B", - "label": { - "zh_Hans": "Qwen\/Qwen3-8B", - "en_US": "Qwen\/Qwen3-8B" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-72B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-72B-Instruct", - "en_US": "Qwen\/Qwen2.5-72B-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-72B-Instruct-128K", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-72B-Instruct-128K", - "en_US": "Qwen\/Qwen2.5-72B-Instruct-128K" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 131072, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-32B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-32B-Instruct", - "en_US": "Qwen\/Qwen2.5-32B-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-14B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-14B-Instruct", - "en_US": "Qwen\/Qwen2.5-14B-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-7B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-7B-Instruct", - "en_US": "Qwen\/Qwen2.5-7B-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-Coder-32B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-Coder-32B-Instruct", - "en_US": "Qwen\/Qwen2.5-Coder-32B-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-Coder-7B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-Coder-7B-Instruct", - "en_US": "Qwen\/Qwen2.5-Coder-7B-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 131072, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-VL-72B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-VL-72B-Instruct", - "en_US": "Qwen\/Qwen2.5-VL-72B-Instruct" - }, - "model_type": "llm", - "features": [ - "vision" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 131072, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2.5-VL-32B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2.5-VL-32B-Instruct", - "en_US": "Qwen\/Qwen2.5-VL-32B-Instruct" - }, - "model_type": "llm", - "features": [ - "vision" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 131072, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Pro\/Qwen\/Qwen2.5-VL-7B-Instruct", - "label": { - "zh_Hans": "Pro\/Qwen\/Qwen2.5-VL-7B-Instruct", - "en_US": "Pro\/Qwen\/Qwen2.5-VL-7B-Instruct" - }, - "model_type": "llm", - "features": [ - "vision" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "THUDM\/GLM-4.1V-9B-Thinking", - "label": { - "zh_Hans": "THUDM\/glm-41v-9b-thinking", - "en_US": "THUDM\/glm-41v-9b-thinking" - }, - "model_type": "llm", - "features": [ - "vision" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 16384, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "THUDM\/glm-4-9b-chat", - "label": { - "zh_Hans": "THUDM\/glm-4-9b-chat", - "en_US": "THUDM\/glm-4-9b-chat" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "zai-org\/GLM-4.5", - "label": { - "zh_Hans": "zai-org\/GLM-4.5", - "en_US": "zai-org\/GLM-4.5" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "zai-org\/GLM-4.5-Air", - "label": { - "zh_Hans": "zai-org\/GLM-4.5-Air", - "en_US": "zai-org\/GLM-4.5-Air" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "zai-org\/GLM-4.6", - "label": { - "zh_Hans": "zai-org\/GLM-4.6", - "en_US": "zai-org\/GLM-4.6" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 200000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "zai-org\/GLM-4.6V", - "label": { - "zh_Hans": "zai-org\/GLM-4.6V", - "en_US": "zai-org\/GLM-4.6V" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "multi-tool-call", - "stream-tool-call", - "vision" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 128000, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-V2.5", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-V2.5", - "en_US": "deepseek-ai\/DeepSeek-V2.5" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Pro\/deepseek-ai\/DeepSeek-V3.2-Exp", - "label": { - "zh_Hans": "Pro\/deepseek-ai\/DeepSeek-V3.2-Exp", - "en_US": "Pro\/deepseek-ai\/DeepSeek-V3.2-Exp" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 163840, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "deepseek-ai\/DeepSeek-V3.2-Exp", - "label": { - "zh_Hans": "deepseek-ai\/DeepSeek-V3.2-Exp", - "en_US": "deepseek-ai\/DeepSeek-V3.2-Exp" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 163840, - "mode": "chat" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "internlm\/internlm2_5-7b-chat", - "label": { - "zh_Hans": "internlm\/internlm2_5-7b-chat", - "en_US": "internlm\/internlm2_5-7b-chat" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/QVQ-72B-Preview", - "label": { - "zh_Hans": "Qwen\/QVQ-72B-Preview", - "en_US": "Qwen\/QVQ-72B-Preview" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call", - "vision" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/QwQ-32B", - "label": { - "zh_Hans": "Qwen\/QwQ-32B", - "en_US": "Qwen\/QwQ-32B" - }, - "model_type": "llm", - "features": [ - "agent-thought", - "tool-call", - "stream-tool-call" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2-7B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2-7B-Instruct", - "en_US": "Qwen\/Qwen2-7B-Instruct" - }, - "model_type": "llm", - "features": [ - "agent-thought" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen2-VL-72B-Instruct", - "label": { - "zh_Hans": "Qwen\/Qwen2-VL-72B-Instruct", - "en_US": "Qwen\/Qwen2-VL-72B-Instruct" - }, - "model_type": "llm", - "features": [ - "vision" - ], - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "mode": "chat" - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "netease-youdao\/bce-reranker-base_v1", - "label": { - "zh_Hans": "netease-youdao\/bce-reranker-base_v1", - "en_US": "netease-youdao\/bce-reranker-base_v1" - }, - "model_type": "rerank", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 512 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "BAAI\/bge-reranker-v2-m3", - "label": { - "zh_Hans": "BAAI\/bge-reranker-v2-m3", - "en_US": "BAAI\/bge-reranker-v2-m3" - }, - "model_type": "rerank", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 8192 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-Reranker-0.6B", - "label": { - "zh_Hans": "Qwen\/Qwen3-Reranker-0.6B", - "en_US": "Qwen\/Qwen3-Reranker-0.6B" - }, - "model_type": "rerank", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-Reranker-4B", - "label": { - "zh_Hans": "Qwen\/Qwen3-Reranker-4B", - "en_US": "Qwen\/Qwen3-Reranker-4B" - }, - "model_type": "rerank", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-Reranker-8B", - "label": { - "zh_Hans": "Qwen\/Qwen3-Reranker-8B", - "en_US": "Qwen\/Qwen3-Reranker-8B" - }, - "model_type": "rerank", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "FunAudioLLM\/SenseVoiceSmall", - "label": { - "zh_Hans": "FunAudioLLM\/SenseVoiceSmall", - "en_US": "FunAudioLLM\/SenseVoiceSmall" - }, - "model_type": "speech2text", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "file_upload_limit": 1, - "supported_file_extensions": "mp3,wav" - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "iic\/SenseVoiceSmall", - "label": { - "zh_Hans": "iic\/SenseVoiceSmall", - "en_US": "iic\/SenseVoiceSmall" - }, - "model_type": "speech2text", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "file_upload_limit": 1, - "supported_file_extensions": "mp3,wav" - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "netease-youdao\/bce-embedding-base_v1", - "label": { - "zh_Hans": "netease-youdao\/bce-embedding-base_v1", - "en_US": "netease-youdao\/bce-embedding-base_v1" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 512, - "max_chunks": 1 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "BAAI\/bge-large-en-v1.5", - "label": { - "zh_Hans": "BAAI\/bge-large-en-v1.5", - "en_US": "BAAI\/bge-large-en-v1.5" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 512, - "max_chunks": 1 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "BAAI\/bge-large-zh-v1.5", - "label": { - "zh_Hans": "BAAI\/bge-large-zh-v1.5", - "en_US": "BAAI\/bge-large-zh-v1.5" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 512, - "max_chunks": 1 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "BAAI\/bge-m3", - "label": { - "zh_Hans": "BAAI\/bge-m3", - "en_US": "BAAI\/bge-m3" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 8192, - "max_chunks": 1 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-Embedding-0.6B", - "label": { - "zh_Hans": "Qwen\/Qwen3-Embedding-0.6B", - "en_US": "Qwen\/Qwen3-Embedding-0.6B" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "max_chunks": 1 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-Embedding-4B", - "label": { - "zh_Hans": "Qwen\/Qwen3-Embedding-4B", - "en_US": "Qwen\/Qwen3-Embedding-4B" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "max_chunks": 1 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "Qwen\/Qwen3-Embedding-8B", - "label": { - "zh_Hans": "Qwen\/Qwen3-Embedding-8B", - "en_US": "Qwen\/Qwen3-Embedding-8B" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 32768, - "max_chunks": 1 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "FunAudioLLM\/CosyVoice2-0.5B", - "label": { - "zh_Hans": "FunAudioLLM\/CosyVoice2-0.5B", - "en_US": "FunAudioLLM\/CosyVoice2-0.5B" - }, - "model_type": "tts", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "audio_type": "mp3", - "default_voice": "FunAudioLLM\/CosyVoice2-0.5B:alex", - "max_workers": 5, - "voices": [ - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "FunAudioLLM\/CosyVoice2-0.5B:alex", - "name": "Alex\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "FunAudioLLM\/CosyVoice2-0.5B:benjamin", - "name": "Benjamin\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "FunAudioLLM\/CosyVoice2-0.5B:charles", - "name": "Charles\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "FunAudioLLM\/CosyVoice2-0.5B:david", - "name": "David\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "FunAudioLLM\/CosyVoice2-0.5B:anna", - "name": "Anna\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "FunAudioLLM\/CosyVoice2-0.5B:bella", - "name": "Bella\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "FunAudioLLM\/CosyVoice2-0.5B:claire", - "name": "Claire\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "FunAudioLLM\/CosyVoice2-0.5B:diana", - "name": "Diana\uff08\u5973\u58f0\uff09" - } - ] - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "fishaudio\/fish-speech-1.4", - "label": { - "zh_Hans": "fishaudio\/fish-speech-1.4", - "en_US": "fishaudio\/fish-speech-1.4" - }, - "model_type": "tts", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "audio_type": "mp3", - "default_voice": "fishaudio\/fish-speech-1.4:alex", - "max_workers": 5, - "voices": [ - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.4:alex", - "name": "Alex\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.4:benjamin", - "name": "Benjamin\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.4:charles", - "name": "Charles\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.4:david", - "name": "David\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.4:anna", - "name": "Anna\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.4:bella", - "name": "Bella\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.4:claire", - "name": "Claire\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.4:diana", - "name": "Diana\uff08\u5973\u58f0\uff09" - } - ] - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "fishaudio\/fish-speech-1.5", - "label": { - "zh_Hans": "fishaudio\/fish-speech-1.5", - "en_US": "fishaudio\/fish-speech-1.5" - }, - "model_type": "tts", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "audio_type": "mp3", - "default_voice": "fishaudio\/fish-speech-1.5:alex", - "max_workers": 5, - "voices": [ - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.5:alex", - "name": "Alex\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.5:benjamin", - "name": "Benjamin\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.5:charles", - "name": "Charles\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.5:david", - "name": "David\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.5:anna", - "name": "Anna\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.5:bella", - "name": "Bella\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.5:claire", - "name": "Claire\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "fishaudio\/fish-speech-1.5:diana", - "name": "Diana\uff08\u5973\u58f0\uff09" - } - ] - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - }, - { - "model": "RVC-Boss\/GPT-SoVITS", - "label": { - "zh_Hans": "RVC-Boss\/GPT-SoVITS", - "en_US": "RVC-Boss\/GPT-SoVITS" - }, - "model_type": "tts", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "audio_type": "mp3", - "default_voice": "RVC-Boss\/GPT-SoVITS:alex", - "max_workers": 5, - "voices": [ - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "RVC-Boss\/GPT-SoVITS:alex", - "name": "Alex\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "RVC-Boss\/GPT-SoVITS:benjamin", - "name": "Benjamin\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "RVC-Boss\/GPT-SoVITS:charles", - "name": "Charles\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "RVC-Boss\/GPT-SoVITS:david", - "name": "David\uff08\u7537\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "RVC-Boss\/GPT-SoVITS:anna", - "name": "Anna\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "RVC-Boss\/GPT-SoVITS:bella", - "name": "Bella\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "RVC-Boss\/GPT-SoVITS:claire", - "name": "Claire\uff08\u5973\u58f0\uff09" - }, - { - "language": [ - "zh-Hans", - "en-US" - ], - "mode": "RVC-Boss\/GPT-SoVITS:diana", - "name": "Diana\uff08\u5973\u58f0\uff09" - } - ] - }, - "deprecated": true, - "status": "active", - "load_balancing_enabled": false, - "has_invalid_load_balancing_configs": false, - "provider": { - "provider": "langgenius\/siliconflow\/siliconflow", - "label": { - "zh_Hans": "\u7845\u57fa\u6d41\u52a8", - "en_US": "SiliconFlow" - }, - "icon_small": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_small\/en_US" - }, - "icon_small_dark": null, - "icon_large": { - "zh_Hans": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/zh_Hans", - "en_US": "\/console\/api\/workspaces\/fe3bcf55-9a04-4850-8473-7f97e1c09b97\/model-providers\/langgenius\/siliconflow\/siliconflow\/icon_large\/en_US" - }, - "supported_model_types": [ - "llm", - "text-embedding", - "rerank", - "speech2text", - "tts" - ], - "models": [], - "tenant_id": "fe3bcf55-9a04-4850-8473-7f97e1c09b97" - } - } - ] -} \ No newline at end of file diff --git a/urbanLifelineWeb/.gitignore b/urbanLifelineWeb/.gitignore deleted file mode 100644 index 61651879..00000000 --- a/urbanLifelineWeb/.gitignore +++ /dev/null @@ -1,62 +0,0 @@ -.vscode/chrome-debug-profile -packages/*/node_modules -node_modules -docs - -# Dependencies -node_modules/ -.pnpm-store/ -.pnpm-debug.log - -# Build outputs -dist/ -**/dist/ -**/build/ - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* - -# Environment files -.env -.env.* -!.env.example - -# Local development -.cache/ -.temp/ -.turbo/ - -# Module Federation -**/__mf__temp/ -**/.__mf__temp/ - -# Testing -coverage/ -**/coverage/ - -# Debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Misc -.DS_Store -Thumbs.db - -packages/hello_uni \ No newline at end of file diff --git a/urbanLifelineWeb/.npmrc b/urbanLifelineWeb/.npmrc deleted file mode 100644 index a7522fb6..00000000 --- a/urbanLifelineWeb/.npmrc +++ /dev/null @@ -1,5 +0,0 @@ -auto-install-peers=true -shamefully-hoist=true -shared-workspace-lockfile=false -strict-peer-dependencies=false -prefer-frozen-lockfile=true diff --git a/urbanLifelineWeb/.trae/documents/修复平台应用空白页面问题.md b/urbanLifelineWeb/.trae/documents/修复平台应用空白页面问题.md deleted file mode 100644 index 0f2a5bef..00000000 --- a/urbanLifelineWeb/.trae/documents/修复平台应用空白页面问题.md +++ /dev/null @@ -1,144 +0,0 @@ -# 问题分析 - -根据用户提供的信息和代码检查,已经确定了导致平台应用在 build/preview 模式下出现空白页面的根本原因: - -## 1. 循环依赖死锁 - -平台应用的 `vue-vendor` chunk 中包含了顶层 `await`,用于等待 Module Federation 的 `loadShare` 完成: -```javascript -const Z=await X.then(e=>e()); // 等待 vue -const Pe=await Ee.then(e=>e()); // 等待 vue-router -``` - -这导致了以下循环依赖: -1. `vue-vendor` 加载时,执行顶层 `await`,等待 `loadShare` 完成 -2. `loadShare` 需要初始化 Module Federation -3. Module Federation 初始化又依赖 `vue-vendor` 文件 -4. 形成循环依赖死锁,整个应用初始化被阻塞 - -## 2. 配置问题 - -从配置文件可以看到: -- 平台模块的 `vite.config.ts` 中,`shared` 配置包含了 `vue` 和 `vue-router` -- 共享模块的 `vite.config.ts` 中,`shared` 配置也包含了 `vue` 和 `vue-router` -- 平台模块的 `manualChunks` 将 `vue` 和 `vue-router` 打包到了 `vue-vendor` chunk 中 - -# 解决方案 - -## 1. 修改平台模块的 Vite 配置 - -### 1.1 移除 shared 配置中的 vue 和 vue-router - -从平台模块的 `shared` 配置中移除 `vue` 和 `vue-router`,避免 Module Federation 尝试共享这些核心依赖。 - -```typescript -// packages/platform/vite.config.ts -federation({ - name: 'platform', - remotes: { - shared: { - type: 'module', - name: 'shared', - entry: sharedEntry - } - }, - shared: { - // 移除 vue 和 vue-router,避免循环依赖 - // vue: {}, - // 'vue-router': {}, - 'element-plus': {}, - axios: {} - } -}) -``` - -### 1.2 调整 manualChunks 配置 - -保持 `manualChunks` 配置不变,继续将 `vue` 和 `vue-router` 打包到 `vue-vendor` chunk 中,但不再尝试通过 Module Federation 共享它们。 - -## 2. 修改共享模块的 Vite 配置 - -### 2.1 移除 shared 配置中的 vue 和 vue-router - -从共享模块的 `shared` 配置中移除 `vue` 和 `vue-router`,避免 Module Federation 尝试共享这些核心依赖。 - -```typescript -// packages/shared/vite.config.ts -federation({ - name: 'shared', - filename: 'remoteEntry.js', - exposes: { - // ... 暴露的模块 - }, - shared: { - // 移除 vue 和 vue-router,避免循环依赖 - // vue: {}, - // 'vue-router': {}, - 'element-plus': {}, - 'lucide-vue-next': {}, - axios: {} - } -}) -``` - -## 3. 重新构建和测试 - -### 3.1 构建共享模块 - -```bash -# 切换到共享模块目录 -cd f:/Project/urbanLifeline/urbanLifelineWeb/packages/shared - -# 构建共享模块 -pnpm build -``` - -### 3.2 构建平台模块 - -```bash -# 切换到平台模块目录 -cd f:/Project/urbanLifeline/urbanLifelineWeb/packages/platform - -# 构建平台模块 -pnpm build - -# 启动预览服务器 -pnpm preview -``` - -### 3.3 验证应用是否正常运行 - -- 访问 `https://org.xyzh.yslg/platform/` -- 检查控制台是否显示 `✅ Platform 应用启动成功` 日志 -- 确认页面不再是空白,显示正常内容 - -# 预期结果 - -- 应用能够正常初始化,控制台显示 `✅ Platform 应用启动成功` 日志 -- 访问 `https://org.xyzh.yslg/platform/` 时显示正常内容,而不是空白页面 -- 所有依赖模块都能正确加载,没有循环依赖死锁 - -# 风险评估 - -- **依赖重复加载**:移除 `vue` 和 `vue-router` 从 `shared` 配置中可能导致这些依赖在多个模块中重复加载,但这是解决循环依赖死锁的必要代价 -- **构建错误**:需要确保修改后的配置能够正确构建 -- **运行时错误**:需要验证移除共享依赖后,应用是否能够正常运行 - -# 后续优化建议 - -1. **使用更稳定的 Module Federation 配置**:考虑使用 `@module-federation/runtime` 或其他更稳定的 Module Federation 实现 -2. **调整打包策略**:避免将核心依赖(如 `vue` 和 `vue-router`)与 Module Federation 相关代码打包到同一个 chunk 中 -3. **添加错误处理**:在应用初始化过程中添加错误处理,当依赖加载失败时给出明确提示 -4. **改进日志记录**:在应用初始化的关键节点添加更多日志,便于定位问题 - -# 执行步骤 - -1. **修改平台模块的 Vite 配置**:移除 `shared` 配置中的 `vue` 和 `vue-router` -2. **修改共享模块的 Vite 配置**:移除 `shared` 配置中的 `vue` 和 `vue-router` -3. **构建共享模块**:确保共享模块能够正确构建 -4. **构建平台模块**:确保平台模块能够正确构建 -5. **启动预览服务器**:启动平台模块的预览服务器 -6. **验证应用是否正常运行**:访问应用并验证是否正常运行 -7. **检查控制台输出**:确认控制台显示预期的日志 - -通过执行以上步骤,我们可以解决平台应用在 build/preview 模式下出现空白页面的问题,确保应用能够正常初始化和运行。 \ No newline at end of file diff --git a/urbanLifelineWeb/.vscode/launch.json b/urbanLifelineWeb/.vscode/launch.json deleted file mode 100644 index 5b544fc2..00000000 --- a/urbanLifelineWeb/.vscode/launch.json +++ /dev/null @@ -1,157 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "启动 Shared 开发服务器", - "type": "node-terminal", - "request": "launch", - "command": "npm run dev", - "cwd": "${workspaceFolder}/packages/shared", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "new", - "showReuseMessage": true, - "clear": false - } - }, - { - "name": "预览 Shared 开发服务器", - "type": "node-terminal", - "request": "launch", - "command": "npm run preview", - "cwd": "${workspaceFolder}/packages/shared", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "new", - "showReuseMessage": true, - "clear": false - } - }, - { - "name": "启动 Platform 开发服务器", - "type": "node-terminal", - "request": "launch", - "command": "npm run dev", - "cwd": "${workspaceFolder}/packages/platform", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "new", - "showReuseMessage": true, - "clear": false - } - }, - { - "name": "预览 Platform 开发服务器", - "type": "node-terminal", - "request": "launch", - "command": "npm run preview", - "cwd": "${workspaceFolder}/packages/platform", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "new", - "showReuseMessage": true, - "clear": false - } - }, - { - "name": "启动 workcase 开发服务器", - "type": "node-terminal", - "request": "launch", - "command": "npm run dev", - "cwd": "${workspaceFolder}/packages/workcase", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "new", - "showReuseMessage": true, - "clear": false - } - }, - { - "name": "预览 workcase 开发服务器", - "type": "node-terminal", - "request": "launch", - "command": "npm run preview", - "cwd": "${workspaceFolder}/packages/workcase", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "new", - "showReuseMessage": true, - "clear": false - } - }, - { - "name": "启动 Bidding 开发服务器", - "type": "node-terminal", - "request": "launch", - "command": "npm run dev", - "cwd": "${workspaceFolder}/packages/bidding", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "new", - "showReuseMessage": true, - "clear": false - } - }, - { - "name": "预览 Bidding 开发服务器", - "type": "node-terminal", - "request": "launch", - "command": "npm run preview", - "cwd": "${workspaceFolder}/packages/bidding", - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "new", - "showReuseMessage": true, - "clear": false - } - } - ], - "compounds": [ - { - "name": "启动所有 Web 项目", - "configurations": [ - "启动 Shared 开发服务器", - "启动 Platform 开发服务器", - "启动 workcase 开发服务器", - // "启动 Bidding 开发服务器" - ], - "stopAll": true, - "presentation": { - "hidden": false, - "group": "", - "order": 1 - } - }, - { - "name": "启动所有预览 Web 项目", - "configurations": [ - "预览 Shared 开发服务器", - "预览 Platform 开发服务器", - "预览 workcase 开发服务器", - // "启动 Bidding 开发服务器" - ], - "stopAll": true, - "presentation": { - "hidden": false, - "group": "", - "order": 1 - } - } - ] -} diff --git a/urbanLifelineWeb/.windsurf/workflows/urban-lifeline-web.md b/urbanLifelineWeb/.windsurf/workflows/urban-lifeline-web.md deleted file mode 100644 index 93a66856..00000000 --- a/urbanLifelineWeb/.windsurf/workflows/urban-lifeline-web.md +++ /dev/null @@ -1 +0,0 @@ -lucide-vue-next 使用这个图标库替代elementplus的图标库 \ No newline at end of file diff --git a/urbanLifelineWeb/NGINX_SSO_CONFIG.md b/urbanLifelineWeb/NGINX_SSO_CONFIG.md deleted file mode 100644 index b0f85133..00000000 --- a/urbanLifelineWeb/NGINX_SSO_CONFIG.md +++ /dev/null @@ -1,267 +0,0 @@ -# Nginx单点登录配置说明 - -## 架构概述 - -本系统使用 **Platform** 作为统一入口和单点登录服务,其他服务(Workcase、Bidding)通过 Nginx 代理访问。 - -## 访问方式 - -### 开发环境(推荐通过Nginx访问) - -1. **启动Nginx** - ```bash - # Windows - cd f:\Environment\Nginx\nginx-1.28.0 - start nginx - ``` - -2. **启动各服务** - ```bash - # Platform (5001端口) - pnpm --filter platform dev - - # Workcase (5003端口) - pnpm --filter workcase dev - - # Bidding (5002端口) - pnpm --filter bidding dev - - # 后端API (8180端口) - # 启动Spring Boot应用 - ``` - -3. **访问地址** - - **统一入口**: http://localhost (Nginx 80端口) - - Platform: http://localhost/ - - Workcase: http://localhost/workcase - - Bidding: http://localhost/bidding - - 后端API: http://localhost/api - -### 生产环境 - -与开发环境配置完全一致,只需将各服务构建后部署即可。 - -```bash -# 构建所有服务 -pnpm build - -# Nginx配置已经就绪,直接启动即可 -``` - -## Nginx配置详解 - -### 核心配置 (nginx.conf) - -```nginx -# Platform 主应用(单点登录入口) -location / { - proxy_pass http://localhost:7001/; -} - -# Workcase 工单服务 -location /workcase/ { - proxy_pass http://localhost:7003/; -} - -# Bidding 招标服务 -location /bidding/ { - proxy_pass http://localhost:7002/; -} - -# 后端 API 统一入口 -location /api/ { - proxy_pass http://localhost:8180/; -} -``` - -## 单点登录流程 - -### 1. 用户访问流程 - -``` -用户访问 http://localhost - ↓ -Nginx代理到 Platform (5001) - ↓ -Platform检查token - ↓ -未登录 → 显示登录页 -已登录 → 显示主页和菜单 -``` - -### 2. 子服务访问流程 - -``` -用户点击"泰豪小电"菜单 - ↓ -Platform iframe加载 http://localhost/workcase - ↓ -Nginx代理到 Workcase (5003) - ↓ -Workcase从LocalStorage读取token - ↓ -有token → 加载workcase路由 -无token → 重定向到 /login (Platform登录页) -``` - -### 3. Token共享机制 - -所有服务共享同一个LocalStorage(因为都在同一个域名下),因此: - -- **Token存储**: `localStorage.setItem('token', ...)` -- **用户信息**: `localStorage.setItem('loginDomain', ...)` -- **视图数据**: `loginDomain.userViews` - -每个服务根据 `service` 字段筛选自己的视图: -```typescript -// Workcase筛选 -const workcaseViews = allViews.filter(view => view.service === 'workcase') - -// Platform筛选 -const platformViews = allViews.filter(view => view.service === 'platform') -``` - -## 配置文件 - -### 1. Shared配置 (`packages/shared/src/config/index.ts`) - -```typescript -sso: { - platformUrl: '/', // Platform地址(相对路径) - workcaseUrl: '/workcase', // Workcase地址 - biddingUrl: '/bidding' // Bidding地址 -} -``` - -### 2. App-config.js(各服务) - -**Platform** (`packages/platform/public/app-config.js`): -```javascript -sso: { - platformUrl: '/', - workcaseUrl: '/workcase', - biddingUrl: '/bidding' -} -``` - -**Workcase** (`packages/workcase/public/app-config.js`): -```javascript -sso: { - platformUrl: '/', - workcaseUrl: '/workcase', - biddingUrl: '/bidding' -} -``` - -## 路由配置 - -### Workcase路由守卫 - -```typescript -// 未登录重定向到Platform登录页 -if (requiresAuth && !hasToken) { - const platformUrl = APP_CONFIG.sso?.platformUrl || '/' - const loginPath = platformUrl.endsWith('/') - ? `${platformUrl}login` - : `${platformUrl}/login` - const platformLoginUrl = `${loginPath}?redirect=${encodeURIComponent(window.location.href)}` - window.location.href = platformLoginUrl -} -``` - -### 动态路由加载 - -```typescript -// 从LocalStorage加载并筛选本服务的视图 -const allViews = loadViewsFromStorage('loginDomain', 'userViews') -const workcaseViews = allViews.filter(view => view.service === 'workcase') -addDynamicRoutes(workcaseViews) -``` - -## 数据库配置 - -### 视图表service字段 - -确保 `tb_sys_view` 表的视图数据正确设置了 `service` 字段: - -```sql --- Platform视图 -('VIEW-P001', 'view_platform_home', '全部应用', NULL, '/agents', ..., - 'route', NULL, 'platform', 'SidebarLayout', ...) - --- Workcase视图 -('VIEW-W001', 'view_workcase_home', '工单首页', NULL, '/home', ..., - 'route', NULL, 'workcase', 'SidebarLayout', ...) - --- Bidding视图 -('VIEW-B001', 'view_bidding_home', '首页', NULL, '/home', ..., - 'route', NULL, 'bidding', 'DefaultLayout', ...) -``` - -## 开发建议 - -### 方式一:通过Nginx访问(推荐) - -**优点**: -- 与生产环境完全一致 -- 测试单点登录功能 -- 避免跨域问题 - -**配置**: -- 所有服务使用相对路径 `/`, `/workcase`, `/bidding` -- 通过 http://localhost 访问 - -### 方式二:直接访问各服务端口 - -**优点**: -- 独立开发调试 -- HMR更快 - -**配置**: -- 修改 `devConfig.sso` 为绝对URL - ```typescript - sso: { - platformUrl: 'http://localhost:7001', - workcaseUrl: 'http://localhost:7003', - biddingUrl: 'http://localhost:7002' - } - ``` -- 直接访问 http://localhost:7001, http://localhost:7003 - -## 常见问题 - -### 1. 登录后跳转到错误的地址 - -**原因**: `platformUrl` 配置不正确 - -**解决**: 检查 `app-config.js` 中的 `sso.platformUrl` 配置 - -### 2. Token无法共享 - -**原因**: 不同端口访问导致LocalStorage隔离 - -**解决**: 统一通过Nginx访问(http://localhost) - -### 3. Nginx无法启动 - -**检查**: -- 80端口是否被占用 -- nginx.conf配置是否正确 - -### 4. 子服务路由404 - -**检查**: -- Vite配置中的 `base` 是否正确设置 -- Workcase: `base: '/workcase'` -- Bidding: `base: '/bidding'` - -## 重启服务 - -```bash -# 重启Nginx(Windows) -nginx -s reload - -# 或完全重启 -nginx -s quit -start nginx -``` diff --git a/urbanLifelineWeb/README.md b/urbanLifelineWeb/README.md deleted file mode 100644 index 0df50980..00000000 --- a/urbanLifelineWeb/README.md +++ /dev/null @@ -1,233 +0,0 @@ -# Urban Lifeline Web 微前端项目 - -基于 **@module-federation/vite** 的微前端架构,包含共享模块和多个业务应用。 - -> ✨ **v2.0 升级**:已从 `@originjs/vite-plugin-federation` 迁移到官方维护的 `@module-federation/vite`,获得更好的开发体验和稳定性! - -## 📦 项目结构 - -``` -urbanLifelineWeb/ -├── packages/ -│ ├── shared/ # 共享模块 (端口 5000) -│ ├── platform/ # 主平台应用 (端口 5001) -│ ├── bidding/ # 招标管理应用 (端口 5002) -│ └── workcase/ # 案例管理应用 (端口 5003) -└── package.json -``` - -## 🚀 快速开始 - -### 1. 安装依赖 - -```bash -# 使用 pnpm 安装(推荐) -pnpm install - -# 或使用 install.bat 脚本 -install.bat -``` - -### 2. 启动开发服务器 - -```bash -# 方式1: 使用启动脚本(Windows,推荐) -start-all.bat - -# 方式2: 使用 pnpm 并行启动所有服务 -pnpm run dev - -# 方式3: 手动启动(需要两个终端) -# 终端1 - 启动 shared -cd packages/shared -pnpm run dev # http://localhost:7000 - -# 终端2 - 启动 platform -cd packages/platform -pnpm run dev # http://localhost:7001 -``` - -### 3. 构建生产版本 - -```bash -# 构建所有应用 -pnpm run build - -# 或单独构建 -cd packages/shared && pnpm run build -cd packages/platform && pnpm run build -cd packages/bidding && pnpm run build -cd packages/workcase && pnpm run build -``` - -## 🌐 端口分配 - -| 服务 | 端口 | 说明 | -|------|------|------| -| Shared | 5000 | 共享组件和工具库 | -| Platform | 5001 | 主平台应用 | -| Bidding | 5002 | 招标管理应用 | -| Workcase | 5003 | 案例管理应用 | - -## 🔧 技术栈 - -- **框架**: Vue 3.5 + TypeScript -- **构建工具**: Vite 6.0 -- **UI 组件库**: Element Plus 2.9 -- **状态管理**: Pinia 2.2 -- **路由**: Vue Router 4.5 -- **工具库**: VueUse - -## 📝 Module Federation 配置 - -### Shared 配置 (packages/shared/vite.config.ts) - -```typescript -import { federation } from '@module-federation/vite' - -export default defineConfig({ - plugins: [ - federation({ - name: 'shared', - filename: 'remoteEntry.js', - exposes: { - './FileUpload': './src/components/fileupload/FileUpload.vue', - './DynamicFormItem': './src/components/dynamicFormItem/DynamicFormItem.vue', - './api': './src/api/index.ts', - './authAPI': './src/api/auth/auth.ts', - './fileAPI': './src/api/file/file.ts', - './utils': './src/utils/index.ts', - './types': './src/types/index.ts', - './components': './src/components/index.ts' - }, - shared: { - vue: {}, - 'vue-router': {}, - 'element-plus': {}, - '@element-plus/icons-vue': {}, - axios: {} - } - }) - ], - server: { - port: 7000, - strictPort: true, // 关键:锁定端口,避免漂移 - host: true, - cors: true - } -}) -``` - -### Platform 配置 (packages/platform/vite.config.ts) - -```typescript -import { federation } from '@module-federation/vite' - -export default defineConfig({ - plugins: [ - federation({ - name: 'platform', - remotes: { - shared: { - type: 'module', // 关键:必须指定 ES module 类型 - name: 'shared', - entry: 'http://localhost:7000/remoteEntry.js' - } - }, - shared: { - vue: {}, - 'vue-router': {}, - 'element-plus': {}, - axios: {} - } - }) - ] -}) -``` - -### 使用示例 - -```typescript -// 在 platform 中导入 shared 的组件 -import FileUpload from 'shared/FileUpload' -import DynamicFormItem from 'shared/DynamicFormItem' -import { authAPI } from 'shared/authAPI' -import { getAesInstance } from 'shared/utils' -import type { LoginParam, SysUserVO } from 'shared/types' - -// 在组件中使用 - - - -``` - -### 优势 - -- ✅ **开发模式直接支持**:无需构建,直接 dev 即可 -- ✅ **完整的热更新**:修改 shared 代码自动更新到 platform -- ✅ **自动路径处理**:无需关心 shared 内部的 `@/` 路径 -- ✅ **依赖去重**:vue、element-plus 等只加载一次 -- ✅ **企业级稳定**:官方维护,支持 Vite 6 - -## 🎯 开发工作流 - -### 日常开发 - -1. **启动服务**(每天开始) - ```bash - # 使用脚本一键启动 - start-all.bat - - # 或手动启动 - cd packages/shared && pnpm run dev # 终端1 - cd packages/platform && pnpm run dev # 终端2 - ``` - -2. **修改代码** - - 修改 shared 组件 → 保存 → 自动热更新 ✨ - - 修改 platform 页面 → 保存 → 自动热更新 ✨ - -3. **结束开发** - - 按 Ctrl+C 停止所有服务 - -### 添加新的共享模块 - -1. **在 shared 中创建组件** - ```bash - # 例如创建新组件 - packages/shared/src/components/mynew/MyNewComponent.vue - ``` - -2. **在 shared/vite.config.ts 中暴露** - ```typescript - exposes: { - './MyNewComponent': './src/components/mynew/MyNewComponent.vue' - } - ``` - -3. **在 platform 中使用** - ```typescript - import MyNewComponent from 'shared/MyNewComponent' - ``` - -### API 代理 - -所有应用的 `/api` 请求会代理到后端服务 `http://localhost:8080` - -### 跨域配置 - -开发环境下所有服务已启用 CORS,支持跨域访问。 - -## 🔥 注意事项 - -1. **包管理器**: 必须使用 pnpm(项目使用 pnpm workspace) -2. **启动顺序**: 必须先启动 `shared` 服务(5000端口),再启动其他应用 -3. **端口占用**: 确保 5000-5003 端口未被占用,shared 使用 strictPort 模式 -4. **Node 版本**: 建议使用 Node.js 18+ -5. **Module Federation**: remoteEntry.js 路径为 `http://localhost:7000/remoteEntry.js`(不是 /assets/) diff --git a/urbanLifelineWeb/example/DocumentSegmentDialog.vue b/urbanLifelineWeb/example/DocumentSegmentDialog.vue deleted file mode 100644 index 906005e1..00000000 --- a/urbanLifelineWeb/example/DocumentSegmentDialog.vue +++ /dev/null @@ -1,855 +0,0 @@ - - - - - - diff --git a/urbanLifelineWeb/example/jitsi-meet/useJitsiTranscription.js b/urbanLifelineWeb/example/jitsi-meet/useJitsiTranscription.js deleted file mode 100644 index 25634e1e..00000000 --- a/urbanLifelineWeb/example/jitsi-meet/useJitsiTranscription.js +++ /dev/null @@ -1,161 +0,0 @@ -// src/composables/useJitsiTranscription.ts -import { ref } from 'vue'; -import { XunfeiTranscription } from '@/utils/xunfei'; - -export function useJitsiTranscription(meetingId: string) { - const isRecording = ref(false); - const currentSpeaker = ref(null); - let mediaRecorder: MediaRecorder | null = null; - let xunfeiWs: XunfeiTranscription | null = null; - - // 初始化Jitsi API - const initJitsiApi = (domain: string, roomName: string) => { - const api = new JitsiMeetExternalAPI(domain, { - roomName: roomName, - width: '100%', - height: '100%', - parentNode: document.querySelector('#jitsi-container'), - userInfo: { - displayName: '张三', - email: 'zhangsan@example.com' - } - }); - - // 监听主讲人变化(核心:识别说话人) - api.addEventListener('dominantSpeakerChanged', (event) => { - const speakerId = event.id; - console.log('主讲人切换:', speakerId); - - // 获取说话人信息 - api.getParticipantsInfo().then(participants => { - const speaker = participants.find(p => p.participantId === speakerId); - if (speaker) { - currentSpeaker.value = speaker.displayName; - console.log('当前说话人:', speaker.displayName); - - // 开始录制该说话人的音频 - startRecording(speakerId, speaker.displayName); - } - }); - }); - - // 监听音频轨道添加 - api.addEventListener('trackAdded', (event) => { - if (event.track.getType() === 'audio') { - console.log('音频轨道添加:', event.track.getParticipantId()); - } - }); - - return api; - }; - - // 开始录制音频 - const startRecording = async (speakerId: string, speakerName: string) => { - try { - // 获取会议音频流 - const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); - - mediaRecorder = new MediaRecorder(stream, { - mimeType: 'audio/webm' - }); - - let audioChunks: Blob[] = []; - - mediaRecorder.ondataavailable = (event) => { - if (event.data.size > 0) { - audioChunks.push(event.data); - } - }; - - // 每3秒发送一次音频数据进行转写 - mediaRecorder.onstop = async () => { - const audioBlob = new Blob(audioChunks, { type: 'audio/webm' }); - - // 发送到讯飞/阿里云进行转写 - const transcription = await transcribeAudio(audioBlob, speakerId, speakerName); - - // 保存转录结果 - await saveTranscription(meetingId, { - speakerId: speakerId, - speakerName: speakerName, - content: transcription.text, - confidence: transcription.confidence, - startTime: new Date().toISOString(), - endTime: new Date().toISOString() - }); - - audioChunks = []; - }; - - mediaRecorder.start(); - isRecording.value = true; - - // 每3秒停止并重新开始,实现分段录制 - setInterval(() => { - if (mediaRecorder && mediaRecorder.state === 'recording') { - mediaRecorder.stop(); - setTimeout(() => mediaRecorder?.start(), 100); - } - }, 3000); - - } catch (error) { - console.error('录制失败:', error); - } - }; - - // 使用讯飞实时转写 - const transcribeAudio = async (audioBlob: Blob, speakerId: string, speakerName: string) => { - // 连接讯飞WebSocket - if (!xunfeiWs) { - xunfeiWs = new XunfeiTranscription({ - appId: 'YOUR_APP_ID', - apiKey: 'YOUR_API_KEY', - onResult: (result) => { - console.log('实时转写结果:', result); - - // 实时保存到数据库 - saveTranscription(meetingId, { - speakerId: speakerId, - speakerName: speakerName, - content: result.text, - confidence: result.confidence, - startTime: result.startTime, - endTime: result.endTime, - isFinal: result.isFinal - }); - } - }); - } - - // 发送音频数据 - const arrayBuffer = await audioBlob.arrayBuffer(); - xunfeiWs.send(arrayBuffer); - - return { - text: '转写结果(异步返回)', - confidence: 0.95 - }; - }; - - // 保存转录结果到后端 - const saveTranscription = async (meetingId: string, data: any) => { - try { - await fetch('/api/workcase/meeting/transcription/save', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - meetingId: meetingId, - ...data - }) - }); - } catch (error) { - console.error('保存转录失败:', error); - } - }; - - return { - initJitsiApi, - isRecording, - currentSpeaker - }; -} \ No newline at end of file diff --git a/urbanLifelineWeb/install.bat b/urbanLifelineWeb/install.bat deleted file mode 100644 index fcd057a7..00000000 --- a/urbanLifelineWeb/install.bat +++ /dev/null @@ -1,72 +0,0 @@ -@echo off -echo ==================================== -echo Urban Lifeline Web - 安装依赖脚本 -echo ==================================== -echo. - -echo [1/5] 安装根项目依赖... -call npm install -if errorlevel 1 ( - echo 根项目依赖安装失败! - pause - exit /b 1 -) -echo. - -echo [2/5] 安装 shared 模块依赖... -cd packages\shared -call npm install -if errorlevel 1 ( - echo Shared 模块依赖安装失败! - pause - exit /b 1 -) -cd ..\.. -echo. - -echo [3/5] 安装 platform 应用依赖... -cd packages\platform -call npm install -if errorlevel 1 ( - echo Platform 应用依赖安装失败! - pause - exit /b 1 -) -cd ..\.. -echo. - -echo [4/5] 安装 bidding 应用依赖... -cd packages\bidding -call npm install -if errorlevel 1 ( - echo Bidding 应用依赖安装失败! - pause - exit /b 1 -) -cd ..\.. -echo. - -echo [5/5] 安装 workcase 应用依赖... -cd packages\workcase -call npm install -if errorlevel 1 ( - echo Workcase 应用依赖安装失败! - pause - exit /b 1 -) -cd ..\.. -echo. - -echo ==================================== -echo ✓ 所有依赖安装完成! -echo ==================================== -echo. -echo 下一步: -echo 启动所有服务: npm run dev:all -echo 或单独启动: -echo - Shared: npm run dev:shared -echo - Platform: npm run dev:platform -echo - Bidding: npm run dev:bidding -echo - Workcase: npm run dev:workcase -echo. -pause diff --git a/urbanLifelineWeb/package-lock.json b/urbanLifelineWeb/package-lock.json deleted file mode 100644 index 902036f8..00000000 --- a/urbanLifelineWeb/package-lock.json +++ /dev/null @@ -1,7070 +0,0 @@ -{ - "name": "urbanlifeline-web", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "urbanlifeline-web", - "version": "1.0.0", - "workspaces": [ - "packages/*" - ], - "devDependencies": { - "concurrently": "^9.1.0", - "rimraf": "^5.0.5", - "sass": "^1.94.2", - "sass-embedded": "^1.93.3" - }, - "engines": { - "node": ">=16.0.0", - "pnpm": ">=8.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", - "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bufbuild/protobuf": { - "version": "2.10.1", - "resolved": "https://registry.npmmirror.com/@bufbuild/protobuf/-/protobuf-2.10.1.tgz", - "integrity": "sha512-ckS3+vyJb5qGpEYv/s1OebUHDi/xSNtfgw1wqKZo7MR9F2z+qXr0q5XagafAG/9O0QPVIUfST0smluYSTpYFkg==", - "dev": true, - "license": "(Apache-2.0 AND BSD-3-Clause)" - }, - "node_modules/@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/@element-plus/icons-vue": { - "version": "2.3.2", - "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", - "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", - "license": "MIT", - "peerDependencies": { - "vue": "^3.2.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.7.3", - "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.3.tgz", - "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.4.tgz", - "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.3", - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@module-federation/error-codes": { - "version": "0.21.6", - "resolved": "https://registry.npmmirror.com/@module-federation/error-codes/-/error-codes-0.21.6.tgz", - "integrity": "sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@module-federation/runtime": { - "version": "0.21.6", - "resolved": "https://registry.npmmirror.com/@module-federation/runtime/-/runtime-0.21.6.tgz", - "integrity": "sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@module-federation/error-codes": "0.21.6", - "@module-federation/runtime-core": "0.21.6", - "@module-federation/sdk": "0.21.6" - } - }, - "node_modules/@module-federation/runtime-core": { - "version": "0.21.6", - "resolved": "https://registry.npmmirror.com/@module-federation/runtime-core/-/runtime-core-0.21.6.tgz", - "integrity": "sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@module-federation/error-codes": "0.21.6", - "@module-federation/sdk": "0.21.6" - } - }, - "node_modules/@module-federation/sdk": { - "version": "0.21.6", - "resolved": "https://registry.npmmirror.com/@module-federation/sdk/-/sdk-0.21.6.tgz", - "integrity": "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@module-federation/vite": { - "version": "1.9.3", - "resolved": "https://registry.npmmirror.com/@module-federation/vite/-/vite-1.9.3.tgz", - "integrity": "sha512-MV6XI3FX6okEMJ7FdmvFmYuu7DygRoLljKT8atrBwFhlttsgBbswpqMj4P4Fs/X+pFmbIi/ntFzVhsrG0qQnGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@module-federation/runtime": "^0.21.6", - "@module-federation/sdk": "^0.21.6", - "@rollup/pluginutils": "^5.1.0", - "defu": "^6.1.4", - "estree-walker": "^2", - "magic-string": "^0.30.11", - "pathe": "^1.1.2" - } - }, - "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" - } - }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@popperjs/core": { - "name": "@sxzz/popperjs-es", - "version": "2.11.7", - "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", - "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.53", - "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", - "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", - "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", - "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", - "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", - "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", - "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", - "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", - "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", - "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", - "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", - "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", - "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", - "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", - "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", - "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", - "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", - "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", - "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", - "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", - "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", - "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", - "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", - "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@shared/all": { - "resolved": "packages/shared", - "link": true - }, - "node_modules/@stomp/stompjs": { - "version": "7.2.1", - "resolved": "https://registry.npmmirror.com/@stomp/stompjs/-/stompjs-7.2.1.tgz", - "integrity": "sha512-DLd/WeicnHS5SsWWSk3x6/pcivqchNaEvg9UEGVqAcfYEBVmS9D6980ckXjTtfpXLjdLDsd96M7IuX4w7nzq5g==", - "license": "Apache-2.0" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", - "license": "MIT" - }, - "node_modules/@types/lodash-es": { - "version": "4.17.12", - "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", - "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", - "license": "MIT", - "dependencies": { - "@types/lodash": "*" - } - }, - "node_modules/@types/node": { - "version": "22.19.1", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.19.1.tgz", - "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/sockjs-client": { - "version": "1.5.4", - "resolved": "https://registry.npmmirror.com/@types/sockjs-client/-/sockjs-client-1.5.4.tgz", - "integrity": "sha512-zk+uFZeWyvJ5ZFkLIwoGA/DfJ+pYzcZ8eH4H/EILCm2OBZyHH6Hkdna1/UWL/CFruh5wj6ES7g75SvUB0VsH5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/web-bluetooth": { - "version": "0.0.20", - "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", - "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", - "license": "MIT" - }, - "node_modules/@urbanlifeline/bidding": { - "resolved": "packages/bidding", - "link": true - }, - "node_modules/@urbanlifeline/platform": { - "resolved": "packages/platform", - "link": true - }, - "node_modules/@urbanlifeline/workcase": { - "resolved": "packages/workcase", - "link": true - }, - "node_modules/@vitejs/plugin-vue": { - "version": "5.2.4", - "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", - "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0", - "vue": "^3.2.25" - } - }, - "node_modules/@vitejs/plugin-vue-jsx": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-4.2.0.tgz", - "integrity": "sha512-DSTrmrdLp+0LDNF77fqrKfx7X0ErRbOcUAgJL/HbSesqQwoUvUQ4uYQqaex+rovqgGcoPqVk+AwUh3v9CuiYIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.27.1", - "@rolldown/pluginutils": "^1.0.0-beta.9", - "@vue/babel-plugin-jsx": "^1.4.0" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0", - "vue": "^3.0.0" - } - }, - "node_modules/@volar/language-core": { - "version": "2.4.15", - "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.15.tgz", - "integrity": "sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/source-map": "2.4.15" - } - }, - "node_modules/@volar/source-map": { - "version": "2.4.15", - "resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.15.tgz", - "integrity": "sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@volar/typescript": { - "version": "2.4.15", - "resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.15.tgz", - "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "path-browserify": "^1.0.1", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue/babel-helper-vue-transform-on": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", - "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/babel-plugin-jsx": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", - "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.2", - "@vue/babel-helper-vue-transform-on": "1.5.0", - "@vue/babel-plugin-resolve-type": "1.5.0", - "@vue/shared": "^3.5.18" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - } - } - }, - "node_modules/@vue/babel-plugin-resolve-type": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", - "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/parser": "^7.28.0", - "@vue/compiler-sfc": "^3.5.18" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.25.tgz", - "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.25", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz", - "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==", - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz", - "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.25", - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.6", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", - "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "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, - "license": "MIT", - "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } - }, - "node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "license": "MIT" - }, - "node_modules/@vue/language-core": { - "version": "2.2.12", - "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-2.2.12.tgz", - "integrity": "sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "@vue/compiler-dom": "^3.5.0", - "@vue/compiler-vue2": "^2.7.16", - "@vue/shared": "^3.5.0", - "alien-signals": "^1.0.3", - "minimatch": "^9.0.3", - "muggle-string": "^0.4.1", - "path-browserify": "^1.0.1" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@vue/reactivity": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.25.tgz", - "integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==", - "license": "MIT", - "dependencies": { - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.25.tgz", - "integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.25.tgz", - "integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.25", - "@vue/runtime-core": "3.5.25", - "@vue/shared": "3.5.25", - "csstype": "^3.1.3" - } - }, - "node_modules/@vue/server-renderer": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.25.tgz", - "integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==", - "license": "MIT", - "dependencies": { - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25" - }, - "peerDependencies": { - "vue": "3.5.25" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.25.tgz", - "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==", - "license": "MIT" - }, - "node_modules/@vueuse/core": { - "version": "11.3.0", - "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-11.3.0.tgz", - "integrity": "sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==", - "license": "MIT", - "dependencies": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "11.3.0", - "@vueuse/shared": "11.3.0", - "vue-demi": ">=0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/metadata": { - "version": "11.3.0", - "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-11.3.0.tgz", - "integrity": "sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/shared": { - "version": "11.3.0", - "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-11.3.0.tgz", - "integrity": "sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==", - "license": "MIT", - "dependencies": { - "vue-demi": ">=0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/alien-signals": { - "version": "1.0.13", - "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-1.0.13.tgz", - "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/async-validator": { - "version": "4.2.5", - "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", - "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmmirror.com/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.3", - "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.3.tgz", - "integrity": "sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-builder": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/buffer-builder/-/buffer-builder-0.2.0.tgz", - "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", - "dev": true, - "license": "MIT/X11" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001761", - "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz", - "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/colorjs.io": { - "version": "0.5.2", - "resolved": "https://registry.npmmirror.com/colorjs.io/-/colorjs.io-0.5.2.tgz", - "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concurrently": { - "version": "9.2.1", - "resolved": "https://registry.npmmirror.com/concurrently/-/concurrently-9.2.1.tgz", - "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "4.1.2", - "rxjs": "7.8.2", - "shell-quote": "1.8.3", - "supports-color": "8.1.1", - "tree-kill": "1.2.2", - "yargs": "17.7.2" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/dayjs": { - "version": "1.11.19", - "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmmirror.com/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true, - "license": "MIT" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destr": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/destr/-/destr-2.0.5.tgz", - "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", - "license": "MIT" - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.266", - "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz", - "integrity": "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==", - "dev": true, - "license": "ISC" - }, - "node_modules/element-plus": { - "version": "2.12.0", - "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.12.0.tgz", - "integrity": "sha512-M9YLSn2np9OnqrSKWsiXvGe3qnF8pd94+TScsHj1aTMCD+nSEvucXermf807qNt6hOP040le0e5Aft7E9ZfHmA==", - "license": "MIT", - "dependencies": { - "@ctrl/tinycolor": "^3.4.1", - "@element-plus/icons-vue": "^2.3.2", - "@floating-ui/dom": "^1.0.1", - "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", - "@types/lodash": "^4.17.20", - "@types/lodash-es": "^4.17.12", - "@vueuse/core": "^9.1.0", - "async-validator": "^4.2.5", - "dayjs": "^1.11.19", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "lodash-unified": "^1.0.3", - "memoize-one": "^6.0.0", - "normalize-wheel-es": "^1.2.0" - }, - "peerDependencies": { - "vue": "^3.2.0" - } - }, - "node_modules/element-plus/node_modules/@types/web-bluetooth": { - "version": "0.0.16", - "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", - "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==", - "license": "MIT" - }, - "node_modules/element-plus/node_modules/@vueuse/core": { - "version": "9.13.0", - "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz", - "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", - "license": "MIT", - "dependencies": { - "@types/web-bluetooth": "^0.0.16", - "@vueuse/metadata": "9.13.0", - "@vueuse/shared": "9.13.0", - "vue-demi": "*" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/element-plus/node_modules/@vueuse/metadata": { - "version": "9.13.0", - "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz", - "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/element-plus/node_modules/@vueuse/shared": { - "version": "9.13.0", - "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz", - "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", - "license": "MIT", - "dependencies": { - "vue-demi": "*" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/eventsource/-/eventsource-2.0.2.tgz", - "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmmirror.com/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmmirror.com/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "license": "Apache-2.0", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmmirror.com/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/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, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmmirror.com/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "license": "MIT" - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/immutable": { - "version": "5.1.4", - "resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.1.4.tgz", - "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", - "dev": true, - "license": "MIT" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, - "node_modules/lodash-unified": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", - "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", - "license": "MIT", - "peerDependencies": { - "@types/lodash-es": "*", - "lodash": "*", - "lodash-es": "*" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lucide-vue-next": { - "version": "0.561.0", - "resolved": "https://registry.npmmirror.com/lucide-vue-next/-/lucide-vue-next-0.561.0.tgz", - "integrity": "sha512-c5HUckO0qHklVSOf/0vaSR3pEb8fYImRDCRDLde56uqS9js0D/e3RAvq0/YFWjkmyOBKCb0/IdskdoHZQEkT5g==", - "license": "ISC", - "peerDependencies": { - "vue": ">=3.0.1" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", - "license": "MIT" - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/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, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/node-fetch-native": { - "version": "1.6.7", - "resolved": "https://registry.npmmirror.com/node-fetch-native/-/node-fetch-native-1.6.7.tgz", - "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-wheel-es": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", - "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", - "license": "BSD-3-Clause" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ofetch": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/ofetch/-/ofetch-1.5.1.tgz", - "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", - "license": "MIT", - "dependencies": { - "destr": "^2.0.5", - "node-fetch-native": "^1.6.7", - "ufo": "^1.6.1" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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, - "license": "MIT" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" - }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pinia": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.3.1.tgz", - "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", - "license": "MIT", - "dependencies": { - "@vue/devtools-api": "^6.6.3", - "vue-demi": "^0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "typescript": ">=4.4.4", - "vue": "^2.7.0 || ^3.5.11" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmmirror.com/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rimraf": { - "version": "5.0.10", - "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-5.0.10.tgz", - "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.53.3.tgz", - "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.53.3", - "@rollup/rollup-android-arm64": "4.53.3", - "@rollup/rollup-darwin-arm64": "4.53.3", - "@rollup/rollup-darwin-x64": "4.53.3", - "@rollup/rollup-freebsd-arm64": "4.53.3", - "@rollup/rollup-freebsd-x64": "4.53.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", - "@rollup/rollup-linux-arm-musleabihf": "4.53.3", - "@rollup/rollup-linux-arm64-gnu": "4.53.3", - "@rollup/rollup-linux-arm64-musl": "4.53.3", - "@rollup/rollup-linux-loong64-gnu": "4.53.3", - "@rollup/rollup-linux-ppc64-gnu": "4.53.3", - "@rollup/rollup-linux-riscv64-gnu": "4.53.3", - "@rollup/rollup-linux-riscv64-musl": "4.53.3", - "@rollup/rollup-linux-s390x-gnu": "4.53.3", - "@rollup/rollup-linux-x64-gnu": "4.53.3", - "@rollup/rollup-linux-x64-musl": "4.53.3", - "@rollup/rollup-openharmony-arm64": "4.53.3", - "@rollup/rollup-win32-arm64-msvc": "4.53.3", - "@rollup/rollup-win32-ia32-msvc": "4.53.3", - "@rollup/rollup-win32-x64-gnu": "4.53.3", - "@rollup/rollup-win32-x64-msvc": "4.53.3", - "fsevents": "~2.3.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/sass": { - "version": "1.94.2", - "resolved": "https://registry.npmmirror.com/sass/-/sass-1.94.2.tgz", - "integrity": "sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" - } - }, - "node_modules/sass-embedded": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded/-/sass-embedded-1.93.3.tgz", - "integrity": "sha512-+VUy01yfDqNmIVMd/LLKl2TTtY0ovZN0rTonh+FhKr65mFwIYgU9WzgIZKS7U9/SPCQvWTsTGx9jyt+qRm/XFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bufbuild/protobuf": "^2.5.0", - "buffer-builder": "^0.2.0", - "colorjs.io": "^0.5.0", - "immutable": "^5.0.2", - "rxjs": "^7.4.0", - "supports-color": "^8.1.1", - "sync-child-process": "^1.0.2", - "varint": "^6.0.0" - }, - "bin": { - "sass": "dist/bin/sass.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "optionalDependencies": { - "sass-embedded-all-unknown": "1.93.3", - "sass-embedded-android-arm": "1.93.3", - "sass-embedded-android-arm64": "1.93.3", - "sass-embedded-android-riscv64": "1.93.3", - "sass-embedded-android-x64": "1.93.3", - "sass-embedded-darwin-arm64": "1.93.3", - "sass-embedded-darwin-x64": "1.93.3", - "sass-embedded-linux-arm": "1.93.3", - "sass-embedded-linux-arm64": "1.93.3", - "sass-embedded-linux-musl-arm": "1.93.3", - "sass-embedded-linux-musl-arm64": "1.93.3", - "sass-embedded-linux-musl-riscv64": "1.93.3", - "sass-embedded-linux-musl-x64": "1.93.3", - "sass-embedded-linux-riscv64": "1.93.3", - "sass-embedded-linux-x64": "1.93.3", - "sass-embedded-unknown-all": "1.93.3", - "sass-embedded-win32-arm64": "1.93.3", - "sass-embedded-win32-x64": "1.93.3" - } - }, - "node_modules/sass-embedded-all-unknown": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.93.3.tgz", - "integrity": "sha512-3okGgnE41eg+CPLtAPletu6nQ4N0ij7AeW+Sl5Km4j29XcmqZQeFwYjHe1AlKTEgLi/UAONk1O8i8/lupeKMbw==", - "cpu": [ - "!arm", - "!arm64", - "!riscv64", - "!x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "sass": "1.93.3" - } - }, - "node_modules/sass-embedded-all-unknown/node_modules/sass": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass/-/sass-1.93.3.tgz", - "integrity": "sha512-elOcIZRTM76dvxNAjqYrucTSI0teAF/L2Lv0s6f6b7FOwcwIuA357bIE871580AjHJuSvLIRUosgV+lIWx6Rgg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" - } - }, - "node_modules/sass-embedded-android-arm": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-android-arm/-/sass-embedded-android-arm-1.93.3.tgz", - "integrity": "sha512-8xOw9bywfOD6Wv24BgCmgjkk6tMrsOTTHcb28KDxeJtFtoxiUyMbxo0vChpPAfp2Hyg2tFFKS60s0s4JYk+Raw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-android-arm64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.93.3.tgz", - "integrity": "sha512-uqUl3Kt1IqdGVAcAdbmC+NwuUJy8tM+2ZnB7/zrt6WxWVShVCRdFnWR9LT8HJr7eJN7AU8kSXxaVX/gedanPsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-android-riscv64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.93.3.tgz", - "integrity": "sha512-2jNJDmo+3qLocjWqYbXiBDnfgwrUeZgZFHJIwAefU7Fn66Ot7rsXl+XPwlokaCbTpj7eMFIqsRAZ/uDueXNCJg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-android-x64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-android-x64/-/sass-embedded-android-x64-1.93.3.tgz", - "integrity": "sha512-y0RoAU6ZenQFcjM9PjQd3cRqRTjqwSbtWLL/p68y2oFyh0QGN0+LQ826fc0ZvU/AbqCsAizkqjzOn6cRZJxTTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-darwin-arm64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.93.3.tgz", - "integrity": "sha512-7zb/hpdMOdKteK17BOyyypemglVURd1Hdz6QGsggy60aUFfptTLQftLRg8r/xh1RbQAUKWFbYTNaM47J9yPxYg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-darwin-x64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.93.3.tgz", - "integrity": "sha512-Ek1Vp8ZDQEe327Lz0b7h3hjvWH3u9XjJiQzveq74RPpJQ2q6d9LfWpjiRRohM4qK6o4XOHw1X10OMWPXJtdtWg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-arm": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.93.3.tgz", - "integrity": "sha512-yeiv2y+dp8B4wNpd3+JsHYD0mvpXSfov7IGyQ1tMIR40qv+ROkRqYiqQvAOXf76Qwh4Y9OaYZtLpnsPjfeq6mA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-arm64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.93.3.tgz", - "integrity": "sha512-RBrHWgfd8Dd8w4fbmdRVXRrhh8oBAPyeWDTKAWw8ZEmuXfVl4ytjDuyxaVilh6rR1xTRTNpbaA/YWApBlLrrNw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-musl-arm": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.93.3.tgz", - "integrity": "sha512-fU0fwAwbp7sBE3h5DVU5UPzvaLg7a4yONfFWkkcCp6ZrOiPuGRHXXYriWQ0TUnWy4wE+svsVuWhwWgvlb/tkKg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-musl-arm64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.93.3.tgz", - "integrity": "sha512-PS829l+eUng+9W4PFclXGb4uA2+965NHV3/Sa5U7qTywjeeUUYTZg70dJHSqvhrBEfCc2XJABeW3adLJbyQYkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-musl-riscv64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.93.3.tgz", - "integrity": "sha512-cK1oBY+FWQquaIGEeQ5H74KTO8cWsSWwXb/WaildOO9U6wmUypTgUYKQ0o5o/29nZbWWlM1PHuwVYTSnT23Jjg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-musl-x64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.93.3.tgz", - "integrity": "sha512-A7wkrsHu2/I4Zpa0NMuPGkWDVV7QGGytxGyUq3opSXgAexHo/vBPlGoDXoRlSdex0cV+aTMRPjoGIfdmNlHwyg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-riscv64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.93.3.tgz", - "integrity": "sha512-vWkW1+HTF5qcaHa6hO80gx/QfB6GGjJUP0xLbnAoY4pwEnw5ulGv6RM8qYr8IDhWfVt/KH+lhJ2ZFxnJareisQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-x64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.93.3.tgz", - "integrity": "sha512-k6uFxs+e5jSuk1Y0niCwuq42F9ZC5UEP7P+RIOurIm8w/5QFa0+YqeW+BPWEW5M1FqVOsNZH3qGn4ahqvAEjPA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-unknown-all": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.93.3.tgz", - "integrity": "sha512-o5wj2rLpXH0C+GJKt/VpWp6AnMsCCbfFmnMAttcrsa+U3yrs/guhZ3x55KAqqUsE8F47e3frbsDL+1OuQM5DAA==", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "!android", - "!darwin", - "!linux", - "!win32" - ], - "dependencies": { - "sass": "1.93.3" - } - }, - "node_modules/sass-embedded-unknown-all/node_modules/sass": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass/-/sass-1.93.3.tgz", - "integrity": "sha512-elOcIZRTM76dvxNAjqYrucTSI0teAF/L2Lv0s6f6b7FOwcwIuA357bIE871580AjHJuSvLIRUosgV+lIWx6Rgg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" - } - }, - "node_modules/sass-embedded-win32-arm64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.93.3.tgz", - "integrity": "sha512-0dOfT9moy9YmBolodwYYXtLwNr4jL4HQC9rBfv6mVrD7ud8ue2kDbn+GVzj1hEJxvEexVSmDCf7MHUTLcGs9xQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-win32-x64": { - "version": "1.93.3", - "resolved": "https://registry.npmmirror.com/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.93.3.tgz", - "integrity": "sha512-wHFVfxiS9hU/sNk7KReD+lJWRp3R0SLQEX4zfOnRP2zlvI2X4IQR5aZr9GNcuMP6TmNpX0nQPZTegS8+h9RrEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.19.1", - "resolved": "https://registry.npmmirror.com/send/-/send-0.19.1.tgz", - "integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/send/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-static/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-static/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/serve-static/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/serve-static/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmmirror.com/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-static/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sockjs-client": { - "version": "1.6.1", - "resolved": "https://registry.npmmirror.com/sockjs-client/-/sockjs-client-1.6.1.tgz", - "integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==", - "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "eventsource": "^2.0.2", - "faye-websocket": "^0.11.4", - "inherits": "^2.0.4", - "url-parse": "^1.5.10" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://tidelift.com/funding/github/npm/sockjs-client" - } - }, - "node_modules/sockjs-client/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sync-child-process": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/sync-child-process/-/sync-child-process-1.0.2.tgz", - "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "sync-message-port": "^1.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/sync-message-port": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/sync-message-port/-/sync-message-port-1.1.3.tgz", - "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.6.1", - "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.6.1.tgz", - "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", - "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmmirror.com/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/varint": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", - "dev": true, - "license": "MIT" - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmmirror.com/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/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, - "license": "MIT" - }, - "node_modules/vue": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.25.tgz", - "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-sfc": "3.5.25", - "@vue/runtime-dom": "3.5.25", - "@vue/server-renderer": "3.5.25", - "@vue/shared": "3.5.25" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, - "node_modules/vue-router": { - "version": "4.6.3", - "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.3.tgz", - "integrity": "sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==", - "license": "MIT", - "dependencies": { - "@vue/devtools-api": "^6.6.4" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "vue": "^3.5.0" - } - }, - "node_modules/vue-tsc": { - "version": "2.2.12", - "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-2.2.12.tgz", - "integrity": "sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/typescript": "2.4.15", - "@vue/language-core": "2.2.12" - }, - "bin": { - "vue-tsc": "bin/vue-tsc.js" - }, - "peerDependencies": { - "typescript": ">=5.0.0" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmmirror.com/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "license": "Apache-2.0", - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmmirror.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workcase_wechat": { - "resolved": "packages/workcase_wechat", - "link": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "packages/bidding": { - "name": "@urbanlifeline/bidding", - "version": "1.0.0", - "dependencies": { - "@element-plus/icons-vue": "^2.3.2", - "@vueuse/core": "^11.3.0", - "axios": "^1.7.9", - "element-plus": "^2.12.0", - "lucide-vue-next": "^0.561.0", - "pinia": "^2.2.8", - "vue": "^3.5.13", - "vue-router": "^4.5.0" - }, - "devDependencies": { - "@module-federation/vite": "^1.9.3", - "@types/node": "^20.10.0", - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "typescript": "^5.7.2", - "vite": "^6.0.3", - "vue-tsc": "^2.2.0" - } - }, - "packages/bidding/node_modules/@types/node": { - "version": "20.19.30", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.19.30.tgz", - "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "packages/platform": { - "name": "@urbanlifeline/platform", - "version": "1.0.0", - "dependencies": { - "@element-plus/icons-vue": "^2.3.2", - "@vueuse/core": "^11.3.0", - "axios": "^1.7.9", - "element-plus": "^2.12.0", - "lucide-vue-next": "^0.561.0", - "pinia": "^2.2.8", - "vue": "^3.5.13", - "vue-router": "^4.5.0" - }, - "devDependencies": { - "@module-federation/vite": "^1.9.3", - "@types/node": "^22.0.0", - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "typescript": "^5.7.2", - "vite": "^6.0.3", - "vue-tsc": "^2.2.0" - } - }, - "packages/shared": { - "name": "@shared/all", - "version": "1.0.0", - "dependencies": { - "@element-plus/icons-vue": "^2.3.2", - "@stomp/stompjs": "^7.2.1", - "axios": "^1.7.0", - "cors": "^2.8.5", - "element-plus": "^2.12.0", - "express": "^4.18.2", - "lucide-vue-next": "^0.561.0", - "ofetch": "^1.4.1", - "sockjs-client": "^1.6.1", - "vue": "^3.5.13", - "vue-router": "^4.5.0" - }, - "devDependencies": { - "@module-federation/vite": "^1.9.3", - "@types/node": "^20.10.0", - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "npm-run-all": "^4.1.5", - "sass": "^1.80.6", - "sass-embedded": "^1.80.6", - "typescript": "^5.7.2", - "vite": "^6.0.3" - }, - "peerDependencies": { - "typescript": ">=5.0.0", - "vue": "^3.5.13" - } - }, - "packages/shared/node_modules/@types/node": { - "version": "20.19.25", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.19.25.tgz", - "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "packages/shared/node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/async-function": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/available-typed-arrays": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "packages/shared/node_modules/call-bind": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/chalk": { - "version": "2.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "packages/shared/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "packages/shared/node_modules/cross-spawn": { - "version": "6.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "packages/shared/node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.2", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "packages/shared/node_modules/data-view-buffer": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/data-view-byte-length": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "packages/shared/node_modules/data-view-byte-offset": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/define-data-property": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/define-properties": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/error-ex": { - "version": "1.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "packages/shared/node_modules/es-abstract": { - "version": "1.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/es-to-primitive": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "packages/shared/node_modules/for-each": { - "version": "0.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/function.prototype.name": { - "version": "1.1.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/functions-have-names": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/generator-function": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/get-symbol-description": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/globalthis": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/has-bigints": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/has-property-descriptors": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/has-proto": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/hosted-git-info": { - "version": "2.8.9", - "dev": true, - "license": "ISC" - }, - "packages/shared/node_modules/internal-slot": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/is-array-buffer": { - "version": "3.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-arrayish": { - "version": "0.2.1", - "dev": true, - "license": "MIT" - }, - "packages/shared/node_modules/is-async-function": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-bigint": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-boolean-object": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-callable": { - "version": "1.2.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-data-view": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-date-object": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-finalizationregistry": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-generator-function": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-map": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-negative-zero": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-number-object": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-regex": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-set": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-string": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-symbol": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-typed-array": { - "version": "1.1.15", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-weakmap": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-weakref": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/is-weakset": { - "version": "2.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/isarray": { - "version": "2.0.5", - "dev": true, - "license": "MIT" - }, - "packages/shared/node_modules/json-parse-better-errors": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "packages/shared/node_modules/load-json-file": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/memorystream": { - "version": "0.3.1", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "packages/shared/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "packages/shared/node_modules/nice-try": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "packages/shared/node_modules/normalize-package-data": { - "version": "2.5.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "packages/shared/node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "packages/shared/node_modules/npm-run-all": { - "version": "4.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": ">= 4" - } - }, - "packages/shared/node_modules/object-keys": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/object.assign": { - "version": "4.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/own-keys": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/parse-json": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/path-key": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/path-type": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/pidtree": { - "version": "0.3.1", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "packages/shared/node_modules/pify": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/possible-typed-array-names": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/read-pkg": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/safe-array-concat": { - "version": "1.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/safe-push-apply": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/safe-regex-test": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/set-function-length": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/set-function-name": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/set-proto": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/shebang-command": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "packages/shared/node_modules/shebang-regex": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "packages/shared/node_modules/spdx-correct": { - "version": "3.2.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "packages/shared/node_modules/spdx-exceptions": { - "version": "2.5.0", - "dev": true, - "license": "CC-BY-3.0" - }, - "packages/shared/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "packages/shared/node_modules/spdx-license-ids": { - "version": "3.0.22", - "dev": true, - "license": "CC0-1.0" - }, - "packages/shared/node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/string.prototype.padend": { - "version": "3.1.6", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/string.prototype.trim": { - "version": "1.2.10", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/string.prototype.trimend": { - "version": "1.0.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/strip-bom": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "packages/shared/node_modules/typed-array-buffer": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "packages/shared/node_modules/typed-array-byte-length": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/typed-array-length": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/unbox-primitive": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "packages/shared/node_modules/which": { - "version": "1.3.1", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "packages/shared/node_modules/which-boxed-primitive": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/which-builtin-type": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/which-collection": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/shared/node_modules/which-typed-array": { - "version": "1.1.19", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "packages/wechat_demo": { - "name": "taihao-service-miniprogram", - "version": "1.0.0", - "extraneous": true, - "dependencies": { - "@vant/weapp": "^1.11.7" - } - }, - "packages/workcase": { - "name": "@urbanlifeline/workcase", - "version": "1.0.0", - "dependencies": { - "@element-plus/icons-vue": "^2.3.2", - "@stomp/stompjs": "^7.2.1", - "@vueuse/core": "^11.3.0", - "axios": "^1.7.9", - "element-plus": "^2.8.6", - "lucide-vue-next": "^0.561.0", - "pinia": "^2.2.8", - "sockjs-client": "^1.6.1", - "vue": "^3.5.13", - "vue-router": "^4.5.0" - }, - "devDependencies": { - "@module-federation/vite": "^1.9.3", - "@types/node": "^22.0.0", - "@types/sockjs-client": "^1.5.4", - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "typescript": "^5.7.2", - "vite": "^6.0.3", - "vue-tsc": "^2.2.0" - } - }, - "packages/workcase_wechat": {} - } -} diff --git a/urbanLifelineWeb/package.json b/urbanLifelineWeb/package.json deleted file mode 100644 index 330cd1de..00000000 --- a/urbanLifelineWeb/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "urbanlifeline-web", - "version": "1.0.0", - "private": true, - "type": "module", - "packageManager": "pnpm@8.10.0", - "scripts": { - "dev": "pnpm -r --parallel --filter \"@*/*\" run dev", - "build": "pnpm -r --filter \"@*/*\" run build", - "clean": "rimraf node_modules && rimraf packages/*/node_modules" - }, - "devDependencies": { - "concurrently": "^9.1.0", - "rimraf": "^5.0.5", - "sass": "^1.94.2", - "sass-embedded": "^1.93.3" - }, - "engines": { - "node": ">=16.0.0", - "pnpm": ">=8.0.0" - }, - "workspaces": [ - "packages/*" - ] -} diff --git a/urbanLifelineWeb/packages/bidding/index.html b/urbanLifelineWeb/packages/bidding/index.html deleted file mode 100644 index 4f5733d0..00000000 --- a/urbanLifelineWeb/packages/bidding/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - 招标管理系统 - - - - - - - - - -
- - - - - diff --git a/urbanLifelineWeb/packages/bidding/package.json b/urbanLifelineWeb/packages/bidding/package.json deleted file mode 100644 index 1bfcd3c0..00000000 --- a/urbanLifelineWeb/packages/bidding/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@urbanlifeline/bidding", - "version": "1.0.0", - "type": "module", - "private": true, - "scripts": { - "dev": "vite --port 5002 --host", - "build": "vue-tsc && vite build", - "preview": "vite preview --port 5002" - }, - "dependencies": { - "vue": "^3.5.13", - "vue-router": "^4.5.0", - "pinia": "^2.2.8", - "element-plus": "^2.12.0", - "@element-plus/icons-vue": "^2.3.2", - "@vueuse/core": "^11.3.0", - "axios": "^1.7.9", - "lucide-vue-next": "^0.561.0" - }, - "devDependencies": { - "@module-federation/vite": "^1.9.3", - "@types/node": "^20.10.0", - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "typescript": "^5.7.2", - "vite": "^6.0.3", - "vue-tsc": "^2.2.0" - } -} diff --git a/urbanLifelineWeb/packages/bidding/pnpm-lock.yaml b/urbanLifelineWeb/packages/bidding/pnpm-lock.yaml deleted file mode 100644 index 4ea2b16c..00000000 --- a/urbanLifelineWeb/packages/bidding/pnpm-lock.yaml +++ /dev/null @@ -1,1753 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@element-plus/icons-vue': - specifier: ^2.3.2 - version: 2.3.2(vue@3.5.25) - '@vueuse/core': - specifier: ^11.3.0 - version: 11.3.0(vue@3.5.25) - axios: - specifier: ^1.7.9 - version: 1.13.2 - element-plus: - specifier: ^2.12.0 - version: 2.12.0(vue@3.5.25) - lucide-vue-next: - specifier: ^0.561.0 - version: 0.561.0(vue@3.5.25) - pinia: - specifier: ^2.2.8 - version: 2.3.1(typescript@5.9.3)(vue@3.5.25) - vue: - specifier: ^3.5.13 - version: 3.5.25(typescript@5.9.3) - vue-router: - specifier: ^4.5.0 - version: 4.6.3(vue@3.5.25) - -devDependencies: - '@module-federation/vite': - specifier: ^1.9.3 - version: 1.9.4 - '@types/node': - specifier: ^20.10.0 - version: 20.19.27 - '@vitejs/plugin-vue': - specifier: ^5.2.1 - version: 5.2.4(vite@6.4.1)(vue@3.5.25) - '@vitejs/plugin-vue-jsx': - specifier: ^4.1.1 - version: 4.2.0(vite@6.4.1)(vue@3.5.25) - typescript: - specifier: ^5.7.2 - version: 5.9.3 - vite: - specifier: ^6.0.3 - version: 6.4.1(@types/node@20.19.27) - vue-tsc: - specifier: ^2.2.0 - version: 2.2.12(typescript@5.9.3) - -packages: - - /@babel/code-frame@7.27.1: - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - dev: true - - /@babel/compat-data@7.28.5: - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core@7.28.5: - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator@7.28.5: - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - dev: true - - /@babel/helper-annotate-as-pure@7.27.3: - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.28.5 - dev: true - - /@babel/helper-compilation-targets@7.27.2: - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - - /@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5): - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-globals@7.28.0: - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-member-expression-to-functions@7.28.5: - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-module-imports@7.27.1: - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5): - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-optimise-call-expression@7.27.1: - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.28.5 - dev: true - - /@babel/helper-plugin-utils@7.27.1: - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-skip-transparent-expression-wrappers@7.27.1: - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-string-parser@7.27.1: - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-identifier@7.28.5: - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-option@7.27.1: - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helpers@7.28.4: - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - dev: true - - /@babel/parser@7.28.5: - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.28.5 - - /@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - - /@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - - /@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5): - resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/template@7.27.2: - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - dev: true - - /@babel/traverse@7.28.5: - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types@7.28.5: - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - /@ctrl/tinycolor@3.6.1: - resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} - engines: {node: '>=10'} - dev: false - - /@element-plus/icons-vue@2.3.2(vue@3.5.25): - resolution: {integrity: sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==} - peerDependencies: - vue: ^3.2.0 - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /@esbuild/aix-ppc64@0.25.12: - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm64@0.25.12: - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.25.12: - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.25.12: - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.25.12: - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.25.12: - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.25.12: - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.25.12: - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.25.12: - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.25.12: - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.25.12: - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.25.12: - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.25.12: - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.25.12: - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.25.12: - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.25.12: - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.25.12: - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-arm64@0.25.12: - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.25.12: - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-arm64@0.25.12: - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.25.12: - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openharmony-arm64@0.25.12: - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.25.12: - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.25.12: - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.25.12: - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.25.12: - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@floating-ui/core@1.7.3: - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - dependencies: - '@floating-ui/utils': 0.2.10 - dev: false - - /@floating-ui/dom@1.7.4: - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 - dev: false - - /@floating-ui/utils@0.2.10: - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - dev: false - - /@jridgewell/gen-mapping@0.3.13: - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - - /@jridgewell/remapping@2.3.5: - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.5.5: - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - /@jridgewell/trace-mapping@0.3.31: - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - dev: true - - /@module-federation/error-codes@0.21.6: - resolution: {integrity: sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==} - dev: true - - /@module-federation/runtime-core@0.21.6: - resolution: {integrity: sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==} - dependencies: - '@module-federation/error-codes': 0.21.6 - '@module-federation/sdk': 0.21.6 - dev: true - - /@module-federation/runtime@0.21.6: - resolution: {integrity: sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==} - dependencies: - '@module-federation/error-codes': 0.21.6 - '@module-federation/runtime-core': 0.21.6 - '@module-federation/sdk': 0.21.6 - dev: true - - /@module-federation/sdk@0.21.6: - resolution: {integrity: sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==} - dev: true - - /@module-federation/vite@1.9.4: - resolution: {integrity: sha512-7UckjGCqpN6mCRs8J9+T/we0s4msl4SFJERG1uVQslIQJvomuOeu/+keIAbK6M4vjgRwXxkHKyWPhr95uhdulg==} - dependencies: - '@module-federation/runtime': 0.21.6 - '@module-federation/sdk': 0.21.6 - '@rollup/pluginutils': 5.3.0 - defu: 6.1.4 - estree-walker: 2.0.2 - magic-string: 0.30.21 - pathe: 1.1.2 - transitivePeerDependencies: - - rollup - dev: true - - /@rolldown/pluginutils@1.0.0-beta.53: - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} - dev: true - - /@rollup/pluginutils@5.3.0: - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - dev: true - - /@rollup/rollup-android-arm-eabi@4.53.3: - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-android-arm64@4.53.3: - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-darwin-arm64@4.53.3: - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-darwin-x64@4.53.3: - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-freebsd-arm64@4.53.3: - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-freebsd-x64@4.53.3: - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm-gnueabihf@4.53.3: - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} - cpu: [arm] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm-musleabihf@4.53.3: - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} - cpu: [arm] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm64-gnu@4.53.3: - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} - cpu: [arm64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm64-musl@4.53.3: - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} - cpu: [arm64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-loong64-gnu@4.53.3: - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} - cpu: [loong64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-ppc64-gnu@4.53.3: - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-riscv64-gnu@4.53.3: - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-riscv64-musl@4.53.3: - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} - cpu: [riscv64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-s390x-gnu@4.53.3: - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} - cpu: [s390x] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-x64-gnu@4.53.3: - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} - cpu: [x64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-x64-musl@4.53.3: - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} - cpu: [x64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-openharmony-arm64@4.53.3: - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} - cpu: [arm64] - os: [openharmony] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-arm64-msvc@4.53.3: - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-ia32-msvc@4.53.3: - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-x64-gnu@4.53.3: - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-x64-msvc@4.53.3: - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@sxzz/popperjs-es@2.11.7: - resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==} - dev: false - - /@types/estree@1.0.8: - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - dev: true - - /@types/lodash-es@4.17.12: - resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - dependencies: - '@types/lodash': 4.17.21 - dev: false - - /@types/lodash@4.17.21: - resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} - dev: false - - /@types/node@20.19.27: - resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==} - dependencies: - undici-types: 6.21.0 - dev: true - - /@types/web-bluetooth@0.0.16: - resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} - dev: false - - /@types/web-bluetooth@0.0.20: - resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} - dev: false - - /@vitejs/plugin-vue-jsx@4.2.0(vite@6.4.1)(vue@3.5.25): - resolution: {integrity: sha512-DSTrmrdLp+0LDNF77fqrKfx7X0ErRbOcUAgJL/HbSesqQwoUvUQ4uYQqaex+rovqgGcoPqVk+AwUh3v9CuiYIw==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.53 - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.5) - vite: 6.4.1(@types/node@20.19.27) - vue: 3.5.25(typescript@5.9.3) - transitivePeerDependencies: - - supports-color - dev: true - - /@vitejs/plugin-vue@5.2.4(vite@6.4.1)(vue@3.5.25): - resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.2.25 - dependencies: - vite: 6.4.1(@types/node@20.19.27) - vue: 3.5.25(typescript@5.9.3) - dev: true - - /@volar/language-core@2.4.15: - resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} - dependencies: - '@volar/source-map': 2.4.15 - dev: true - - /@volar/source-map@2.4.15: - resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==} - dev: true - - /@volar/typescript@2.4.15: - resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} - dependencies: - '@volar/language-core': 2.4.15 - path-browserify: 1.0.1 - vscode-uri: 3.1.0 - dev: true - - /@vue/babel-helper-vue-transform-on@1.5.0: - resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} - dev: true - - /@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.5): - resolution: {integrity: sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - peerDependenciesMeta: - '@babel/core': - optional: true - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@vue/babel-helper-vue-transform-on': 1.5.0 - '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.28.5) - '@vue/shared': 3.5.25 - transitivePeerDependencies: - - supports-color - dev: true - - /@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.28.5): - resolution: {integrity: sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/parser': 7.28.5 - '@vue/compiler-sfc': 3.5.25 - transitivePeerDependencies: - - supports-color - dev: true - - /@vue/compiler-core@3.5.25: - resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} - dependencies: - '@babel/parser': 7.28.5 - '@vue/shared': 3.5.25 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - - /@vue/compiler-dom@3.5.25: - resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} - dependencies: - '@vue/compiler-core': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/compiler-sfc@3.5.25: - resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} - dependencies: - '@babel/parser': 7.28.5 - '@vue/compiler-core': 3.5.25 - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - estree-walker: 2.0.2 - magic-string: 0.30.21 - postcss: 8.5.6 - source-map-js: 1.2.1 - - /@vue/compiler-ssr@3.5.25: - resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} - dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/compiler-vue2@2.7.16: - resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} - dependencies: - de-indent: 1.0.2 - he: 1.2.0 - dev: true - - /@vue/devtools-api@6.6.4: - resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - dev: false - - /@vue/language-core@2.2.12(typescript@5.9.3): - resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.25 - alien-signals: 1.0.13 - minimatch: 9.0.5 - muggle-string: 0.4.1 - path-browserify: 1.0.1 - typescript: 5.9.3 - dev: true - - /@vue/reactivity@3.5.25: - resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} - dependencies: - '@vue/shared': 3.5.25 - - /@vue/runtime-core@3.5.25: - resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} - dependencies: - '@vue/reactivity': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/runtime-dom@3.5.25: - resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} - dependencies: - '@vue/reactivity': 3.5.25 - '@vue/runtime-core': 3.5.25 - '@vue/shared': 3.5.25 - csstype: 3.2.3 - - /@vue/server-renderer@3.5.25(vue@3.5.25): - resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} - peerDependencies: - vue: 3.5.25 - dependencies: - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - vue: 3.5.25(typescript@5.9.3) - - /@vue/shared@3.5.25: - resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} - - /@vueuse/core@11.3.0(vue@3.5.25): - resolution: {integrity: sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==} - dependencies: - '@types/web-bluetooth': 0.0.20 - '@vueuse/metadata': 11.3.0 - '@vueuse/shared': 11.3.0(vue@3.5.25) - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /@vueuse/core@9.13.0(vue@3.5.25): - resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} - dependencies: - '@types/web-bluetooth': 0.0.16 - '@vueuse/metadata': 9.13.0 - '@vueuse/shared': 9.13.0(vue@3.5.25) - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /@vueuse/metadata@11.3.0: - resolution: {integrity: sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==} - dev: false - - /@vueuse/metadata@9.13.0: - resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} - dev: false - - /@vueuse/shared@11.3.0(vue@3.5.25): - resolution: {integrity: sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==} - dependencies: - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /@vueuse/shared@9.13.0(vue@3.5.25): - resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} - dependencies: - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /alien-signals@1.0.13: - resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} - dev: true - - /async-validator@4.2.5: - resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} - dev: false - - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: false - - /axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /baseline-browser-mapping@2.9.3: - resolution: {integrity: sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==} - hasBin: true - dev: true - - /brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - dependencies: - balanced-match: 1.0.2 - dev: true - - /browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - baseline-browser-mapping: 2.9.3 - caniuse-lite: 1.0.30001759 - electron-to-chromium: 1.5.266 - node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) - dev: true - - /call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - dev: false - - /caniuse-lite@1.0.30001759: - resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==} - dev: true - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: false - - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - - /csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - /dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} - dev: false - - /de-indent@1.0.2: - resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} - dev: true - - /debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - - /defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: false - - /dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - dev: false - - /electron-to-chromium@1.5.266: - resolution: {integrity: sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==} - dev: true - - /element-plus@2.12.0(vue@3.5.25): - resolution: {integrity: sha512-M9YLSn2np9OnqrSKWsiXvGe3qnF8pd94+TScsHj1aTMCD+nSEvucXermf807qNt6hOP040le0e5Aft7E9ZfHmA==} - peerDependencies: - vue: ^3.2.0 - dependencies: - '@ctrl/tinycolor': 3.6.1 - '@element-plus/icons-vue': 2.3.2(vue@3.5.25) - '@floating-ui/dom': 1.7.4 - '@popperjs/core': /@sxzz/popperjs-es@2.11.7 - '@types/lodash': 4.17.21 - '@types/lodash-es': 4.17.12 - '@vueuse/core': 9.13.0(vue@3.5.25) - async-validator: 4.2.5 - dayjs: 1.11.19 - lodash: 4.17.21 - lodash-es: 4.17.21 - lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21) - memoize-one: 6.0.0 - normalize-wheel-es: 1.2.0 - vue: 3.5.25(typescript@5.9.3) - transitivePeerDependencies: - - '@vue/composition-api' - dev: false - - /entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - /es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - dev: false - - /es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - dev: false - - /es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - dev: false - - /es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - dev: false - - /esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - dev: true - - /escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - dev: true - - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - /fdir@6.5.0(picomatch@4.0.3): - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - dependencies: - picomatch: 4.0.3 - dev: true - - /follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: false - - /form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - dev: false - - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: false - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - - /get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - dev: false - - /get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - dev: false - - /gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - dev: false - - /has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - dev: false - - /has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.1.0 - dev: false - - /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - dev: false - - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - - /jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - dev: false - - /lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21): - resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==} - peerDependencies: - '@types/lodash-es': '*' - lodash: '*' - lodash-es: '*' - dependencies: - '@types/lodash-es': 4.17.12 - lodash: 4.17.21 - lodash-es: 4.17.21 - dev: false - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lucide-vue-next@0.561.0(vue@3.5.25): - resolution: {integrity: sha512-c5HUckO0qHklVSOf/0vaSR3pEb8fYImRDCRDLde56uqS9js0D/e3RAvq0/YFWjkmyOBKCb0/IdskdoHZQEkT5g==} - peerDependencies: - vue: '>=3.0.1' - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - /math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - dev: false - - /memoize-one@6.0.0: - resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - dev: false - - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: false - - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - dev: false - - /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.2 - dev: true - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /muggle-string@0.4.1: - resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - dev: true - - /nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - /node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - dev: true - - /normalize-wheel-es@1.2.0: - resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==} - dev: false - - /path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - dev: true - - /pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - dev: true - - /picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - /picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - dev: true - - /pinia@2.3.1(typescript@5.9.3)(vue@3.5.25): - resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==} - peerDependencies: - typescript: '>=4.4.4' - vue: ^2.7.0 || ^3.5.11 - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@vue/devtools-api': 6.6.4 - typescript: 5.9.3 - vue: 3.5.25(typescript@5.9.3) - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - dev: false - - /postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false - - /rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 - fsevents: 2.3.3 - dev: true - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true - - /source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - /tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - dev: true - - /typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - /undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - dev: true - - /update-browserslist-db@1.2.2(browserslist@4.28.1): - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - dev: true - - /vite@6.4.1(@types/node@20.19.27): - resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - dependencies: - '@types/node': 20.19.27 - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.3 - tinyglobby: 0.2.15 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /vscode-uri@3.1.0: - resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} - dev: true - - /vue-demi@0.14.10(vue@3.5.25): - resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - peerDependencies: - '@vue/composition-api': ^1.0.0-rc.1 - vue: ^3.0.0-0 || ^2.6.0 - peerDependenciesMeta: - '@vue/composition-api': - optional: true - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /vue-router@4.6.3(vue@3.5.25): - resolution: {integrity: sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==} - peerDependencies: - vue: ^3.5.0 - dependencies: - '@vue/devtools-api': 6.6.4 - vue: 3.5.25(typescript@5.9.3) - dev: false - - /vue-tsc@2.2.12(typescript@5.9.3): - resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} - hasBin: true - peerDependencies: - typescript: '>=5.0.0' - dependencies: - '@volar/typescript': 2.4.15 - '@vue/language-core': 2.2.12(typescript@5.9.3) - typescript: 5.9.3 - dev: true - - /vue@3.5.25(typescript@5.9.3): - resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-sfc': 3.5.25 - '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25) - '@vue/shared': 3.5.25 - typescript: 5.9.3 - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true diff --git a/urbanLifelineWeb/packages/bidding/public/app-config.js b/urbanLifelineWeb/packages/bidding/public/app-config.js deleted file mode 100644 index b196c62c..00000000 --- a/urbanLifelineWeb/packages/bidding/public/app-config.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @description 应用运行时配置文件 (支持 Docker 环境变量替换) - * - * 占位符说明: - * - __PLACEHOLDER__ 格式的值会在 Docker 启动时被环境变量替换 - * - 如果环境变量未设置,将使用默认值 - * - * Docker 部署: - * 1. 通过 volume 挂载覆盖此文件 - * 2. 或通过启动脚本替换占位符 - */ - -window.APP_RUNTIME_CONFIG = { - // 环境标识 - env: '__APP_ENV__', - - // API 配置 - api: { - baseUrl: '__API_BASE_URL__', - timeout: 30000 - }, - - // 应用基础路径 - baseUrl: '/', - - // 文件配置 - file: { - downloadUrl: '__API_BASE_URL__/urban-lifeline/file/download/', - uploadUrl: '__API_BASE_URL__/urban-lifeline/file/upload', - maxSize: { - image: 5, - video: 100, - document: 10 - }, - acceptTypes: { - image: 'image/*', - video: 'video/*', - document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx' - } - }, - - // Token 配置 - token: { - key: 'token', - refreshThreshold: 300000 - }, - - // 公共资源路径 - publicImgPath: '__PUBLIC_PATH__/img', - publicWebPath: '__PUBLIC_PATH__', - - // 单点登录配置 - sso: { - platformUrl: '__SSO_PLATFORM_URL__', - workcaseUrl: '__SSO_WORKCASE_URL__', - biddingUrl: '__SSO_BIDDING_URL__' - }, - - // AES 加密密钥 - aesSecretKey: '__AES_SECRET_KEY__', - - // 功能开关 - features: { - enableDebug: false, - enableMockData: false - } -}; diff --git a/urbanLifelineWeb/packages/bidding/public/app-config.local.js b/urbanLifelineWeb/packages/bidding/public/app-config.local.js deleted file mode 100644 index 284797f1..00000000 --- a/urbanLifelineWeb/packages/bidding/public/app-config.local.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @description 本地开发环境配置文件 - * 用于 dev 和 preview 模式 - */ - -window.APP_RUNTIME_CONFIG = { - // 环境标识 - env: 'production', - - // API 配置 - api: { - baseUrl: 'https://org.xyzh.yslg/api', - timeout: 30000 - }, - - // 应用基础路径 - baseUrl: '/bidding/', - - // 文件配置 - file: { - downloadUrl: 'https://org.xyzh.yslg/api/urban-lifeline/file/download/', - uploadUrl: 'https://org.xyzh.yslg/api/urban-lifeline/file/upload', - maxSize: { - image: 5, - video: 100, - document: 10 - }, - acceptTypes: { - image: 'image/*', - video: 'video/*', - document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx' - } - }, - - // Token 配置 - token: { - key: 'token', - refreshThreshold: 300000 - }, - - // 公共资源路径 - publicImgPath: '/bidding/img', - publicWebPath: '/bidding', - - // 单点登录配置 - sso: { - platformUrl: 'https://org.xyzh.yslg/platform/', - workcaseUrl: 'https://org.xyzh.yslg/workcase/', - biddingUrl: 'https://org.xyzh.yslg/bidding/' - }, - - // AES 加密密钥(本地开发用,生产环境需要替换) - aesSecretKey: 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=', - - // 功能开关 - features: { - enableDebug: true, - enableMockData: false - } -}; diff --git a/urbanLifelineWeb/packages/bidding/public/logo.jpg b/urbanLifelineWeb/packages/bidding/public/logo.jpg deleted file mode 100644 index 18b5da66..00000000 Binary files a/urbanLifelineWeb/packages/bidding/public/logo.jpg and /dev/null differ diff --git a/urbanLifelineWeb/packages/bidding/src/App.vue b/urbanLifelineWeb/packages/bidding/src/App.vue deleted file mode 100644 index 7c3ac93e..00000000 --- a/urbanLifelineWeb/packages/bidding/src/App.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/bidding/src/config/index.ts b/urbanLifelineWeb/packages/bidding/src/config/index.ts deleted file mode 100644 index fb6c89ec..00000000 --- a/urbanLifelineWeb/packages/bidding/src/config/index.ts +++ /dev/null @@ -1,216 +0,0 @@ -/** - * @description 应用运行时配置 - * - * 配置加载策略: - * 1. 开发环境:使用内置开发配置 - * 2. 生产环境:从 window.APP_RUNTIME_CONFIG 读取(来自 app-config.js) - * 3. Docker部署:启动时替换 app-config.js 中的占位符 - */ - -// ============================================ -// 类型定义 -// ============================================ -export interface AppRuntimeConfig { - env?: string; - api: { - baseUrl: string; - timeout: number; - }; - baseUrl: string; - file: { - downloadUrl: string; - uploadUrl: string; - maxSize: { - image: number; - video: number; - document: number; - }; - acceptTypes: { - image: string; - video: string; - document: string; - }; - }; - token: { - key: string; - refreshThreshold: number; - }; - publicImgPath: string; - publicWebPath: string; - sso?: { - platformUrl: string; - workcaseUrl: string; - biddingUrl: string; - }; - aesSecretKey?: string; - features?: { - enableDebug?: boolean; - enableMockData?: boolean; - [key: string]: any; - }; -} - -// ============================================ -// 环境检测 -// ============================================ -const isDev = (import.meta as any).env?.DEV ?? false; - -// ============================================ -// 开发环境配置 -// ============================================ -const devConfig: AppRuntimeConfig = { - env: 'development', - api: { - baseUrl: '/api', - timeout: 30000 - }, - baseUrl: '/', - file: { - downloadUrl: '/api/urban-lifeline/file/download/', - uploadUrl: '/api/urban-lifeline/file/upload', - maxSize: { image: 5, video: 100, document: 10 }, - acceptTypes: { - image: 'image/*', - video: 'video/*', - document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx' - } - }, - token: { - key: 'token', - refreshThreshold: 300000 - }, - publicImgPath: '/img', - publicWebPath: '/', - sso: { - platformUrl: '/', - workcaseUrl: '/workcase', - biddingUrl: '/bidding' - }, - aesSecretKey: 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=', - features: { - enableDebug: true, - enableMockData: false - } -}; - -// ============================================ -// 生产环境默认配置(兜底) -// ============================================ -const prodDefaultConfig: AppRuntimeConfig = { - env: 'production', - api: { - baseUrl: '/api', - timeout: 30000 - }, - baseUrl: '/', - file: { - downloadUrl: '/api/urban-lifeline/file/download/', - uploadUrl: '/api/urban-lifeline/file/upload', - maxSize: { image: 5, video: 100, document: 10 }, - acceptTypes: { - image: 'image/*', - video: 'video/*', - document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx' - } - }, - token: { - key: 'token', - refreshThreshold: 300000 - }, - publicImgPath: '/img', - publicWebPath: '/', - sso: { - platformUrl: '/', - workcaseUrl: '/workcase', - biddingUrl: '/bidding' - }, - aesSecretKey: 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=', - features: { - enableDebug: false, - enableMockData: false - } -}; - -// ============================================ -// 配置加载 -// ============================================ - -/** - * 检查值是否为未替换的占位符 - */ -const isPlaceholder = (value: any): boolean => { - return typeof value === 'string' && value.startsWith('__') && value.endsWith('__'); -}; - -/** - * 深度合并配置,跳过占位符值 - */ -const mergeConfig = (target: any, source: any): any => { - const result = { ...target }; - for (const key in source) { - const value = source[key]; - if (value && typeof value === 'object' && !Array.isArray(value)) { - result[key] = mergeConfig(target[key] || {}, value); - } else if (!isPlaceholder(value)) { - result[key] = value; - } - } - return result; -}; - -/** - * 获取运行时配置 - */ -const getRuntimeConfig = (): AppRuntimeConfig => { - if (isDev) { - console.log('[Config] 开发环境,使用内置配置'); - return devConfig; - } - - try { - const runtimeConfig = (window as any).APP_RUNTIME_CONFIG; - if (runtimeConfig && typeof runtimeConfig === 'object') { - const merged = mergeConfig(prodDefaultConfig, runtimeConfig); - console.log('[Config] 加载运行时配置', merged); - return merged; - } - } catch (e) { - console.warn('[Config] 无法读取外部配置', e); - } - - console.log('[Config] 使用默认生产配置'); - return prodDefaultConfig; -}; - -// 当前配置 -const config = getRuntimeConfig(); - -// ============================================ -// 导出 -// ============================================ - -// AES 密钥 -export const AES_SECRET_KEY = config.aesSecretKey || 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI='; - -// 常用配置项 -export const API_BASE_URL = config.api.baseUrl; -export const FILE_DOWNLOAD_URL = config.file.downloadUrl; -export const FILE_UPLOAD_URL = config.file.uploadUrl; -export const PUBLIC_IMG_PATH = config.publicImgPath; -export const PUBLIC_WEB_PATH = config.publicWebPath; - -// 完整配置对象 -export const APP_CONFIG = { - title: '泰豪电源招投标系统', - env: config.env || 'production', - baseUrl: config.baseUrl, - api: config.api, - file: config.file, - token: config.token, - publicImgPath: config.publicImgPath, - publicWebPath: config.publicWebPath, - sso: config.sso || { platformUrl: '/', workcaseUrl: '/workcase', biddingUrl: '/bidding' }, - features: config.features || {} -}; - -export default APP_CONFIG; diff --git a/urbanLifelineWeb/packages/bidding/src/layouts/SidebarLayout/SidebarLayout.scss b/urbanLifelineWeb/packages/bidding/src/layouts/SidebarLayout/SidebarLayout.scss deleted file mode 100644 index c089e29c..00000000 --- a/urbanLifelineWeb/packages/bidding/src/layouts/SidebarLayout/SidebarLayout.scss +++ /dev/null @@ -1,191 +0,0 @@ -// ==================== 品牌色变量 ==================== -$brand-color: #0055AA; -$brand-color-light: #EBF5FF; -$brand-color-hover: #004488; - -.sidebar-layout { - display: flex; - width: 100%; - height: 100vh; - overflow: hidden; - background: #fff; - font-family: 'Inter', 'Noto Sans SC', sans-serif; -} - -// ==================== 侧边栏 ==================== -.sidebar { - width: 256px; - height: 100%; - background: #fff; - display: flex; - flex-direction: column; - color: #333; - flex-shrink: 0; - transition: width 0.3s ease; - border-right: 1px solid #f1f5f9; - z-index: 50; - - &.collapsed { - width: 80px; - overflow: visible; - - .sidebar-header { - padding: 16px 0; - justify-content: center; - } - - .nav-item { - justify-content: center; - padding: 12px; - border-radius: 8px; - margin: 0 12px; - - span { - display: none; - } - } - - .user-section { - justify-content: center; - padding: 16px; - - .user-name { - display: none; - } - } - } -} - -.sidebar-header { - height: 64px; - padding: 0 16px; - margin-bottom: 8px; - display: flex; - align-items: center; - justify-content: space-between; - user-select: none; -} - -.collapse-btn { - width: 32px; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 8px; - cursor: pointer; - color: #94a3b8; - background: transparent; - border: none; - transition: all 0.2s; - flex-shrink: 0; - - &:hover { - background: #f1f5f9; - color: #64748b; - } -} - -.logo { - display: flex; - align-items: center; - gap: 8px; - - .logo-img { - height: 32px; - width: auto; - border-radius: 8px; - object-fit: contain; - } - - .logo-text { - font-size: 16px; - font-weight: 600; - color: #1e293b; - letter-spacing: -0.02em; - } -} - -// 导航菜单 -.nav-menu { - flex: 1; - padding: 8px 12px; -} - -.nav-section { - padding: 0; -} - -.nav-item { - position: relative; - display: flex; - align-items: center; - gap: 12px; - padding: 12px 16px; - margin-bottom: 2px; - border-radius: 8px; - cursor: pointer; - transition: all 0.2s ease; - color: #64748b; - font-size: 14px; - font-weight: 500; - - &:hover { - background: $brand-color-light; - color: $brand-color; - } - - &.active { - background: $brand-color; - color: #fff; - box-shadow: 0 4px 12px rgba($brand-color, 0.25); - } - - span { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} - -// 用户信息 -.user-section { - padding: 16px; - border-top: 1px solid #f1f5f9; - background: #f8fafc; - cursor: pointer; - transition: background 0.2s; - - &:hover { - background: #f1f5f9; - } - - .user-info-wrapper { - display: flex; - align-items: center; - gap: 12px; - } - - .user-avatar { - position: relative; - flex-shrink: 0; - } - - .user-name { - font-size: 14px; - font-weight: 500; - color: #374151; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} - -// ==================== 主内容区 ==================== -.main-content { - flex: 1; - height: 100%; - overflow: hidden; - background: #f8fafc; - position: relative; -} diff --git a/urbanLifelineWeb/packages/bidding/src/layouts/SidebarLayout/SidebarLayout.vue b/urbanLifelineWeb/packages/bidding/src/layouts/SidebarLayout/SidebarLayout.vue deleted file mode 100644 index b973566f..00000000 --- a/urbanLifelineWeb/packages/bidding/src/layouts/SidebarLayout/SidebarLayout.vue +++ /dev/null @@ -1,249 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/bidding/src/layouts/index.ts b/urbanLifelineWeb/packages/bidding/src/layouts/index.ts deleted file mode 100644 index 8f619aeb..00000000 --- a/urbanLifelineWeb/packages/bidding/src/layouts/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as SidebarLayout } from './SidebarLayout/SidebarLayout.vue' -export { BlankLayout, SubSidebarLayout } from 'shared/layouts'; \ No newline at end of file diff --git a/urbanLifelineWeb/packages/bidding/src/main.ts b/urbanLifelineWeb/packages/bidding/src/main.ts deleted file mode 100644 index 7b7be01c..00000000 --- a/urbanLifelineWeb/packages/bidding/src/main.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { createApp } from 'vue' -import { createPinia } from 'pinia' -import ElementPlus from 'element-plus' -import 'element-plus/dist/index.css' - -// 注意:shared 的样式现在通过 index.html 中的 标签加载 -// 不再需要在这里导入:import 'shared/styles' - -import App from './App.vue' -import router from './router/' - -// 导入需要的 Lucide 图标 -import { - LayoutGrid, - FileText, - Users, - User, - Settings, - Home, - ChevronDown, - ChevronRight, - ChevronLeft, - PanelLeftClose, - PanelLeftOpen, - RefreshCw, - LogOut, - Plus, - Trash2, - Search, - Menu -} from 'lucide-vue-next' - -// Lucide 图标映射 -const lucideIcons = { - LayoutGrid, - FileText, - Users, - User, - Settings, - Home, - ChevronDown, - ChevronRight, - ChevronLeft, - PanelLeftClose, - PanelLeftOpen, - RefreshCw, - LogOut, - Plus, - Trash2, - Search, - Menu -} - -// 异步初始化应用 -async function initApp() { - // 创建 Vue 应用 - const app = createApp(App) - - // 注册 Pinia - const pinia = createPinia() - app.use(pinia) - - // 注册 Element Plus - app.use(ElementPlus) - - // 注册 Lucide 图标 - for (const [name, component] of Object.entries(lucideIcons)) { - app.component(name, component) - } - - // 注册路由 - app.use(router) - - // 挂载应用 - app.mount('#app') - - console.log('✅ Bidding 应用启动成功') -} - -// 启动应用 -initApp() diff --git a/urbanLifelineWeb/packages/bidding/src/router/dynamicRoute.ts b/urbanLifelineWeb/packages/bidding/src/router/dynamicRoute.ts deleted file mode 100644 index ed0af139..00000000 --- a/urbanLifelineWeb/packages/bidding/src/router/dynamicRoute.ts +++ /dev/null @@ -1,165 +0,0 @@ -/** - * 动态路由生成模块(Bidding 特定) - * - * 职责: - * 1. 提供 Bidding 特定的布局和组件配置 - * 2. 调用 shared 中的通用路由生成方法 - * 3. 将生成的路由添加到 Bidding 的 router 实例 - */ - -/// - -import type { RouteRecordRaw } from 'vue-router' -import router from './index' -import { SidebarLayout } from '@/layouts' - -// 动态导入 shared 模块(避免顶层 import 阻塞) -async function loadSharedModules() { - const [routeUtils, types] = await Promise.all([ - import('shared/utils/route'), - import('shared/types') - ]) - return { routeUtils, types } -} - -// Bidding 布局组件映射 -const biddingLayoutMap: Record Promise> = { - 'SidebarLayout': () => Promise.resolve({ default: SidebarLayout }), - 'NavigationLayout': () => Promise.resolve({ default: SidebarLayout }), - 'BasicLayout': () => Promise.resolve({ default: SidebarLayout }), - // 动态导入 shared 的布局组件,避免静态导入阻塞 - 'BlankLayout': () => import('shared/layouts').then(m => ({ default: m.BlankLayout })), - 'SubSidebarLayout': () => import('shared/layouts').then(m => ({ default: m.SubSidebarLayout })) -} - -// 视图组件加载器 -const VIEW_MODULES = import.meta.glob<{ default: any }>('../views/**/*.vue') - -/** - * 视图组件加载函数 - * @param componentPath 组件路径(如 "bidding/Home" 或 "bidding/List") - */ -function viewLoader(componentPath: string): (() => Promise) | null { - // 将后台路径转换为 ../views 格式 - let path = componentPath - - // 移除开头的斜杠(如果有) - if (path.startsWith('/')) { - path = path.substring(1) - } - - // 补全 .vue 后缀(如果没有) - if (!path.endsWith('.vue')) { - path += '.vue' - } - - // 转换为 ../views 格式(匹配 import.meta.glob 的 key) - const fullPath = `../views/${path}` - - console.log('[Bidding viewLoader] 尝试加载组件:', componentPath, '→', fullPath) - - const loader = VIEW_MODULES[fullPath] - - if (!loader) { - console.warn('[Bidding viewLoader] 组件未找到:', fullPath) - console.log('[Bidding viewLoader] 可用的组件:', Object.keys(VIEW_MODULES)) - return null - } - - return loader as () => Promise -} - -// Bidding 路由生成器配置 -const routeConfig: any = { - layoutMap: biddingLayoutMap, - viewLoader, - notFoundComponent: () => import('vue').then(({ h }) => ({ - default: { - render() { return h('div', { style: { padding: '20px', textAlign: 'center' } }, '404 - 页面未找到') } - } - })) -} - -// Bidding 路由生成选项 -const routeOptions: any = { - asRootChildren: false, // 直接作为根级路由,不是某个布局的子路由 - iframePlaceholder: () => import('shared/components').then(m => ({ default: m.IframeView })), - verbose: true // 启用详细日志 -} - -/** - * 添加动态路由(Bidding 特定) - * @param views 视图列表(用作菜单) - */ -export async function addDynamicRoutes(views: any[]) { - if (!views || views.length === 0) { - console.warn('[Bidding] addDynamicRoutes: 视图列表为空') - return - } - - console.log('[Bidding] addDynamicRoutes: 开始添加动态路由,视图数量:', views.length) - - try { - // 动态加载 shared 模块 - const { routeUtils } = await loadSharedModules() - const { generateSimpleRoutes } = routeUtils - - // 使用 shared 中的通用方法生成路由 - const routes = generateSimpleRoutes(views, routeConfig, routeOptions) - - // 直接将路由添加到根级别(不是作为Root的children) - routes.forEach(route => { - console.log('[Bidding] addDynamicRoutes: 添加路由', route.path, '使用布局:', route.component?.name || 'unknown') - router.addRoute(route) - }) - - } catch (error) { - console.error('[Bidding] addDynamicRoutes: 添加路由失败', error) - throw error - } -} - -/** - * 从 LocalStorage 获取菜单并生成路由(Bidding 特定) - * - * 使用 shared 中的通用 loadViewsFromStorage 方法 - * 筛选出 service='bidding' 的视图 - */ -export async function loadRoutesFromStorage(): Promise { - try { - console.log('[Bidding] loadRoutesFromStorage: 开始加载动态路由') - - // 动态加载 shared 模块 - const { routeUtils } = await loadSharedModules() - const { loadViewsFromStorage } = routeUtils - - // 使用 shared 中的通用方法加载视图数据 - const allViews = loadViewsFromStorage('loginDomain', 'userViews') - - console.log('[Bidding] loadRoutesFromStorage: 加载的所有视图数量:', allViews?.length || 0) - - if (allViews) { - // 过滤出 bidding 服务的视图 - const biddingViews = allViews.filter((view: any) => - view.service === 'bidding' - ) - - console.log('[Bidding] loadRoutesFromStorage: 过滤后的 bidding 视图:', biddingViews) - - if (biddingViews.length === 0) { - console.warn('[Bidding] loadRoutesFromStorage: 没有找到 bidding 服务的视图') - return false - } - - // 使用 Bidding 的 addDynamicRoutes 添加路由 - await addDynamicRoutes(biddingViews) - return true - } - - console.warn('[Bidding] loadRoutesFromStorage: 未能加载视图数据') - return false - } catch (error) { - console.error('[Bidding] loadRoutesFromStorage: 加载路由失败', error) - return false - } -} diff --git a/urbanLifelineWeb/packages/bidding/src/router/index.ts b/urbanLifelineWeb/packages/bidding/src/router/index.ts deleted file mode 100644 index de596033..00000000 --- a/urbanLifelineWeb/packages/bidding/src/router/index.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' -// @ts-ignore - 动态导入,避免顶层 import 阻塞 -import { loadRoutesFromStorage } from './dynamicRoute' - -// 同步检查 token(直接读取 localStorage,避免导入 shared 模块) -function hasTokenSync(): boolean { - const token = localStorage.getItem('token') - return !!token && token.length > 0 -} - -// bidding应用的动态路由会根据layout字段自动添加,不需要预定义Root布局 -const routes: RouteRecordRaw[] = [] - -const router = createRouter({ - history: createWebHistory('/bidding'), // 与nginx保持一致,使用/bidding前缀 - routes -}) - -// 标记动态路由是否已加载 -let dynamicRoutesLoaded = false - -// 路由守卫 -router.beforeEach(async (to, from, next) => { - console.log('[Bidding Router] 路由守卫触发:', { - to: to.path, - from: from.path, - meta: to.meta - }) - - // 设置页面标题 - if (to.meta.title) { - document.title = `${to.meta.title} - 招标管理系统` - } - - // 检查是否需要登录 - const requiresAuth = to.meta.requiresAuth !== false - const hasToken = hasTokenSync() - - console.log('[Bidding Router] 认证检查:', { - requiresAuth, - hasToken, - tokenValue: localStorage.getItem('token') - }) - - // 其他页面:检查是否需要登录 - if (requiresAuth && !hasToken) { - // 需要登录但未登录,重定向到 platform 的登录页 - // 重要:必须使用完整URL(包含origin),避免被bidding的路由拦截造成循环 - const currentUrl = window.location.href - const origin = window.location.origin - - // 构建platform登录页的完整URL - const loginUrl = `${origin}/login?redirect=${encodeURIComponent(currentUrl)}` - - console.log('[Bidding Router] 未登录,重定向到Platform登录页:', loginUrl) - - // 使用完整URL跳转,跳出bidding的路由系统 - window.location.href = loginUrl - return - } - - // 如果已登录且动态路由未加载,先加载动态路由 - if (hasToken && !dynamicRoutesLoaded) { - console.log('[Bidding Router] 开始加载动态路由...') - console.log('[Bidding Router] LocalStorage 内容:', { - loginDomain: localStorage.getItem('loginDomain'), - token: localStorage.getItem('token') - }) - - dynamicRoutesLoaded = true - - try { - const loaded = await loadRoutesFromStorage?.() - - console.log('[Bidding Router] 动态路由加载结果:', loaded) - console.log('[Bidding Router] 当前路径:', to.path) - console.log('[Bidding Router] 所有路由:', router.getRoutes().map(r => r.path)) - - if (loaded) { - // 动态路由加载成功,重新导航以匹配新添加的路由 - console.log('[Bidding Router] 动态路由加载成功,重新导航到:', to.path) - next({ ...to, replace: true }) - return - } else { - console.warn('[Bidding Router] 动态路由加载失败') - } - } catch (error) { - console.error('[Bidding Router] 动态路由加载异常:', error) - } - } - - console.log('[Bidding Router] 继续正常导航') - next() -}) - -// 重置动态路由加载状态 -export function resetDynamicRoutes() { - dynamicRoutesLoaded = false -} - -export default router diff --git a/urbanLifelineWeb/packages/bidding/src/types/shared.d.ts b/urbanLifelineWeb/packages/bidding/src/types/shared.d.ts deleted file mode 100644 index 89e856fc..00000000 --- a/urbanLifelineWeb/packages/bidding/src/types/shared.d.ts +++ /dev/null @@ -1,206 +0,0 @@ -/** - * Shared Module Federation 类型声明 - * 用于 TypeScript 识别远程模块 - */ - -// ========== 组件模块 ========== -declare module 'shared/components' { - export const FileUpload: any - export const FileHistory: any - export const DynamicFormItem: any - export const IframeView: any -} - -declare module 'shared/components/file/FileUpload' { - import { DefineComponent } from 'vue' - const FileUpload: DefineComponent<{}, {}, any> - export default FileUpload -} -declare module 'shared/components/file/FileHistory' { - import { DefineComponent } from 'vue' - const FileHistory: DefineComponent<{}, {}, any> - export default FileHistory -} - -declare module 'shared/components/DynamicFormItem' { - import { DefineComponent } from 'vue' - const DynamicFormItem: DefineComponent<{}, {}, any> - export default DynamicFormItem -} - -declare module 'shared/components/iframe/IframeView.vue' { - import { DefineComponent } from 'vue' - const IframeView: DefineComponent<{}, {}, any> - export default IframeView -} - -declare module 'shared/components/ai/knowledge/DocumentSegment.vue' { - import { DefineComponent } from 'vue' - const DocumentSegment: DefineComponent<{}, {}, any> - export default DocumentSegment -} - -declare module 'shared/components/ai/knowledge/DocumentDetail.vue' { - import { DefineComponent } from 'vue' - const DocumentDetail: DefineComponent<{}, {}, any> - export default DocumentDetail -} - - -// ========== API 模块 ========== -declare module 'shared/api' { - import type { AxiosResponse, AxiosRequestConfig } from 'axios' - - interface ApiInstance { - get(url: string, config?: AxiosRequestConfig): Promise> - post(url: string, data?: any, config?: AxiosRequestConfig): Promise> - put(url: string, data?: any, config?: AxiosRequestConfig): Promise> - delete(url: string, config?: AxiosRequestConfig): Promise> - uploadPut(url: string, data: FormData, config?: AxiosRequestConfig): Promise> - } - - export const api: ApiInstance - export const TokenManager: any - export const authAPI: any - export const fileAPI: any -} - -declare module 'shared/api/auth' { - export const authAPI: any -} - -declare module 'shared/api/file' { - export const fileAPI: any -} - -declare module 'shared/api/ai' { - export const agentAPI: any - export const aiKnowledgeAPI: any - export const aiChatAPI: any -} - -// ============ types模块 ================== -declare module 'shared/types' { - export type { BaseDTO, BaseVO } from '../../../shared/src/types/base' - - // 重新导出 response - export type { ResultDomain } from '../../../shared/src/types/response' - - // 重新导出 page - export type { PageDomain, PageParam, PageRequest } from '../../../shared/src/types/page' - - // 重新导出 auth - export type { LoginParam, LoginDomain } from '../../../shared/src/types/auth' - - // 重新导出 sys - export type { SysUserVO, SysConfigVO, TbSysViewDTO } from '../../../shared/src/types/sys' - - // 重新导出 file - export type { TbSysFileDTO } from '../../../shared/src/types/file' - - // 重新导出 ai - export type { - TbKnowledge, - TbKnowledgeFile, - TbAgent, - PromptCard, - TbChat, - TbChatMessage, - DifyFileInfo, - ChatPrepareData, - StopChatParams, - CommentMessageParams - } from '../../../shared/src/types/ai' - - // 重新导出 menu - export type { MenuItem, toMenuItem, toMenuItems } from '../../../shared/src/types/menu' -} - -// ================ utils工具 ========================== -declare module 'shared/utils' { - export const initAesEncrypt: any - export const getAesInstance: any - export const formatFileSize: any - export const isImageFile: any - export const getFileTypeIcon: any - export const isValidFileType: any - export const getFilePreviewUrl: any -} - -declare module 'shared/utils/route' { - import { RouteRecordRaw } from 'vue-router' - import type { TbSysViewDTO } from 'shared/types' - - export interface RouteGeneratorConfig { - layoutMap: Record Promise> - viewLoader: (componentPath: string) => (() => Promise) | null - staticRoutes?: RouteRecordRaw[] - notFoundComponent?: () => Promise - } - - export interface GenerateSimpleRoutesOptions { - asRootChildren?: boolean - iframePlaceholder?: () => Promise - verbose?: boolean - } - - export function generateRoutes( - views: TbSysViewDTO[], - config: RouteGeneratorConfig - ): RouteRecordRaw[] - - export function generateSimpleRoutes( - views: TbSysViewDTO[], - config: RouteGeneratorConfig, - options?: GenerateSimpleRoutesOptions - ): RouteRecordRaw[] - - export function buildMenuTree( - views: TbSysViewDTO[], - staticRoutes?: RouteRecordRaw[] - ): TbSysViewDTO[] - - export function filterMenusByPermissions( - views: TbSysViewDTO[], - permissions: string[] - ): TbSysViewDTO[] - - export function findMenuByPath( - views: TbSysViewDTO[], - path: string - ): TbSysViewDTO | null - - export function getMenuPath( - views: TbSysViewDTO[], - targetViewId: string - ): TbSysViewDTO[] - - export function getFirstAccessibleMenuUrl( - views: TbSysViewDTO[] - ): string | null - - export function loadViewsFromStorage( - storageKey?: string, - viewsPath?: string - ): TbSysViewDTO[] | null -} - -declare module 'shared/utils/device' { - export enum DeviceType { - MOBILE = 'mobile', - DESKTOP = 'desktop' - } - - export function getDeviceType(): DeviceType - export function isMobile(): boolean - export function isDesktop(): boolean - export function useDevice(): any -} - -// ========== Layouts 布局模块 ========== -declare module 'shared/layouts' { - import { DefineComponent } from 'vue' - - export const BlankLayout: DefineComponent<{}, {}, any> - export const SubSidebarLayout: DefineComponent<{}, {}, any> -} diff --git a/urbanLifelineWeb/packages/bidding/tsconfig.json b/urbanLifelineWeb/packages/bidding/tsconfig.json deleted file mode 100644 index 477484fe..00000000 --- a/urbanLifelineWeb/packages/bidding/tsconfig.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "lib": ["ESNext", "DOM", "DOM.Iterable"], - "types": ["node"], - "jsx": "preserve", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "allowSyntheticDefaultImports": true, - "isolatedModules": true, - "noEmit": true, - "baseUrl": ".", - "paths": { - "@/*": ["src/*"], - "@shared/*": ["../shared/src/*"] - } - }, - "include": [ - "src/**/*", - "*.ts", - "*.vue" - ], - "exclude": [ - "node_modules", - "dist" - ] -} diff --git a/urbanLifelineWeb/packages/bidding/vite.config.ts b/urbanLifelineWeb/packages/bidding/vite.config.ts deleted file mode 100644 index 3342c231..00000000 --- a/urbanLifelineWeb/packages/bidding/vite.config.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import vueJsx from '@vitejs/plugin-vue-jsx' -import { federation } from '@module-federation/vite' -import { resolve, dirname } from 'path' -import { fileURLToPath } from 'url' -import fs from 'fs' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = dirname(__filename) - -// 开发环境 shared 模块地址 -const DEV_SHARED_URL = 'https://localhost:7000/shared/remoteEntry.js' -// 生产环境使用相对路径,通过 Nginx 代理访问 -const PROD_SHARED_URL = '/shared/remoteEntry.js' - -export default defineConfig(({ mode }) => { - const isDev = mode === 'development' - const sharedEntry = isDev ? DEV_SHARED_URL : PROD_SHARED_URL - - return { - base: '/bidding/', - - plugins: [ - vue({ - script: { - defineModel: true, - propsDestructure: true - } - }), - vueJsx(), - federation({ - name: 'bidding', - remotes: { - shared: { - type: 'module', - name: 'shared', - entry: sharedEntry - } - }, - shared: { - vue: {}, - 'vue-router': {}, - 'element-plus': {}, - axios: {} - } - }) - ], - - define: { - __VUE_OPTIONS_API__: true, - __VUE_PROD_DEVTOOLS__: true, - __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: true - }, - - resolve: { - alias: { - '@': resolve(__dirname, 'src') - } - }, - - server: { - port: 7002, - host: true, - cors: true, - open: '/bidding/', - https: (() => { - try { - return { - key: fs.readFileSync('C:/Users/FK05/443/localhost+3-key.pem'), - cert: fs.readFileSync('C:/Users/FK05/443/localhost+3.pem') - } - } catch { - return undefined - } - })(), - hmr: { - path: '/@vite/client', - port: 7002 - }, - proxy: { - '/api': { - target: 'http://localhost:8180', - changeOrigin: true, - rewrite: (path: string) => path.replace(/^\/api/, '') - } - } - }, - - build: { - target: 'esnext', - outDir: 'dist', - sourcemap: true - // 注意:不要使用 manualChunks 分割 vue/vue-router/element-plus - // 因为它们已经在 Module Federation 的 shared 中声明 - // 同时使用会导致循环依赖死锁 - }, - - preview: { - port: 7002, - host: true, - cors: true, - https: (() => { - try { - return { - key: fs.readFileSync('C:/Users/FK05/443/localhost+3-key.pem'), - cert: fs.readFileSync('C:/Users/FK05/443/localhost+3.pem') - } - } catch { - return undefined - } - })(), - headers: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization' - } - } - } -}) diff --git a/urbanLifelineWeb/packages/platform/.env.example b/urbanLifelineWeb/packages/platform/.env.example deleted file mode 100644 index 7f7cbc86..00000000 --- a/urbanLifelineWeb/packages/platform/.env.example +++ /dev/null @@ -1,9 +0,0 @@ -# Platform 应用环境变量示例 -# 复制此文件为 .env.local 或 .env.production 使用 - -# API 基础地址(Gateway 地址) -VITE_API_BASE_URL=http://localhost:8180 - -# AES 加密密钥(可选,默认使用配置文件中的密钥) -# 生产环境建议通过环境变量配置 -# VUE_APP_AES_SECRET_KEY=1234567890qwer diff --git a/urbanLifelineWeb/packages/platform/Dockerfile.dev b/urbanLifelineWeb/packages/platform/Dockerfile.dev deleted file mode 100644 index f95bc99f..00000000 --- a/urbanLifelineWeb/packages/platform/Dockerfile.dev +++ /dev/null @@ -1,21 +0,0 @@ -FROM node:20-alpine - -RUN npm install -g pnpm@latest - -WORKDIR /app - -# 复制依赖文件 -COPY packages/portal/package.json ./ -COPY pnpm-lock.yaml pnpm-workspace.yaml ./ - -# 安装依赖 -RUN pnpm install --frozen-lockfile - -# 复制源代码 -COPY packages/portal/ ./ - -# 暴露端口 -EXPOSE 3000 - -# 开发模式(HMR) -CMD ["pnpm", "dev", "--host", "0.0.0.0"] diff --git a/urbanLifelineWeb/packages/platform/ROUTE_GUIDE.md b/urbanLifelineWeb/packages/platform/ROUTE_GUIDE.md deleted file mode 100644 index b534adcf..00000000 --- a/urbanLifelineWeb/packages/platform/ROUTE_GUIDE.md +++ /dev/null @@ -1,382 +0,0 @@ -# Platform 路由集成指南 - -## 快速开始 - -### TL;DR - -1. **shared 提供**:路由生成工具、菜单处理、设备检测 -2. **platform 定义**:布局组件映射、视图加载器 -3. **platform 生成**:调用 `generateRoutes()` 生成自己的路由 - -```typescript -// 1. 导入工具 -import { generateRoutes, type RouteGeneratorConfig } from 'shared/utils/route' -import type { SysMenu } from 'shared/types' - -// 2. 配置生成器 -const config: RouteGeneratorConfig = { - layoutMap: { /* 布局映射 */ }, - viewLoader: (path) => { /* 组件加载 */ } -} - -// 3. 生成路由 -const routes = generateRoutes(menus, config) - -// 4. 添加到路由 -routes.forEach(route => router.addRoute(route)) -``` - -## 架构说明 - -Platform 使用 shared 提供的路由生成工具来动态生成路由。架构如下: - -``` -┌─────────────────────────────────────────────────────────────┐ -│ shared │ -│ ┌───────────────────────────────────────────────────────┐ │ -│ │ utils/route/route-generator.ts │ │ -│ │ - generateRoutes() 路由生成 │ │ -│ │ - buildMenuTree() 菜单树构建 │ │ -│ │ - filterMenusByPermissions() 权限过滤 │ │ -│ │ - findMenuByPath() 路径查找 │ │ -│ │ - getMenuPath() 面包屑路径 │ │ -│ │ - getFirstAccessibleMenuUrl() 首页跳转 │ │ -│ └───────────────────────────────────────────────────────┘ │ -│ ┌───────────────────────────────────────────────────────┐ │ -│ │ utils/device.ts │ │ -│ │ - getDeviceType() 设备类型检测 │ │ -│ │ - isMobile() 移动端判断 │ │ -│ │ - useDevice() 响应式 Hook │ │ -│ └───────────────────────────────────────────────────────┘ │ -│ ┌───────────────────────────────────────────────────────┐ │ -│ │ types/sys/menu.ts & types/enums.ts │ │ -│ │ - SysMenu 菜单接口 │ │ -│ │ - ViewType 视图类型枚举 │ │ -│ └───────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - ↓ - ┌─────────────────────────────────────┐ - │ Module Federation (远程模块) │ - │ - shared/utils/route │ - │ - shared/utils/device │ - │ - shared/types │ - └─────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────────────┐ -│ platform │ -│ ┌───────────────────────────────────────────────────────┐ │ -│ │ src/router/index.ts │ │ -│ │ 1. 定义布局组件映射 (platformLayoutMap) │ │ -│ │ 2. 定义视图组件加载器 (viewLoader) │ │ -│ │ 3. 调用 generateRoutes() 生成动态路由 │ │ -│ │ 4. 添加到 Vue Router │ │ -│ └───────────────────────────────────────────────────────┘ │ -│ ┌───────────────────────────────────────────────────────┐ │ -│ │ src/layouts/ │ │ -│ │ - SidebarLayout.vue 侧边栏布局 │ │ -│ │ - NavigationLayout.vue 导航布局(如需) │ │ -│ │ - BasicLayout.vue 基础布局(如需) │ │ -│ └───────────────────────────────────────────────────────┘ │ -│ ┌───────────────────────────────────────────────────────┐ │ -│ │ src/views/ │ │ -│ │ - 各种页面组件 │ │ -│ └───────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -## 使用步骤 - -### 1. 在 router/index.ts 中配置路由生成器 - -```typescript -import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' -import { generateRoutes, type RouteGeneratorConfig } from 'shared/utils/route' -import type { SysMenu } from 'shared/types' -import { SidebarLayout } from '../layouts' - -// 1. 定义布局组件映射 -const platformLayoutMap: Record Promise> = { - 'SidebarLayout': () => Promise.resolve({ default: SidebarLayout }), - 'NavigationLayout': () => Promise.resolve({ default: SidebarLayout }), // 可复用或自定义 - 'BasicLayout': () => Promise.resolve({ default: SidebarLayout }), -} - -// 2. 定义视图组件加载器 -const VIEW_MODULES = import.meta.glob('../views/**/*.vue') - -function viewLoader(componentPath: string): (() => Promise) | null { - // 将后台路径转换为实际路径 - let path = componentPath - if (!path.startsWith('../')) { - if (!path.startsWith('/')) { - path = '/' + path - } - path = '../views' + path - } - if (!path.endsWith('.vue')) { - path += '.vue' - } - - const loader = VIEW_MODULES[path] - return loader ? (loader as () => Promise) : null -} - -// 3. 创建路由生成器配置 -const routeConfig: RouteGeneratorConfig = { - layoutMap: platformLayoutMap, - viewLoader, - staticRoutes: routes, // 可选:静态路由 - notFoundComponent: () => import('../views/public/404.vue') // 可选 -} - -// 4. 动态添加路由的函数 -export function addDynamicRoutes(menus: SysMenu[]) { - const dynamicRoutes = generateRoutes(menus, routeConfig) - - dynamicRoutes.forEach(route => { - router.addRoute(route) - }) - - console.log('✅ 动态路由已添加', dynamicRoutes.length, '个') -} -``` - -### 2. 在应用初始化时调用 - -```typescript -// main.ts 或登录成功后 -import { addDynamicRoutes } from './router' -import { menuAPI } from 'shared/api' - -// 获取用户菜单 -const response = await menuAPI.getUserMenus() -if (response.success && response.data) { - // 添加动态路由 - addDynamicRoutes(response.data) - - // 跳转到首页或指定页面 - router.push('/home') -} -``` - -## 菜单数据格式 - -```typescript -interface SysMenu { - menuID: string // 菜单ID,作为路由 name - parentID?: string // 父菜单ID,'0' 表示根菜单 - name: string // 菜单名称 - url?: string // 路由路径,如 '/user/profile' - type: ViewType // 视图类型(0=目录 1=菜单 2=按钮 3=页面) - icon?: string // 图标 - component?: string // 组件路径,如 'user/profile/ProfileView' - layout?: string // 布局名称,如 'SidebarLayout' - orderNum?: number // 排序号 - permission?: string // 权限标识 - hidden?: boolean // 是否隐藏 - children?: SysMenu[] // 子菜单 -} - -enum ViewType { - NAVBAR = 0, // 导航栏/目录 - SIDEBAR = 1, // 侧边栏/菜单 - BUTTON = 2, // 按钮(权限控制,不生成路由) - ROUTE = 3 // 空白页/路由页面 -} -``` - -## 示例菜单数据 - -```typescript -const menus: SysMenu[] = [ - { - menuID: 'user-center', - parentID: '0', - name: '用户中心', - url: '/user', - type: ViewType.NAVBAR, - icon: 'User', - layout: 'SidebarLayout', - orderNum: 1, - children: [ - { - menuID: 'user-profile', - parentID: 'user-center', - name: '个人信息', - url: '/user/profile', - type: ViewType.SIDEBAR, - component: 'user/profile/ProfileView', - orderNum: 1 - }, - { - menuID: 'user-settings', - parentID: 'user-center', - name: '账号设置', - url: '/user/settings', - type: ViewType.SIDEBAR, - component: 'user/settings/SettingsView', - orderNum: 2 - } - ] - } -] -``` - -## 布局组件要求 - -布局组件必须包含 `` 用于渲染子路由: - -```vue - -``` - -## 响应式布局(可选) - -如果需要移动端适配,可以使用 shared 的设备检测工具: - -```typescript -import { getDeviceType, DeviceType } from 'shared/utils/device' - -const deviceType = getDeviceType() -if (deviceType === DeviceType.MOBILE) { - // 移动端逻辑 -} -``` - -## 工具方法说明 - -所有工具方法从 `shared/utils/route` 导入: - -```typescript -import { - generateRoutes, - buildMenuTree, - filterMenusByPermissions, - findMenuByPath, - getMenuPath, - getFirstAccessibleMenuUrl, - type RouteGeneratorConfig -} from 'shared/utils/route' - -import type { SysMenu } from 'shared/types' -import { ViewType } from 'shared/types/enums' -``` - -### generateRoutes(menus, config) -根据菜单生成路由配置数组 - -**参数:** -- `menus: SysMenu[]` - 菜单列表 -- `config: RouteGeneratorConfig` - 路由生成器配置 - -**返回:** `RouteRecordRaw[]` - -### buildMenuTree(menus, staticRoutes?) -将扁平菜单列表转换为树形结构 - -**参数:** -- `menus: SysMenu[]` - 菜单列表 -- `staticRoutes?: RouteRecordRaw[]` - 静态路由(可选) - -**返回:** `SysMenu[]` - -### filterMenusByPermissions(menus, permissions) -根据权限过滤菜单 - -**参数:** -- `menus: SysMenu[]` - 菜单列表 -- `permissions: string[]` - 权限列表 - -**返回:** `SysMenu[]` - -### findMenuByPath(menus, path) -根据路径查找菜单项 - -**参数:** -- `menus: SysMenu[]` - 菜单列表 -- `path: string` - 路由路径 - -**返回:** `SysMenu | null` - -### getMenuPath(menus, targetMenuId) -获取菜单路径数组(用于面包屑导航) - -**参数:** -- `menus: SysMenu[]` - 菜单列表 -- `targetMenuId: string` - 目标菜单ID - -**返回:** `SysMenu[]` - -### getFirstAccessibleMenuUrl(menus) -获取第一个可访问的菜单URL(用于登录后跳转) - -**参数:** -- `menus: SysMenu[]` - 菜单列表 - -**返回:** `string | null` - -## 注意事项 - -1. **shared 服务必须先启动**:因为使用 Module Federation,platform 依赖 shared 的远程模块 -2. **布局组件必须包含 router-view**:否则子路由无法渲染 -3. **组件路径映射**:确保 `viewLoader` 能正确加载组件 -4. **静态路由优先**:如果菜单标记为 `__STATIC_ROUTE__`,不会重复生成路由 -5. **路由守卫**:记得在 `router.beforeEach` 中添加权限检查 - -## 调试技巧 - -1. **查看生成的路由**: -```typescript -console.log('所有路由:', router.getRoutes()) -console.log('路由数量:', router.getRoutes().length) -``` - -2. **查看菜单树结构**: -```typescript -import { buildMenuTree } from 'shared/utils/route' - -const tree = buildMenuTree(menus) -console.log('菜单树:', JSON.stringify(tree, null, 2)) -``` - -3. **查看当前路由信息**: -```typescript -console.log('当前路由:', router.currentRoute.value) -console.log('路由路径:', router.currentRoute.value.path) -console.log('路由参数:', router.currentRoute.value.params) -console.log('路由元数据:', router.currentRoute.value.meta) -``` - -4. **测试菜单查找**: -```typescript -import { findMenuByPath, getMenuPath } from 'shared/utils/route' - -// 根据路径查找菜单 -const menu = findMenuByPath(menus, '/user/profile') -console.log('找到的菜单:', menu) - -// 获取面包屑路径 -const breadcrumb = getMenuPath(menus, 'user-profile') -console.log('面包屑:', breadcrumb.map(m => m.name).join(' > ')) -``` - -5. **检查视图组件加载**: -```typescript -// 在 viewLoader 中添加日志 -function viewLoader(componentPath: string) { - console.log('尝试加载组件:', componentPath) - const path = /* 转换逻辑 */ - const loader = VIEW_MODULES[path] - console.log('找到的加载器:', loader ? '✅' : '❌') - return loader ? (loader as () => Promise) : null -} -``` diff --git a/urbanLifelineWeb/packages/platform/index.html b/urbanLifelineWeb/packages/platform/index.html deleted file mode 100644 index 42165d02..00000000 --- a/urbanLifelineWeb/packages/platform/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - 泰豪电源 AI 数智化平台 - - - - - - - - - -
- - - - - diff --git a/urbanLifelineWeb/packages/platform/package.json b/urbanLifelineWeb/packages/platform/package.json deleted file mode 100644 index b645e8b0..00000000 --- a/urbanLifelineWeb/packages/platform/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@urbanlifeline/platform", - "version": "1.0.0", - "type": "module", - "private": true, - "scripts": { - "dev": "vite --host", - "build": "vue-tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "@element-plus/icons-vue": "^2.3.2", - "@vueuse/core": "^11.3.0", - "axios": "^1.7.9", - "element-plus": "^2.12.0", - "lucide-vue-next": "^0.561.0", - "pinia": "^2.2.8", - "vue": "^3.5.13", - "vue-router": "^4.5.0" - }, - "devDependencies": { - "@module-federation/vite": "^1.9.3", - "@types/node": "^22.0.0", - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "typescript": "^5.7.2", - "vite": "^6.0.3", - "vue-tsc": "^2.2.0" - } -} diff --git a/urbanLifelineWeb/packages/platform/pnpm-lock.yaml b/urbanLifelineWeb/packages/platform/pnpm-lock.yaml deleted file mode 100644 index bbe29ff3..00000000 --- a/urbanLifelineWeb/packages/platform/pnpm-lock.yaml +++ /dev/null @@ -1,1753 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@element-plus/icons-vue': - specifier: ^2.3.2 - version: 2.3.2(vue@3.5.25) - '@vueuse/core': - specifier: ^11.3.0 - version: 11.3.0(vue@3.5.25) - axios: - specifier: ^1.7.9 - version: 1.13.2 - element-plus: - specifier: ^2.12.0 - version: 2.12.0(vue@3.5.25) - lucide-vue-next: - specifier: ^0.561.0 - version: 0.561.0(vue@3.5.25) - pinia: - specifier: ^2.2.8 - version: 2.3.1(typescript@5.9.3)(vue@3.5.25) - vue: - specifier: ^3.5.13 - version: 3.5.25(typescript@5.9.3) - vue-router: - specifier: ^4.5.0 - version: 4.6.3(vue@3.5.25) - -devDependencies: - '@module-federation/vite': - specifier: ^1.9.3 - version: 1.9.3 - '@types/node': - specifier: ^22.0.0 - version: 22.19.1 - '@vitejs/plugin-vue': - specifier: ^5.2.1 - version: 5.2.4(vite@6.4.1)(vue@3.5.25) - '@vitejs/plugin-vue-jsx': - specifier: ^4.1.1 - version: 4.2.0(vite@6.4.1)(vue@3.5.25) - typescript: - specifier: ^5.7.2 - version: 5.9.3 - vite: - specifier: ^6.0.3 - version: 6.4.1(@types/node@22.19.1) - vue-tsc: - specifier: ^2.2.0 - version: 2.2.12(typescript@5.9.3) - -packages: - - /@babel/code-frame@7.27.1: - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - dev: true - - /@babel/compat-data@7.28.5: - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core@7.28.5: - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator@7.28.5: - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - dev: true - - /@babel/helper-annotate-as-pure@7.27.3: - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.28.5 - dev: true - - /@babel/helper-compilation-targets@7.27.2: - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - - /@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5): - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-globals@7.28.0: - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-member-expression-to-functions@7.28.5: - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-module-imports@7.27.1: - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5): - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-optimise-call-expression@7.27.1: - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.28.5 - dev: true - - /@babel/helper-plugin-utils@7.27.1: - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-skip-transparent-expression-wrappers@7.27.1: - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-string-parser@7.27.1: - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-identifier@7.28.5: - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-option@7.27.1: - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helpers@7.28.4: - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - dev: true - - /@babel/parser@7.28.5: - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.28.5 - - /@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - - /@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - - /@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5): - resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/template@7.27.2: - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - dev: true - - /@babel/traverse@7.28.5: - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types@7.28.5: - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - /@ctrl/tinycolor@3.6.1: - resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} - engines: {node: '>=10'} - dev: false - - /@element-plus/icons-vue@2.3.2(vue@3.5.25): - resolution: {integrity: sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==} - peerDependencies: - vue: ^3.2.0 - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /@esbuild/aix-ppc64@0.25.12: - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm64@0.25.12: - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.25.12: - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.25.12: - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.25.12: - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.25.12: - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.25.12: - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.25.12: - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.25.12: - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.25.12: - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.25.12: - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.25.12: - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.25.12: - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.25.12: - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.25.12: - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.25.12: - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.25.12: - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-arm64@0.25.12: - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.25.12: - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-arm64@0.25.12: - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.25.12: - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openharmony-arm64@0.25.12: - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.25.12: - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.25.12: - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.25.12: - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.25.12: - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@floating-ui/core@1.7.3: - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - dependencies: - '@floating-ui/utils': 0.2.10 - dev: false - - /@floating-ui/dom@1.7.4: - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 - dev: false - - /@floating-ui/utils@0.2.10: - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - dev: false - - /@jridgewell/gen-mapping@0.3.13: - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - - /@jridgewell/remapping@2.3.5: - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.5.5: - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - /@jridgewell/trace-mapping@0.3.31: - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - dev: true - - /@module-federation/error-codes@0.21.6: - resolution: {integrity: sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==} - dev: true - - /@module-federation/runtime-core@0.21.6: - resolution: {integrity: sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==} - dependencies: - '@module-federation/error-codes': 0.21.6 - '@module-federation/sdk': 0.21.6 - dev: true - - /@module-federation/runtime@0.21.6: - resolution: {integrity: sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==} - dependencies: - '@module-federation/error-codes': 0.21.6 - '@module-federation/runtime-core': 0.21.6 - '@module-federation/sdk': 0.21.6 - dev: true - - /@module-federation/sdk@0.21.6: - resolution: {integrity: sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==} - dev: true - - /@module-federation/vite@1.9.3: - resolution: {integrity: sha512-MV6XI3FX6okEMJ7FdmvFmYuu7DygRoLljKT8atrBwFhlttsgBbswpqMj4P4Fs/X+pFmbIi/ntFzVhsrG0qQnGQ==} - dependencies: - '@module-federation/runtime': 0.21.6 - '@module-federation/sdk': 0.21.6 - '@rollup/pluginutils': 5.3.0 - defu: 6.1.4 - estree-walker: 2.0.2 - magic-string: 0.30.21 - pathe: 1.1.2 - transitivePeerDependencies: - - rollup - dev: true - - /@rolldown/pluginutils@1.0.0-beta.53: - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} - dev: true - - /@rollup/pluginutils@5.3.0: - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - dev: true - - /@rollup/rollup-android-arm-eabi@4.53.3: - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-android-arm64@4.53.3: - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-darwin-arm64@4.53.3: - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-darwin-x64@4.53.3: - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-freebsd-arm64@4.53.3: - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-freebsd-x64@4.53.3: - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm-gnueabihf@4.53.3: - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} - cpu: [arm] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm-musleabihf@4.53.3: - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} - cpu: [arm] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm64-gnu@4.53.3: - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} - cpu: [arm64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm64-musl@4.53.3: - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} - cpu: [arm64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-loong64-gnu@4.53.3: - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} - cpu: [loong64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-ppc64-gnu@4.53.3: - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-riscv64-gnu@4.53.3: - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-riscv64-musl@4.53.3: - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} - cpu: [riscv64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-s390x-gnu@4.53.3: - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} - cpu: [s390x] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-x64-gnu@4.53.3: - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} - cpu: [x64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-x64-musl@4.53.3: - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} - cpu: [x64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-openharmony-arm64@4.53.3: - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} - cpu: [arm64] - os: [openharmony] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-arm64-msvc@4.53.3: - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-ia32-msvc@4.53.3: - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-x64-gnu@4.53.3: - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-x64-msvc@4.53.3: - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@sxzz/popperjs-es@2.11.7: - resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==} - dev: false - - /@types/estree@1.0.8: - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - dev: true - - /@types/lodash-es@4.17.12: - resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - dependencies: - '@types/lodash': 4.17.21 - dev: false - - /@types/lodash@4.17.21: - resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} - dev: false - - /@types/node@22.19.1: - resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==} - dependencies: - undici-types: 6.21.0 - dev: true - - /@types/web-bluetooth@0.0.16: - resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} - dev: false - - /@types/web-bluetooth@0.0.20: - resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} - dev: false - - /@vitejs/plugin-vue-jsx@4.2.0(vite@6.4.1)(vue@3.5.25): - resolution: {integrity: sha512-DSTrmrdLp+0LDNF77fqrKfx7X0ErRbOcUAgJL/HbSesqQwoUvUQ4uYQqaex+rovqgGcoPqVk+AwUh3v9CuiYIw==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.53 - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.5) - vite: 6.4.1(@types/node@22.19.1) - vue: 3.5.25(typescript@5.9.3) - transitivePeerDependencies: - - supports-color - dev: true - - /@vitejs/plugin-vue@5.2.4(vite@6.4.1)(vue@3.5.25): - resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.2.25 - dependencies: - vite: 6.4.1(@types/node@22.19.1) - vue: 3.5.25(typescript@5.9.3) - dev: true - - /@volar/language-core@2.4.15: - resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} - dependencies: - '@volar/source-map': 2.4.15 - dev: true - - /@volar/source-map@2.4.15: - resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==} - dev: true - - /@volar/typescript@2.4.15: - resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} - dependencies: - '@volar/language-core': 2.4.15 - path-browserify: 1.0.1 - vscode-uri: 3.1.0 - dev: true - - /@vue/babel-helper-vue-transform-on@1.5.0: - resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} - dev: true - - /@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.5): - resolution: {integrity: sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - peerDependenciesMeta: - '@babel/core': - optional: true - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@vue/babel-helper-vue-transform-on': 1.5.0 - '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.28.5) - '@vue/shared': 3.5.25 - transitivePeerDependencies: - - supports-color - dev: true - - /@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.28.5): - resolution: {integrity: sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/parser': 7.28.5 - '@vue/compiler-sfc': 3.5.25 - transitivePeerDependencies: - - supports-color - dev: true - - /@vue/compiler-core@3.5.25: - resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} - dependencies: - '@babel/parser': 7.28.5 - '@vue/shared': 3.5.25 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - - /@vue/compiler-dom@3.5.25: - resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} - dependencies: - '@vue/compiler-core': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/compiler-sfc@3.5.25: - resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} - dependencies: - '@babel/parser': 7.28.5 - '@vue/compiler-core': 3.5.25 - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - estree-walker: 2.0.2 - magic-string: 0.30.21 - postcss: 8.5.6 - source-map-js: 1.2.1 - - /@vue/compiler-ssr@3.5.25: - resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} - dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/compiler-vue2@2.7.16: - resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} - dependencies: - de-indent: 1.0.2 - he: 1.2.0 - dev: true - - /@vue/devtools-api@6.6.4: - resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - dev: false - - /@vue/language-core@2.2.12(typescript@5.9.3): - resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.25 - alien-signals: 1.0.13 - minimatch: 9.0.5 - muggle-string: 0.4.1 - path-browserify: 1.0.1 - typescript: 5.9.3 - dev: true - - /@vue/reactivity@3.5.25: - resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} - dependencies: - '@vue/shared': 3.5.25 - - /@vue/runtime-core@3.5.25: - resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} - dependencies: - '@vue/reactivity': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/runtime-dom@3.5.25: - resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} - dependencies: - '@vue/reactivity': 3.5.25 - '@vue/runtime-core': 3.5.25 - '@vue/shared': 3.5.25 - csstype: 3.2.3 - - /@vue/server-renderer@3.5.25(vue@3.5.25): - resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} - peerDependencies: - vue: 3.5.25 - dependencies: - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - vue: 3.5.25(typescript@5.9.3) - - /@vue/shared@3.5.25: - resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} - - /@vueuse/core@11.3.0(vue@3.5.25): - resolution: {integrity: sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==} - dependencies: - '@types/web-bluetooth': 0.0.20 - '@vueuse/metadata': 11.3.0 - '@vueuse/shared': 11.3.0(vue@3.5.25) - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /@vueuse/core@9.13.0(vue@3.5.25): - resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} - dependencies: - '@types/web-bluetooth': 0.0.16 - '@vueuse/metadata': 9.13.0 - '@vueuse/shared': 9.13.0(vue@3.5.25) - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /@vueuse/metadata@11.3.0: - resolution: {integrity: sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==} - dev: false - - /@vueuse/metadata@9.13.0: - resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} - dev: false - - /@vueuse/shared@11.3.0(vue@3.5.25): - resolution: {integrity: sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==} - dependencies: - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /@vueuse/shared@9.13.0(vue@3.5.25): - resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} - dependencies: - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /alien-signals@1.0.13: - resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} - dev: true - - /async-validator@4.2.5: - resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} - dev: false - - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: false - - /axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /baseline-browser-mapping@2.9.3: - resolution: {integrity: sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==} - hasBin: true - dev: true - - /brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - dependencies: - balanced-match: 1.0.2 - dev: true - - /browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - baseline-browser-mapping: 2.9.3 - caniuse-lite: 1.0.30001759 - electron-to-chromium: 1.5.266 - node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) - dev: true - - /call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - dev: false - - /caniuse-lite@1.0.30001759: - resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==} - dev: true - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: false - - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - - /csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - /dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} - dev: false - - /de-indent@1.0.2: - resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} - dev: true - - /debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - - /defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: false - - /dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - dev: false - - /electron-to-chromium@1.5.266: - resolution: {integrity: sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==} - dev: true - - /element-plus@2.12.0(vue@3.5.25): - resolution: {integrity: sha512-M9YLSn2np9OnqrSKWsiXvGe3qnF8pd94+TScsHj1aTMCD+nSEvucXermf807qNt6hOP040le0e5Aft7E9ZfHmA==} - peerDependencies: - vue: ^3.2.0 - dependencies: - '@ctrl/tinycolor': 3.6.1 - '@element-plus/icons-vue': 2.3.2(vue@3.5.25) - '@floating-ui/dom': 1.7.4 - '@popperjs/core': /@sxzz/popperjs-es@2.11.7 - '@types/lodash': 4.17.21 - '@types/lodash-es': 4.17.12 - '@vueuse/core': 9.13.0(vue@3.5.25) - async-validator: 4.2.5 - dayjs: 1.11.19 - lodash: 4.17.21 - lodash-es: 4.17.21 - lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21) - memoize-one: 6.0.0 - normalize-wheel-es: 1.2.0 - vue: 3.5.25(typescript@5.9.3) - transitivePeerDependencies: - - '@vue/composition-api' - dev: false - - /entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - /es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - dev: false - - /es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - dev: false - - /es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - dev: false - - /es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - dev: false - - /esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - dev: true - - /escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - dev: true - - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - /fdir@6.5.0(picomatch@4.0.3): - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - dependencies: - picomatch: 4.0.3 - dev: true - - /follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: false - - /form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - dev: false - - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: false - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - - /get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - dev: false - - /get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - dev: false - - /gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - dev: false - - /has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - dev: false - - /has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.1.0 - dev: false - - /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - dev: false - - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - - /jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - dev: false - - /lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21): - resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==} - peerDependencies: - '@types/lodash-es': '*' - lodash: '*' - lodash-es: '*' - dependencies: - '@types/lodash-es': 4.17.12 - lodash: 4.17.21 - lodash-es: 4.17.21 - dev: false - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lucide-vue-next@0.561.0(vue@3.5.25): - resolution: {integrity: sha512-c5HUckO0qHklVSOf/0vaSR3pEb8fYImRDCRDLde56uqS9js0D/e3RAvq0/YFWjkmyOBKCb0/IdskdoHZQEkT5g==} - peerDependencies: - vue: '>=3.0.1' - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - /math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - dev: false - - /memoize-one@6.0.0: - resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - dev: false - - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: false - - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - dev: false - - /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.2 - dev: true - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /muggle-string@0.4.1: - resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - dev: true - - /nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - /node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - dev: true - - /normalize-wheel-es@1.2.0: - resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==} - dev: false - - /path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - dev: true - - /pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - dev: true - - /picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - /picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - dev: true - - /pinia@2.3.1(typescript@5.9.3)(vue@3.5.25): - resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==} - peerDependencies: - typescript: '>=4.4.4' - vue: ^2.7.0 || ^3.5.11 - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@vue/devtools-api': 6.6.4 - typescript: 5.9.3 - vue: 3.5.25(typescript@5.9.3) - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - dev: false - - /postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false - - /rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 - fsevents: 2.3.3 - dev: true - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true - - /source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - /tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - dev: true - - /typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - /undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - dev: true - - /update-browserslist-db@1.2.2(browserslist@4.28.1): - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - dev: true - - /vite@6.4.1(@types/node@22.19.1): - resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - dependencies: - '@types/node': 22.19.1 - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.3 - tinyglobby: 0.2.15 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /vscode-uri@3.1.0: - resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} - dev: true - - /vue-demi@0.14.10(vue@3.5.25): - resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - peerDependencies: - '@vue/composition-api': ^1.0.0-rc.1 - vue: ^3.0.0-0 || ^2.6.0 - peerDependenciesMeta: - '@vue/composition-api': - optional: true - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /vue-router@4.6.3(vue@3.5.25): - resolution: {integrity: sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==} - peerDependencies: - vue: ^3.5.0 - dependencies: - '@vue/devtools-api': 6.6.4 - vue: 3.5.25(typescript@5.9.3) - dev: false - - /vue-tsc@2.2.12(typescript@5.9.3): - resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} - hasBin: true - peerDependencies: - typescript: '>=5.0.0' - dependencies: - '@volar/typescript': 2.4.15 - '@vue/language-core': 2.2.12(typescript@5.9.3) - typescript: 5.9.3 - dev: true - - /vue@3.5.25(typescript@5.9.3): - resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-sfc': 3.5.25 - '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25) - '@vue/shared': 3.5.25 - typescript: 5.9.3 - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true diff --git a/urbanLifelineWeb/packages/platform/public/app-config.js b/urbanLifelineWeb/packages/platform/public/app-config.js deleted file mode 100644 index b196c62c..00000000 --- a/urbanLifelineWeb/packages/platform/public/app-config.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @description 应用运行时配置文件 (支持 Docker 环境变量替换) - * - * 占位符说明: - * - __PLACEHOLDER__ 格式的值会在 Docker 启动时被环境变量替换 - * - 如果环境变量未设置,将使用默认值 - * - * Docker 部署: - * 1. 通过 volume 挂载覆盖此文件 - * 2. 或通过启动脚本替换占位符 - */ - -window.APP_RUNTIME_CONFIG = { - // 环境标识 - env: '__APP_ENV__', - - // API 配置 - api: { - baseUrl: '__API_BASE_URL__', - timeout: 30000 - }, - - // 应用基础路径 - baseUrl: '/', - - // 文件配置 - file: { - downloadUrl: '__API_BASE_URL__/urban-lifeline/file/download/', - uploadUrl: '__API_BASE_URL__/urban-lifeline/file/upload', - maxSize: { - image: 5, - video: 100, - document: 10 - }, - acceptTypes: { - image: 'image/*', - video: 'video/*', - document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx' - } - }, - - // Token 配置 - token: { - key: 'token', - refreshThreshold: 300000 - }, - - // 公共资源路径 - publicImgPath: '__PUBLIC_PATH__/img', - publicWebPath: '__PUBLIC_PATH__', - - // 单点登录配置 - sso: { - platformUrl: '__SSO_PLATFORM_URL__', - workcaseUrl: '__SSO_WORKCASE_URL__', - biddingUrl: '__SSO_BIDDING_URL__' - }, - - // AES 加密密钥 - aesSecretKey: '__AES_SECRET_KEY__', - - // 功能开关 - features: { - enableDebug: false, - enableMockData: false - } -}; diff --git a/urbanLifelineWeb/packages/platform/public/app-config.local.js b/urbanLifelineWeb/packages/platform/public/app-config.local.js deleted file mode 100644 index 497a7286..00000000 --- a/urbanLifelineWeb/packages/platform/public/app-config.local.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @description 本地开发环境配置文件 - * 用于 dev 和 preview 模式 - */ - -window.APP_RUNTIME_CONFIG = { - // 环境标识 - env: 'production', - - // API 配置 - api: { - baseUrl: 'https://org.xyzh.yslg/api', - timeout: 30000 - }, - - // 应用基础路径 - baseUrl: '/platform/', - - // 文件配置 - file: { - downloadUrl: 'https://org.xyzh.yslg/api/urban-lifeline/file/download/', - uploadUrl: 'https://org.xyzh.yslg/api/urban-lifeline/file/upload', - maxSize: { - image: 5, - video: 100, - document: 10 - }, - acceptTypes: { - image: 'image/*', - video: 'video/*', - document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx' - } - }, - - // Token 配置 - token: { - key: 'token', - refreshThreshold: 300000 - }, - - // 公共资源路径 - publicImgPath: '/platform/img', - publicWebPath: '/platform', - - // 单点登录配置 - sso: { - platformUrl: 'https://org.xyzh.yslg/platform/', - workcaseUrl: 'https://org.xyzh.yslg/workcase/', - biddingUrl: 'https://org.xyzh.yslg/bidding/' - }, - - // AES 加密密钥(本地开发用,生产环境需要替换) - aesSecretKey: 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=', - - // 功能开关 - features: { - enableDebug: true, - enableMockData: false - } -}; diff --git a/urbanLifelineWeb/packages/platform/public/avatar.svg b/urbanLifelineWeb/packages/platform/public/avatar.svg deleted file mode 100644 index b537ce1d..00000000 --- a/urbanLifelineWeb/packages/platform/public/avatar.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/urbanLifelineWeb/packages/platform/public/favicon.svg b/urbanLifelineWeb/packages/platform/public/favicon.svg deleted file mode 100644 index 0064d6fc..00000000 --- a/urbanLifelineWeb/packages/platform/public/favicon.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/platform/public/logo.jpg b/urbanLifelineWeb/packages/platform/public/logo.jpg deleted file mode 100644 index 18b5da66..00000000 Binary files a/urbanLifelineWeb/packages/platform/public/logo.jpg and /dev/null differ diff --git a/urbanLifelineWeb/packages/platform/src/App.vue b/urbanLifelineWeb/packages/platform/src/App.vue deleted file mode 100644 index 6898edb1..00000000 --- a/urbanLifelineWeb/packages/platform/src/App.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/platform/src/api/ai/agent.ts b/urbanLifelineWeb/packages/platform/src/api/ai/agent.ts deleted file mode 100644 index 0c3534ed..00000000 --- a/urbanLifelineWeb/packages/platform/src/api/ai/agent.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { api } from 'shared/api' -import type { ResultDomain } from 'shared/types' - - -/** - * 认证 API - * 通过 Gateway (8180) 访问 Auth Service (8181) - * 路由规则:/urban-lifeline/auth/** → auth-service/urban-lifeline/auth/** - */ -export const agentAPI = { - baseUrl: "/urban-lifeline/xxx",//随后端更新 - - /** - * 获取智能体列表 - * @returns 智能体列表 - */ - async agentList(): Promise> { - // const response = await api.post(`${this.baseUrl}/send-sms-code`, { phone }) - // return response.data - return []; - }, - - /** - * 新增智能体 - * @param agent 智能体信息 - * @returns 智能体信息 - */ - async addAgent(agent: any): Promise> { - // const response = await api.post(`${this.baseUrl}/send-sms-code`, { phone }) - // return response.data - return []; - }, - - /** - * 更新智能体 - * @param agent 智能体信息 - * @returns 智能体信息 - */ - async updateAgent(agent: any): Promise> { - // const response = await api.post(`${this.baseUrl}/send-sms-code`, { phone }) - // return response.data - return []; - }, - - /** - * 删除智能体 - * @param agentId 智能体ID - * @returns 智能体信息 - */ - async deleteAgent(agentId: string): Promise> { - // const response = await api.post(`${this.baseUrl}/send-sms-code`, { phone }) - // return response.data - return []; - }, - -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/api/ai/chat.ts b/urbanLifelineWeb/packages/platform/src/api/ai/chat.ts deleted file mode 100644 index 0890204c..00000000 --- a/urbanLifelineWeb/packages/platform/src/api/ai/chat.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { api } from 'shared/api' -import type { ResultDomain } from 'shared/types' - - -/** - * 认证 API - * 通过 Gateway (8180) 访问 Auth Service (8181) - * 路由规则:/urban-lifeline/auth/** → auth-service/urban-lifeline/auth/** - */ -export const chatAPI = { - baseUrl: "/urban-lifeline/xxx",//随后端更新 - - /** - * 根据agentId获取聊天会话id - * @param agentId agentId - * @returns 发送结果 - */ - async chatHistory(agentId: string): Promise> { - // const response = await api.post(`${this.baseUrl}/send-sms-code`, { phone }) - // return response.data - return []; - }, - - /** - * 根据agentId和conversationId获取聊天记录 - * @param agentId agentId - * @param conversationId conversationId - * @returns 发送结果 - */ - async chatConversation(agentId: string, conversationId: string): Promise> { - // const response = await api.post(`${this.baseUrl}/send-sms-code`, { phone }) - // return response.data - return []; - }, -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/api/ai/index.ts b/urbanLifelineWeb/packages/platform/src/api/ai/index.ts deleted file mode 100644 index 2ba168f1..00000000 --- a/urbanLifelineWeb/packages/platform/src/api/ai/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './agent' -export * from './chat' diff --git a/urbanLifelineWeb/packages/platform/src/api/index.ts b/urbanLifelineWeb/packages/platform/src/api/index.ts deleted file mode 100644 index a726f637..00000000 --- a/urbanLifelineWeb/packages/platform/src/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ai' \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/config/README.md b/urbanLifelineWeb/packages/platform/src/config/README.md deleted file mode 100644 index 41b691da..00000000 --- a/urbanLifelineWeb/packages/platform/src/config/README.md +++ /dev/null @@ -1,254 +0,0 @@ -# Platform 应用配置说明 - -## AES 加密配置 - -### 密钥配置 - -**配置文件**:`src/config/index.ts` - -```typescript -export const AES_SECRET_KEY = '1234567890qwer' -``` - -**注意事项**: -1. ✅ 密钥已配置为 `1234567890qwer`,与后端保持一致 -2. ⚠️ 该密钥与后端 `application.yml` 中的 `security.aes.secret-key` 必须相同 -3. 🔒 生产环境应从环境变量或配置中心获取,不要硬编码 - -### 对应后端配置 - -**Gateway** (`gateway/src/main/resources/application.yml`): -```yaml -security: - aes: - secret-key: 1234567890qwer -``` - -**Auth Service** (`auth/src/main/resources/application.yml`): -```yaml -security: - aes: - secret-key: 1234567890qwer -``` - -## 使用示例 - -### 1. 登录时加密密码 - -```typescript -import { authAPI } from '@shared/api/auth' -import { getAesInstance } from '@shared/utils' - -async function handleLogin(username: string, password: string) { - try { - // 1. 获取 AES 加密实例 - const aes = getAesInstance() - - // 2. 加密密码 - const encryptedPassword = await aes.encryptPassword(password) - - // 3. 发送登录请求 - const response = await authAPI.login({ - username, - password: encryptedPassword, // 使用加密后的密码 - loginType: 'password' - }) - - if (response.data.success) { - console.log('登录成功') - // 保存 token 等操作 - } - } catch (error) { - console.error('登录失败:', error) - } -} -``` - -### 2. 注册时加密手机号和密码 - -```typescript -import { authAPI } from '@shared/api/auth' -import { getAesInstance } from '@shared/utils' - -async function handleRegister(phone: string, password: string, smsCode: string, sessionId: string) { - try { - const aes = getAesInstance() - - // 加密敏感信息 - const encryptedPhone = await aes.encryptPhone(phone) - const encryptedPassword = await aes.encryptPassword(password) - - // 发送注册请求 - const response = await authAPI.register({ - registerType: 'phone', - phone: encryptedPhone, - password: encryptedPassword, - confirmPassword: encryptedPassword, - smsCode, - smsSessionId: sessionId - }) - - if (response.data.success) { - console.log('注册成功') - } - } catch (error) { - console.error('注册失败:', error) - } -} -``` - -### 3. 数据脱敏显示 - -```typescript -import { AesUtils } from '@shared/utils' - -// 显示脱敏手机号 -const phone = '13812345678' -const maskedPhone = AesUtils.maskPhone(phone) -console.log(maskedPhone) // 输出:138****5678 - -// 显示脱敏身份证号 -const idCard = '110101199001011234' -const maskedIdCard = AesUtils.maskIdCard(idCard) -console.log(maskedIdCard) // 输出:110101********1234 -``` - -## 初始化流程 - -### 应用启动时自动初始化 - -**文件**:`src/main.ts` - -```typescript -import { AES_SECRET_KEY } from './config' -import { initAesEncrypt } from '@shared/utils' - -async function initApp() { - // 初始化 AES 加密工具 - await initAesEncrypt(AES_SECRET_KEY) - - // ... 其他初始化操作 -} - -initApp() -``` - -### 初始化状态检查 - -```typescript -import { getAesInstance } from '@shared/utils' - -try { - const aes = getAesInstance() - console.log('✅ AES 加密工具已初始化') -} catch (error) { - console.error('❌ AES 加密工具未初始化:', error) -} -``` - -## 加密流程图 - -``` -用户输入密码 - ↓ -前端 AES 加密 (1234567890qwer) - ↓ -发送加密后的密码 - ↓ -Gateway (不解密,直接转发) - ↓ -Auth Service 接收 - ↓ -AES 解密 (1234567890qwer) - ↓ -BCrypt 再次加密 - ↓ -存入数据库 -``` - -## 安全建议 - -### 开发环境 -- ✅ 使用固定密钥 `1234567890qwer` -- ✅ 密钥在代码中配置 - -### 生产环境 -- 🔒 从环境变量获取密钥 -- 🔒 使用配置中心(Nacos) -- 🔒 定期轮换密钥 -- 🔒 密钥长度至少 32 字符 - -### 示例:从环境变量获取 - -```typescript -// 生产环境配置 -export const AES_SECRET_KEY = process.env.VUE_APP_AES_SECRET_KEY || '1234567890qwer' -``` - -## 故障排查 - -### 问题:登录时提示"密码错误" - -**可能原因**:前后端密钥不一致 - -**排查步骤**: -1. 检查前端配置:`src/config/index.ts` 中的 `AES_SECRET_KEY` -2. 检查后端配置:`application.yml` 中的 `security.aes.secret-key` -3. 确保两者完全一致 - -**解决方案**: -```bash -# 前端 -export const AES_SECRET_KEY = '1234567890qwer' - -# 后端 -security: - aes: - secret-key: 1234567890qwer -``` - -### 问题:"AES 加密工具未初始化" - -**原因**:`initAesEncrypt()` 未被调用 - -**解决**:检查 `main.ts` 中是否正确调用初始化函数 - -### 问题:加密后的数据无法解密 - -**可能原因**: -1. 密钥不正确 -2. 数据被篡改 -3. Base64 编码问题 - -**调试方法**: -```typescript -const aes = getAesInstance() -const original = 'test123' -const encrypted = await aes.encrypt(original) -const decrypted = await aes.decrypt(encrypted) -console.log(original === decrypted) // 应该输出 true -``` - -## API 参考 - -### 配置项 - -| 配置项 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| `AES_SECRET_KEY` | `string` | `'1234567890qwer'` | AES 加密密钥 | -| `API_BASE_URL` | `string` | `'http://localhost:8180'` | API 基础地址 | -| `APP_CONFIG.name` | `string` | `'泰豪电源 AI 数智化平台'` | 应用名称 | -| `APP_CONFIG.version` | `string` | `'1.0.0'` | 应用版本 | - -### 环境变量 - -| 变量名 | 说明 | 示例 | -|--------|------|------| -| `VITE_API_BASE_URL` | API 基础地址 | `https://api.example.com` | -| `VUE_APP_AES_SECRET_KEY` | AES 密钥(生产) | `your-secret-key-32-chars-long` | - -## 更多信息 - -- AES 加密工具详细文档:`@shared/utils/crypto/README.md` -- Auth API 文档:`@shared/api/auth/auth.ts` -- 后端 AES 实现:`urbanLifelineServ/common/common-utils/src/main/java/org/xyzh/common/utils/crypto/AesEncryptUtil.java` diff --git a/urbanLifelineWeb/packages/platform/src/config/index.ts b/urbanLifelineWeb/packages/platform/src/config/index.ts deleted file mode 100644 index dcd54616..00000000 --- a/urbanLifelineWeb/packages/platform/src/config/index.ts +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @description 应用运行时配置 - * - * 配置加载策略: - * 1. 开发环境:使用内置开发配置 - * 2. 生产环境:从 window.APP_RUNTIME_CONFIG 读取(来自 app-config.js) - * 3. Docker部署:启动时替换 app-config.js 中的占位符 - */ - -// ============================================ -// 类型定义 -// ============================================ -export interface AppRuntimeConfig { - env?: string; - api: { - baseUrl: string; - timeout: number; - }; - baseUrl: string; - file: { - downloadUrl: string; - uploadUrl: string; - maxSize: { - image: number; - video: number; - document: number; - }; - acceptTypes: { - image: string; - video: string; - document: string; - }; - }; - token: { - key: string; - refreshThreshold: number; - }; - publicImgPath: string; - publicWebPath: string; - sso?: { - platformUrl: string; - workcaseUrl: string; - biddingUrl: string; - }; - aesSecretKey?: string; - features?: { - enableDebug?: boolean; - enableMockData?: boolean; - [key: string]: any; - }; -} - -// ============================================ -// 环境检测 -// ============================================ -const isDev = (import.meta as any).env?.DEV ?? false; - -// ============================================ -// 开发环境配置 -// ============================================ -const devConfig: AppRuntimeConfig = { - env: 'development', - api: { - baseUrl: '/api', - timeout: 30000 - }, - baseUrl: '/', - file: { - downloadUrl: '/api/urban-lifeline/file/download/', - uploadUrl: '/api/urban-lifeline/file/upload', - maxSize: { image: 5, video: 100, document: 10 }, - acceptTypes: { - image: 'image/*', - video: 'video/*', - document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx' - } - }, - token: { - key: 'token', - refreshThreshold: 300000 - }, - publicImgPath: '/img', - publicWebPath: '/', - sso: { - platformUrl: '/', - workcaseUrl: '/workcase', - biddingUrl: '/bidding' - }, - aesSecretKey: 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=', - features: { - enableDebug: true, - enableMockData: false - } -}; - -// ============================================ -// 生产环境默认配置(兜底) -// ============================================ -const prodDefaultConfig: AppRuntimeConfig = { - env: 'production', - api: { - baseUrl: '/api', - timeout: 30000 - }, - baseUrl: '/', - file: { - downloadUrl: '/api/urban-lifeline/file/download/', - uploadUrl: '/api/urban-lifeline/file/upload', - maxSize: { image: 5, video: 100, document: 10 }, - acceptTypes: { - image: 'image/*', - video: 'video/*', - document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx' - } - }, - token: { - key: 'token', - refreshThreshold: 300000 - }, - publicImgPath: '/img', - publicWebPath: '/', - sso: { - platformUrl: '/', - workcaseUrl: '/workcase', - biddingUrl: '/bidding' - }, - aesSecretKey: 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=', - features: { - enableDebug: false, - enableMockData: false - } -}; - -// ============================================ -// 配置加载 -// ============================================ - -/** - * 检查值是否为未替换的占位符 - */ -const isPlaceholder = (value: any): boolean => { - return typeof value === 'string' && value.startsWith('__') && value.endsWith('__'); -}; - -/** - * 深度合并配置,跳过占位符值 - */ -const mergeConfig = (target: any, source: any): any => { - const result = { ...target }; - for (const key in source) { - const value = source[key]; - if (value && typeof value === 'object' && !Array.isArray(value)) { - result[key] = mergeConfig(target[key] || {}, value); - } else if (!isPlaceholder(value)) { - result[key] = value; - } - } - return result; -}; - -/** - * 获取运行时配置 - */ -const getRuntimeConfig = (): AppRuntimeConfig => { - if (isDev) { - console.log('[Config] 开发环境,使用内置配置'); - return devConfig; - } - - try { - const runtimeConfig = (window as any).APP_RUNTIME_CONFIG; - if (runtimeConfig && typeof runtimeConfig === 'object') { - // 合并配置,未替换的占位符使用默认值 - const merged = mergeConfig(prodDefaultConfig, runtimeConfig); - console.log('[Config] 加载运行时配置', merged); - return merged; - } - } catch (e) { - console.warn('[Config] 无法读取外部配置', e); - } - - console.log('[Config] 使用默认生产配置'); - return prodDefaultConfig; -}; - -// 当前配置 -const config = getRuntimeConfig(); - -// ============================================ -// 导出 -// ============================================ - -// AES 密钥 -export const AES_SECRET_KEY = config.aesSecretKey || 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI='; - -// 常用配置项 -export const API_BASE_URL = config.api.baseUrl; -export const FILE_DOWNLOAD_URL = config.file.downloadUrl; -export const FILE_UPLOAD_URL = config.file.uploadUrl; -export const PUBLIC_IMG_PATH = config.publicImgPath; -export const PUBLIC_WEB_PATH = config.publicWebPath; - -// 完整配置对象 -export const APP_CONFIG = { - title: '泰豪电源 AI 数智化平台', - name: '泰豪电源 AI 数智化平台', - version: '1.0.0', - copyright: '泰豪电源', - env: config.env || 'production', - baseUrl: config.baseUrl, - api: config.api, - file: config.file, - token: config.token, - publicImgPath: config.publicImgPath, - publicWebPath: config.publicWebPath, - sso: config.sso || { platformUrl: '/', workcaseUrl: '/workcase', biddingUrl: '/bidding' }, - features: config.features || {} -}; - -export default APP_CONFIG; diff --git a/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/AdminSidebarLayout.scss b/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/AdminSidebarLayout.scss deleted file mode 100644 index 10c3db4e..00000000 --- a/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/AdminSidebarLayout.scss +++ /dev/null @@ -1,307 +0,0 @@ -// ==================== 品牌色变量 ==================== -$brand-color: #0055AA; -$brand-color-light: #EBF5FF; -$brand-color-hover: #004488; - -.sidebar-layout { - display: flex; - width: 100%; - height: 100vh; - overflow: hidden; - background: #fff; - font-family: 'Inter', 'Noto Sans SC', sans-serif; -} - -// ==================== 2级侧边栏 ==================== -.sidebar { - width: 224px; - height: 100%; - background: #fff; - display: flex; - flex-direction: column; - color: #333; - flex-shrink: 0; - transition: width 0.3s ease; - border-right: 1px solid #f1f5f9; - - &.collapsed { - width: 64px; - - .sidebar-header { - padding: 16px 0; - justify-content: center; - - .logo { - display: none; - } - - .collapse-btn { - display: flex; - } - } - - .nav-item { - justify-content: center; - padding: 10px; - margin: 2px 8px; - - span { - display: none; - } - } - - .user-section { - justify-content: center; - padding: 16px 8px; - - .user-name, .back-icon { - display: none; - } - } - } -} - -// 侧边栏头部 -.sidebar-header { - height: 64px; - padding: 0 16px; - border-bottom: 1px solid #f1f5f9; - display: flex; - align-items: center; - justify-content: space-between; -} - -.collapse-btn { - width: 28px; - height: 28px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 6px; - cursor: pointer; - color: #94a3b8; - background: transparent; - border: none; - transition: all 0.2s; - - &:hover { - background: #f1f5f9; - color: #64748b; - } -} -.logo-img { - width: 100%; - height: 32px; - border-radius: 8px; - object-fit: contain; -} -.logo { - display: flex; - align-items: center; - gap: 8px; - - .logo-text { - font-size: 15px; - font-weight: 600; - color: #1e293b; - } -} - -// 导航菜单 -.nav-menu { - flex: 1; - // overflow-y: auto; - padding: 8px 0; - - &::-webkit-scrollbar { - width: 4px; - } - - &::-webkit-scrollbar-thumb { - background: rgba(0, 0, 0, 0.1); - border-radius: 4px; - } -} - -.nav-section { - padding: 0; -} - -.nav-item { - display: flex; - align-items: center; - gap: 8px; - padding: 10px 16px; - margin: 2px 8px; - border-radius: 8px; - cursor: pointer; - transition: all 0.2s ease; - color: #64748b; - font-size: 14px; - font-weight: 500; - - &:hover { - background: #f8fafc; - color: #475569; - } - - &.active { - background: $brand-color-light; - color: $brand-color; - } - - .el-icon { - font-size: 18px; - flex-shrink: 0; - } - - span { - flex: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} - -// 用户信息 -.user-section { - padding: 16px; - border-top: 1px solid #f1f5f9; - display: flex; - align-items: center; - gap: 12px; - - .user-avatar { - width: 36px; - height: 36px; - cursor: pointer; - transition: transform 0.2s; - flex-shrink: 0; - - &:hover { - transform: scale(1.05); - } - - :deep(.el-avatar) { - width: 100%; - height: 100%; - } - } - - .user-name { - flex: 1; - font-size: 14px; - font-weight: 500; - color: #374151; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .back-icon { - width: 32px; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 6px; - cursor: pointer; - color: #94a3b8; - transition: all 0.2s; - flex-shrink: 0; - - &:hover { - color: $brand-color; - background: $brand-color-light; - } - - .el-icon { - font-size: 18px; - } - } -} - -// ==================== 主内容区 ==================== -.main-content { - flex: 1; - height: 100%; - overflow: hidden; - background: #f8fafc; - position: relative; -} - -// iframe 容器 -.iframe-container { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - position: relative; -} - -.iframe-header { - height: 56px; - padding: 0 24px; - display: flex; - align-items: center; - justify-content: space-between; - border-bottom: 1px solid #e2e8f0; - background: #fff; - flex-shrink: 0; -} - -.iframe-title { - font-size: 16px; - font-weight: 600; - color: #1e293b; -} - -.content-iframe { - flex: 1; - width: 100%; - height: 100%; - border: none; - background: #fff; -} - -.iframe-loading { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - display: flex; - flex-direction: column; - align-items: center; - gap: 12px; - color: $brand-color; - font-size: 14px; - z-index: 10; - - .el-icon { - font-size: 32px; - } -} - -// ==================== 响应式 ==================== -@media (max-width: 768px) { - .sidebar { - width: 64px; - - &:not(.collapsed) { - width: 224px; - position: fixed; - left: 0; - top: 0; - z-index: 1000; - box-shadow: 4px 0 16px rgba(0, 0, 0, 0.1); - } - } - - .iframe-header { - padding: 0 16px; - - .iframe-title { - font-size: 14px; - } - } -} diff --git a/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/AdminSidebarLayout.vue b/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/AdminSidebarLayout.vue deleted file mode 100644 index 99929a52..00000000 --- a/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/AdminSidebarLayout.vue +++ /dev/null @@ -1,255 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/README.md b/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/README.md deleted file mode 100644 index 8279319f..00000000 --- a/urbanLifelineWeb/packages/platform/src/layouts/AdminSidebarLayout/README.md +++ /dev/null @@ -1,214 +0,0 @@ -# SidebarLayout 侧边栏布局组件 - -## 功能特性 - -### 🎯 核心功能 -- **侧边栏菜单导航**:左侧固定侧边栏,支持折叠/展开 -- **双模式内容区**: - - **路由模式**:普通路由页面渲染 - - **iframe 模式**:嵌入外部应用(招标助手、泰豪小电、智能体编排) -- **用户信息展示**:底部用户头像和下拉菜单 -- **响应式设计**:支持移动端适配 - -### 📱 菜单配置 - -```typescript -const menuItems: MenuItem[] = [ - { - key: 'home', - label: '工作台', - icon: 'Grid', - path: '/home', - type: 'route' - }, - { - key: 'bidding', - label: '招标助手', - icon: 'Document', - iframeUrl: 'http://localhost:7002', - type: 'iframe' - }, - { - key: 'service', - label: '泰豪小电', - icon: 'Service', - iframeUrl: 'http://localhost:7003', - type: 'iframe' - }, - { - key: 'workflow', - label: '智能体编排', - icon: 'Connection', - iframeUrl: 'http://localhost:3000', // Dify 地址 - type: 'iframe' - } -] -``` - -## 使用方式 - -### 在路由中使用 - -```typescript -// router/index.ts -import { SidebarLayout } from '@/layouts' - -const routes = [ - { - path: '/', - component: SidebarLayout, - children: [ - { - path: '/home', - component: () => import('@/views/Home.vue') - }, - { - path: '/chat', - component: () => import('@/views/Chat.vue') - } - ] - } -] -``` - -### 在 App.vue 中使用 - -```vue - - - -``` - -## 菜单项类型 - -```typescript -interface MenuItem { - key: string // 唯一标识 - label: string // 显示名称 - icon: string // Element Plus 图标组件名 - path?: string // 路由路径(route 类型必需) - iframeUrl?: string // iframe URL(iframe 类型必需) - type: 'route' | 'iframe' // 菜单类型 -} -``` - -## iframe 应用说明 - -### 1. 招标助手 (Bidding) -- **端口**:5002 -- **URL**:http://localhost:7002 -- **说明**:招投标业务管理系统 - -### 2. 泰豪小电 (Service) -- **端口**:5003 -- **URL**:http://localhost:7003 -- **说明**:智能客服工单管理系统 - -### 3. 智能体编排 (Workflow) -- **端口**:3000 -- **URL**:http://localhost:3000 -- **说明**:Dify 智能体编排界面 - -## 样式自定义 - -### 主题色调整 - -```scss -// 修改侧边栏背景色 -.sidebar { - background: #F0EAF4; // 当前淡紫色背景 -} - -// 修改激活项颜色 -.nav-item.active { - background: rgba(124, 58, 237, 0.15); - color: #7c3aed; -} -``` - -### 侧边栏宽度 - -```scss -.sidebar { - width: 220px; // 展开宽度 - - &.collapsed { - width: 64px; // 折叠宽度 - } -} -``` - -## 功能说明 - -### 侧边栏折叠 -- 点击头部箭头图标可切换折叠/展开状态 -- 折叠后只显示图标,展开后显示图标+文字 - -### iframe 加载 -- 自动显示加载中状态 -- 支持刷新按钮重新加载 -- 显示当前应用标题 - -### 用户操作 -- **个人中心**:跳转到 /profile -- **系统设置**:跳转到 /settings -- **退出登录**:跳转到 /login - -## 注意事项 - -1. **跨域问题**:确保 iframe 应用允许被嵌入 - ```nginx - # nginx 配置 - add_header X-Frame-Options "SAMEORIGIN"; - # 或者 - add_header Content-Security-Policy "frame-ancestors 'self' http://localhost:7001"; - ``` - -2. **端口配置**:确保对应服务已启动 - - platform: 5001 - - bidding: 5002 - - workcase: 5003 - - dify: 3000 - -3. **路由同步**:iframe 模式不会改变浏览器 URL - -4. **通信机制**:如需与 iframe 通信,使用 postMessage API - -## 扩展建议 - -### 添加新菜单项 - -```typescript -// 在 menuItems 数组中添加 -{ - key: 'new-app', - label: '新应用', - icon: 'Plus', - iframeUrl: 'http://localhost:7004', - type: 'iframe' -} -``` - -### 动态菜单加载 - -```typescript -// 从 API 获取菜单配置 -const loadMenus = async () => { - const response = await fetch('/api/menus') - menuItems.value = await response.json() -} -``` - -### 权限控制 - -```typescript -const menuItems = computed(() => { - return allMenuItems.filter(item => - hasPermission(item.key) - ) -}) -``` diff --git a/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/README.md b/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/README.md deleted file mode 100644 index 8279319f..00000000 --- a/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/README.md +++ /dev/null @@ -1,214 +0,0 @@ -# SidebarLayout 侧边栏布局组件 - -## 功能特性 - -### 🎯 核心功能 -- **侧边栏菜单导航**:左侧固定侧边栏,支持折叠/展开 -- **双模式内容区**: - - **路由模式**:普通路由页面渲染 - - **iframe 模式**:嵌入外部应用(招标助手、泰豪小电、智能体编排) -- **用户信息展示**:底部用户头像和下拉菜单 -- **响应式设计**:支持移动端适配 - -### 📱 菜单配置 - -```typescript -const menuItems: MenuItem[] = [ - { - key: 'home', - label: '工作台', - icon: 'Grid', - path: '/home', - type: 'route' - }, - { - key: 'bidding', - label: '招标助手', - icon: 'Document', - iframeUrl: 'http://localhost:7002', - type: 'iframe' - }, - { - key: 'service', - label: '泰豪小电', - icon: 'Service', - iframeUrl: 'http://localhost:7003', - type: 'iframe' - }, - { - key: 'workflow', - label: '智能体编排', - icon: 'Connection', - iframeUrl: 'http://localhost:3000', // Dify 地址 - type: 'iframe' - } -] -``` - -## 使用方式 - -### 在路由中使用 - -```typescript -// router/index.ts -import { SidebarLayout } from '@/layouts' - -const routes = [ - { - path: '/', - component: SidebarLayout, - children: [ - { - path: '/home', - component: () => import('@/views/Home.vue') - }, - { - path: '/chat', - component: () => import('@/views/Chat.vue') - } - ] - } -] -``` - -### 在 App.vue 中使用 - -```vue - - - -``` - -## 菜单项类型 - -```typescript -interface MenuItem { - key: string // 唯一标识 - label: string // 显示名称 - icon: string // Element Plus 图标组件名 - path?: string // 路由路径(route 类型必需) - iframeUrl?: string // iframe URL(iframe 类型必需) - type: 'route' | 'iframe' // 菜单类型 -} -``` - -## iframe 应用说明 - -### 1. 招标助手 (Bidding) -- **端口**:5002 -- **URL**:http://localhost:7002 -- **说明**:招投标业务管理系统 - -### 2. 泰豪小电 (Service) -- **端口**:5003 -- **URL**:http://localhost:7003 -- **说明**:智能客服工单管理系统 - -### 3. 智能体编排 (Workflow) -- **端口**:3000 -- **URL**:http://localhost:3000 -- **说明**:Dify 智能体编排界面 - -## 样式自定义 - -### 主题色调整 - -```scss -// 修改侧边栏背景色 -.sidebar { - background: #F0EAF4; // 当前淡紫色背景 -} - -// 修改激活项颜色 -.nav-item.active { - background: rgba(124, 58, 237, 0.15); - color: #7c3aed; -} -``` - -### 侧边栏宽度 - -```scss -.sidebar { - width: 220px; // 展开宽度 - - &.collapsed { - width: 64px; // 折叠宽度 - } -} -``` - -## 功能说明 - -### 侧边栏折叠 -- 点击头部箭头图标可切换折叠/展开状态 -- 折叠后只显示图标,展开后显示图标+文字 - -### iframe 加载 -- 自动显示加载中状态 -- 支持刷新按钮重新加载 -- 显示当前应用标题 - -### 用户操作 -- **个人中心**:跳转到 /profile -- **系统设置**:跳转到 /settings -- **退出登录**:跳转到 /login - -## 注意事项 - -1. **跨域问题**:确保 iframe 应用允许被嵌入 - ```nginx - # nginx 配置 - add_header X-Frame-Options "SAMEORIGIN"; - # 或者 - add_header Content-Security-Policy "frame-ancestors 'self' http://localhost:7001"; - ``` - -2. **端口配置**:确保对应服务已启动 - - platform: 5001 - - bidding: 5002 - - workcase: 5003 - - dify: 3000 - -3. **路由同步**:iframe 模式不会改变浏览器 URL - -4. **通信机制**:如需与 iframe 通信,使用 postMessage API - -## 扩展建议 - -### 添加新菜单项 - -```typescript -// 在 menuItems 数组中添加 -{ - key: 'new-app', - label: '新应用', - icon: 'Plus', - iframeUrl: 'http://localhost:7004', - type: 'iframe' -} -``` - -### 动态菜单加载 - -```typescript -// 从 API 获取菜单配置 -const loadMenus = async () => { - const response = await fetch('/api/menus') - menuItems.value = await response.json() -} -``` - -### 权限控制 - -```typescript -const menuItems = computed(() => { - return allMenuItems.filter(item => - hasPermission(item.key) - ) -}) -``` diff --git a/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/SidebarLayout.scss b/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/SidebarLayout.scss deleted file mode 100644 index 9b3dd704..00000000 --- a/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/SidebarLayout.scss +++ /dev/null @@ -1,416 +0,0 @@ -// ==================== 品牌色变量 ==================== -$brand-color: #0055AA; -$brand-color-light: #EBF5FF; -$brand-color-hover: #004488; - -.sidebar-layout { - display: flex; - width: 100%; - height: 100vh; - overflow: hidden; - background: #fff; - font-family: 'Inter', 'Noto Sans SC', sans-serif; -} - -// ==================== 1级侧边栏 ==================== -.sidebar { - width: 256px; - height: 100%; - background: #fff; - display: flex; - flex-direction: column; - color: #333; - flex-shrink: 0; - transition: width 0.3s ease; - border-right: 1px solid #f1f5f9; - z-index: 50; - - &.collapsed { - width: 80px; - overflow: visible; - - .sidebar-header { - padding: 16px 0; - justify-content: center; - } - - .nav-item { - justify-content: center; - padding: 12px; - border-radius: 8px; - margin: 0 12px; - - span { - display: none; - } - - // 折叠状态下显示 tooltip - &:hover .nav-tooltip { - opacity: 1; - visibility: visible; - } - } - - .user-section { - justify-content: center; - padding: 16px; - - .user-info, .user-more { - display: none; - } - } - } -} - -// 侧边栏头部 -.sidebar-header { - height: 64px; - padding: 0 16px; - margin-bottom: 8px; - display: flex; - align-items: center; - justify-content: space-between; - user-select: none; -} - -.collapse-btn { - width: 32px; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 8px; - cursor: pointer; - color: #94a3b8; - background: transparent; - border: none; - transition: all 0.2s; - flex-shrink: 0; - - &:hover { - background: #f1f5f9; - color: #64748b; - } - - .el-icon { - font-size: 18px; - } -} - -.logo-img { - height: 32px; - width: 100%; - border-radius: 8px; - object-fit: contain; -} -.logo { - display: flex; - align-items: center; - gap: 8px; - - .logo-text { - font-size: 16px; - font-weight: 600; - color: #1e293b; - letter-spacing: -0.02em; - } -} - -// 折叠状态下的 Logo(可点击展开) -.logo-collapsed { - position: relative; - display: flex; - justify-content: center; - cursor: pointer; - padding: 8px; - border-radius: 12px; - transition: all 0.2s; - - &:hover { - background: #f1f5f9; - - .logo-tooltip { - opacity: 1; - visibility: visible; - } - } - - .logo-img { - width: 100%; - height: 32px; - border-radius: 8px; - object-fit: contain; - } - - .logo-tooltip { - position: absolute; - left: 50%; - top: calc(100% + 8px); - transform: translateX(-50%); - background: #1e293b; - color: #fff; - padding: 8px 16px; - border-radius: 8px; - font-size: 13px; - font-weight: 600; - white-space: nowrap; - z-index: 100; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); - opacity: 0; - visibility: hidden; - transition: all 0.2s; - pointer-events: none; - - .tooltip-arrow { - position: absolute; - left: 50%; - bottom: 100%; - transform: translateX(-50%); - border: 6px solid transparent; - border-bottom-color: #1e293b; - } - } -} - -// 导航菜单 -.nav-menu { - flex: 1; - // overflow-y: auto; - padding: 8px 12px; - - &::-webkit-scrollbar { - width: 4px; - } - - &::-webkit-scrollbar-thumb { - background: rgba(0, 0, 0, 0.1); - border-radius: 4px; - } - - &::-webkit-scrollbar-track { - background: transparent; - } -} - -.nav-section { - padding: 0; -} - -.nav-item { - position: relative; - display: flex; - align-items: center; - gap: 12px; - padding: 12px 16px; - margin-bottom: 2px; - border-radius: 8px; - cursor: pointer; - transition: all 0.2s ease; - color: #64748b; - font-size: 14px; - font-weight: 500; - - &:hover { - background: $brand-color-light; - color: $brand-color; - } - - &.active { - background: $brand-color; - color: #fff; - box-shadow: 0 4px 12px rgba($brand-color, 0.25); - - .el-icon { - color: #fff; - } - } - - .el-icon { - font-size: 18px; - flex-shrink: 0; - transition: color 0.2s; - } - - span { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - // 折叠时的 Tooltip - .nav-tooltip { - position: absolute; - left: calc(100% + 16px); - top: 50%; - transform: translateY(-50%); - background: #1e293b; - color: #fff; - padding: 6px 12px; - border-radius: 6px; - font-size: 12px; - white-space: nowrap; - z-index: 100; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - opacity: 0; - visibility: hidden; - transition: all 0.2s; - pointer-events: none; - - .tooltip-arrow { - position: absolute; - right: 100%; - top: 50%; - transform: translateY(-50%); - border: 5px solid transparent; - border-right-color: #1e293b; - } - } -} - -// 用户信息 -.user-section { - padding: 16px; - border-top: 1px solid #f1f5f9; - background: #f8fafc; - cursor: pointer; - transition: background 0.2s; - - &:hover { - background: #f1f5f9; - - .user-name { - color: $brand-color; - } - } - - .user-info-wrapper { - display: flex; - align-items: center; - gap: 12px; - } - - .user-avatar { - position: relative; - flex-shrink: 0; - - &::after { - content: ''; - position: absolute; - bottom: 0; - right: 0; - width: 10px; - height: 10px; - background: #22c55e; - border: 2px solid #fff; - border-radius: 50%; - } - } - - .user-info { - flex: 1; - min-width: 0; - } - - .user-name { - font-size: 14px; - font-weight: 500; - color: #374151; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - transition: color 0.2s; - } - - .user-more { - color: #94a3b8; - - &:hover { - color: #64748b; - } - } -} - -// ==================== 主内容区 ==================== -.main-content { - flex: 1; - height: 100%; - overflow: hidden; - background: #f8fafc; - position: relative; -} - -// iframe 容器 -.iframe-container { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - position: relative; -} - -.iframe-header { - height: 56px; - padding: 0 24px; - display: flex; - align-items: center; - justify-content: space-between; - border-bottom: 1px solid #e2e8f0; - background: #fff; - flex-shrink: 0; -} - -.iframe-title { - font-size: 16px; - font-weight: 600; - color: #1e293b; -} - -.content-iframe { - flex: 1; - width: 100%; - height: 100%; - border: none; - background: #fff; -} - -.iframe-loading { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - display: flex; - flex-direction: column; - align-items: center; - gap: 12px; - color: $brand-color; - font-size: 14px; - z-index: 10; - - .el-icon { - font-size: 32px; - } -} - -// ==================== 响应式 ==================== -@media (max-width: 768px) { - .sidebar { - width: 80px; - - &:not(.collapsed) { - width: 256px; - position: fixed; - left: 0; - top: 0; - z-index: 1000; - box-shadow: 4px 0 16px rgba(0, 0, 0, 0.1); - } - } - - .iframe-header { - padding: 0 16px; - - .iframe-title { - font-size: 14px; - } - } -} diff --git a/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/SidebarLayout.vue b/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/SidebarLayout.vue deleted file mode 100644 index 66bb27b1..00000000 --- a/urbanLifelineWeb/packages/platform/src/layouts/SidebarLayout/SidebarLayout.vue +++ /dev/null @@ -1,273 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/layouts/index.ts b/urbanLifelineWeb/packages/platform/src/layouts/index.ts deleted file mode 100644 index 2966e5b8..00000000 --- a/urbanLifelineWeb/packages/platform/src/layouts/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { default as SidebarLayout } from "./SidebarLayout/SidebarLayout.vue"; -export { default as AdminSidebarLayout } from "./AdminSidebarLayout/AdminSidebarLayout.vue"; -// BlankLayout从shared导入 -export { BlankLayout, SubSidebarLayout } from 'shared/layouts'; \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/main.ts b/urbanLifelineWeb/packages/platform/src/main.ts deleted file mode 100644 index 7049815f..00000000 --- a/urbanLifelineWeb/packages/platform/src/main.ts +++ /dev/null @@ -1,132 +0,0 @@ -console.log('📦 main.ts 模块开始加载...') - -import { createApp } from 'vue' -import { createPinia } from 'pinia' -import ElementPlus from 'element-plus' -import 'element-plus/dist/index.css' - -// 注意:shared 的样式现在通过 index.html 中的 标签加载 -// 不再需要在这里导入:import 'shared/styles' - -import App from './App.vue' -import router from './router/' -import { AES_SECRET_KEY } from './config' - -// 导入需要的 Lucide 图标(用于动态组件) -import { - MessageCircle, - LayoutGrid, - Workflow, - FileText, - Headphones, - BarChart3, - Users, - User, - Settings, - Home, - Ticket, - Bot, - ScrollText, - Monitor, - Server, - ChevronDown, - ChevronRight, - ChevronLeft, - PanelLeftClose, - PanelLeftOpen, - RefreshCw, - Loader, - LogOut, - Plus, - Trash2, - Clock, - Search, - AlertTriangle, - Wrench, - Paperclip, - Send, - History, - X, - Menu, - Zap -} from 'lucide-vue-next' - -// Lucide 图标映射(用于全局注册) -const lucideIcons = { - MessageCircle, - LayoutGrid, - Workflow, - FileText, - Headphones, - BarChart3, - Users, - User, - Settings, - Home, - Ticket, - Bot, - ScrollText, - Monitor, - Server, - ChevronDown, - ChevronRight, - ChevronLeft, - PanelLeftClose, - PanelLeftOpen, - RefreshCw, - Loader, - LogOut, - Plus, - Trash2, - Clock, - Search, - AlertTriangle, - Wrench, - Paperclip, - Send, - History, - X, - Menu, - Zap -} - -// 异步初始化应用 -async function initApp() { - // 1. 创建 Vue 应用 - const app = createApp(App) - - // 2. 注册 Pinia - const pinia = createPinia() - app.use(pinia) - - // 3. 注册 Element Plus - app.use(ElementPlus) - - // 4. 注册 Lucide 图标(用于动态组件) - for (const [name, component] of Object.entries(lucideIcons)) { - app.component(name, component) - } - - // 5. 注册路由 - app.use(router) - - // 6. 立即挂载应用(不等待 AES 初始化) - app.mount('#app') - - console.log('✅ Platform 应用启动成功') - - // 7. 后台初始化 AES 加密工具(不阻塞渲染) - try { - const { initAesEncrypt } = await import('shared/utils') - await initAesEncrypt(AES_SECRET_KEY) - console.log('✅ AES 加密工具初始化成功') - } catch (error) { - console.error('❌ AES 加密工具初始化失败:', error) - } -} - -// 启动应用 -console.log('🚀 开始初始化 Platform 应用...') -initApp().catch(error => { - console.error('❌ 应用初始化失败:', error) -}) diff --git a/urbanLifelineWeb/packages/platform/src/router/dynamicRoute.ts b/urbanLifelineWeb/packages/platform/src/router/dynamicRoute.ts deleted file mode 100644 index 75762d32..00000000 --- a/urbanLifelineWeb/packages/platform/src/router/dynamicRoute.ts +++ /dev/null @@ -1,180 +0,0 @@ -/** - * 动态路由生成模块(Platform 特定) - * - * 职责: - * 1. 提供 Platform 特定的布局和组件配置 - * 2. 调用 shared 中的通用路由生成方法 - * 3. 将生成的路由添加到 Platform 的 router 实例 - */ - -/// - -import type { RouteRecordRaw } from 'vue-router' -import router from './index' -import { SidebarLayout, AdminSidebarLayout } from '@/layouts' - -// 动态导入 shared 模块(避免顶层 import 阻塞) -async function loadSharedModules() { - const [routeUtils, types] = await Promise.all([ - import('shared/utils/route'), - import('shared/types') - ]) - return { routeUtils, types } -} - -// Platform 布局组件映射 -const platformLayoutMap: Record Promise> = { - 'SidebarLayout': () => Promise.resolve({ default: SidebarLayout }), - 'NavigationLayout': () => Promise.resolve({ default: SidebarLayout }), - 'BasicLayout': () => Promise.resolve({ default: SidebarLayout }), - 'AdminSidebarLayout': () => Promise.resolve({ default: AdminSidebarLayout }), - // 动态导入 shared 的布局组件,避免静态导入阻塞 - 'BlankLayout': () => import('shared/layouts').then(m => ({ default: m.BlankLayout })), - 'SubSidebarLayout': () => import('shared/layouts').then(m => ({ default: m.SubSidebarLayout })) -} - -// 视图组件加载器 -const VIEW_MODULES = import.meta.glob<{ default: any }>('@/views/**/*.vue') - -/** - * 视图组件加载函数 - * @param componentPath 组件路径(如 "public/Chat/AIChatView.vue") - */ -function viewLoader(componentPath: string): (() => Promise) | null { - // 将后台路径转换为 @/views 格式 - let path = componentPath - - // 移除开头的斜杠(如果有) - if (path.startsWith('/')) { - path = path.substring(1) - } - - // 补全 .vue 后缀(如果没有) - if (!path.endsWith('.vue')) { - path += '.vue' - } - - // 转换为 /src/views 格式(匹配 import.meta.glob 的 key) - const fullPath = `/src/views/${path}` - - console.log('[Platform viewLoader] 尝试加载组件:', componentPath, '→', fullPath) - - const loader = VIEW_MODULES[fullPath] - - if (!loader) { - console.warn('[Platform viewLoader] 组件未找到:', fullPath) - console.log('[Platform viewLoader] 可用的组件:', Object.keys(VIEW_MODULES)) - return null - } - - return loader as () => Promise -} - -// Platform 路由生成器配置 -const routeConfig: any = { - layoutMap: platformLayoutMap, - viewLoader, - notFoundComponent: () => Promise.resolve({ - default: { - template: '

404 - 页面未找到

' - } - }) -} - -// Platform 路由生成选项 -const routeOptions: any = { - asRootChildren: false, // 直接作为根级路由,不是某个布局的子路由 - iframePlaceholder: () => import('shared/components').then(m => ({ default: m.IframeView })), - verbose: true // 启用详细日志 -} - -/** - * 添加动态路由(Platform 特定) - * @param views 视图列表(用作菜单) - */ -export async function addDynamicRoutes(views: any[]) { - if (!views || views.length === 0) { - console.warn('[Platform] addDynamicRoutes: 视图列表为空') - return - } - - console.log('[Platform] addDynamicRoutes: 开始添加动态路由,视图数量:', views.length) - - try { - // 动态加载 shared 模块 - const { routeUtils } = await loadSharedModules() - const { generateSimpleRoutes } = routeUtils - - // 使用 shared 中的通用方法生成路由 - const routes = generateSimpleRoutes(views, routeConfig, routeOptions) - - // 直接将路由添加到根级别(不是作为Root的children) - routes.forEach(route => { - console.log('[Platform] addDynamicRoutes: 添加路由', route.path, '使用布局:', route.component?.name || 'unknown') - router.addRoute(route) - }) - - // 动态添加根路径重定向到第一个菜单项 - if (routes.length > 0) { - const firstRoute = routes[0] - router.addRoute({ - path: '/', - redirect: firstRoute.path - }) - console.log('[Platform] addDynamicRoutes: 添加根路径重定向到', firstRoute.path) - } - - } catch (error) { - console.error('[Platform] addDynamicRoutes: 添加路由失败', error) - throw error - } -} - -// ============================================ -// 以下为 Platform 特有的辅助函数 -// 通用的路由生成逻辑已迁移到 shared/utils/route -// ============================================ - -/** - * 从 LocalStorage 获取菜单并生成路由(Platform 特定) - * - * 使用 shared 中的通用 loadViewsFromStorage 方法 - */ -export async function loadRoutesFromStorage(): Promise { - try { - console.log('[Platform] loadRoutesFromStorage: 开始加载动态路由') - - // 动态加载 shared 模块 - const { routeUtils } = await loadSharedModules() - const { loadViewsFromStorage } = routeUtils - - // 使用 shared 中的通用方法加载视图数据 - const allViews = loadViewsFromStorage('loginDomain', 'userViews') - - console.log('[Platform] loadRoutesFromStorage: 加载的所有视图数量:', allViews?.length || 0) - - if (allViews) { - // 过滤出 platform 服务的视图 - const platformViews = allViews.filter((view: any) => - view.service === 'platform' - ) - - console.log('[Platform] loadRoutesFromStorage: 过滤后的 platform 视图:', platformViews) - - if (platformViews.length === 0) { - console.warn('[Platform] loadRoutesFromStorage: 没有找到 platform 服务的视图') - return false - } - - // 使用 Platform 的 addDynamicRoutes 添加路由 - await addDynamicRoutes(platformViews) - return true - } - - console.warn('[Platform] loadRoutesFromStorage: 未能加载视图数据') - return false - } catch (error) { - console.error('[Platform] loadRoutesFromStorage: 加载路由失败', error) - return false - } -} diff --git a/urbanLifelineWeb/packages/platform/src/router/index.ts b/urbanLifelineWeb/packages/platform/src/router/index.ts deleted file mode 100644 index a37e45bb..00000000 --- a/urbanLifelineWeb/packages/platform/src/router/index.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' -import { loadRoutesFromStorage } from './dynamicRoute' - -// 同步检查 token(用于非异步场景) -function hasTokenSync(): boolean { - try { - const token = localStorage.getItem('token') - return !!token - } catch { - return false - } -} - -// platform应用的动态路由会根据layout字段自动添加,不需要预定义Root布局 -// 参考 workcase 的方式:不预定义 404 路由,避免过早匹配 -const routes: RouteRecordRaw[] = [ - { - path: '/login', - name: 'Login', - component: () => import('@/views/public/Login/Login.vue'), - meta: { - title: '登录', - requiresAuth: false // 不需要登录 - } - } -] - -const router = createRouter({ - history: createWebHistory('/platform/'), - routes -}) - -// 标记动态路由是否已加载 -let dynamicRoutesLoaded = false - -// 路由守卫 -router.beforeEach(async (to, from, next) => { - console.log('[Platform Router] 路由守卫触发:', { - to: to.path, - from: from.path, - dynamicRoutesLoaded - }) - - // 设置页面标题 - if (to.meta.title) { - document.title = `${to.meta.title} - 泰豪电源 AI 数智化平台` - } - - // 检查是否需要登录(使用同步方法,避免阻塞) - const requiresAuth = to.meta.requiresAuth !== false // 默认需要登录 - const hasToken = hasTokenSync() - - if (requiresAuth && !hasToken) { - // 需要登录但未登录,跳转到登录页 - next({ - path: '/login', - query: { redirect: to.fullPath } // 保存原始路径 - }) - return - } - - if (to.path === '/login' && hasToken) { - // 已登录但访问登录页,跳转到首页 - next('/') - return - } - - // 如果已登录且动态路由未加载,先加载动态路由 - if (hasToken && !dynamicRoutesLoaded) { - console.log('[Platform Router] 开始加载动态路由...') - dynamicRoutesLoaded = true // 先设置标志,避免重复加载 - - try { - const loaded = await loadRoutesFromStorage() - - console.log('[Platform Router] 动态路由加载结果:', loaded) - - if (loaded) { - console.log('[Platform Router] 动态路由加载成功') - console.log('[Platform Router] 所有路由:', router.getRoutes().map(r => r.path)) - - if (to.path === '/') { - // 访问根路径,重定向到第一个可用路由 - const firstRoute = getFirstAvailableRoute() - if (firstRoute && firstRoute !== '/') { - console.log('[Platform Router] 根路径重定向到:', firstRoute) - next({ path: firstRoute, replace: true }) - return - } - } else { - // 动态路由加载成功,重新导航以匹配新添加的路由 - console.log('[Platform Router] 动态路由加载成功,重新导航到:', to.path) - next({ ...to, replace: true }) - return - } - } else { - console.warn('[Platform Router] 动态路由加载失败') - dynamicRoutesLoaded = false // 重置标志,允许下次重试 - } - } catch (error) { - console.error('[Platform Router] 加载动态路由失败:', error) - dynamicRoutesLoaded = false // 重置标志,允许下次重试 - } - } - - // 如果已登录且访问根路径,但动态路由已加载,重定向到第一个可用路由 - if (hasToken && to.path === '/' && dynamicRoutesLoaded) { - const firstRoute = getFirstAvailableRoute() - if (firstRoute && firstRoute !== '/') { - console.log('[Platform Router] 已登录访问根路径,重定向到:', firstRoute) - next({ path: firstRoute, replace: true }) - return - } - } - - console.log('[Platform Router] 继续正常导航') - next() -}) - -/** - * 获取第一个可用的路由路径 - */ -function getFirstAvailableRoute(): string | null { - try { - console.log('[Platform Router] 开始获取第一个可用路由...') - - const loginDomainStr = localStorage.getItem('loginDomain') - if (!loginDomainStr) { - console.warn('[Platform Router] localStorage 中没有 loginDomain') - return null - } - - const loginDomain = JSON.parse(loginDomainStr) - const userViews = loginDomain.userViews || [] - - console.log('[Platform Router] 所有用户视图:', userViews.length) - - // 过滤出 platform 服务的非 admin 视图 - // 注意:不限制 type,因为首页路由可能是 type=3(路由类型)而不是 type=1(菜单类型) - const platformViews = userViews.filter((view: any) => - view.service === 'platform' && - !view.url?.startsWith('/admin') && - view.url // 必须有 url 字段 - ) - - console.log('[Platform Router] Platform 服务视图:', platformViews) - - if (platformViews.length === 0) { - console.warn('[Platform Router] 没有找到 platform 服务的视图') - return null - } - - // 按 orderNum 排序 - platformViews.sort((a: any, b: any) => (a.orderNum || 0) - (b.orderNum || 0)) - - const firstRoute = platformViews[0].url - console.log('[Platform Router] 第一个路由:', firstRoute, '视图:', platformViews[0].name) - - return firstRoute - } catch (error) { - console.error('[Platform Router] 获取首页路由失败:', error) - return null - } -} - -// 导出动态路由生成函数 -export { addDynamicRoutes, loadRoutesFromStorage } from './dynamicRoute' - -// 重置动态路由加载状态(用于登录后重新加载) -export function resetDynamicRoutes() { - dynamicRoutesLoaded = false -} - -export default router diff --git a/urbanLifelineWeb/packages/platform/src/types/shared.d.ts b/urbanLifelineWeb/packages/platform/src/types/shared.d.ts deleted file mode 100644 index 0e142e0b..00000000 --- a/urbanLifelineWeb/packages/platform/src/types/shared.d.ts +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Shared Module Federation 类型声明 - * 用于 TypeScript 识别远程模块 - */ - -// ========== 组件模块 ========== -declare module 'shared/components' { - export const FileUpload: any - export const FileHistory: any - export const DynamicFormItem: any - export const IframeView: any -} - -declare module 'shared/components/file/FileUpload' { - import { DefineComponent } from 'vue' - const FileUpload: DefineComponent<{}, {}, any> - export default FileUpload -} -declare module 'shared/components/file/FileHistory' { - import { DefineComponent } from 'vue' - const FileHistory: DefineComponent<{}, {}, any> - export default FileHistory -} - -declare module 'shared/components/DynamicFormItem' { - import { DefineComponent } from 'vue' - const DynamicFormItem: DefineComponent<{}, {}, any> - export default DynamicFormItem -} - -declare module 'shared/components/iframe/IframeView.vue' { - import { DefineComponent } from 'vue' - const IframeView: DefineComponent<{}, {}, any> - export default IframeView -} - -declare module 'shared/components/ai/knowledge/DocumentSegment.vue' { - import { DefineComponent } from 'vue' - const DocumentSegment: DefineComponent<{}, {}, any> - export default DocumentSegment -} - -declare module 'shared/components/ai/knowledge/DocumentDetail.vue' { - import { DefineComponent } from 'vue' - const DocumentDetail: DefineComponent<{}, {}, any> - export default DocumentDetail -} - - -// ========== API 模块 ========== -declare module 'shared/api' { - import type { AxiosResponse, AxiosRequestConfig } from 'axios' - - interface ApiInstance { - get(url: string,data?: any, config?: AxiosRequestConfig): Promise> - post(url: string, data?: any, config?: AxiosRequestConfig): Promise> - put(url: string, data?: any, config?: AxiosRequestConfig): Promise> - delete(url: string, config?: AxiosRequestConfig): Promise> - uploadPut(url: string, data: FormData, config?: AxiosRequestConfig): Promise> - } - - export const api: ApiInstance - export const TokenManager: any -} - -declare module 'shared/api/auth' { - export const authAPI: any -} - -declare module 'shared/api/file' { - export const fileAPI: any -} - -declare module 'shared/api/ai' { - export const agentAPI: any - export const aiKnowledgeAPI: any - export const aiChatAPI: any -} - -// ============ types模块 ================== -declare module 'shared/types' { - // 基础类型 - export interface OrderField { - field: string - order: 'ASC' | 'DESC' - } - - export interface BaseDTO { - optsn?: string - creator?: string - updater?: string - deptPath?: string - remark?: string - createTime?: string - updateTime?: string - deleteTime?: string - deleted?: boolean - limit?: number - startTime?: string - endTime?: string - orderFields?: OrderField[] - } - - export interface BaseVO extends BaseDTO { - id?: string - creatorName?: string - updaterName?: string - } - - // 重新导出 response - export type { ResultDomain } from '../../../shared/src/types/response' - - // 重新导出 page - export type { PageDomain, PageParam, PageRequest } from '../../../shared/src/types/page' - - // 重新导出 auth - export type { LoginParam, LoginDomain } from '../../../shared/src/types/auth' - - // 重新导出 sys - export type { SysUserVO, SysConfigVO, TbSysViewDTO } from '../../../shared/src/types/sys' - - // 重新导出 file - export type { TbSysFileDTO } from '../../../shared/src/types/file' - - // 重新导出 ai - export type { - TbKnowledge, - TbKnowledgeFile, - TbAgent, - PromptCard, - TbChat, - TbChatMessage, - DifyFileInfo, - ChatPrepareData, - CreateChatParam, - StopChatParam, - CommentMessageParam, - ChatListParam, - ChatMessageListParam, - SSEMessageData, - SSECallbacks, - SSETask, - TbKnowledgeFileLog - } from '../../../shared/src/types/ai' - - // 重新导出 menu - export type { MenuItem, toMenuItem, toMenuItems } from '../../../shared/src/types/menu' -} - -// ================ utils工具 ========================== -declare module 'shared/utils' { - export const initAesEncrypt: any - export const getAesInstance: any - export const formatFileSize: any - export const isImageFile: any - export const getFileTypeIcon: any - export const isValidFileType: any - export const getFilePreviewUrl: any -} - -declare module 'shared/utils/route' { - import { RouteRecordRaw } from 'vue-router' - import type { TbSysViewDTO } from 'shared/types' - - export interface RouteGeneratorConfig { - layoutMap: Record Promise> - viewLoader: (componentPath: string) => (() => Promise) | null - staticRoutes?: RouteRecordRaw[] - notFoundComponent?: () => Promise - } - - export interface GenerateSimpleRoutesOptions { - asRootChildren?: boolean - iframePlaceholder?: () => Promise - verbose?: boolean - } - - export function generateRoutes( - views: TbSysViewDTO[], - config: RouteGeneratorConfig - ): RouteRecordRaw[] - - export function generateSimpleRoutes( - views: TbSysViewDTO[], - config: RouteGeneratorConfig, - options?: GenerateSimpleRoutesOptions - ): RouteRecordRaw[] - - export function buildMenuTree( - views: TbSysViewDTO[], - staticRoutes?: RouteRecordRaw[] - ): TbSysViewDTO[] - - export function filterMenusByPermissions( - views: TbSysViewDTO[], - permissions: string[] - ): TbSysViewDTO[] - - export function findMenuByPath( - views: TbSysViewDTO[], - path: string - ): TbSysViewDTO | null - - export function getMenuPath( - views: TbSysViewDTO[], - targetViewId: string - ): TbSysViewDTO[] - - export function getFirstAccessibleMenuUrl( - views: TbSysViewDTO[] - ): string | null - - export function loadViewsFromStorage( - storageKey?: string, - viewsPath?: string - ): TbSysViewDTO[] | null -} - -declare module 'shared/utils/device' { - export enum DeviceType { - MOBILE = 'mobile', - DESKTOP = 'desktop' - } - - export function getDeviceType(): DeviceType - export function isMobile(): boolean - export function isDesktop(): boolean - export function useDevice(): any -} - -// ========== Layouts 布局模块 ========== -declare module 'shared/layouts' { - import { DefineComponent } from 'vue' - - export const BlankLayout: DefineComponent<{}, {}, any> - export const SubSidebarLayout: DefineComponent<{}, {}, any> -} diff --git a/urbanLifelineWeb/packages/platform/src/views/admin/overview/OverviewView.scss b/urbanLifelineWeb/packages/platform/src/views/admin/overview/OverviewView.scss deleted file mode 100644 index 8b137891..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/admin/overview/OverviewView.scss +++ /dev/null @@ -1 +0,0 @@ - diff --git a/urbanLifelineWeb/packages/platform/src/views/admin/overview/OverviewView.vue b/urbanLifelineWeb/packages/platform/src/views/admin/overview/OverviewView.vue deleted file mode 100644 index e0a2c51d..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/admin/overview/OverviewView.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/views/admin/userManagement/UserManagementView.scss b/urbanLifelineWeb/packages/platform/src/views/admin/userManagement/UserManagementView.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/urbanLifelineWeb/packages/platform/src/views/admin/userManagement/UserManagementView.vue b/urbanLifelineWeb/packages/platform/src/views/admin/userManagement/UserManagementView.vue deleted file mode 100644 index d249c512..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/admin/userManagement/UserManagementView.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Agents/AgentPlatformView.scss b/urbanLifelineWeb/packages/platform/src/views/public/Agents/AgentPlatformView.scss deleted file mode 100644 index 140bdd06..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Agents/AgentPlatformView.scss +++ /dev/null @@ -1,68 +0,0 @@ -.apps-view { - padding: 32px 48px; - height: 100%; - overflow-y: auto; - background: #f9fafb; -} - -.page-header { - margin-bottom: 24px; - - h1 { - font-size: 24px; - color: #1f2937; - margin-bottom: 8px; - } - - p { - color: #6b7280; - font-size: 14px; - } -} - -.toolbar-section { - display: flex; - justify-content: space-between; - align-items: center; - gap: 16px; - margin-bottom: 24px; - - .search-input { - max-width: 400px; - } -} - -.category-tabs { - display: flex; - gap: 8px; - margin-bottom: 24px; - flex-wrap: wrap; - - .tab-item { - padding: 8px 20px; - border-radius: 20px; - font-size: 14px; - color: #6b7280; - background: #fff; - border: 1px solid #e5e7eb; - cursor: pointer; - transition: all 0.2s; - - &:hover { - color: #0055AA; - border-color: #0055AA; - } - - &.active { - color: #fff; - background: #0055AA; - border-color: #0055AA; - } - } -} - -.agents-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 20px; -} diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Agents/AgentPlatformView.vue b/urbanLifelineWeb/packages/platform/src/views/public/Agents/AgentPlatformView.vue deleted file mode 100644 index 30025adc..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Agents/AgentPlatformView.vue +++ /dev/null @@ -1,256 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Agents/README.md b/urbanLifelineWeb/packages/platform/src/views/public/Agents/README.md deleted file mode 100644 index d8911988..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Agents/README.md +++ /dev/null @@ -1,259 +0,0 @@ -# 智能体平台 AgentPlatformView - -## 功能概览 - -完整的智能体管理平台,支持浏览、搜索、分类、新增和编辑智能体。 - -## 文件结构 - -``` -Agents/ -├── AgentPlatformView.vue # 主视图组件 -├── AgentPlatformView.scss # 主视图样式 -├── components/ -│ ├── AgentCard/ # 智能体卡片组件 -│ │ ├── AgentCard.vue -│ │ └── AgentCard.scss -│ └── AgentEdit/ # 智能体编辑对话框组件 -│ ├── AgentEdit.vue -│ └── AgentEdit.scss -└── README.md # 本文档 -``` - -## 核心功能 - -### 1. 智能体展示 -- ✅ 网格布局展示智能体卡片 -- ✅ 显示图标/图片、名称、描述、使用次数 -- ✅ 支持点击跳转到聊天页面 -- ✅ 悬停动画效果 - -### 2. 搜索和筛选 -- ✅ 搜索框实时搜索(名称/描述) -- ✅ 分类标签筛选(全部/内容创作/办公助手/业务助手/城市生命线) -- ✅ 组合搜索和分类筛选 - -### 3. 智能体管理 -- ✅ 新增智能体 -- ✅ 编辑智能体(预留接口) -- ✅ 图片上传(支持预览) -- ✅ 表单验证 - -### 4. 高级配置 -- ✅ API 链接配置 -- ✅ Dify API Key 配置 -- ✅ 自定义引导词 -- ✅ 提示卡片配置(最多3个) - -## Mock 数据 - -### 智能体列表 -```typescript -[ - { - id: 'default', - name: '城市生命线助手', - description: '智能城市基础设施安全管理...', - icon: '🏙️', - color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', - category: 'lifeline', - usage: 15680 - }, - // ... 其他智能体 -] -``` - -### 分类列表 -- **all**: 全部 -- **content**: 内容创作 -- **office**: 办公助手 -- **business**: 业务助手 -- **lifeline**: 城市生命线 - -## 组件说明 - -### AgentPlatformView(主视图) -主要功能: -- 展示智能体网格 -- 搜索和分类筛选 -- 调用子组件 - -Props: 无 - -Events: 无 - -### AgentCard(卡片组件) -显示单个智能体信息 - -Props: -- `agent`: Agent - 智能体数据 - -Events: -- `click`: () => void - 卡片点击事件 - -### AgentEdit(编辑对话框) -智能体新增/编辑表单 - -Props: -- `modelValue`: boolean - 对话框显示状态 -- `agent?`: Agent | null - 编辑的智能体数据(null 为新增模式) - -Events: -- `update:modelValue`: (value: boolean) => void - 更新显示状态 -- `save`: (data: Partial) => void - 保存事件 - -## 数据接口 - -### Agent 类型定义 -```typescript -interface Agent { - id?: string - name: string - description: string - icon?: string - imageUrl?: string - color?: string - category: string - usage?: number - apiUrl?: string - difyApiKey?: string - welcomeMessage?: string - suggestions?: string[] -} -``` - -## 接入真实 API - -### 1. 加载智能体列表 -在 `AgentPlatformView.vue` 的 `onMounted` 中: - -```typescript -import { onMounted } from 'vue' -import { agentAPI } from '@/api/agent' - -onMounted(async () => { - try { - const data = await agentAPI.getList() - agents.value = data - } catch (error) { - console.error('加载失败:', error) - ElMessage.error('加载智能体列表失败') - } -}) -``` - -### 2. 创建智能体 -在 `handleSaveAgent` 函数中(新增时): - -```typescript -const newAgent = await agentAPI.create(agentData) -agents.value.unshift(newAgent) -ElMessage.success('智能体创建成功') -``` - -### 3. 更新智能体 -在 `handleSaveAgent` 函数中(编辑时): - -```typescript -await agentAPI.update(editingAgent.value.id, agentData) -const index = agents.value.findIndex(a => a.id === editingAgent.value!.id) -if (index > -1) { - agents.value[index] = { ...agents.value[index], ...agentData } -} -ElMessage.success('智能体更新成功') -``` - -### 4. 图片上传 -在 `AgentEdit.vue` 的 `handleFileChange` 中: - -```typescript -const uploadedUrl = await uploadAPI.upload(file) -formData.value.imageUrl = uploadedUrl -``` - -## 路由配置 - -```typescript -{ - path: '/agents', - name: 'Agents', - component: () => import('@/views/public/Agents/AgentPlatformView.vue'), - meta: { - title: '智能体平台' - } -} -``` - -## 样式特点 - -### 设计风格 -- 网格响应式布局(auto-fill, minmax(280px, 1fr)) -- 现代卡片设计 -- 流畅动画效果 -- 渐变色支持 - -### 主题色 -- 主色调:紫色 `#7c3aed` -- 背景色:浅灰 `#f9fafb` -- 边框色:`#e5e7eb` -- 文字色:`#1f2937` - -### 动画效果 -- 卡片悬停:上移4px + 阴影 -- 分类标签:颜色渐变 -- 上传区域:边框颜色变化 - -## 依赖 - -- Vue 3 -- Element Plus -- TypeScript -- Vue Router - -## 注意事项 - -1. 所有字段使用 4 个空格缩进(符合用户规则) -2. Mock 数据在组件内,便于测试 -3. 已预留 API 接口位置,用 TODO 标注 -4. **图片上传使用 FileUpload 组件的 cover 模式** - - 智能体封面:120x120 像素,最大 5MB - - 提示词图标:60x60 像素,最大 2MB - - 自动上传到服务器,返回 URL -5. 表单验证在保存时进行 -6. 提示词最多3个,动态添加/删除 -7. **依赖 shared 包的 FileUpload 组件**(需确保正确配置) - -## 待优化功能 - -- [ ] 智能体删除功能 -- [ ] 智能体排序功能 -- [ ] 批量操作 -- [ ] 智能体详情页 -- [ ] 统计数据展示 -- [ ] 导入/导出功能 -- [ ] 权限控制 - -## API 接口设计建议 - -```typescript -// agent API -export const agentAPI = { - // 获取列表 - async getList(params?: { - category?: string - keyword?: string - }): Promise {}, - - // 创建 - async create(data: Partial): Promise {}, - - // 更新 - async update(id: string, data: Partial): Promise {}, - - // 删除 - async delete(id: string): Promise {}, - - // 获取详情 - async getDetail(id: string): Promise {} -} -``` diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentCard/AgentCard.scss b/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentCard/AgentCard.scss deleted file mode 100644 index 37be7b73..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentCard/AgentCard.scss +++ /dev/null @@ -1,69 +0,0 @@ -.agent-card { - background: #fff; - border: 1px solid #e5e7eb; - border-radius: 16px; - padding: 24px; - cursor: pointer; - transition: all 0.3s ease; - - &:hover { - border-color: #0055AA; - box-shadow: 0 8px 24px rgba(0, 85, 170, 0.12); - transform: translateY(-4px); - } - - .card-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - margin-bottom: 16px; - - .agent-icon { - width: 52px; - height: 52px; - border-radius: 14px; - display: flex; - align-items: center; - justify-content: center; - font-size: 26px; - overflow: hidden; - - img { - width: 100%; - height: 100%; - object-fit: cover; - } - } - } - - .agent-name { - font-size: 17px; - font-weight: 600; - color: #1f2937; - margin-bottom: 8px; - } - - .agent-desc { - font-size: 13px; - color: #6b7280; - line-height: 1.6; - margin-bottom: 16px; - display: -webkit-box; - -webkit-line-clamp: 2; - line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - min-height: 40px; - } - - .card-footer { - display: flex; - justify-content: space-between; - align-items: center; - - .usage-count { - font-size: 12px; - color: #9ca3af; - } - } -} diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentCard/AgentCard.vue b/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentCard/AgentCard.vue deleted file mode 100644 index d561c5c6..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentCard/AgentCard.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentEdit/AgentEdit.scss b/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentEdit/AgentEdit.scss deleted file mode 100644 index 0e20e8d4..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentEdit/AgentEdit.scss +++ /dev/null @@ -1,88 +0,0 @@ -.agent-cover-upload { - width: 120px; - height: 120px; - - :deep(.area.cover) { - border-radius: 12px; - } - - :deep(.image-wrapper) { - border-radius: 12px; - } - - :deep(.image) { - border-radius: 12px; - } -} - -.suggestions-input { - display: flex; - flex-direction: column; - gap: 12px; - - .suggestion-card-item { - display: flex; - align-items: center; - gap: 12px; - - .card-icon-upload { - flex-shrink: 0; - width: 80px !important; - height: 32px !important; - - :deep(.file-upload.cover) { - width: 80px !important; - height: 32px !important; - } - - :deep(.area.cover) { - width: 80px !important; - height: 32px !important; - padding: 0 !important; - min-height: unset !important; - display: flex !important; - align-items: center !important; - justify-content: center !important; - - .content { - padding: 0; - margin: 0; - width: auto; - height: auto; - } - - .text, - .tip { - display: none; - } - - .icon { - margin: 0 !important; - - .plus { - width: 16px; - height: 16px; - - &::before { - width: 1px; - height: 16px; - } - - &::after { - width: 16px; - height: 1px; - } - } - } - } - } - - .card-text-input { - flex: 1; - } - - .delete-btn { - flex-shrink: 0; - } - } -} diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentEdit/AgentEdit.vue b/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentEdit/AgentEdit.vue deleted file mode 100644 index 9c2c1285..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Agents/components/AgentEdit/AgentEdit.vue +++ /dev/null @@ -1,252 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Chat/AIChatView.scss b/urbanLifelineWeb/packages/platform/src/views/public/Chat/AIChatView.scss deleted file mode 100644 index f8ec433a..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Chat/AIChatView.scss +++ /dev/null @@ -1,386 +0,0 @@ -.chat-view { - display: flex; - flex-direction: row; - height: 100%; - background: #fff; - position: relative; -} - -// 左侧侧边栏样式 - ChatGPT Style -.chat-sidebar { - width: 260px; - background: #f7f7f8; - border-right: 1px solid #e5e7eb; - display: flex; - flex-direction: column; - transition: width 0.3s ease; - - &.collapsed { - width: 60px; - - .new-chat-btn { - padding: 10px; - justify-content: center; - } - } - - .sidebar-header { - padding: 12px; - display: flex; - flex-direction: column; - gap: 8px; - border-bottom: 1px solid #e5e7eb; - } - - .new-chat-btn { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - padding: 10px 16px; - background: #fff; - border: 1px solid #e5e7eb; - border-radius: 8px; - font-size: 14px; - color: #374151; - cursor: pointer; - transition: all 0.2s; - - &:hover { - background: #f3f4f6; - border-color: #0055AA; - color: #0055AA; - } - } - - .collapse-toggle { - width: 100%; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - padding: 10px 16px; - background: #fff; - border: 1px solid #e5e7eb; - border-radius: 8px; - font-size: 14px; - color: #6b7280; - cursor: pointer; - transition: all 0.2s; - - &:hover { - background: #f3f4f6; - color: #0055AA; - } - } - - .conversations-list { - flex: 1; - overflow-y: auto; - padding: 12px 8px; - } - - .list-section { - margin-bottom: 16px; - - .section-title { - padding: 8px 12px; - font-size: 12px; - color: #9ca3af; - font-weight: 500; - } - } - - .conversation-item { - display: flex; - align-items: center; - gap: 10px; - padding: 10px 12px; - border-radius: 8px; - cursor: pointer; - transition: all 0.2s; - color: #374151; - - &:hover { - background: #e5e7eb; - - .conv-actions { - opacity: 1; - } - } - - &.active { - background: #e5e7eb; - } - - .conv-title { - flex: 1; - font-size: 14px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .conv-actions { - opacity: 0; - display: flex; - gap: 4px; - transition: opacity 0.2s; - - .action-icon { - padding: 4px; - border-radius: 4px; - color: #6b7280; - - &:hover { - background: #d1d5db; - color: #ef4444; - } - } - } - } -} - -// 主聊天区域 -.chat-main { - flex: 1; - display: flex; - flex-direction: column; - min-width: 0; -} - -.chat-header { - padding: 16px 24px; - border-bottom: 1px solid #e5e7eb; - - .agent-dropdown { - cursor: pointer; - } - - .header-title { - display: flex; - align-items: center; - gap: 8px; - font-size: 16px; - font-weight: 500; - color: #374151; - cursor: pointer; - padding: 8px 12px; - border-radius: 8px; - transition: all 0.2s; - - &:hover { - background: #f3f4f6; - color: #0055AA; - } - - .agent-icon { - font-size: 20px; - } - } -} - -.dropdown-agent-icon { - margin-right: 8px; - font-size: 16px; -} - -:deep(.el-dropdown-menu__item.is-active) { - background: rgba(0, 85, 170, 0.1); - color: #0055AA; -} - -.chat-content { - flex: 1; - overflow-y: auto; - padding: 40px 80px; -} - -.welcome-section { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 400px; -} - -.messages-container { - display: flex; - flex-direction: column; - gap: 24px; - - .message { - display: flex; - gap: 12px; - - &.user { - flex-direction: row-reverse; - - .message-content { - align-items: flex-end; - - .message-text { - background: #0055AA; - color: #fff; - } - } - } - - .message-avatar { - flex-shrink: 0; - - .ai-avatar-small { - width: 40px; - height: 40px; - border-radius: 10px; - object-fit: contain; - background: #f3f4f6; - padding: 4px; - } - - .user-avatar-small { - width: 40px; - height: 40px; - background: #e5e7eb; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 18px; - } - } - - .message-content { - display: flex; - flex-direction: column; - gap: 4px; - max-width: 70%; - - .message-text { - padding: 12px 16px; - background: #f3f4f6; - border-radius: 12px; - color: #1f2937; - line-height: 1.6; - white-space: pre-wrap; - } - - .message-time { - font-size: 12px; - color: #9ca3af; - padding: 0 4px; - } - } - } -} - -.typing-indicator { - display: flex; - gap: 4px; - padding: 16px; - - span { - width: 8px; - height: 8px; - background: #9ca3af; - border-radius: 50%; - animation: typing 1.4s infinite ease-in-out both; - - &:nth-child(1) { animation-delay: -0.32s; } - &:nth-child(2) { animation-delay: -0.16s; } - } -} - -@keyframes typing { - 0%, 80%, 100% { - transform: scale(0.6); - opacity: 0.5; - } - 40% { - transform: scale(1); - opacity: 1; - } -} - -.input-area { - padding: 20px 80px 30px; - background: #fff; - - .input-wrapper { - background: #f9fafb; - border: 1px solid #e5e7eb; - border-radius: 12px; - padding: 12px 16px; - - textarea { - width: 100%; - border: none; - background: transparent; - resize: none; - outline: none; - font-size: 14px; - color: #1f2937; - min-height: 24px; - max-height: 120px; - - &::placeholder { - color: #9ca3af; - } - } - - .input-actions { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 12px; - - .action-buttons, .send-actions { - display: flex; - gap: 8px; - } - - .action-btn { - width: 32px; - height: 32px; - border-radius: 8px; - display: flex; - align-items: center; - justify-content: center; - color: #6b7280; - transition: all 0.2s; - border: none; - background: transparent; - cursor: pointer; - - &:hover { - background: #e5e7eb; - color: #374151; - } - } - - .send-btn { - width: 36px; - height: 36px; - background: #0055AA; - border-radius: 8px; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - transition: all 0.2s; - border: none; - cursor: pointer; - - &:hover:not(:disabled) { - background: #004488; - } - - &:disabled { - background: #d1d5db; - cursor: not-allowed; - } - } - } - } -} diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Chat/AIChatView.vue b/urbanLifelineWeb/packages/platform/src/views/public/Chat/AIChatView.vue deleted file mode 100644 index 2c4958e8..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Chat/AIChatView.vue +++ /dev/null @@ -1,427 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Chat/README.md b/urbanLifelineWeb/packages/platform/src/views/public/Chat/README.md deleted file mode 100644 index 621bbbf7..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Chat/README.md +++ /dev/null @@ -1,176 +0,0 @@ -# AI 聊天界面组件 - -## 功能概览 - -完整的 AI 聊天界面实现,包含侧边栏对话历史、智能体切换、消息交互等功能。 - -## 文件结构 - -``` -Chat/ -├── AIChatView.vue # 主聊天界面组件 -├── AIChatView.scss # 主界面样式 -├── components/ -│ ├── ChatDefault/ # 欢迎界面组件 -│ │ ├── ChatDefault.vue -│ │ └── ChatDefault.scss -│ └── ChatHistory/ # 历史记录组件(预留) -│ ├── ChatHistory.vue -│ └── ChatHistory.scss -└── README.md # 本文档 -``` - -## 核心功能 - -### 1. 侧边栏功能 -- ✅ 对话历史列表(今天/历史记录分组) -- ✅ 新建对话 -- ✅ 删除对话 -- ✅ 侧边栏收起/展开 - -### 2. 智能体系统 -- ✅ 多智能体支持(城市生命线、应急处理、数据分析、安全检查) -- ✅ 智能体切换(下拉选择) -- ✅ 每个智能体独立的欢迎信息和建议 - -### 3. 消息交互 -- ✅ 消息发送/接收 -- ✅ 用户/AI 消息区分显示 -- ✅ 打字中动画效果 -- ✅ 消息时间显示 -- ✅ 自动滚动到底部 - -### 4. 输入功能 -- ✅ 多行文本输入 -- ✅ Enter 发送(Shift+Enter 换行) -- ✅ 附件、表情、图片等功能按钮(UI 已实现) -- ✅ 发送按钮禁用状态 - -## Mock 数据 - -### 智能体列表 -```typescript -[ - { - id: 'default', - name: '城市生命线助手', - icon: '🏙️', - color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', - description: '我是城市生命线智能助手,专注于城市基础设施安全管理' - }, - // ... 其他智能体 -] -``` - -### Mock API 响应 -发送消息后,系统会在 1-2 秒后返回随机的 Mock 响应: -- "根据城市生命线安全管理的相关规定,我为您分析如下..." -- "这是一个很好的问题。让我详细为您解答..." -- "基于您的需求,我建议采取以下措施..." -- "从专业角度来看,这个问题需要综合考虑多个因素..." - -## 样式特点 - -### 设计风格 -- ChatGPT 风格的侧边栏布局 -- 现代简约的配色方案 -- 流畅的动画效果 -- 响应式设计 - -### 主题色 -- 主色调:紫色 `#7c3aed` -- 背景色:灰白 `#f7f7f8` -- 边框色:浅灰 `#e5e7eb` -- 文字色:深灰 `#374151` - -## 使用方式 - -### 基本使用 -```vue - - - -``` - -### 集成到路由 -```typescript -{ - path: '/chat', - name: 'Chat', - component: () => import('@/views/public/Chat/AIChatView.vue') -} -``` - -## 后续接入真实 API - -### 修改发送消息函数 -在 `AIChatView.vue` 中找到 `handleSend` 函数,将 Mock 实现替换为真实 API 调用: - -```typescript -// 替换这部分 Mock 代码 -setTimeout(async () => { - const mockResponses = [...] - // ... -}, 1000) - -// 改为真实 API 调用 -try { - const response = await chatAPI.sendMessage({ - message: text, - agentId: currentAgent.value.id, - conversationId: currentConversationId.value - }) - - const assistantMessage: Message = { - id: response.id, - content: response.content, - role: 'assistant', - timestamp: response.timestamp - } - messages.value.push(assistantMessage) -} catch (error) { - console.error('发送失败:', error) -} -``` - -### 加载历史对话 -在 `onMounted` 中添加历史对话加载: - -```typescript -onMounted(async () => { - try { - const history = await chatAPI.getConversations() - conversations.value = history - } catch (error) { - console.error('加载历史失败:', error) - } -}) -``` - -## 依赖 - -- Vue 3 -- Element Plus -- TypeScript - -## 注意事项 - -1. 确保已安装 Element Plus 并正确配置图标 -2. `/logo.jpg` 需要存在于 public 目录 -3. 消息滚动使用了 `scrollTop`,需要在有高度的容器中使用 -4. 缩进使用 4 个空格(符合用户规则) - -## 待优化功能 - -- [ ] 消息流式输出 -- [ ] 代码块语法高亮 -- [ ] Markdown 渲染 -- [ ] 消息重新生成 -- [ ] 消息编辑 -- [ ] 导出对话记录 -- [ ] 附件上传功能实现 -- [ ] 语音输入功能实现 diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatDefault/ChatDefault.scss b/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatDefault/ChatDefault.scss deleted file mode 100644 index 763f8793..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatDefault/ChatDefault.scss +++ /dev/null @@ -1,82 +0,0 @@ -.chat-default { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - width: 100%; -} - -.ai-avatar { - width: 88px; - height: 88px; - margin-bottom: 24px; - - .avatar-icon { - width: 100%; - height: 100%; - border-radius: 16px; - display: flex; - align-items: center; - justify-content: center; - font-size: 40px; - color: #fff; - } -} - -.welcome-text { - color: #6b7280; - font-size: 14px; - margin-bottom: 12px; - text-align: center; -} - -.welcome-title { - font-size: 24px; - font-weight: 600; - color: #1f2937; - margin-bottom: 40px; - text-align: center; -} - -.suggestion-cards { - display: flex; - gap: 16px; - flex-wrap: wrap; - justify-content: center; - max-width: 800px; - - .suggestion-card { - width: 220px; - padding: 20px; - background: #f9fafb; - border: 1px solid #e5e7eb; - border-radius: 12px; - cursor: pointer; - transition: all 0.2s ease; - - &:hover { - border-color: #0055AA; - box-shadow: 0 4px 12px rgba(0, 85, 170, 0.15); - transform: translateY(-2px); - } - - .card-icon { - width: 40px; - height: 40px; - border-radius: 10px; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - font-size: 20px; - margin-bottom: 12px; - } - - .card-text { - color: #374151; - font-size: 14px; - line-height: 1.5; - margin: 0; - } - } -} diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatDefault/ChatDefault.vue b/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatDefault/ChatDefault.vue deleted file mode 100644 index 44d9d593..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatDefault/ChatDefault.vue +++ /dev/null @@ -1,109 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatHistory/ChatHistory.scss b/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatHistory/ChatHistory.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatHistory/ChatHistory.vue b/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatHistory/ChatHistory.vue deleted file mode 100644 index 2b0f0a77..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Chat/components/ChatHistory/ChatHistory.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Login/Login.vue b/urbanLifelineWeb/packages/platform/src/views/public/Login/Login.vue deleted file mode 100644 index f32aebb2..00000000 --- a/urbanLifelineWeb/packages/platform/src/views/public/Login/Login.vue +++ /dev/null @@ -1,274 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/platform/tsconfig.json b/urbanLifelineWeb/packages/platform/tsconfig.json deleted file mode 100644 index 86113252..00000000 --- a/urbanLifelineWeb/packages/platform/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "lib": ["ESNext", "DOM", "DOM.Iterable"], - "types": ["node"], - "jsx": "preserve", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "allowSyntheticDefaultImports": true, - "isolatedModules": true, - "noEmit": true, - "baseUrl": ".", - "paths": { - "@/*": ["src/*"] - } - }, - "include": [ - "src/**/*", - "*.ts", - "*.vue" - ], - "exclude": [ - "node_modules", - "dist" - ] -} diff --git a/urbanLifelineWeb/packages/platform/vite.config.ts b/urbanLifelineWeb/packages/platform/vite.config.ts deleted file mode 100644 index c08a8878..00000000 --- a/urbanLifelineWeb/packages/platform/vite.config.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import vueJsx from '@vitejs/plugin-vue-jsx' -import { federation } from '@module-federation/vite' -import { resolve, dirname } from 'path' -import { fileURLToPath } from 'url' -import fs from 'fs' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = dirname(__filename) - -// 开发环境 shared 模块地址 -const DEV_SHARED_URL = 'https://localhost:7000/shared/remoteEntry.js' -// 生产环境使用相对路径,通过 Nginx 代理访问 -const PROD_SHARED_URL = '/shared/remoteEntry.js' - -export default defineConfig(({ mode }) => { - const isDev = mode === 'development' - const sharedEntry = isDev ? DEV_SHARED_URL : PROD_SHARED_URL - - return { - base: '/platform/', - - plugins: [ - vue({ - script: { - defineModel: true, - propsDestructure: true - } - }), - vueJsx(), - federation({ - name: 'platform', - remotes: { - shared: { - type: 'module', - name: 'shared', - entry: sharedEntry - } - }, - shared: { - vue: {}, - 'vue-router': {}, - 'element-plus': {}, - axios: {} - } - }) - ], - - define: { - __VUE_OPTIONS_API__: true, - __VUE_PROD_DEVTOOLS__: true, - __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: true - }, - - resolve: { - alias: { - '@': resolve(__dirname, 'src') - } - }, - - server: { - port: 7001, - host: true, - cors: true, - open: '/', - https: (() => { - try { - return { - key: fs.readFileSync('C:/Users/FK05/443/localhost+3-key.pem'), - cert: fs.readFileSync('C:/Users/FK05/443/localhost+3.pem') - } - } catch { - return undefined - } - })(), - hmr: { - path: '/@vite/client', - port: 7001 - }, - proxy: { - '/api': { - target: 'http://localhost:8180', - changeOrigin: true, - rewrite: (path: string) => path.replace(/^\/api/, '') - } - } - }, - - build: { - target: 'esnext', - outDir: 'dist', - sourcemap: true - // 注意:不要使用 manualChunks 分割 vue/vue-router/element-plus - // 因为它们已经在 Module Federation 的 shared 中声明 - // 同时使用会导致循环依赖死锁 - }, - preview: { - port: 7001, - host: true, - cors: true, - https: (() => { - try { - return { - key: fs.readFileSync('C:/Users/FK05/443/localhost+3-key.pem'), - cert: fs.readFileSync('C:/Users/FK05/443/localhost+3.pem') - } - } catch { - return undefined - } - })(), - headers: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization' - } - } - } -}) diff --git a/urbanLifelineWeb/packages/shared/Dockerfile.dev b/urbanLifelineWeb/packages/shared/Dockerfile.dev deleted file mode 100644 index fa20972e..00000000 --- a/urbanLifelineWeb/packages/shared/Dockerfile.dev +++ /dev/null @@ -1,22 +0,0 @@ -FROM node:20-alpine - -# 安装 pnpm -RUN npm install -g pnpm@latest - -WORKDIR /app - -# 复制 package.json -COPY packages/shared/package.json ./ -COPY pnpm-lock.yaml pnpm-workspace.yaml ./ - -# 安装依赖 -RUN pnpm install --frozen-lockfile - -# 复制源代码 -COPY packages/shared/ ./ - -# 暴露端口 -EXPOSE 5000 - -# 开发模式启动(支持热更新) -CMD ["pnpm", "dev", "--host", "0.0.0.0"] diff --git a/urbanLifelineWeb/packages/shared/EXPOSES.md b/urbanLifelineWeb/packages/shared/EXPOSES.md deleted file mode 100644 index e279e897..00000000 --- a/urbanLifelineWeb/packages/shared/EXPOSES.md +++ /dev/null @@ -1,195 +0,0 @@ -# Shared 模块导出规范 - -## 导出路径组织 - -为了保持代码的清晰性和可维护性,shared 包的模块导出已按照功能分类组织。 - -### 组件模块 (Components) - -```typescript -// 整体导出 -import { FileUpload, DynamicFormItem } from 'shared/components' - -// 单独导入(推荐) -import FileUpload from 'shared/components/file/FileUpload' -import DynamicFormItem from 'shared/components/DynamicFormItem' -``` - -**可用组件:** -- `shared/components/file/FileUpload` - 文件上传组件(支持 cover/dialog/content 三种模式) -- `shared/components/DynamicFormItem` - 动态表单项组件 - ---- - -### API 模块 - -```typescript -// 整体导出 -import { api, TokenManager } from 'shared/api' - -// 单独导入(推荐) -import { authAPI } from 'shared/api/auth' -import { fileAPI } from 'shared/api/file' -``` - -**可用 API:** -- `shared/api` - API 基础模块和 TokenManager -- `shared/api/auth` - 认证相关 API -- `shared/api/file` - 文件管理 API - ---- - -### Utils 工具模块 - -```typescript -// 整体导出 -import { formatFileSize, isImageFile } from 'shared/utils' - -// 单独导入 -import { getDeviceType, isMobile } from 'shared/utils/device' -import { - generateSimpleRoutes, - loadViewsFromStorage, - buildMenuTree -} from 'shared/utils/route' -import { formatFileSize, isImageFile } from 'shared/utils/file' -``` - -**可用工具:** -- `shared/utils` - 通用工具函数集合 -- `shared/utils/device` - 设备检测工具 -- `shared/utils/route` - 路由生成和菜单构建工具 - - `generateSimpleRoutes()` - 生成简化路由(适合直接添加到 router) - - `loadViewsFromStorage()` - 从 localStorage 加载视图数据 - - `buildMenuTree()` - 构建菜单树结构 - - `generateRoutes()` - 生成完整路由配置 - - 更多工具函数... -- `shared/utils/file` - 文件处理工具 - ---- - -### Types 类型模块 - -```typescript -// 整体导出 -import type { LoginParam, TbSysViewDTO } from 'shared/types' - -// 单独导入 -import type { LoginParam, LoginDomain } from 'shared/types/auth' -import type { TbSysFileDTO } from 'shared/types/file' -import type { SysUserVO, SysConfigVO } from 'shared/types/sys' -``` - -**可用类型:** -- `shared/types` - 所有类型的统一导出 -- `shared/types/base` - 基础类型(BaseVO, BaseDTO 等) -- `shared/types/auth` - 认证相关类型 -- `shared/types/file` - 文件相关类型 -- `shared/types/sys` - 系统相关类型 - ---- - -## 向后兼容性 - -为了保持向后兼容,旧的导入路径仍然可用(但不推荐): - -```typescript -// ❌ 旧路径(不推荐,但仍可用) -import FileUpload from 'shared/FileUpload' -import { authAPI } from 'shared/authAPI' -import { fileAPI } from 'shared/fileAPI' - -// ✅ 新路径(推荐) -import FileUpload from 'shared/components/file/FileUpload' -import { authAPI } from 'shared/api/auth' -import { fileAPI } from 'shared/api/file' -``` - ---- - -## 最佳实践 - -### 1. 使用明确的路径 - -```typescript -// ✅ 推荐:路径清晰,便于理解 -import FileUpload from 'shared/components/file/FileUpload' -import { authAPI } from 'shared/api/auth' - -// ❌ 不推荐:路径模糊 -import FileUpload from 'shared/FileUpload' -``` - -### 2. 按需导入 - -```typescript -// ✅ 推荐:只导入需要的模块 -import { formatFileSize } from 'shared/utils/file' - -// ❌ 不推荐:导入整个模块 -import * as utils from 'shared/utils' -``` - -### 3. 使用类型导入 - -```typescript -// ✅ 推荐:明确标识类型导入 -import type { LoginParam } from 'shared/types/auth' -import { authAPI } from 'shared/api/auth' - -// ❌ 不推荐:混合导入 -import { LoginParam, authAPI } from 'shared/types' -``` - ---- - -## 添加新模块 - -如果需要添加新的导出模块,请按照以下步骤: - -1. **在 vite.config.ts 中添加导出** - ```typescript - exposes: { - './components/YourComponent': './src/components/yourcomponent/YourComponent.vue' - } - ``` - -2. **在 shared.d.ts 中添加类型声明** - ```typescript - declare module 'shared/components/YourComponent' { - import { DefineComponent } from 'vue' - const YourComponent: DefineComponent<{}, {}, any> - export default YourComponent - } - ``` - -3. **更新此文档** - ---- - -## 常见问题 - -### Q: TypeScript 报错找不到模块? -A: 尝试以下方法: -1. 重启 TypeScript 语言服务器(VS Code: `Ctrl+Shift+P` → Restart TS Server) -2. 确认 `shared.d.ts` 文件已正确更新 -3. 检查 shared 包是否已正确构建 - -### Q: 运行时找不到模块? -A: 确保: -1. shared 包已启动(`npm run dev` 在 shared 目录) -2. `vite.config.ts` 中的 exposes 配置正确 -3. Module Federation 配置正确加载 - -### Q: 如何查看所有可用模块? -A: 查看 `packages/shared/vite.config.ts` 的 `exposes` 配置 - ---- - -## 更新日志 - -### 2025-12-12 -- ✅ 重新组织导出路径,使用清晰的分类前缀 -- ✅ 添加向后兼容性支持 -- ✅ 更新类型声明文件 -- ✅ 添加更多常用模块导出 diff --git a/urbanLifelineWeb/packages/shared/ROUTE_REFACTOR.md b/urbanLifelineWeb/packages/shared/ROUTE_REFACTOR.md deleted file mode 100644 index f0104258..00000000 --- a/urbanLifelineWeb/packages/shared/ROUTE_REFACTOR.md +++ /dev/null @@ -1,287 +0,0 @@ -# 路由生成逻辑重构说明 - -## 重构目标 - -将 Platform 中的通用路由生成逻辑提取到 shared 包中,使其他 web 服务也可以复用。 - -## 架构设计 - -### 职责划分 - -**Shared 包(shared/utils/route)** -- ✅ 提供通用的路由生成方法 -- ✅ 提供视图树构建方法 -- ✅ 提供 localStorage 数据加载方法 -- ✅ 不依赖特定的 router 实例 -- ✅ 不依赖特定的组件加载方式 - -**Platform 包(platform/src/router/dynamicRoute.ts)** -- ✅ 提供 Platform 特定的布局组件映射 -- ✅ 提供 Platform 特定的组件加载器 -- ✅ 调用 shared 中的通用方法 -- ✅ 将生成的路由添加到 Platform 的 router 实例 - -## 核心方法 - -### Shared 包新增方法 - -#### 1. `generateSimpleRoutes()` -```typescript -export function generateSimpleRoutes( - views: TbSysViewDTO[], - config: RouteGeneratorConfig, - options?: GenerateSimpleRoutesOptions -): RouteRecordRaw[] -``` - -**功能**:生成简化的路由配置,适合直接添加到 router - -**参数**: -- `views` - 视图列表 -- `config` - 路由生成器配置(布局映射、组件加载器等) -- `options` - 可选配置 - - `asRootChildren` - 是否作为根路由的子路由 - - `iframePlaceholder` - iframe 类型视图的占位组件 - - `verbose` - 是否启用详细日志 - -**返回**:路由配置数组 - -#### 2. `loadViewsFromStorage()` -```typescript -export function loadViewsFromStorage( - storageKey?: string, - viewsPath?: string -): TbSysViewDTO[] | null -``` - -**功能**:从 localStorage 加载视图数据 - -**参数**: -- `storageKey` - localStorage 的 key(默认:'loginDomain') -- `viewsPath` - 视图数据在对象中的路径(默认:'userViews',支持嵌套如 'user.views') - -**返回**:视图列表,如果不存在返回 null - -### Platform 包简化后的方法 - -#### 1. `addDynamicRoutes()` -```typescript -export function addDynamicRoutes(views: TbSysViewDTO[]) { - // 使用 shared 中的通用方法生成路由 - const routes = generateSimpleRoutes(views, routeConfig, routeOptions) - - // 将生成的路由添加到 Platform 的 router - routes.forEach(route => { - router.addRoute('Root', route) - }) -} -``` - -#### 2. `loadRoutesFromStorage()` -```typescript -export function loadRoutesFromStorage(): boolean { - // 使用 shared 中的通用方法加载视图数据 - const views = loadViewsFromStorage('loginDomain', 'userViews') - - if (views) { - addDynamicRoutes(views) - return true - } - - return false -} -``` - -## 使用示例 - -### 在 Platform 中使用 - -```typescript -import { loadRoutesFromStorage, addDynamicRoutes } from '@/router/dynamicRoute' - -// 从 localStorage 加载并添加路由 -loadRoutesFromStorage() - -// 或者手动传入视图数据 -const views = [...] // 从 API 获取 -addDynamicRoutes(views) -``` - -### 在其他 Web 服务中使用 - -```typescript -import { - generateSimpleRoutes, - loadViewsFromStorage, - type RouteGeneratorConfig -} from 'shared/utils/route' -import router from './router' - -// 1. 配置路由生成器 -const config: RouteGeneratorConfig = { - layoutMap: { - 'MyLayout': () => import('./layouts/MyLayout.vue') - }, - viewLoader: (path) => { - // 自定义组件加载逻辑 - return () => import(`./views/${path}.vue`) - } -} - -// 2. 加载视图数据 -const views = loadViewsFromStorage() - -// 3. 生成路由 -if (views) { - const routes = generateSimpleRoutes(views, config, { - asRootChildren: true, - verbose: true - }) - - // 4. 添加到 router - routes.forEach(route => { - router.addRoute('Root', route) - }) -} -``` - -## 配置说明 - -### RouteGeneratorConfig - -```typescript -interface RouteGeneratorConfig { - /** 布局组件映射表 */ - layoutMap: Record Promise> - - /** 视图组件加载器 */ - viewLoader: (componentPath: string) => (() => Promise) | null - - /** 静态路由列表(可选) */ - staticRoutes?: RouteRecordRaw[] - - /** 404 组件(可选) */ - notFoundComponent?: () => Promise -} -``` - -### GenerateSimpleRoutesOptions - -```typescript -interface GenerateSimpleRoutesOptions { - /** 是否作为根路由的子路由(路径去掉前导 /) */ - asRootChildren?: boolean - - /** iframe 类型视图的占位组件 */ - iframePlaceholder?: () => Promise - - /** 是否启用详细日志 */ - verbose?: boolean -} -``` - -## 优势 - -### 1. 代码复用 -- ✅ 通用逻辑只需维护一份 -- ✅ 其他 web 服务可以直接使用 -- ✅ 减少重复代码 - -### 2. 职责清晰 -- ✅ Shared 负责通用逻辑 -- ✅ 各个服务负责特定配置 -- ✅ 易于理解和维护 - -### 3. 灵活性 -- ✅ 通过配置注入实现定制化 -- ✅ 支持多种使用方式 -- ✅ 易于扩展 - -### 4. 可测试性 -- ✅ 通用方法独立测试 -- ✅ 配置化便于 mock -- ✅ 减少耦合 - -## 迁移指南 - -如果其他服务想要使用 shared 中的路由生成逻辑: - -### 步骤 1:准备配置 - -```typescript -// 1. 准备布局组件映射 -const layoutMap = { - 'MainLayout': () => import('./layouts/MainLayout.vue'), - 'BlankLayout': () => import('./layouts/BlankLayout.vue') -} - -// 2. 准备组件加载器 -const VIEW_MODULES = import.meta.glob('./views/**/*.vue') -const viewLoader = (path: string) => { - const fullPath = `./views/${path}.vue` - return VIEW_MODULES[fullPath] || null -} - -// 3. 组装配置 -const config: RouteGeneratorConfig = { - layoutMap, - viewLoader -} -``` - -### 步骤 2:加载视图数据 - -```typescript -import { loadViewsFromStorage } from 'shared/utils/route' - -// 从 localStorage 加载 -const views = loadViewsFromStorage('loginDomain', 'userViews') - -// 或从 API 加载 -// const views = await api.getUserViews() -``` - -### 步骤 3:生成并添加路由 - -```typescript -import { generateSimpleRoutes } from 'shared/utils/route' - -if (views) { - const routes = generateSimpleRoutes(views, config, { - asRootChildren: true, - verbose: process.env.NODE_ENV === 'development' - }) - - routes.forEach(route => { - router.addRoute('YourRootRouteName', route) - }) -} -``` - -## 注意事项 - -1. **组件加载器**:每个服务的组件路径可能不同,需要自行实现 `viewLoader` -2. **布局组件**:需要提供服务特定的布局组件映射 -3. **路由实例**:需要自行将生成的路由添加到服务的 router 实例 -4. **iframe 支持**:如果需要支持 iframe 视图,需要提供占位组件 - -## 文件变更 - -### 新增文件 -- `shared/src/utils/route/route-generator.ts` - 新增通用方法 - -### 修改文件 -- `shared/src/utils/route/index.ts` - 新增导出 -- `shared/vite.config.ts` - 新增导出配置 -- `shared/EXPOSES.md` - 更新文档 -- `platform/src/router/dynamicRoute.ts` - 简化代码 -- `platform/src/types/shared.d.ts` - 新增类型声明 - -## 更新日志 - -### 2025-12-12 -- ✅ 将路由生成通用逻辑提取到 shared -- ✅ 新增 `generateSimpleRoutes` 方法 -- ✅ 新增 `loadViewsFromStorage` 方法 -- ✅ 简化 Platform 的 dynamicRoute.ts -- ✅ 更新文档和类型声明 diff --git a/urbanLifelineWeb/packages/shared/index.html b/urbanLifelineWeb/packages/shared/index.html deleted file mode 100644 index f43cc28c..00000000 --- a/urbanLifelineWeb/packages/shared/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Shared Components Demo - - -
- - - diff --git a/urbanLifelineWeb/packages/shared/package-lock.json b/urbanLifelineWeb/packages/shared/package-lock.json deleted file mode 100644 index ad0341e2..00000000 --- a/urbanLifelineWeb/packages/shared/package-lock.json +++ /dev/null @@ -1,4398 +0,0 @@ -{ - "name": "@shared/all", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@shared/all", - "version": "1.0.0", - "dependencies": { - "@vueuse/core": "^11.3.0", - "element-plus": "^2.12.0", - "pinia": "^2.2.8", - "vue": "^3.5.13", - "vue-router": "^4.5.0" - }, - "devDependencies": { - "@originjs/vite-plugin-federation": "^1.3.6", - "@types/node": "^22.0.0", - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "npm-run-all": "^4.1.5", - "typescript": "^5.7.2", - "vite": "^6.0.3" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", - "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/@element-plus/icons-vue": { - "version": "2.3.2", - "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", - "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", - "license": "MIT", - "peerDependencies": { - "vue": "^3.2.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.7.3", - "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.3.tgz", - "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.4.tgz", - "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.3", - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@originjs/vite-plugin-federation": { - "version": "1.4.1", - "resolved": "https://registry.npmmirror.com/@originjs/vite-plugin-federation/-/vite-plugin-federation-1.4.1.tgz", - "integrity": "sha512-Uo08jW5pj1t58OUKuZNkmzcfTN2pqeVuAWCCiKf/75/oll4Efq4cHOqSE1FXMlvwZNGDziNdDyBbQ5IANem3CQ==", - "dev": true, - "license": "MulanPSL-2.0", - "dependencies": { - "estree-walker": "^3.0.2", - "magic-string": "^0.27.0" - }, - "engines": { - "node": ">=14.0.0", - "pnpm": ">=7.0.1" - } - }, - "node_modules/@popperjs/core": { - "name": "@sxzz/popperjs-es", - "version": "2.11.7", - "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", - "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.53", - "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", - "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", - "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", - "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", - "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", - "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", - "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", - "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", - "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", - "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", - "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", - "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", - "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", - "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", - "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", - "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", - "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", - "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", - "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", - "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", - "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", - "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", - "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", - "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", - "license": "MIT" - }, - "node_modules/@types/lodash-es": { - "version": "4.17.12", - "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", - "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", - "license": "MIT", - "dependencies": { - "@types/lodash": "*" - } - }, - "node_modules/@types/node": { - "version": "22.19.1", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.19.1.tgz", - "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/web-bluetooth": { - "version": "0.0.20", - "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", - "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", - "license": "MIT" - }, - "node_modules/@vitejs/plugin-vue": { - "version": "5.2.4", - "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", - "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0", - "vue": "^3.2.25" - } - }, - "node_modules/@vitejs/plugin-vue-jsx": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-4.2.0.tgz", - "integrity": "sha512-DSTrmrdLp+0LDNF77fqrKfx7X0ErRbOcUAgJL/HbSesqQwoUvUQ4uYQqaex+rovqgGcoPqVk+AwUh3v9CuiYIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.27.1", - "@rolldown/pluginutils": "^1.0.0-beta.9", - "@vue/babel-plugin-jsx": "^1.4.0" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0", - "vue": "^3.0.0" - } - }, - "node_modules/@vue/babel-helper-vue-transform-on": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", - "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/babel-plugin-jsx": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", - "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.2", - "@vue/babel-helper-vue-transform-on": "1.5.0", - "@vue/babel-plugin-resolve-type": "1.5.0", - "@vue/shared": "^3.5.18" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - } - } - }, - "node_modules/@vue/babel-plugin-resolve-type": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", - "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/parser": "^7.28.0", - "@vue/compiler-sfc": "^3.5.18" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.25.tgz", - "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.25", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-core/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz", - "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==", - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz", - "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.25", - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.6", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, - "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", - "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "license": "MIT" - }, - "node_modules/@vue/reactivity": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.25.tgz", - "integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==", - "license": "MIT", - "dependencies": { - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.25.tgz", - "integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.25.tgz", - "integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.25", - "@vue/runtime-core": "3.5.25", - "@vue/shared": "3.5.25", - "csstype": "^3.1.3" - } - }, - "node_modules/@vue/server-renderer": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.25.tgz", - "integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==", - "license": "MIT", - "dependencies": { - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25" - }, - "peerDependencies": { - "vue": "3.5.25" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.25.tgz", - "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==", - "license": "MIT" - }, - "node_modules/@vueuse/core": { - "version": "11.3.0", - "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-11.3.0.tgz", - "integrity": "sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==", - "license": "MIT", - "dependencies": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "11.3.0", - "@vueuse/shared": "11.3.0", - "vue-demi": ">=0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/metadata": { - "version": "11.3.0", - "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-11.3.0.tgz", - "integrity": "sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/shared": { - "version": "11.3.0", - "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-11.3.0.tgz", - "integrity": "sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==", - "license": "MIT", - "dependencies": { - "vue-demi": ">=0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/async-validator": { - "version": "4.2.5", - "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", - "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", - "license": "MIT" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.3", - "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.3.tgz", - "integrity": "sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001759", - "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz", - "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/dayjs": { - "version": "1.11.19", - "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.266", - "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz", - "integrity": "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==", - "dev": true, - "license": "ISC" - }, - "node_modules/element-plus": { - "version": "2.12.0", - "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.12.0.tgz", - "integrity": "sha512-M9YLSn2np9OnqrSKWsiXvGe3qnF8pd94+TScsHj1aTMCD+nSEvucXermf807qNt6hOP040le0e5Aft7E9ZfHmA==", - "license": "MIT", - "dependencies": { - "@ctrl/tinycolor": "^3.4.1", - "@element-plus/icons-vue": "^2.3.2", - "@floating-ui/dom": "^1.0.1", - "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", - "@types/lodash": "^4.17.20", - "@types/lodash-es": "^4.17.12", - "@vueuse/core": "^9.1.0", - "async-validator": "^4.2.5", - "dayjs": "^1.11.19", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "lodash-unified": "^1.0.3", - "memoize-one": "^6.0.0", - "normalize-wheel-es": "^1.2.0" - }, - "peerDependencies": { - "vue": "^3.2.0" - } - }, - "node_modules/element-plus/node_modules/@types/web-bluetooth": { - "version": "0.0.16", - "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", - "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==", - "license": "MIT" - }, - "node_modules/element-plus/node_modules/@vueuse/core": { - "version": "9.13.0", - "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz", - "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", - "license": "MIT", - "dependencies": { - "@types/web-bluetooth": "^0.0.16", - "@vueuse/metadata": "9.13.0", - "@vueuse/shared": "9.13.0", - "vue-demi": "*" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/element-plus/node_modules/@vueuse/metadata": { - "version": "9.13.0", - "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz", - "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/element-plus/node_modules/@vueuse/shared": { - "version": "9.13.0", - "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz", - "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", - "license": "MIT", - "dependencies": { - "vue-demi": "*" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, - "node_modules/lodash-unified": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", - "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", - "license": "MIT", - "peerDependencies": { - "@types/lodash-es": "*", - "lodash": "*", - "lodash-es": "*" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", - "license": "MIT" - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmmirror.com/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmmirror.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/normalize-wheel-es": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", - "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", - "license": "BSD-3-Clause" - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmmirror.com/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmmirror.com/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/pinia": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.3.1.tgz", - "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", - "license": "MIT", - "dependencies": { - "@vue/devtools-api": "^6.6.3", - "vue-demi": "^0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "typescript": ">=4.4.4", - "vue": "^2.7.0 || ^3.5.11" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rollup": { - "version": "4.53.3", - "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.53.3.tgz", - "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.53.3", - "@rollup/rollup-android-arm64": "4.53.3", - "@rollup/rollup-darwin-arm64": "4.53.3", - "@rollup/rollup-darwin-x64": "4.53.3", - "@rollup/rollup-freebsd-arm64": "4.53.3", - "@rollup/rollup-freebsd-x64": "4.53.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", - "@rollup/rollup-linux-arm-musleabihf": "4.53.3", - "@rollup/rollup-linux-arm64-gnu": "4.53.3", - "@rollup/rollup-linux-arm64-musl": "4.53.3", - "@rollup/rollup-linux-loong64-gnu": "4.53.3", - "@rollup/rollup-linux-ppc64-gnu": "4.53.3", - "@rollup/rollup-linux-riscv64-gnu": "4.53.3", - "@rollup/rollup-linux-riscv64-musl": "4.53.3", - "@rollup/rollup-linux-s390x-gnu": "4.53.3", - "@rollup/rollup-linux-x64-gnu": "4.53.3", - "@rollup/rollup-linux-x64-musl": "4.53.3", - "@rollup/rollup-openharmony-arm64": "4.53.3", - "@rollup/rollup-win32-arm64-msvc": "4.53.3", - "@rollup/rollup-win32-ia32-msvc": "4.53.3", - "@rollup/rollup-win32-x64-gnu": "4.53.3", - "@rollup/rollup-win32-x64-msvc": "4.53.3", - "fsevents": "~2.3.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmmirror.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmmirror.com/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.padend": { - "version": "3.1.6", - "resolved": "https://registry.npmmirror.com/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", - "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/update-browserslist-db": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", - "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmmirror.com/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vue": { - "version": "3.5.25", - "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.25.tgz", - "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-sfc": "3.5.25", - "@vue/runtime-dom": "3.5.25", - "@vue/server-renderer": "3.5.25", - "@vue/shared": "3.5.25" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, - "node_modules/vue-router": { - "version": "4.6.3", - "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.3.tgz", - "integrity": "sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==", - "license": "MIT", - "dependencies": { - "@vue/devtools-api": "^6.6.4" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "vue": "^3.5.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmmirror.com/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - } - } -} diff --git a/urbanLifelineWeb/packages/shared/package.json b/urbanLifelineWeb/packages/shared/package.json deleted file mode 100644 index 5ce9b2eb..00000000 --- a/urbanLifelineWeb/packages/shared/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@shared/all", - "version": "1.0.0", - "type": "module", - "private": true, - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview", - "serve": "node server.js" - }, - "dependencies": { - "@element-plus/icons-vue": "^2.3.2", - "@stomp/stompjs": "^7.2.1", - "axios": "^1.7.0", - "cors": "^2.8.5", - "element-plus": "^2.12.0", - "express": "^4.18.2", - "lucide-vue-next": "^0.561.0", - "ofetch": "^1.4.1", - "sockjs-client": "^1.6.1", - "vue": "^3.5.13", - "vue-router": "^4.5.0" - }, - "devDependencies": { - "@module-federation/vite": "^1.9.3", - "@types/node": "^20.10.0", - "@vitejs/plugin-vue": "^5.2.1", - "@vitejs/plugin-vue-jsx": "^4.1.1", - "npm-run-all": "^4.1.5", - "sass": "^1.80.6", - "sass-embedded": "^1.80.6", - "typescript": "^5.7.2", - "vite": "^6.0.3" - }, - "peerDependencies": { - "typescript": ">=5.0.0", - "vue": "^3.5.13" - } -} diff --git a/urbanLifelineWeb/packages/shared/pnpm-lock.yaml b/urbanLifelineWeb/packages/shared/pnpm-lock.yaml deleted file mode 100644 index 0b4a5cbc..00000000 --- a/urbanLifelineWeb/packages/shared/pnpm-lock.yaml +++ /dev/null @@ -1,3614 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@element-plus/icons-vue': - specifier: ^2.3.2 - version: 2.3.2(vue@3.5.25) - '@stomp/stompjs': - specifier: ^7.2.1 - version: 7.2.1 - axios: - specifier: ^1.7.0 - version: 1.13.2 - cors: - specifier: ^2.8.5 - version: 2.8.5 - element-plus: - specifier: ^2.12.0 - version: 2.12.0(vue@3.5.25) - express: - specifier: ^4.18.2 - version: 4.22.1 - lucide-vue-next: - specifier: ^0.561.0 - version: 0.561.0(vue@3.5.25) - ofetch: - specifier: ^1.4.1 - version: 1.5.1 - sockjs-client: - specifier: ^1.6.1 - version: 1.6.1 - vue: - specifier: ^3.5.13 - version: 3.5.25(typescript@5.9.3) - vue-router: - specifier: ^4.5.0 - version: 4.6.3(vue@3.5.25) - -devDependencies: - '@module-federation/vite': - specifier: ^1.9.3 - version: 1.9.3 - '@types/node': - specifier: ^20.10.0 - version: 20.19.25 - '@vitejs/plugin-vue': - specifier: ^5.2.1 - version: 5.2.4(vite@6.4.1)(vue@3.5.25) - '@vitejs/plugin-vue-jsx': - specifier: ^4.1.1 - version: 4.2.0(vite@6.4.1)(vue@3.5.25) - npm-run-all: - specifier: ^4.1.5 - version: 4.1.5 - sass: - specifier: ^1.80.6 - version: 1.94.2 - sass-embedded: - specifier: ^1.80.6 - version: 1.93.3 - typescript: - specifier: ^5.7.2 - version: 5.9.3 - vite: - specifier: ^6.0.3 - version: 6.4.1(@types/node@20.19.25)(sass-embedded@1.93.3)(sass@1.94.2) - -packages: - - /@babel/code-frame@7.27.1: - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - dev: true - - /@babel/compat-data@7.28.5: - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core@7.28.5: - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator@7.28.5: - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - dev: true - - /@babel/helper-annotate-as-pure@7.27.3: - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.28.5 - dev: true - - /@babel/helper-compilation-targets@7.27.2: - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - - /@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5): - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-globals@7.28.0: - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-member-expression-to-functions@7.28.5: - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-module-imports@7.27.1: - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5): - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-optimise-call-expression@7.27.1: - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.28.5 - dev: true - - /@babel/helper-plugin-utils@7.27.1: - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-skip-transparent-expression-wrappers@7.27.1: - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-string-parser@7.27.1: - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-identifier@7.28.5: - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-option@7.27.1: - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helpers@7.28.4: - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - dev: true - - /@babel/parser@7.28.5: - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.28.5 - - /@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - - /@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5): - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - - /@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5): - resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/template@7.27.2: - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - dev: true - - /@babel/traverse@7.28.5: - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types@7.28.5: - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - /@bufbuild/protobuf@2.10.1: - resolution: {integrity: sha512-ckS3+vyJb5qGpEYv/s1OebUHDi/xSNtfgw1wqKZo7MR9F2z+qXr0q5XagafAG/9O0QPVIUfST0smluYSTpYFkg==} - dev: true - - /@ctrl/tinycolor@3.6.1: - resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} - engines: {node: '>=10'} - dev: false - - /@element-plus/icons-vue@2.3.2(vue@3.5.25): - resolution: {integrity: sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==} - peerDependencies: - vue: ^3.2.0 - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /@esbuild/aix-ppc64@0.25.12: - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm64@0.25.12: - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.25.12: - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.25.12: - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.25.12: - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.25.12: - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.25.12: - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.25.12: - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.25.12: - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.25.12: - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.25.12: - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.25.12: - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.25.12: - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.25.12: - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.25.12: - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.25.12: - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.25.12: - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-arm64@0.25.12: - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.25.12: - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-arm64@0.25.12: - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.25.12: - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openharmony-arm64@0.25.12: - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.25.12: - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.25.12: - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.25.12: - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.25.12: - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@floating-ui/core@1.7.3: - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - dependencies: - '@floating-ui/utils': 0.2.10 - dev: false - - /@floating-ui/dom@1.7.4: - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 - dev: false - - /@floating-ui/utils@0.2.10: - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - dev: false - - /@jridgewell/gen-mapping@0.3.13: - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - - /@jridgewell/remapping@2.3.5: - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.5.5: - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - /@jridgewell/trace-mapping@0.3.31: - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - dev: true - - /@module-federation/error-codes@0.21.6: - resolution: {integrity: sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==} - dev: true - - /@module-federation/runtime-core@0.21.6: - resolution: {integrity: sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==} - dependencies: - '@module-federation/error-codes': 0.21.6 - '@module-federation/sdk': 0.21.6 - dev: true - - /@module-federation/runtime@0.21.6: - resolution: {integrity: sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==} - dependencies: - '@module-federation/error-codes': 0.21.6 - '@module-federation/runtime-core': 0.21.6 - '@module-federation/sdk': 0.21.6 - dev: true - - /@module-federation/sdk@0.21.6: - resolution: {integrity: sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==} - dev: true - - /@module-federation/vite@1.9.3: - resolution: {integrity: sha512-MV6XI3FX6okEMJ7FdmvFmYuu7DygRoLljKT8atrBwFhlttsgBbswpqMj4P4Fs/X+pFmbIi/ntFzVhsrG0qQnGQ==} - dependencies: - '@module-federation/runtime': 0.21.6 - '@module-federation/sdk': 0.21.6 - '@rollup/pluginutils': 5.3.0 - defu: 6.1.4 - estree-walker: 2.0.2 - magic-string: 0.30.21 - pathe: 1.1.2 - transitivePeerDependencies: - - rollup - dev: true - - /@parcel/watcher-android-arm64@2.5.1: - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-darwin-arm64@2.5.1: - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-darwin-x64@2.5.1: - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-freebsd-x64@2.5.1: - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-linux-arm-glibc@2.5.1: - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-linux-arm-musl@2.5.1: - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-linux-arm64-glibc@2.5.1: - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-linux-arm64-musl@2.5.1: - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-linux-x64-glibc@2.5.1: - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-linux-x64-musl@2.5.1: - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-win32-arm64@2.5.1: - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-win32-ia32@2.5.1: - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} - engines: {node: '>= 10.0.0'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher-win32-x64@2.5.1: - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@parcel/watcher@2.5.1: - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} - engines: {node: '>= 10.0.0'} - requiresBuild: true - dependencies: - detect-libc: 1.0.3 - is-glob: 4.0.3 - micromatch: 4.0.8 - node-addon-api: 7.1.1 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 - dev: true - optional: true - - /@rolldown/pluginutils@1.0.0-beta.53: - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} - dev: true - - /@rollup/pluginutils@5.3.0: - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - dev: true - - /@rollup/rollup-android-arm-eabi@4.53.3: - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-android-arm64@4.53.3: - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-darwin-arm64@4.53.3: - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-darwin-x64@4.53.3: - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-freebsd-arm64@4.53.3: - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-freebsd-x64@4.53.3: - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm-gnueabihf@4.53.3: - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} - cpu: [arm] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm-musleabihf@4.53.3: - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} - cpu: [arm] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm64-gnu@4.53.3: - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} - cpu: [arm64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm64-musl@4.53.3: - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} - cpu: [arm64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-loong64-gnu@4.53.3: - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} - cpu: [loong64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-ppc64-gnu@4.53.3: - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-riscv64-gnu@4.53.3: - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-riscv64-musl@4.53.3: - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} - cpu: [riscv64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-s390x-gnu@4.53.3: - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} - cpu: [s390x] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-x64-gnu@4.53.3: - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} - cpu: [x64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-x64-musl@4.53.3: - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} - cpu: [x64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-openharmony-arm64@4.53.3: - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} - cpu: [arm64] - os: [openharmony] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-arm64-msvc@4.53.3: - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-ia32-msvc@4.53.3: - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-x64-gnu@4.53.3: - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-x64-msvc@4.53.3: - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@stomp/stompjs@7.2.1: - resolution: {integrity: sha512-DLd/WeicnHS5SsWWSk3x6/pcivqchNaEvg9UEGVqAcfYEBVmS9D6980ckXjTtfpXLjdLDsd96M7IuX4w7nzq5g==} - dev: false - - /@sxzz/popperjs-es@2.11.7: - resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==} - dev: false - - /@types/estree@1.0.8: - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - dev: true - - /@types/lodash-es@4.17.12: - resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - dependencies: - '@types/lodash': 4.17.21 - dev: false - - /@types/lodash@4.17.21: - resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} - dev: false - - /@types/node@20.19.25: - resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} - dependencies: - undici-types: 6.21.0 - dev: true - - /@types/web-bluetooth@0.0.16: - resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} - dev: false - - /@vitejs/plugin-vue-jsx@4.2.0(vite@6.4.1)(vue@3.5.25): - resolution: {integrity: sha512-DSTrmrdLp+0LDNF77fqrKfx7X0ErRbOcUAgJL/HbSesqQwoUvUQ4uYQqaex+rovqgGcoPqVk+AwUh3v9CuiYIw==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.53 - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.5) - vite: 6.4.1(@types/node@20.19.25)(sass-embedded@1.93.3)(sass@1.94.2) - vue: 3.5.25(typescript@5.9.3) - transitivePeerDependencies: - - supports-color - dev: true - - /@vitejs/plugin-vue@5.2.4(vite@6.4.1)(vue@3.5.25): - resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.2.25 - dependencies: - vite: 6.4.1(@types/node@20.19.25)(sass-embedded@1.93.3)(sass@1.94.2) - vue: 3.5.25(typescript@5.9.3) - dev: true - - /@vue/babel-helper-vue-transform-on@1.5.0: - resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} - dev: true - - /@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.5): - resolution: {integrity: sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - peerDependenciesMeta: - '@babel/core': - optional: true - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@vue/babel-helper-vue-transform-on': 1.5.0 - '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.28.5) - '@vue/shared': 3.5.25 - transitivePeerDependencies: - - supports-color - dev: true - - /@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.28.5): - resolution: {integrity: sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/parser': 7.28.5 - '@vue/compiler-sfc': 3.5.25 - transitivePeerDependencies: - - supports-color - dev: true - - /@vue/compiler-core@3.5.25: - resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} - dependencies: - '@babel/parser': 7.28.5 - '@vue/shared': 3.5.25 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - - /@vue/compiler-dom@3.5.25: - resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} - dependencies: - '@vue/compiler-core': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/compiler-sfc@3.5.25: - resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} - dependencies: - '@babel/parser': 7.28.5 - '@vue/compiler-core': 3.5.25 - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - estree-walker: 2.0.2 - magic-string: 0.30.21 - postcss: 8.5.6 - source-map-js: 1.2.1 - - /@vue/compiler-ssr@3.5.25: - resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} - dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/devtools-api@6.6.4: - resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - dev: false - - /@vue/reactivity@3.5.25: - resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} - dependencies: - '@vue/shared': 3.5.25 - - /@vue/runtime-core@3.5.25: - resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} - dependencies: - '@vue/reactivity': 3.5.25 - '@vue/shared': 3.5.25 - - /@vue/runtime-dom@3.5.25: - resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} - dependencies: - '@vue/reactivity': 3.5.25 - '@vue/runtime-core': 3.5.25 - '@vue/shared': 3.5.25 - csstype: 3.2.3 - - /@vue/server-renderer@3.5.25(vue@3.5.25): - resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} - peerDependencies: - vue: 3.5.25 - dependencies: - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - vue: 3.5.25(typescript@5.9.3) - - /@vue/shared@3.5.25: - resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} - - /@vueuse/core@9.13.0(vue@3.5.25): - resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} - dependencies: - '@types/web-bluetooth': 0.0.16 - '@vueuse/metadata': 9.13.0 - '@vueuse/shared': 9.13.0(vue@3.5.25) - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /@vueuse/metadata@9.13.0: - resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} - dev: false - - /@vueuse/shared@9.13.0(vue@3.5.25): - resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} - dependencies: - vue-demi: 0.14.10(vue@3.5.25) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - dev: false - - /accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - dev: false - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - dev: true - - /array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - dev: true - - /array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - dev: false - - /arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - is-array-buffer: 3.0.5 - dev: true - - /async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} - dev: true - - /async-validator@4.2.5: - resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} - dev: false - - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: false - - /available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - dependencies: - possible-typed-array-names: 1.1.0 - dev: true - - /axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /baseline-browser-mapping@2.9.3: - resolution: {integrity: sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==} - hasBin: true - dev: true - - /body-parser@1.20.4: - resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.1 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.14.0 - raw-body: 2.5.3 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - dev: false - - /brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - requiresBuild: true - dependencies: - fill-range: 7.1.1 - dev: true - optional: true - - /browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - baseline-browser-mapping: 2.9.3 - caniuse-lite: 1.0.30001759 - electron-to-chromium: 1.5.266 - node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) - dev: true - - /buffer-builder@0.2.0: - resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} - dev: true - - /bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - dev: false - - /call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - /call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - dev: true - - /call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - /caniuse-lite@1.0.30001759: - resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==} - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true - - /chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - dependencies: - readdirp: 4.1.2 - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true - - /colorjs.io@0.5.2: - resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} - dev: true - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: false - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - - /content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - dependencies: - safe-buffer: 5.2.1 - dev: false - - /content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - dev: false - - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - - /cookie-signature@1.0.7: - resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} - dev: false - - /cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - dev: false - - /cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - dev: false - - /cross-spawn@6.0.6: - resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} - engines: {node: '>=4.8'} - dependencies: - nice-try: 1.0.5 - path-key: 2.0.1 - semver: 5.7.2 - shebang-command: 1.2.0 - which: 1.3.1 - dev: true - - /csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - /data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - dev: true - - /data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - dev: true - - /data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - dev: true - - /dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} - dev: false - - /debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.0.0 - dev: false - - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: false - - /debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - - /define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - dev: true - - /define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - dev: true - - /defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: false - - /depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dev: false - - /destr@2.0.5: - resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - dev: false - - /destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - dev: false - - /detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - requiresBuild: true - dev: true - optional: true - - /dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - /ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - dev: false - - /electron-to-chromium@1.5.266: - resolution: {integrity: sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==} - dev: true - - /element-plus@2.12.0(vue@3.5.25): - resolution: {integrity: sha512-M9YLSn2np9OnqrSKWsiXvGe3qnF8pd94+TScsHj1aTMCD+nSEvucXermf807qNt6hOP040le0e5Aft7E9ZfHmA==} - peerDependencies: - vue: ^3.2.0 - dependencies: - '@ctrl/tinycolor': 3.6.1 - '@element-plus/icons-vue': 2.3.2(vue@3.5.25) - '@floating-ui/dom': 1.7.4 - '@popperjs/core': /@sxzz/popperjs-es@2.11.7 - '@types/lodash': 4.17.21 - '@types/lodash-es': 4.17.12 - '@vueuse/core': 9.13.0(vue@3.5.25) - async-validator: 4.2.5 - dayjs: 1.11.19 - lodash: 4.17.21 - lodash-es: 4.17.21 - lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21) - memoize-one: 6.0.0 - normalize-wheel-es: 1.2.0 - vue: 3.5.25(typescript@5.9.3) - transitivePeerDependencies: - - '@vue/composition-api' - dev: false - - /encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - dev: false - - /encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - dev: false - - /entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - /error-ex@1.3.4: - resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - dependencies: - is-arrayish: 0.2.1 - dev: true - - /es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.2 - arraybuffer.prototype.slice: 1.0.4 - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - data-view-buffer: 1.0.2 - data-view-byte-length: 1.0.2 - data-view-byte-offset: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - get-symbol-description: 1.1.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - internal-slot: 1.1.0 - is-array-buffer: 3.0.5 - is-callable: 1.2.7 - is-data-view: 1.0.2 - is-negative-zero: 2.0.3 - is-regex: 1.2.1 - is-set: 2.0.3 - is-shared-array-buffer: 1.0.4 - is-string: 1.1.1 - is-typed-array: 1.1.15 - is-weakref: 1.1.1 - math-intrinsics: 1.1.0 - object-inspect: 1.13.4 - object-keys: 1.1.1 - object.assign: 4.1.7 - own-keys: 1.0.1 - regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 - safe-push-apply: 1.0.0 - safe-regex-test: 1.1.0 - set-proto: 1.0.0 - stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.3 - typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 - unbox-primitive: 1.1.0 - which-typed-array: 1.1.19 - dev: true - - /es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - /es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - /es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - - /es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - /es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - dev: true - - /esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - dev: true - - /escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - dev: true - - /escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - dev: false - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true - - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - /etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - dev: false - - /eventsource@2.0.2: - resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} - engines: {node: '>=12.0.0'} - dev: false - - /express@4.22.1: - resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} - engines: {node: '>= 0.10.0'} - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.4 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.0.7 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.2 - fresh: 0.5.2 - http-errors: 2.0.1 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.12 - proxy-addr: 2.0.7 - qs: 6.14.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.1 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.2 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - dev: false - - /faye-websocket@0.11.4: - resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} - engines: {node: '>=0.8.0'} - dependencies: - websocket-driver: 0.7.4 - dev: false - - /fdir@6.5.0(picomatch@4.0.3): - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - dependencies: - picomatch: 4.0.3 - dev: true - - /fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - requiresBuild: true - dependencies: - to-regex-range: 5.0.1 - dev: true - optional: true - - /finalhandler@1.3.2: - resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} - engines: {node: '>= 0.8'} - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - dev: false - - /follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: false - - /for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.7 - dev: true - - /form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - dev: false - - /forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - dev: false - - /fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - dev: false - - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - /function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - functions-have-names: 1.2.3 - hasown: 2.0.2 - is-callable: 1.2.7 - dev: true - - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true - - /generator-function@2.0.1: - resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} - engines: {node: '>= 0.4'} - dev: true - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - - /get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - /get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - /get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - dev: true - - /globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - dev: true - - /gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true - - /has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - dev: true - - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - dependencies: - es-define-property: 1.0.1 - dev: true - - /has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} - dependencies: - dunder-proto: 1.0.1 - dev: true - - /has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - /has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.1.0 - - /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - - /hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - dev: true - - /http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - dev: false - - /http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - dev: false - - /http-parser-js@0.5.10: - resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} - dev: false - - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - dev: false - - /immutable@5.1.4: - resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: false - - /internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.1.0 - dev: true - - /ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - dev: false - - /is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - dev: true - - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true - - /is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} - dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - dev: true - - /is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} - dependencies: - has-bigints: 1.1.0 - dev: true - - /is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - dev: true - - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - dev: true - - /is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - dependencies: - hasown: 2.0.2 - dev: true - - /is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-typed-array: 1.1.15 - dev: true - - /is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - requiresBuild: true - dev: true - optional: true - - /is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - dev: true - - /is-generator-function@1.1.2: - resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - generator-function: 2.0.1 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - requiresBuild: true - dependencies: - is-extglob: 2.1.1 - dev: true - optional: true - - /is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - dev: true - - /is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - dev: true - - /is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - requiresBuild: true - dev: true - optional: true - - /is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - dev: true - - /is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - dev: true - - /is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - dev: true - - /is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - dev: true - - /is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 - dev: true - - /is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - dependencies: - which-typed-array: 1.1.19 - dev: true - - /is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - dev: true - - /is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - dev: true - - /is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - dev: true - - /isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - - /jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /json-parse-better-errors@1.0.2: - resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} - dev: true - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /load-json-file@4.0.0: - resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} - engines: {node: '>=4'} - dependencies: - graceful-fs: 4.2.11 - parse-json: 4.0.0 - pify: 3.0.0 - strip-bom: 3.0.0 - dev: true - - /lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - dev: false - - /lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21): - resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==} - peerDependencies: - '@types/lodash-es': '*' - lodash: '*' - lodash-es: '*' - dependencies: - '@types/lodash-es': 4.17.12 - lodash: 4.17.21 - lodash-es: 4.17.21 - dev: false - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lucide-vue-next@0.561.0(vue@3.5.25): - resolution: {integrity: sha512-c5HUckO0qHklVSOf/0vaSR3pEb8fYImRDCRDLde56uqS9js0D/e3RAvq0/YFWjkmyOBKCb0/IdskdoHZQEkT5g==} - peerDependencies: - vue: '>=3.0.1' - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - /math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - /media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - dev: false - - /memoize-one@6.0.0: - resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - dev: false - - /memorystream@0.3.1: - resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} - engines: {node: '>= 0.10.0'} - dev: true - - /merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - dev: false - - /methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - dev: false - - /micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - requiresBuild: true - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - dev: true - optional: true - - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: false - - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - dev: false - - /mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - dev: false - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.12 - dev: true - - /ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: false - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - /nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - /negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - dev: false - - /nice-try@1.0.5: - resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - dev: true - - /node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - requiresBuild: true - dev: true - optional: true - - /node-fetch-native@1.6.7: - resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - dev: false - - /node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - dev: true - - /normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.11 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - dev: true - - /normalize-wheel-es@1.2.0: - resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==} - dev: false - - /npm-run-all@4.1.5: - resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==} - engines: {node: '>= 4'} - hasBin: true - dependencies: - ansi-styles: 3.2.1 - chalk: 2.4.2 - cross-spawn: 6.0.6 - memorystream: 0.3.1 - minimatch: 3.1.2 - pidtree: 0.3.1 - read-pkg: 3.0.0 - shell-quote: 1.8.3 - string.prototype.padend: 3.1.6 - dev: true - - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: false - - /object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - dev: true - - /object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - dev: true - - /ofetch@1.5.1: - resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} - dependencies: - destr: 2.0.5 - node-fetch-native: 1.6.7 - ufo: 1.6.1 - dev: false - - /on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - dependencies: - ee-first: 1.1.1 - dev: false - - /own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.3.0 - object-keys: 1.1.1 - safe-push-apply: 1.0.0 - dev: true - - /parse-json@4.0.0: - resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} - engines: {node: '>=4'} - dependencies: - error-ex: 1.3.4 - json-parse-better-errors: 1.0.2 - dev: true - - /parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - dev: false - - /path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} - dev: true - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true - - /path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - dev: false - - /path-type@3.0.0: - resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} - engines: {node: '>=4'} - dependencies: - pify: 3.0.0 - dev: true - - /pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - dev: true - - /picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - requiresBuild: true - dev: true - optional: true - - /picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - dev: true - - /pidtree@0.3.1: - resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} - engines: {node: '>=0.10'} - hasBin: true - dev: true - - /pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - dev: true - - /possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - dev: true - - /postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - /proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - dev: false - - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false - - /qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} - dependencies: - side-channel: 1.1.0 - dev: false - - /querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - dev: false - - /range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - dev: false - - /raw-body@2.5.3: - resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} - engines: {node: '>= 0.8'} - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - dev: false - - /read-pkg@3.0.0: - resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} - engines: {node: '>=4'} - dependencies: - load-json-file: 4.0.0 - normalize-package-data: 2.5.0 - path-type: 3.0.0 - dev: true - - /readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - dev: true - - /reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - which-builtin-type: 1.2.1 - dev: true - - /regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 - dev: true - - /requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - dev: false - - /resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 - fsevents: 2.3.3 - dev: true - - /rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - dependencies: - tslib: 2.8.1 - dev: true - - /safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - isarray: 2.0.5 - dev: true - - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false - - /safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - isarray: 2.0.5 - dev: true - - /safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - dev: true - - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: false - - /sass-embedded-all-unknown@1.93.3: - resolution: {integrity: sha512-3okGgnE41eg+CPLtAPletu6nQ4N0ij7AeW+Sl5Km4j29XcmqZQeFwYjHe1AlKTEgLi/UAONk1O8i8/lupeKMbw==} - cpu: ['!arm', '!arm64', '!riscv64', '!x64'] - requiresBuild: true - dependencies: - sass: 1.93.3 - dev: true - optional: true - - /sass-embedded-android-arm64@1.93.3: - resolution: {integrity: sha512-uqUl3Kt1IqdGVAcAdbmC+NwuUJy8tM+2ZnB7/zrt6WxWVShVCRdFnWR9LT8HJr7eJN7AU8kSXxaVX/gedanPsg==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /sass-embedded-android-arm@1.93.3: - resolution: {integrity: sha512-8xOw9bywfOD6Wv24BgCmgjkk6tMrsOTTHcb28KDxeJtFtoxiUyMbxo0vChpPAfp2Hyg2tFFKS60s0s4JYk+Raw==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /sass-embedded-android-riscv64@1.93.3: - resolution: {integrity: sha512-2jNJDmo+3qLocjWqYbXiBDnfgwrUeZgZFHJIwAefU7Fn66Ot7rsXl+XPwlokaCbTpj7eMFIqsRAZ/uDueXNCJg==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /sass-embedded-android-x64@1.93.3: - resolution: {integrity: sha512-y0RoAU6ZenQFcjM9PjQd3cRqRTjqwSbtWLL/p68y2oFyh0QGN0+LQ826fc0ZvU/AbqCsAizkqjzOn6cRZJxTTQ==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /sass-embedded-darwin-arm64@1.93.3: - resolution: {integrity: sha512-7zb/hpdMOdKteK17BOyyypemglVURd1Hdz6QGsggy60aUFfptTLQftLRg8r/xh1RbQAUKWFbYTNaM47J9yPxYg==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /sass-embedded-darwin-x64@1.93.3: - resolution: {integrity: sha512-Ek1Vp8ZDQEe327Lz0b7h3hjvWH3u9XjJiQzveq74RPpJQ2q6d9LfWpjiRRohM4qK6o4XOHw1X10OMWPXJtdtWg==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /sass-embedded-linux-arm64@1.93.3: - resolution: {integrity: sha512-RBrHWgfd8Dd8w4fbmdRVXRrhh8oBAPyeWDTKAWw8ZEmuXfVl4ytjDuyxaVilh6rR1xTRTNpbaA/YWApBlLrrNw==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [linux] - libc: glibc - requiresBuild: true - dev: true - optional: true - - /sass-embedded-linux-arm@1.93.3: - resolution: {integrity: sha512-yeiv2y+dp8B4wNpd3+JsHYD0mvpXSfov7IGyQ1tMIR40qv+ROkRqYiqQvAOXf76Qwh4Y9OaYZtLpnsPjfeq6mA==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [linux] - libc: glibc - requiresBuild: true - dev: true - optional: true - - /sass-embedded-linux-musl-arm64@1.93.3: - resolution: {integrity: sha512-PS829l+eUng+9W4PFclXGb4uA2+965NHV3/Sa5U7qTywjeeUUYTZg70dJHSqvhrBEfCc2XJABeW3adLJbyQYkw==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [linux] - libc: musl - requiresBuild: true - dev: true - optional: true - - /sass-embedded-linux-musl-arm@1.93.3: - resolution: {integrity: sha512-fU0fwAwbp7sBE3h5DVU5UPzvaLg7a4yONfFWkkcCp6ZrOiPuGRHXXYriWQ0TUnWy4wE+svsVuWhwWgvlb/tkKg==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [linux] - libc: musl - requiresBuild: true - dev: true - optional: true - - /sass-embedded-linux-musl-riscv64@1.93.3: - resolution: {integrity: sha512-cK1oBY+FWQquaIGEeQ5H74KTO8cWsSWwXb/WaildOO9U6wmUypTgUYKQ0o5o/29nZbWWlM1PHuwVYTSnT23Jjg==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [linux] - libc: musl - requiresBuild: true - dev: true - optional: true - - /sass-embedded-linux-musl-x64@1.93.3: - resolution: {integrity: sha512-A7wkrsHu2/I4Zpa0NMuPGkWDVV7QGGytxGyUq3opSXgAexHo/vBPlGoDXoRlSdex0cV+aTMRPjoGIfdmNlHwyg==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [linux] - libc: musl - requiresBuild: true - dev: true - optional: true - - /sass-embedded-linux-riscv64@1.93.3: - resolution: {integrity: sha512-vWkW1+HTF5qcaHa6hO80gx/QfB6GGjJUP0xLbnAoY4pwEnw5ulGv6RM8qYr8IDhWfVt/KH+lhJ2ZFxnJareisQ==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [linux] - libc: glibc - requiresBuild: true - dev: true - optional: true - - /sass-embedded-linux-x64@1.93.3: - resolution: {integrity: sha512-k6uFxs+e5jSuk1Y0niCwuq42F9ZC5UEP7P+RIOurIm8w/5QFa0+YqeW+BPWEW5M1FqVOsNZH3qGn4ahqvAEjPA==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [linux] - libc: glibc - requiresBuild: true - dev: true - optional: true - - /sass-embedded-unknown-all@1.93.3: - resolution: {integrity: sha512-o5wj2rLpXH0C+GJKt/VpWp6AnMsCCbfFmnMAttcrsa+U3yrs/guhZ3x55KAqqUsE8F47e3frbsDL+1OuQM5DAA==} - os: ['!android', '!darwin', '!linux', '!win32'] - requiresBuild: true - dependencies: - sass: 1.93.3 - dev: true - optional: true - - /sass-embedded-win32-arm64@1.93.3: - resolution: {integrity: sha512-0dOfT9moy9YmBolodwYYXtLwNr4jL4HQC9rBfv6mVrD7ud8ue2kDbn+GVzj1hEJxvEexVSmDCf7MHUTLcGs9xQ==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /sass-embedded-win32-x64@1.93.3: - resolution: {integrity: sha512-wHFVfxiS9hU/sNk7KReD+lJWRp3R0SLQEX4zfOnRP2zlvI2X4IQR5aZr9GNcuMP6TmNpX0nQPZTegS8+h9RrEg==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /sass-embedded@1.93.3: - resolution: {integrity: sha512-+VUy01yfDqNmIVMd/LLKl2TTtY0ovZN0rTonh+FhKr65mFwIYgU9WzgIZKS7U9/SPCQvWTsTGx9jyt+qRm/XFw==} - engines: {node: '>=16.0.0'} - hasBin: true - dependencies: - '@bufbuild/protobuf': 2.10.1 - buffer-builder: 0.2.0 - colorjs.io: 0.5.2 - immutable: 5.1.4 - rxjs: 7.8.2 - supports-color: 8.1.1 - sync-child-process: 1.0.2 - varint: 6.0.0 - optionalDependencies: - sass-embedded-all-unknown: 1.93.3 - sass-embedded-android-arm: 1.93.3 - sass-embedded-android-arm64: 1.93.3 - sass-embedded-android-riscv64: 1.93.3 - sass-embedded-android-x64: 1.93.3 - sass-embedded-darwin-arm64: 1.93.3 - sass-embedded-darwin-x64: 1.93.3 - sass-embedded-linux-arm: 1.93.3 - sass-embedded-linux-arm64: 1.93.3 - sass-embedded-linux-musl-arm: 1.93.3 - sass-embedded-linux-musl-arm64: 1.93.3 - sass-embedded-linux-musl-riscv64: 1.93.3 - sass-embedded-linux-musl-x64: 1.93.3 - sass-embedded-linux-riscv64: 1.93.3 - sass-embedded-linux-x64: 1.93.3 - sass-embedded-unknown-all: 1.93.3 - sass-embedded-win32-arm64: 1.93.3 - sass-embedded-win32-x64: 1.93.3 - dev: true - - /sass@1.93.3: - resolution: {integrity: sha512-elOcIZRTM76dvxNAjqYrucTSI0teAF/L2Lv0s6f6b7FOwcwIuA357bIE871580AjHJuSvLIRUosgV+lIWx6Rgg==} - engines: {node: '>=14.0.0'} - hasBin: true - requiresBuild: true - dependencies: - chokidar: 4.0.3 - immutable: 5.1.4 - source-map-js: 1.2.1 - optionalDependencies: - '@parcel/watcher': 2.5.1 - dev: true - optional: true - - /sass@1.94.2: - resolution: {integrity: sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A==} - engines: {node: '>=14.0.0'} - hasBin: true - dependencies: - chokidar: 4.0.3 - immutable: 5.1.4 - source-map-js: 1.2.1 - optionalDependencies: - '@parcel/watcher': 2.5.1 - dev: true - - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - dev: true - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true - - /send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - dev: false - - /send@0.19.1: - resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} - engines: {node: '>= 0.8.0'} - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - dev: false - - /serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - dev: false - - /set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - dev: true - - /set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - dev: true - - /set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} - dependencies: - dunder-proto: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - dev: true - - /setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - dev: false - - /shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} - dependencies: - shebang-regex: 1.0.0 - dev: true - - /shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} - dev: true - - /shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - dev: true - - /side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - /side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - /side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - /side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - /sockjs-client@1.6.1: - resolution: {integrity: sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==} - engines: {node: '>=12'} - dependencies: - debug: 3.2.7 - eventsource: 2.0.2 - faye-websocket: 0.11.4 - inherits: 2.0.4 - url-parse: 1.5.10 - transitivePeerDependencies: - - supports-color - dev: false - - /source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - /spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.22 - dev: true - - /spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - dev: true - - /spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.22 - dev: true - - /spdx-license-ids@3.0.22: - resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} - dev: true - - /statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - dev: false - - /statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - dev: false - - /stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 - dev: true - - /string.prototype.padend@3.1.6: - resolution: {integrity: sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - dev: true - - /string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-data-property: 1.1.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - has-property-descriptors: 1.0.2 - dev: true - - /string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - dev: true - - /string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - dev: true - - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: true - - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 - dev: true - - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true - - /sync-child-process@1.0.2: - resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} - engines: {node: '>=16.0.0'} - dependencies: - sync-message-port: 1.1.3 - dev: true - - /sync-message-port@1.1.3: - resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} - engines: {node: '>=16.0.0'} - dev: true - - /tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - dev: true - - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - requiresBuild: true - dependencies: - is-number: 7.0.0 - dev: true - optional: true - - /toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - dev: false - - /tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - dev: true - - /type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - dev: false - - /typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - dev: true - - /typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - dev: true - - /typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.10 - dev: true - - /typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 - dev: true - - /typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - /ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - dev: false - - /unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - has-bigints: 1.1.0 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.1 - dev: true - - /undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - dev: true - - /unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - dev: false - - /update-browserslist-db@1.2.2(browserslist@4.28.1): - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - dev: true - - /url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - dev: false - - /utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - dev: false - - /validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - dev: true - - /varint@6.0.0: - resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} - dev: true - - /vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - dev: false - - /vite@6.4.1(@types/node@20.19.25)(sass-embedded@1.93.3)(sass@1.94.2): - resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - dependencies: - '@types/node': 20.19.25 - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.3 - sass: 1.94.2 - sass-embedded: 1.93.3 - tinyglobby: 0.2.15 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /vue-demi@0.14.10(vue@3.5.25): - resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - peerDependencies: - '@vue/composition-api': ^1.0.0-rc.1 - vue: ^3.0.0-0 || ^2.6.0 - peerDependenciesMeta: - '@vue/composition-api': - optional: true - dependencies: - vue: 3.5.25(typescript@5.9.3) - dev: false - - /vue-router@4.6.3(vue@3.5.25): - resolution: {integrity: sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==} - peerDependencies: - vue: ^3.5.0 - dependencies: - '@vue/devtools-api': 6.6.4 - vue: 3.5.25(typescript@5.9.3) - dev: false - - /vue@3.5.25(typescript@5.9.3): - resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-sfc': 3.5.25 - '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25) - '@vue/shared': 3.5.25 - typescript: 5.9.3 - - /websocket-driver@0.7.4: - resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} - engines: {node: '>=0.8.0'} - dependencies: - http-parser-js: 0.5.10 - safe-buffer: 5.2.1 - websocket-extensions: 0.1.4 - dev: false - - /websocket-extensions@0.1.4: - resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} - engines: {node: '>=0.8.0'} - dev: false - - /which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - dev: true - - /which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} - dependencies: - call-bound: 1.0.4 - function.prototype.name: 1.1.8 - has-tostringtag: 1.0.2 - is-async-function: 2.1.1 - is-date-object: 1.1.0 - is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.2 - is-regex: 1.2.1 - is-weakref: 1.1.1 - isarray: 2.0.5 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.19 - dev: true - - /which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - dev: true - - /which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - dev: true - - /which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true diff --git a/urbanLifelineWeb/packages/shared/public/logo.jpg b/urbanLifelineWeb/packages/shared/public/logo.jpg deleted file mode 100644 index 18b5da66..00000000 Binary files a/urbanLifelineWeb/packages/shared/public/logo.jpg and /dev/null differ diff --git a/urbanLifelineWeb/packages/shared/src/App.vue b/urbanLifelineWeb/packages/shared/src/App.vue deleted file mode 100644 index 86f45417..00000000 --- a/urbanLifelineWeb/packages/shared/src/App.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/agent.ts b/urbanLifelineWeb/packages/shared/src/api/ai/agent.ts deleted file mode 100644 index d20e3a89..00000000 --- a/urbanLifelineWeb/packages/shared/src/api/ai/agent.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { api } from '@/api/index' -import type { ResultDomain, PageRequest } from '@/types' -import type { TbAgent } from '@/types/ai' - -/** - * @description 智能体管理接口 - * @filename agent.ts - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -export const agentAPI = { - baseUrl: '/urban-lifeline/ai/agent', - - /** - * 创建智能体 - * @param agent 智能体信息 - */ - async createAgent(agent: TbAgent): Promise> { - const response = await api.post(`${this.baseUrl}`, agent) - return response.data - }, - - /** - * 更新智能体 - * @param agent 智能体信息 - */ - async updateAgent(agent: TbAgent): Promise> { - const response = await api.put(`${this.baseUrl}`, agent) - return response.data - }, - - /** - * 删除智能体 - * @param agentId 智能体ID - */ - async deleteAgent(agentId: string): Promise> { - const response = await api.delete(`${this.baseUrl}/${agentId}`) - return response.data - }, - - /** - * 获取智能体详情 - * @param agentId 智能体ID - */ - async getAgent(agentId: string): Promise> { - const response = await api.get(`${this.baseUrl}/${agentId}`) - return response.data - }, - - /** - * 分页查询智能体 - * @param pageRequest 分页请求参数 - */ - async getAgentPage(pageRequest: PageRequest): Promise> { - const response = await api.post(`${this.baseUrl}/page`, pageRequest) - return response.data - }, - - /** - * 获取智能体列表 - * @param filter 筛选条件 - */ - async getAgentList(filter?: TbAgent): Promise> { - const response = await api.get(`${this.baseUrl}/list`, { params: filter }) - return response.data - } -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts b/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts deleted file mode 100644 index 791e10c4..00000000 --- a/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts +++ /dev/null @@ -1,287 +0,0 @@ -import { api } from '@/api/index' -import type { ResultDomain, PageRequest } from '@/types' -import type { TbKnowledge, TbKnowledgeFile, KnowledgeFileVO, SegmentRequestBody, DocumentStatusRequestBody, TbKnowledgeFileLog } from '@/types/ai' - -/** - * @description AI知识库相关接口 - * @filename aiKnowledge.ts - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -export const aiKnowledgeAPI = { - baseUrl: '/urban-lifeline/ai/knowledge', - - // ====================== 知识库管理 ====================== - - /** - * 创建知识库 - * @param knowledge 知识库信息 - */ - async createKnowledge(knowledge: TbKnowledge): Promise> { - const response = await api.post(`${this.baseUrl}`, knowledge) - return response.data - }, - - /** - * 更新知识库 - * @param knowledge 知识库信息 - */ - async updateKnowledge(knowledge: TbKnowledge): Promise> { - const response = await api.put(`${this.baseUrl}`, knowledge) - return response.data - }, - - /** - * 删除知识库 - * @param knowledgeId 知识库ID - */ - async deleteKnowledge(knowledgeId: string): Promise> { - const response = await api.delete(`${this.baseUrl}/${knowledgeId}`) - return response.data - }, - - /** - * 获取知识库详情 - * @param knowledgeId 知识库ID - */ - async getKnowledge(knowledgeId: string): Promise> { - const response = await api.get(`${this.baseUrl}/${knowledgeId}`) - return response.data - }, - - /** - * 查询知识库列表 - * @param filter 筛选条件 - */ - async listKnowledges(filter?: TbKnowledge): Promise> { - const response = await api.post(`${this.baseUrl}/list`, filter || {}) - return response.data - }, - - /** - * 分页查询知识库 - * @param pageRequest 分页请求 - */ - async pageKnowledges(pageRequest: PageRequest): Promise> { - const response = await api.post(`${this.baseUrl}/page`, pageRequest) - return response.data - }, - - /** - * 获取知识库统计信息 - * @param knowledgeId 知识库ID - */ - async getKnowledgeStats(knowledgeId: string): Promise> { - const response = await api.get(`${this.baseUrl}/${knowledgeId}/stats`) - return response.data - }, - - // ====================== 文件管理 ====================== - - /** - * 获取知识库文档列表(查询本地数据库文件) - * @param knowledgeId 知识库ID - * @param page 页码 - * @param pageSize 每页条数 - */ - async getDocumentList(knowledgeId: string, page = 1, pageSize = 20): Promise> { - const response = await api.post(`${this.baseUrl}/${knowledgeId}/documents`, { - filter: { knowledgeId }, - pageParam: { - page, - pageSize, - total: 0 - } - }) - return response.data - }, - - /** - * 上传文件到知识库 - * @param file 文件 - * @param knowledgeId 知识库ID - * @param indexingTechnique 索引方式 - */ - async uploadToKnowledge( - file: File, - knowledgeId: string, - indexingTechnique?: string - ): Promise> { - const formData = new FormData() - formData.append('file', file) - formData.append('knowledgeId', knowledgeId) - if (indexingTechnique) { - formData.append('indexingTechnique', indexingTechnique) - } - const response = await api.upload(`${this.baseUrl}/file/upload`, formData) - return response.data - }, - - /** - * 批量上传文件到知识库 - * @param files 文件数组 - * @param knowledgeId 知识库ID - * @param indexingTechnique 索引方式 - */ - async batchUploadToKnowledge( - files: File[], - knowledgeId: string, - indexingTechnique?: string - ): Promise> { - const formData = new FormData() - files.forEach(file => formData.append('files', file)) - formData.append('knowledgeId', knowledgeId) - if (indexingTechnique) { - formData.append('indexingTechnique', indexingTechnique) - } - const response = await api.upload(`${this.baseUrl}/file/batch-upload`, formData) - return response.data - }, - - /** - * 更新知识库文件(上传新版本) - * @param file 文件 - * @param knowledgeId 知识库ID - * @param fileRootId 文件根ID - */ - async updateFile( - file: File, - knowledgeId: string, - fileRootId: string - ): Promise> { - const formData = new FormData() - formData.append('file', file) - formData.append('knowledgeId', knowledgeId) - formData.append('fileRootId', fileRootId) - const response = await api.uploadPut(`${this.baseUrl}/file/upload`, formData) - return response.data - }, - - /** - * 删除知识库文件 - * @param fileId 文件ID - */ - async deleteFile(fileRootId: string): Promise> { - const response = await api.delete(`${this.baseUrl}/file/${fileRootId}`) - return response.data - }, - - /** - * 获取文件历史版本 - * @param fileRootId 文件根ID - */ - async getFileHistory(fileRootId: string): Promise> { - const response = await api.get(`${this.baseUrl}/file/${fileRootId}/history`) - return response.data - }, - - // ====================== 文档分段管理 ====================== - - /** - * 获取文档分段列表 - * @param datasetId Dify数据集ID - * @param documentId Dify文档ID - */ - async getDocumentSegments(datasetId: string, documentId: string): Promise>> { - const response = await api.get>( - `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}/segments` - ) - return response.data - }, - - /** - * 创建文档分段 - * @param datasetId Dify数据集ID - * @param documentId Dify文档ID - * @param requestBody 分段内容 - */ - async createSegment( - datasetId: string, - documentId: string, - requestBody: SegmentRequestBody - ): Promise> { - const response = await api.post( - `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}/segments`, - requestBody - ) - return response.data - }, - - /** - * 更新文档分段 - * @param datasetId Dify数据集ID - * @param documentId Dify文档ID - * @param segmentId 分段ID - * @param requestBody 分段内容 - */ - async updateSegment( - datasetId: string, - documentId: string, - segmentId: string, - requestBody: SegmentRequestBody - ): Promise> { - const response = await api.patch( - `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}/segments/${segmentId}`, - requestBody - ) - return response.data - }, - - /** - * 删除文档分段 - * @param datasetId Dify数据集ID - * @param documentId Dify文档ID - * @param segmentId 分段ID - */ - async deleteSegment( - datasetId: string, - documentId: string, - segmentId: string - ): Promise> { - const response = await api.delete( - `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}/segments/${segmentId}` - ) - return response.data - }, - - // ====================== 文档状态管理 ====================== - - /** - * 更新文档状态(启用/禁用/归档) - * @param datasetId Dify数据集ID - * @param action 操作类型: enable/disable/archive/un_archive - * @param requestBody 请求体 - */ - async updateDocumentStatus( - datasetId: string, - action: 'enable' | 'disable' | 'archive' | 'un_archive', - requestBody: DocumentStatusRequestBody - ): Promise> { - const response = await api.patch( - `${this.baseUrl}/datasets/${datasetId}/documents/${action}/status`, - requestBody - ) - return response.data - }, - - // ====================== 日志管理 ====================== - - /** - * 查询知识库操作日志列表 - * @param fileLog 查询条件 - */ - async getFileLogList(fileLog: TbKnowledgeFileLog): Promise> { - const response = await api.post(`${this.baseUrl}/datasets/log/list`, fileLog) - return response.data - }, - - /** - * 分页查询知识库操作日志 - * @param pageRequest 分页请求 - */ - async getFileLogPage(pageRequest: PageRequest): Promise> { - const response = await api.post(`${this.baseUrl}/datasets/log/page`, pageRequest) - return response.data - } -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/aichat.ts b/urbanLifelineWeb/packages/shared/src/api/ai/aichat.ts deleted file mode 100644 index c289ce7b..00000000 --- a/urbanLifelineWeb/packages/shared/src/api/ai/aichat.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { api } from '@/api/index' -import { API_BASE_URL } from '@/config' -import type { ResultDomain } from '@/types' -import type { TbChat, TbChatMessage, ChatPrepareData, StopChatParam, CommentMessageParam, DifyFileInfo } from '@/types/ai' - -/** - * @description AI对话相关接口 - * @filename aichat.ts - * @author yslg - * @copyright xyzh - * @since 2025-12-19 - */ -export const aiChatAPI = { - baseUrl: '/urban-lifeline/ai/chat', - - // ====================== 会话管理 ====================== - - /** - * 创建会话 - * @param chat 会话信息 - */ - async createChat(chat: TbChat): Promise> { - const response = await api.post(`${this.baseUrl}/conversation`, chat) - return response.data - }, - - /** - * 更新会话 - * @param chat 会话信息 - */ - async updateChat(chat: TbChat): Promise> { - const response = await api.put(`${this.baseUrl}/conversation`, chat) - return response.data - }, - - /** - * 删除会话 - * @param chat 会话信息 - */ - async deleteChat(chat: TbChat): Promise> { - const response = await api.delete(`${this.baseUrl}/conversation`, chat ) - return response.data - }, - - /** - * 获取会话列表 - * @param filter 筛选条件 - */ - async getChatList(filter: TbChat): Promise> { - const response = await api.post(`${this.baseUrl}/conversation/list`, filter) - return response.data - }, - - // ====================== 消息管理 ====================== - - /** - * 获取对话消息列表 - * @param filter 筛选条件 - */ - async getMessageList(filter: TbChat): Promise> { - const response = await api.post(`${this.baseUrl}/messages`, filter) - return response.data - }, - - // ====================== 流式对话 ====================== - - /** - * 准备流式对话会话数据 - * @param chatPrepareData 对话预处理数据 - */ - async prepareStreamChat(chatPrepareData: ChatPrepareData): Promise> { - const response = await api.post(`${this.baseUrl}/stream/prepare`, chatPrepareData) - return response.data - }, - - /** - * 获取流式对话SSE URL - * @param sessionId 会话ID - */ - getStreamChatUrl(sessionId: string): string { - return `${API_BASE_URL}${this.baseUrl}/stream?sessionId=${sessionId}` - }, - - /** - * 创建流式对话 EventSource - * @param sessionId 会话ID - */ - createStreamChat(sessionId: string): EventSource { - const url = this.getStreamChatUrl(sessionId) - return new EventSource(url) - }, - - /** - * 停止对话 - * @param params 停止参数 - */ - async stopChat(params: StopChatParam): Promise> { - const response = await api.post(`${this.baseUrl}/stop`, params) - return response.data - }, - - /** - * 评价消息 - * @param params 评价参数 - */ - async commentMessage(params: CommentMessageParam): Promise> { - const response = await api.post(`${this.baseUrl}/comment`, params) - return response.data - }, - - // ====================== 文件上传 ====================== - - /** - * 上传文件用于对话(图文多模态) - * @param file 文件 - * @param agentId 智能体ID - */ - async uploadFileForChat(file: File, agentId: string): Promise> { - const formData = new FormData() - formData.append('file', file) - formData.append('agentId', agentId) - const response = await api.upload(`${this.baseUrl}/file/upload`, formData) - return response.data - } -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/index.ts b/urbanLifelineWeb/packages/shared/src/api/ai/index.ts deleted file mode 100644 index 5a543c72..00000000 --- a/urbanLifelineWeb/packages/shared/src/api/ai/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './agent' -export * from './aichat' -export * from './aiKnowledge' diff --git a/urbanLifelineWeb/packages/shared/src/api/auth/auth.ts b/urbanLifelineWeb/packages/shared/src/api/auth/auth.ts deleted file mode 100644 index cb809ac6..00000000 --- a/urbanLifelineWeb/packages/shared/src/api/auth/auth.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { api } from '@/api/index' -import type { LoginParam, LoginDomain, ResultDomain } from '@/types' - - -/** - * 认证 API - * 通过 Gateway (8180) 访问 Auth Service (8181) - * 路由规则:/urban-lifeline/auth/** → auth-service/urban-lifeline/auth/** - */ -export const authAPI = { - baseUrl: "/urban-lifeline/auth", - - /** - * 用户登录 - * @param loginParam 登录参数 - * @returns 登录结果(包含 token 和用户信息) - */ - async login(loginParam: LoginParam): Promise> { - const response = await api.post(`${this.baseUrl}/login`, loginParam) - return response.data - }, - - /** - * 用户登出 - * @returns 登出结果 - */ - async logout(): Promise> { - const response = await api.post(`${this.baseUrl}/logout`) - return response.data - }, - - /** - * 获取验证码(统一接口) - * @param loginParam 登录参数(包含验证码类型) - * @returns 验证码结果 - */ - async getCaptcha(loginParam: LoginParam): Promise> { - const response = await api.post(`${this.baseUrl}/captcha`, loginParam) - return response.data - }, - - /** - * 刷新 Token - * @returns 新的登录信息 - */ - async refreshToken(): Promise> { - const response = await api.post(`${this.baseUrl}/refresh`) - return response.data - }, - - /** - * 发送邮箱验证码 - * @param email 邮箱地址 - * @returns 发送结果 - */ - async sendEmailCode(email: string): Promise> { - const response = await api.post(`${this.baseUrl}/send-email-code`, { email }) - return response.data - }, - - /** - * 发送短信验证码 - * @param phone 手机号 - * @returns 发送结果 - */ - async sendSmsCode(phone: string): Promise> { - const response = await api.post(`${this.baseUrl}/send-sms-code`, { phone }) - return response.data - }, - - /** - * 用户注册 - * @param registerData 注册数据 - * @returns 注册结果(成功后自动登录,返回 token) - */ - async register(registerData: { - registerType: 'username' | 'phone' | 'email' - username?: string - phone?: string - email?: string - password: string - confirmPassword: string - smsCode?: string - emailCode?: string - smsSessionId?: string - emailSessionId?: string - studentId?: string - }): Promise> { - const response = await api.post(`${this.baseUrl}/register`, registerData) - return response.data - }, - - /** - * 健康检查 - * @returns 健康状态 - */ - async health(): Promise> { - const response = await api.get(`${this.baseUrl}/health`) - return response.data - } -} diff --git a/urbanLifelineWeb/packages/shared/src/api/file/file.ts b/urbanLifelineWeb/packages/shared/src/api/file/file.ts deleted file mode 100644 index cc71e7ff..00000000 --- a/urbanLifelineWeb/packages/shared/src/api/file/file.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { api } from '@/api/index' -import { BatchFileUploadParam, FileUploadParam, ResultDomain, TbSysFileDTO } from '@/types'; - -export const fileAPI = { - baseUrl: "/urban-lifeline/file", - - /** - * 上传文件 - * @param param 文件上传参数 - * @returns Promise> - */ - async uploadFile(param: FileUploadParam): Promise> { - const formData = new FormData(); - formData.append('file', param.file); - if (param.module) { - formData.append('module', param.module); - } - if (param.optsn) { - formData.append('optsn', param.optsn); - } - if (param.uploader) { - formData.append('uploader', param.uploader); - } - // 显式传递原始文件名,确保后端保存正确的文件名 - if (param.file.name) { - formData.append('fileName', param.file.name); - } - const response = await api.upload(`${this.baseUrl}/upload`, formData); - return response.data; - }, - - /** - * 批量上传文件 - * @param param 批量文件上传参数 - * @returns Promise> - */ - async batchUploadFiles(param: BatchFileUploadParam): Promise> { - const formData = new FormData(); - param.files.forEach(file => { - formData.append('files', file); - }); - if (param.module) { - formData.append('module', param.module); - } - if (param.optsn) { - formData.append('optsn', param.optsn); - } - if (param.uploader) { - formData.append('uploader', param.uploader); - } - const response = await api.upload(`${this.baseUrl}/upload/batch`, formData); - return response.data; - }, - - /** - * 根据ID获取文件信息 - * @param fileId 文件ID - * @returns Promise> - */ - async getFileById(fileId: string): Promise> { - const response = await api.get(`${this.baseUrl}/${fileId}`); - return response.data; - }, - - /** - * 批量获取文件信息 - * @param fileIds 文件ID列表 - * @returns Promise> - */ - async getFilesByIds(fileIds: string[]): Promise> { - const response = await api.post(`${this.baseUrl}/list`, { fileIds }); - return response.data; - }, - - /** - * 下载文件 - * @param fileId 文件ID - * @param filename 保存的文件名(可选) - * @returns Promise - */ - async downloadFile(fileId: string, filename?: string): Promise { - return api.download(`${this.baseUrl}/download/${fileId}`, filename); - }, -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/api/index.ts b/urbanLifelineWeb/packages/shared/src/api/index.ts deleted file mode 100644 index ff20b825..00000000 --- a/urbanLifelineWeb/packages/shared/src/api/index.ts +++ /dev/null @@ -1,299 +0,0 @@ -import axios, { AxiosResponse, AxiosError, InternalAxiosRequestConfig } from "axios"; -import { ElLoading, ElMessage } from "element-plus"; -import type { ResultDomain } from "@/types"; -import { API_BASE_URL } from "@/config"; - -/** - * 扩展AxiosRequestConfig以支持自定义配置 - */ -interface CustomAxiosRequestConfig extends Partial { - /** 是否显示加载动画 */ - showLoading?: boolean; - /** 是否显示错误提示 */ - showError?: boolean; - /** 是否需要token */ - requiresAuth?: boolean; -} - -/** - * Token管理 - */ -export const TokenManager = { - /** 获取token(从localStorage获取并检查过期) */ - getToken(): string | null { - const itemStr = localStorage.getItem('token'); - if (!itemStr) return null; - - try { - const item = JSON.parse(itemStr); - const now = Date.now(); - - // 检查是否过期 - if (item.timestamp && item.expiresIn) { - if (now - item.timestamp > item.expiresIn) { - // 已过期,删除 - localStorage.removeItem('token'); - return null; - } - } - - return item.value || itemStr; // 兼容旧数据 - } catch { - // 如果不是JSON格式,直接返回(兼容旧数据) - return itemStr; - } - }, - - /** 设置token(始终使用localStorage,根据rememberMe设置过期时间) */ - setToken(token: string, rememberMe = false): void { - const data = { - value: token, - timestamp: Date.now(), - // 如果不勾选"记住我",设置1天过期时间;勾选则7天 - expiresIn: rememberMe ? 7 * 24 * 60 * 60 * 1000 : 1 * 24 * 60 * 60 * 1000 - }; - localStorage.setItem('token', JSON.stringify(data)); - }, - - /** 移除token */ - removeToken(): void { - localStorage.removeItem('token'); - }, - - /** 检查是否有token */ - hasToken(): boolean { - return !!this.getToken(); - } -}; - -/** - * 创建axios实例 - * - * 说明: - * - 统一使用配置模块提供的 API_BASE_URL 作为基础路径 - * - API_BASE_URL 在开发环境来自 devConfig,在生产环境来自 window.APP_RUNTIME_CONFIG - */ -const request = axios.create({ - baseURL: API_BASE_URL, - timeout: 30000, - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - } -}); - -let loadingInstance: ReturnType | null = null; - -/** - * 请求拦截器 - */ -request.interceptors.request.use( - (config: InternalAxiosRequestConfig) => { - const customConfig = config as CustomAxiosRequestConfig; - - // 默认不显示加载动画,只有 showLoading 为 true 时才展示 - if (customConfig.showLoading === true) { - loadingInstance = ElLoading.service({ - lock: true, - text: "加载中...", - background: "rgba(0, 0, 0, 0.7)", - }); - } - - // 添加token - const token = TokenManager.getToken(); - if (token && config.headers) { - config.headers.Authorization = `Bearer ${token}`; - } - - // 自动处理 FormData:删除 Content-Type,让浏览器自动设置(包含 boundary) - if (config.data instanceof FormData && config.headers) { - delete config.headers['Content-Type']; - } - - return config; - }, - (error: AxiosError) => { - if (loadingInstance) { - loadingInstance.close(); - loadingInstance = null; - } - return Promise.reject(error); - } -); - -/** - * 响应拦截器 - */ -request.interceptors.response.use( - (response: AxiosResponse>) => { - // 关闭加载动画 - if (loadingInstance) { - loadingInstance.close(); - loadingInstance = null; - } - - const result = response.data; - - // 检查是否为ResultDomain格式 - if (result && typeof result === 'object' && 'code' in result) { - // 检查登录状态 - if (result.login === false) { - ElMessage.error(result.message || '请先登录'); - TokenManager.removeToken(); - // 跳转到登录页 - window.location.href = '/login'; - return Promise.reject(new Error('未登录')); - } - - // 检查权限 - if (result.auth === false) { - ElMessage.error(result.message || '没有权限访问'); - return Promise.reject(new Error('无权限')); - } - - // // 检查业务逻辑是否成功 业务逻辑不应该提前判断 - // if (!result.success) { - // const config = response.config as CustomAxiosRequestConfig; - // if (config.showError !== false) { - // ElMessage.error(result.message || '操作失败'); - // } - // return Promise.reject(new Error(result.message || '操作失败')); - // } - - // 返回成功的数据 - return response; - } - - // 非ResultDomain格式,直接返回 - return response; - }, - (error: AxiosError>) => { - // 关闭加载动画 - if (loadingInstance) { - loadingInstance.close(); - loadingInstance = null; - } - - const config = error.config as CustomAxiosRequestConfig; - - // 处理HTTP错误 - if (error.response) { - const { status, data } = error.response; - - switch (status) { - case 401: - ElMessage.error('认证失败,请重新登录'); - TokenManager.removeToken(); - window.location.href = '/login'; - break; - case 403: - ElMessage.error('没有权限访问该资源'); - break; - case 404: - ElMessage.error('请求的资源不存在'); - break; - case 500: - ElMessage.error(data?.message || '服务器内部错误'); - break; - default: - if (config?.showError !== false) { - ElMessage.error(data?.message || '请求失败'); - } - } - } else if (error.request) { - // 请求已发送但没有收到响应 - ElMessage.error('网络错误,请检查网络连接'); - } else { - // 其他错误 - if (config?.showError !== false) { - ElMessage.error(error.message || '请求失败'); - } - } - - return Promise.reject(error); - } -); - -/** - * API封装 - */ -export const api = { - /** - * GET请求 - data参数会作为URL查询参数追加 - */ - get(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise>> { - // 如果有data参数,将其转换为URL查询参数 - if (data) { - const params = new URLSearchParams(); - Object.keys(data).forEach(key => { - if (data[key] !== undefined && data[key] !== null) { - params.append(key, String(data[key])); - } - }); - const queryString = params.toString(); - url += (url.includes('?') ? '&' : '?') + queryString; - } - return request.get>(url, config); - }, - - /** - * POST请求 - data参数放到请求体 - */ - post(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise>> { - return request.post>(url, data, config); - }, - - /** - * PUT请求 - data参数放到请求体 - */ - put(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise>> { - return request.put>(url, data, config); - }, - - /** - * DELETE请求 - data参数放到请求体 - */ - delete(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise>> { - return request.delete>(url, { ...config, data }); - }, - - /** - * PATCH请求 - data参数放到请求体 - */ - patch(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise>> { - return request.patch>(url, data, config); - }, - - /** - * 文件上传 (POST) - 使用 axios postForm - */ - upload(url: string, formData: FormData, config?: CustomAxiosRequestConfig): Promise>> { - return request.postForm>(url, formData, config); - }, - - /** - * 文件上传 (PUT) - 使用 axios putForm - */ - uploadPut(url: string, formData: FormData, config?: CustomAxiosRequestConfig): Promise>> { - return request.putForm>(url, formData, config); - }, - - /** - * 文件下载 - */ - download(url: string, filename?: string, config?: CustomAxiosRequestConfig): Promise { - return request.get(url, { - ...config, - responseType: 'blob' - }).then((response) => { - const blob = new Blob([response.data]); - const link = document.createElement('a'); - link.href = window.URL.createObjectURL(blob); - link.download = filename || 'download'; - link.click(); - window.URL.revokeObjectURL(link.href); - }); - } -}; - -export default request; \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/api/sys/guest.ts b/urbanLifelineWeb/packages/shared/src/api/sys/guest.ts deleted file mode 100644 index 756fe422..00000000 --- a/urbanLifelineWeb/packages/shared/src/api/sys/guest.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { api } from '@/api/index' -import type { TbGuestDTO } from '@/types/sys/guest' -import type { LoginParam, LoginDomain } from '@/types/auth/auth' -import type { ResultDomain, PageRequest } from '@/types' - -/** - * 来客 API - * 通过 Gateway (8180) 访问 System Service - * 路由规则:/urban-lifeline/system/** → system-service - */ -export const guestAPI = { - baseUrl: '/urban-lifeline/system/guest', - - /** - * 创建来客 - */ - async createGuest(guest: TbGuestDTO): Promise> { - const response = await api.post(`${this.baseUrl}`, guest) - return response.data - }, - - /** - * 更新来客 - */ - async updateGuest(guest: TbGuestDTO): Promise> { - const response = await api.put(`${this.baseUrl}`, guest) - return response.data - }, - - /** - * 删除来客 - */ - async deleteGuest(userId: string): Promise> { - const response = await api.delete(`${this.baseUrl}`, { params: { userId } }) - return response.data - }, - - /** - * 根据微信ID查询来客 - */ - async selectGuestByWechat(wechatId: string): Promise> { - const response = await api.get(`${this.baseUrl}/wechat/${wechatId}`) - return response.data - }, - - /** - * 获取来客列表 - */ - async listGuest(filter?: TbGuestDTO): Promise> { - const response = await api.post(`${this.baseUrl}/list`, { params: filter }) - return response.data - }, - - /** - * 分页查询来客 - */ - async pageGuest(pageRequest: PageRequest): Promise> { - const response = await api.post(`${this.baseUrl}/page`, pageRequest) - return response.data - }, - - /** - * 微信小程序用户识别登录 - * 优先尝试员工登录,失败则自动注册/查询来客 - * @param loginParam 登录参数(wechatId或phone必填) - * @returns LoginDomain 包含用户信息和token - */ - async identify(loginParam: LoginParam): Promise> { - const response = await api.post(`${this.baseUrl}/identify`, loginParam) - return response.data - } -} diff --git a/urbanLifelineWeb/packages/shared/src/components/ai/index.ts b/urbanLifelineWeb/packages/shared/src/components/ai/index.ts deleted file mode 100644 index 3f648724..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/ai/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './knowledge' \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentDetail/DocumentDetail.scss b/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentDetail/DocumentDetail.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentDetail/DocumentDetail.vue b/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentDetail/DocumentDetail.vue deleted file mode 100644 index a9125f35..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentDetail/DocumentDetail.vue +++ /dev/null @@ -1,12 +0,0 @@ - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentSegment/DocumentSegment.scss b/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentSegment/DocumentSegment.scss deleted file mode 100644 index fd499675..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentSegment/DocumentSegment.scss +++ /dev/null @@ -1,172 +0,0 @@ -// 文档分段组件样式 - 去掉 scoped 以支持 Module Federation -.segment-dialog { - :deep(.el-dialog) { - border-radius: 14px; - - .el-dialog__header { - padding: 24px 24px 16px; - border-bottom: 1px solid #F3F3F5; - - .el-dialog__title { - font-size: 18px; - font-weight: 500; - color: #101828; - } - } - - .el-dialog__body { - padding: 24px; - background: #FAFAFA; - } - - .el-dialog__footer { - padding: 16px 24px; - border-top: 1px solid #F3F3F5; - } - } -} - -.top-actions { - display: flex; - justify-content: flex-end; - align-items: center; - margin-bottom: 10px; - padding: 8px 20px; - background: #FFFFFF; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 14px; - - .action-buttons { - display: flex; - gap: 12px; - } -} - -.segment-list { - max-height: 520px; - overflow-y: auto; - padding-right: 4px; - - &::-webkit-scrollbar { width: 6px; } - &::-webkit-scrollbar-track { background: transparent; } - &::-webkit-scrollbar-thumb { - background: #D1D5DB; - border-radius: 3px; - &:hover { background: #9CA3AF; } - } - - .segment-item { - background: #FFFFFF; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 14px; - padding: 16px; - margin-bottom: 12px; - transition: all 0.2s; - - &:hover { - border-color: #409eff; - box-shadow: 0 4px 12px rgba(64, 158, 255, 0.12); - } - - &:last-child { margin-bottom: 0; } - } - - .segment-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 12px; - gap: 12px; - - .segment-index { - font-weight: 500; - color: #101828; - font-size: 14px; - white-space: nowrap; - } - - .segment-info { - flex: 1; - font-size: 12px; - color: #6A7282; - white-space: nowrap; - } - - .segment-actions { - display: flex; - align-items: center; - gap: 8px; - flex-wrap: wrap; - } - } - - .segment-content { - margin-bottom: 12px; - - .segment-text { - padding: 12px; - background: #F9FAFB; - border: 1px solid transparent; - border-radius: 8px; - line-height: 1.6; - color: #4A5565; - font-size: 14px; - white-space: pre-wrap; - word-break: break-word; - } - } - - .segment-keywords { - margin-top: 12px; - display: flex; - flex-wrap: wrap; - gap: 8px; - - :deep(.el-tag) { - background: #EFF6FF; - border: 1px solid transparent; - border-radius: 8px; - color: #1447E6; - font-size: 12px; - padding: 2px 8px; - height: 24px; - line-height: 20px; - } - } - - .segment-meta { - margin-top: 12px; - display: flex; - flex-wrap: wrap; - gap: 16px; - padding-top: 12px; - border-top: 1px solid rgba(0, 0, 0, 0.06); - - .meta-item { - display: flex; - align-items: center; - gap: 6px; - font-size: 13px; - color: #667085; - - .el-icon { - font-size: 14px; - color: #9CA3AF; - } - } - } - - .empty-state { - text-align: center; - padding: 80px 20px; - background: #FFFFFF; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 14px; - - p { - font-size: 14px; - color: #6A7282; - margin: 0; - } - } -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentSegment/DocumentSegment.vue b/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentSegment/DocumentSegment.vue deleted file mode 100644 index 5ff8ccf8..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/documentSegment/DocumentSegment.vue +++ /dev/null @@ -1,501 +0,0 @@ - - - - - diff --git a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/index.ts b/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/index.ts deleted file mode 100644 index 782bc94a..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/ai/knowledge/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as DocumentSegment } from './documentSegment/DocumentSegment.vue' -export { default as DocumentDetail } from './documentDetail/DocumentDetail.vue' \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/base/index.ts b/urbanLifelineWeb/packages/shared/src/components/base/index.ts deleted file mode 100644 index fb5deb23..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/base/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Base components placeholder -export {}; \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItem.scss b/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItem.scss deleted file mode 100644 index 6adaf953..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItem.scss +++ /dev/null @@ -1,180 +0,0 @@ -.dynamic-component { - width: 100%; - - // Element Plus 表单项适配 - :deep(.el-form-item) { - margin-bottom: 18px; - - .el-form-item__label { - font-weight: 500; - color: #606266; - font-size: 14px; - } - - .el-form-item__content { - .el-input, - .el-select, - .el-date-editor, - .el-time-picker, - .el-cascader, - .el-tree-select { - width: 100%; - } - - // 数字输入框 - .el-input-number { - width: 100%; - - .el-input__wrapper { - width: 100%; - } - } - - // 复选框组和单选框组 - .el-checkbox-group, - .el-radio-group { - display: flex; - flex-wrap: wrap; - gap: 16px; - - .el-checkbox, - .el-radio { - margin-right: 0; - } - } - - // 开关组件 - .el-switch { - .el-switch__label { - font-size: 14px; - color: #606266; - } - } - - // 滑块组件 - .el-slider { - .el-slider__input { - width: 130px; - } - } - - // 评分组件 - .el-rate { - display: flex; - align-items: center; - - .el-rate__text { - margin-left: 8px; - font-size: 14px; - color: #606266; - } - } - - // 颜色选择器 - .el-color-picker { - .el-color-picker__trigger { - border: 1px solid #dcdfe6; - border-radius: 4px; - - &:hover { - border-color: #c0c4cc; - } - } - } - - // 上传组件 - .el-upload { - &.upload-demo { - .el-upload__tip { - margin-top: 8px; - font-size: 12px; - color: #909399; - } - } - } - - // 级联选择器 - .el-cascader { - .el-cascader__tags { - max-width: 100%; - } - } - - // 树形选择 - .el-tree-select { - .el-tree-select__tags { - max-width: 100%; - } - } - } - - // 错误状态样式 - &.is-error { - .el-input__wrapper, - .el-select__wrapper, - .el-date-editor, - .el-cascader__wrapper, - .el-tree-select__wrapper { - box-shadow: 0 0 0 1px #f56565 inset; - } - } - - // 必填标记 - &.is-required { - .el-form-item__label::before { - content: '*'; - color: #f56565; - margin-right: 4px; - } - } - } - - // 描述信息图标 - .description-icon { - margin-left: 4px; - color: #909399; - cursor: help; - font-size: 14px; - - &:hover { - color: #409eff; - } - } - - // 自定义样式调整 - .el-form-item__content { - // 确保组件占满宽度 - .el-input, - .el-select, - .el-date-editor, - .el-cascader, - .el-tree-select { - width: 100% !important; - } - - // 日期范围选择器特殊处理 - .el-date-editor--daterange, - .el-date-editor--datetimerange { - width: 100% !important; - } - - // 多选标签折叠样式 - .el-tag { - margin-right: 6px; - margin-bottom: 4px; - } - } - - // 响应式设计 - @media (max-width: 768px) { - :deep(.el-form-item) { - .el-form-item__content { - .el-checkbox-group, - .el-radio-group { - flex-direction: column; - gap: 12px; - } - } - } - } -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItem.vue b/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItem.vue deleted file mode 100644 index ea74a24c..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItem.vue +++ /dev/null @@ -1,581 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItemExample.vue b/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItemExample.vue deleted file mode 100644 index 9f869160..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/DynamicFormItemExample.vue +++ /dev/null @@ -1,400 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/index.ts b/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/index.ts deleted file mode 100644 index 157fea08..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/dynamicFormItem/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DynamicFormItem } from './DynamicFormItem.vue' diff --git a/urbanLifelineWeb/packages/shared/src/components/file/fileHistory/FileHistory.scss b/urbanLifelineWeb/packages/shared/src/components/file/fileHistory/FileHistory.scss deleted file mode 100644 index c27cb160..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/file/fileHistory/FileHistory.scss +++ /dev/null @@ -1,33 +0,0 @@ -.file-history-dialog { - .el-dialog__body { - padding: 16px 20px; - } - - .file-history-table { - width: 100%; - - .file-name-cell { - display: flex; - align-items: center; - gap: 8px; - - .file-icon { - color: #409eff; - font-size: 16px; - } - } - } - - .action-buttons { - display: flex !important; - flex-direction: column !important; - align-items: center !important; - justify-content: center !important; - // gap: 4px; - // width: 100%; - - .el-button { - margin: 0 !important; - } - } -} diff --git a/urbanLifelineWeb/packages/shared/src/components/file/fileHistory/FileHistory.vue b/urbanLifelineWeb/packages/shared/src/components/file/fileHistory/FileHistory.vue deleted file mode 100644 index 83407345..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/file/fileHistory/FileHistory.vue +++ /dev/null @@ -1,155 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUpload.scss b/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUpload.scss deleted file mode 100644 index ec9b4d5f..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUpload.scss +++ /dev/null @@ -1,365 +0,0 @@ -// 文件上传组件 - 精简版样式 -.file-upload { - display: inline-block; - width: 100%; - - // 封面模式 - &.cover { - width: 300px; - height: 200px; - - .image-wrapper { - position: relative; - width: 300px; - height: 200px; - border-radius: 6px; - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - background: #f5f7fa; - - &:hover .actions { - opacity: 1; - } - - .image { - display: block; - object-fit: contain; - max-width: 100%; - max-height: 100%; - - &.horizontal { - width: 100%; - height: auto; - } - - &.vertical { - height: 100%; - width: auto; - } - } - - .actions { - position: absolute; - top: 8px; - right: 8px; - opacity: 0; - transition: opacity 0.3s; - } - } - } - - // 弹窗模式 - &.dialog { - .dialog-content { - padding: 0; - } - - .dialog-footer { - display: flex; - gap: 12px; - justify-content: flex-end; - } - } - - // 内容模式 - &.content { - display: block; - } - - // 通用容器 - .container { - padding: 20px 0; - } - - // 上传区域 - .area { - border: 2px dashed #dcdfe6; - border-radius: 8px; - padding: 60px 20px; - text-align: center; - cursor: pointer; - transition: all 0.3s; - background: #fafafa; - min-height: 160px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - position: relative; - - // 封面模式特殊样式 - &.cover { - border: 1px dashed #d9d9d9; - border-radius: 6px; - background: #ffffff; - padding: 30px 20px; - - &:hover { - box-shadow: 0 4px 12px rgba(64, 158, 255, 0.1); - transform: translateY(-2px); - - .icon { - transform: scale(1.1); - } - } - } - - &:hover { - border-color: #409eff; - background: #f0f9ff; - - .icon .plus { - - &::before, - &::after { - background-color: #409eff; - } - } - - .text { - color: #409eff; - } - } - - &.dragover { - border-color: #409eff; - background: #e6f7ff; - border-style: solid; - } - - &.disabled { - cursor: not-allowed; - opacity: 0.6; - } - } - - // 内容区域 - .content { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - width: 100%; - } - - // 图标 - .icon { - margin-bottom: 16px; - transition: all 0.3s; - - .plus { - width: 80px; - height: 80px; - position: relative; - margin: 0 auto; - - &::before, - &::after { - content: ''; - position: absolute; - background-color: #c0c4cc; - transition: all 0.3s; - } - - // 竖线 - &::before { - width: 2px; - height: 80px; - left: 50%; - top: 0; - transform: translateX(-50%); - } - - // 横线 - &::after { - width: 80px; - height: 2px; - left: 0; - top: 50%; - transform: translateY(-50%); - } - } - } - - // 封面模式的小图标 - &.cover .icon .plus { - width: 48px; - height: 48px; - - &::before { - width: 1px; - height: 48px; - } - - &::after { - width: 48px; - height: 1px; - } - } - - // 文字 - .text { - color: #606266; - font-size: 16px; - margin-bottom: 8px; - font-weight: 500; - transition: color 0.3s; - - .link { - color: #409eff; - cursor: pointer; - text-decoration: underline; - } - } - - // 提示 - .tip { - color: #909399; - font-size: 13px; - line-height: 1.5; - max-width: 240px; - } - - // 加载状态 - .loading { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(255, 255, 255, 0.9); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - - .spinner { - font-size: 32px; - color: #409eff; - margin-bottom: 8px; - animation: rotate 1s linear infinite; - } - - div { - font-size: 14px; - color: #606266; - } - } - - // 文件列表 - .files { - margin-top: 20px; - - h4 { - margin: 0 0 12px 0; - font-size: 14px; - font-weight: 600; - color: #374151; - } - } - - // 单个文件 - .file { - display: flex; - align-items: center; - gap: 12px; - padding: 12px; - background-color: #f8fafc; - border-radius: 6px; - margin-bottom: 8px; - transition: background-color 0.2s ease; - - &:hover { - background-color: #e2e8f0; - } - - .preview { - width: 60px; - height: 60px; - border-radius: 4px; - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - background: #f5f7fa; - flex-shrink: 0; - - .thumb { - width: 100%; - height: 100%; - object-fit: cover; - } - - .type-icon { - font-size: 24px; - } - } - - .info { - flex: 1; - min-width: 0; - - .name { - font-size: 14px; - font-weight: 500; - color: #1e293b; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-bottom: 4px; - } - - .size { - font-size: 12px; - color: #64748b; - } - } - - .actions { - display: flex; - gap: 8px; - } - } - - // 操作按钮区域 - .actions { - margin-top: 16px; - text-align: center; - - &:not(.file .actions) { - display: flex; - gap: 12px; - justify-content: center; - } - } -} - -// 动画 -@keyframes rotate { - from { - transform: rotate(0deg); - } - - to { - transform: rotate(360deg); - } -} - -// 响应式设计 -@media (max-width: 768px) { - .file-upload { - &.dialog .modal { - margin: 16px; - padding: 20px; - width: calc(100% - 32px); - } - - .area.cover { - width: 250px; - height: 160px; - } - } -} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUpload.vue b/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUpload.vue deleted file mode 100644 index c6eb689e..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUpload.vue +++ /dev/null @@ -1,579 +0,0 @@ - - - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUploadExample.vue b/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUploadExample.vue deleted file mode 100644 index 9a77b25d..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/file/fileupload/FileUploadExample.vue +++ /dev/null @@ -1,312 +0,0 @@ - - - \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/file/index.ts b/urbanLifelineWeb/packages/shared/src/components/file/index.ts deleted file mode 100644 index d1f2c430..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/file/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as FileUpload } from './fileupload/FileUpload.vue' -export { default as FileHistory } from './fileHistory/FileHistory.vue' \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/components/iframe/IframeView.scss b/urbanLifelineWeb/packages/shared/src/components/iframe/IframeView.scss deleted file mode 100644 index d5cfc06d..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/iframe/IframeView.scss +++ /dev/null @@ -1,75 +0,0 @@ -// IframeView 组件样式 -.iframe-view { - position: relative; - width: 100%; - height: 100%; - overflow: hidden; - display: flex; - flex-direction: column; - - .iframe-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 12px 16px; - background: var(--el-bg-color); - border-bottom: 1px solid var(--el-border-color-light); - flex-shrink: 0; - - .iframe-title { - font-size: 16px; - font-weight: 500; - color: var(--el-text-color-primary); - } - } - - .iframe-content { - width: 100%; - height: 100%; - border: none; - flex: 1; - - &.with-header { - height: calc(100% - 49px); - } - } - - .iframe-error { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - color: var(--el-text-color-secondary); - - .error-icon { - font-size: 48px; - margin-bottom: 16px; - color: var(--el-color-warning); - } - } - - .iframe-loading { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - background: var(--el-bg-color); - gap: 12px; - - .is-loading { - animation: iframe-rotating 1.5s linear infinite; - color: var(--el-color-primary); - } - } -} - -@keyframes iframe-rotating { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} diff --git a/urbanLifelineWeb/packages/shared/src/components/iframe/IframeView.vue b/urbanLifelineWeb/packages/shared/src/components/iframe/IframeView.vue deleted file mode 100644 index 0234e8c1..00000000 --- a/urbanLifelineWeb/packages/shared/src/components/iframe/IframeView.vue +++ /dev/null @@ -1,146 +0,0 @@ -